1 | /* |
---|
2 | Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. |
---|
3 | |
---|
4 | |
---|
5 | The MySQL Connector/J is licensed under the terms of the GPLv2 |
---|
6 | <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors. |
---|
7 | There are special exceptions to the terms and conditions of the GPLv2 as it is applied to |
---|
8 | this software, see the FLOSS License Exception |
---|
9 | <http://www.mysql.com/about/legal/licensing/foss-exception.html>. |
---|
10 | |
---|
11 | This program is free software; you can redistribute it and/or modify it under the terms |
---|
12 | of the GNU General Public License as published by the Free Software Foundation; version 2 |
---|
13 | of the License. |
---|
14 | |
---|
15 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; |
---|
16 | without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
---|
17 | See the GNU General Public License for more details. |
---|
18 | |
---|
19 | You should have received a copy of the GNU General Public License along with this |
---|
20 | program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth |
---|
21 | Floor, Boston, MA 02110-1301 USA |
---|
22 | |
---|
23 | */ |
---|
24 | package com.mysql.jdbc; |
---|
25 | |
---|
26 | import java.io.InputStream; |
---|
27 | import java.io.Reader; |
---|
28 | import java.sql.Date; |
---|
29 | import java.sql.SQLException; |
---|
30 | import java.sql.SQLWarning; |
---|
31 | import java.sql.Time; |
---|
32 | import java.sql.Timestamp; |
---|
33 | import java.sql.Types; |
---|
34 | import java.util.Calendar; |
---|
35 | import java.util.StringTokenizer; |
---|
36 | import java.util.TimeZone; |
---|
37 | |
---|
38 | /** |
---|
39 | * Classes that implement this interface represent one row of data from the |
---|
40 | * MySQL server that might be stored in different ways depending on whether the |
---|
41 | * result set was streaming (so they wrap a reusable packet), or whether the |
---|
42 | * result set was cached or via a server-side cursor (so they represent a |
---|
43 | * byte[][]). |
---|
44 | * |
---|
45 | * Notice that <strong>no</strong> bounds checking is expected for implementors |
---|
46 | * of this interface, it happens in ResultSetImpl. |
---|
47 | * |
---|
48 | * @version $Id: $ |
---|
49 | */ |
---|
50 | public abstract class ResultSetRow { |
---|
51 | protected ExceptionInterceptor exceptionInterceptor; |
---|
52 | |
---|
53 | protected ResultSetRow(ExceptionInterceptor exceptionInterceptor) { |
---|
54 | this.exceptionInterceptor = exceptionInterceptor; |
---|
55 | } |
---|
56 | |
---|
57 | /** |
---|
58 | * The metadata of the fields of this result set. |
---|
59 | */ |
---|
60 | protected Field[] metadata; |
---|
61 | |
---|
62 | /** |
---|
63 | * Called during navigation to next row to close all open |
---|
64 | * streams. |
---|
65 | */ |
---|
66 | public abstract void closeOpenStreams(); |
---|
67 | |
---|
68 | /** |
---|
69 | * Returns data at the given index as an InputStream with no |
---|
70 | * character conversion. |
---|
71 | * |
---|
72 | * @param columnIndex |
---|
73 | * of the column value (starting at 0) to return. |
---|
74 | * @return the value at the given index as an InputStream or null |
---|
75 | * if null. |
---|
76 | * |
---|
77 | * @throws SQLException if an error occurs while retrieving the value. |
---|
78 | */ |
---|
79 | public abstract InputStream getBinaryInputStream(int columnIndex) |
---|
80 | throws SQLException; |
---|
81 | |
---|
82 | /** |
---|
83 | * Returns the value at the given column (index starts at 0) "raw" (i.e. |
---|
84 | * as-returned by the server). |
---|
85 | * |
---|
86 | * @param index |
---|
87 | * of the column value (starting at 0) to return. |
---|
88 | * @return the value for the given column (including NULL if it is) |
---|
89 | * @throws SQLException |
---|
90 | * if an error occurs while retrieving the value. |
---|
91 | */ |
---|
92 | public abstract byte[] getColumnValue(int index) throws SQLException; |
---|
93 | |
---|
94 | protected final java.sql.Date getDateFast(int columnIndex, |
---|
95 | byte[] dateAsBytes, int offset, int length, MySQLConnection conn, |
---|
96 | ResultSetImpl rs, Calendar targetCalendar) throws SQLException { |
---|
97 | |
---|
98 | int year = 0; |
---|
99 | int month = 0; |
---|
100 | int day = 0; |
---|
101 | |
---|
102 | try { |
---|
103 | if (dateAsBytes == null) { |
---|
104 | return null; |
---|
105 | } |
---|
106 | |
---|
107 | boolean allZeroDate = true; |
---|
108 | |
---|
109 | boolean onlyTimePresent = false; |
---|
110 | |
---|
111 | for (int i = 0; i < length; i++) { |
---|
112 | if (dateAsBytes[offset + i] == ':') { |
---|
113 | onlyTimePresent = true; |
---|
114 | break; |
---|
115 | } |
---|
116 | } |
---|
117 | |
---|
118 | for (int i = 0; i < length; i++) { |
---|
119 | byte b = dateAsBytes[offset + i]; |
---|
120 | |
---|
121 | if (b == ' ' || b == '-' || b == '/') { |
---|
122 | onlyTimePresent = false; |
---|
123 | } |
---|
124 | |
---|
125 | if (b != '0' && b != ' ' && b != ':' && b != '-' && b != '/' |
---|
126 | && b != '.') { |
---|
127 | allZeroDate = false; |
---|
128 | |
---|
129 | break; |
---|
130 | } |
---|
131 | } |
---|
132 | |
---|
133 | if (!onlyTimePresent && allZeroDate) { |
---|
134 | |
---|
135 | if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL |
---|
136 | .equals(conn.getZeroDateTimeBehavior())) { |
---|
137 | |
---|
138 | return null; |
---|
139 | } else if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_EXCEPTION |
---|
140 | .equals(conn.getZeroDateTimeBehavior())) { |
---|
141 | throw SQLError.createSQLException("Value '" |
---|
142 | + StringUtils.toString(dateAsBytes) |
---|
143 | + "' can not be represented as java.sql.Date", |
---|
144 | SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor); |
---|
145 | } |
---|
146 | |
---|
147 | // We're left with the case of 'round' to a date Java _can_ |
---|
148 | // represent, which is '0001-01-01'. |
---|
149 | return rs.fastDateCreate(targetCalendar, 1, 1, 1); |
---|
150 | |
---|
151 | } else if (this.metadata[columnIndex].getMysqlType() == MysqlDefs.FIELD_TYPE_TIMESTAMP) { |
---|
152 | // Convert from TIMESTAMP |
---|
153 | switch (length) { |
---|
154 | case 29: |
---|
155 | case 21: |
---|
156 | case 19: { // java.sql.Timestamp format |
---|
157 | year = StringUtils.getInt(dateAsBytes, offset + 0, |
---|
158 | offset + 4); |
---|
159 | month = StringUtils.getInt(dateAsBytes, offset + 5, |
---|
160 | offset + 7); |
---|
161 | day = StringUtils.getInt(dateAsBytes, offset + 8, |
---|
162 | offset + 10); |
---|
163 | |
---|
164 | return rs.fastDateCreate(targetCalendar, year, month, day); |
---|
165 | } |
---|
166 | |
---|
167 | case 14: |
---|
168 | case 8: { |
---|
169 | year = StringUtils.getInt(dateAsBytes, offset + 0, |
---|
170 | offset + 4); |
---|
171 | month = StringUtils.getInt(dateAsBytes, offset + 4, |
---|
172 | offset + 6); |
---|
173 | day = StringUtils.getInt(dateAsBytes, offset + 6, |
---|
174 | offset + 8); |
---|
175 | |
---|
176 | return rs.fastDateCreate(targetCalendar, year, month, day); |
---|
177 | } |
---|
178 | |
---|
179 | case 12: |
---|
180 | case 10: |
---|
181 | case 6: { |
---|
182 | year = StringUtils.getInt(dateAsBytes, offset + 0, |
---|
183 | offset + 2); |
---|
184 | |
---|
185 | if (year <= 69) { |
---|
186 | year = year + 100; |
---|
187 | } |
---|
188 | |
---|
189 | month = StringUtils.getInt(dateAsBytes, offset + 2, |
---|
190 | offset + 4); |
---|
191 | day = StringUtils.getInt(dateAsBytes, offset + 4, |
---|
192 | offset + 6); |
---|
193 | |
---|
194 | return rs.fastDateCreate(targetCalendar, year + 1900, month, day); |
---|
195 | } |
---|
196 | |
---|
197 | case 4: { |
---|
198 | year = StringUtils.getInt(dateAsBytes, offset + 0, |
---|
199 | offset + 4); |
---|
200 | |
---|
201 | if (year <= 69) { |
---|
202 | year = year + 100; |
---|
203 | } |
---|
204 | |
---|
205 | month = StringUtils.getInt(dateAsBytes, offset + 2, |
---|
206 | offset + 4); |
---|
207 | |
---|
208 | return rs.fastDateCreate(targetCalendar, year + 1900, month, 1); |
---|
209 | } |
---|
210 | |
---|
211 | case 2: { |
---|
212 | year = StringUtils.getInt(dateAsBytes, offset + 0, |
---|
213 | offset + 2); |
---|
214 | |
---|
215 | if (year <= 69) { |
---|
216 | year = year + 100; |
---|
217 | } |
---|
218 | |
---|
219 | return rs.fastDateCreate(targetCalendar, year + 1900, 1, 1); |
---|
220 | } |
---|
221 | |
---|
222 | default: |
---|
223 | throw SQLError |
---|
224 | .createSQLException( |
---|
225 | Messages |
---|
226 | .getString( |
---|
227 | "ResultSet.Bad_format_for_Date", |
---|
228 | new Object[] { |
---|
229 | StringUtils.toString( |
---|
230 | dateAsBytes), |
---|
231 | Integer.valueOf(columnIndex + 1) }), |
---|
232 | SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor); //$NON-NLS-1$ |
---|
233 | } /* endswitch */ |
---|
234 | } else if (this.metadata[columnIndex].getMysqlType() == MysqlDefs.FIELD_TYPE_YEAR) { |
---|
235 | |
---|
236 | if (length == 2 || length == 1) { |
---|
237 | year = StringUtils.getInt(dateAsBytes, offset, offset |
---|
238 | + length); |
---|
239 | |
---|
240 | if (year <= 69) { |
---|
241 | year = year + 100; |
---|
242 | } |
---|
243 | |
---|
244 | year += 1900; |
---|
245 | } else { |
---|
246 | year = StringUtils.getInt(dateAsBytes, offset + 0, |
---|
247 | offset + 4); |
---|
248 | } |
---|
249 | |
---|
250 | return rs.fastDateCreate(targetCalendar, year, 1, 1); |
---|
251 | } else if (this.metadata[columnIndex].getMysqlType() == MysqlDefs.FIELD_TYPE_TIME) { |
---|
252 | return rs.fastDateCreate(targetCalendar, 1970, 1, 1); // Return EPOCH |
---|
253 | } else { |
---|
254 | if (length < 10) { |
---|
255 | if (length == 8) { |
---|
256 | return rs.fastDateCreate(targetCalendar, 1970, 1, 1); // Return |
---|
257 | // EPOCH for |
---|
258 | // TIME |
---|
259 | } |
---|
260 | |
---|
261 | throw SQLError |
---|
262 | .createSQLException( |
---|
263 | Messages |
---|
264 | .getString( |
---|
265 | "ResultSet.Bad_format_for_Date", |
---|
266 | new Object[] { |
---|
267 | StringUtils.toString( |
---|
268 | dateAsBytes), |
---|
269 | Integer.valueOf(columnIndex + 1) }), |
---|
270 | SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor); //$NON-NLS-1$ |
---|
271 | } |
---|
272 | |
---|
273 | if (length != 18) { |
---|
274 | year = StringUtils.getInt(dateAsBytes, offset + 0, |
---|
275 | offset + 4); |
---|
276 | month = StringUtils.getInt(dateAsBytes, offset + 5, |
---|
277 | offset + 7); |
---|
278 | day = StringUtils.getInt(dateAsBytes, offset + 8, |
---|
279 | offset + 10); |
---|
280 | } else { |
---|
281 | // JDK-1.3 timestamp format, not real easy to parse |
---|
282 | // positionally :p |
---|
283 | StringTokenizer st = new StringTokenizer(StringUtils.toString( |
---|
284 | dateAsBytes, offset, length, "ISO8859_1"), "- "); |
---|
285 | |
---|
286 | year = Integer.parseInt(st.nextToken()); |
---|
287 | month = Integer.parseInt(st.nextToken()); |
---|
288 | day = Integer.parseInt(st.nextToken()); |
---|
289 | } |
---|
290 | } |
---|
291 | |
---|
292 | return rs.fastDateCreate(targetCalendar, year, month, day); |
---|
293 | } catch (SQLException sqlEx) { |
---|
294 | throw sqlEx; // don't re-wrap |
---|
295 | } catch (Exception e) { |
---|
296 | SQLException sqlEx = SQLError.createSQLException(Messages.getString( |
---|
297 | "ResultSet.Bad_format_for_Date", new Object[] { |
---|
298 | StringUtils.toString(dateAsBytes), |
---|
299 | Integer.valueOf(columnIndex + 1) }), |
---|
300 | SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor); //$NON-NLS-1$ |
---|
301 | sqlEx.initCause(e); |
---|
302 | |
---|
303 | throw sqlEx; |
---|
304 | } |
---|
305 | } |
---|
306 | |
---|
307 | public abstract java.sql.Date getDateFast(int columnIndex, |
---|
308 | MySQLConnection conn, ResultSetImpl rs, Calendar targetCalendar) throws SQLException; |
---|
309 | |
---|
310 | /** |
---|
311 | * Returns the value at the given column (index starts at 0) as an int. * |
---|
312 | * |
---|
313 | * @param index |
---|
314 | * of the column value (starting at 0) to return. |
---|
315 | * @return the value for the given column (returns 0 if NULL, use isNull() |
---|
316 | * to determine if the value was actually NULL) |
---|
317 | * @throws SQLException |
---|
318 | * if an error occurs while retrieving the value. |
---|
319 | */ |
---|
320 | public abstract int getInt(int columnIndex) throws SQLException; |
---|
321 | |
---|
322 | /** |
---|
323 | * Returns the value at the given column (index starts at 0) as a long. * |
---|
324 | * |
---|
325 | * @param index |
---|
326 | * of the column value (starting at 0) to return. |
---|
327 | * @return the value for the given column (returns 0 if NULL, use isNull() |
---|
328 | * to determine if the value was actually NULL) |
---|
329 | * @throws SQLException |
---|
330 | * if an error occurs while retrieving the value. |
---|
331 | */ |
---|
332 | public abstract long getLong(int columnIndex) throws SQLException; |
---|
333 | |
---|
334 | /** |
---|
335 | * |
---|
336 | * @param columnIndex |
---|
337 | * @param bits |
---|
338 | * @param offset |
---|
339 | * @param length |
---|
340 | * @param conn |
---|
341 | * @param rs |
---|
342 | * @param cal |
---|
343 | * @return |
---|
344 | * @throws SQLException |
---|
345 | */ |
---|
346 | protected java.sql.Date getNativeDate(int columnIndex, byte[] bits, |
---|
347 | int offset, int length, MySQLConnection conn, ResultSetImpl rs, Calendar cal) |
---|
348 | throws SQLException { |
---|
349 | |
---|
350 | int year = 0; |
---|
351 | int month = 0; |
---|
352 | int day = 0; |
---|
353 | |
---|
354 | if (length != 0) { |
---|
355 | year = (bits[offset + 0] & 0xff) | ((bits[offset + 1] & 0xff) << 8); |
---|
356 | |
---|
357 | month = bits[offset + 2]; |
---|
358 | day = bits[offset + 3]; |
---|
359 | } |
---|
360 | |
---|
361 | if (length == 0 || ((year == 0) && (month == 0) && (day == 0))) { |
---|
362 | if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL |
---|
363 | .equals(conn.getZeroDateTimeBehavior())) { |
---|
364 | return null; |
---|
365 | } else if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_EXCEPTION |
---|
366 | .equals(conn.getZeroDateTimeBehavior())) { |
---|
367 | throw SQLError |
---|
368 | .createSQLException( |
---|
369 | "Value '0000-00-00' can not be represented as java.sql.Date", |
---|
370 | SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor); |
---|
371 | } |
---|
372 | |
---|
373 | year = 1; |
---|
374 | month = 1; |
---|
375 | day = 1; |
---|
376 | } |
---|
377 | |
---|
378 | if (!rs.useLegacyDatetimeCode) { |
---|
379 | return TimeUtil.fastDateCreate(year, month, day, cal); |
---|
380 | } |
---|
381 | |
---|
382 | return rs.fastDateCreate(cal == null ? rs.getCalendarInstanceForSessionOrNew() : cal, year, |
---|
383 | month, day); |
---|
384 | } |
---|
385 | |
---|
386 | public abstract Date getNativeDate(int columnIndex, MySQLConnection conn, |
---|
387 | ResultSetImpl rs, Calendar cal) throws SQLException; |
---|
388 | |
---|
389 | protected Object getNativeDateTimeValue(int columnIndex, byte[] bits, |
---|
390 | int offset, int length, Calendar targetCalendar, int jdbcType, |
---|
391 | int mysqlType, TimeZone tz, boolean rollForward, MySQLConnection conn, |
---|
392 | ResultSetImpl rs) throws SQLException { |
---|
393 | |
---|
394 | int year = 0; |
---|
395 | int month = 0; |
---|
396 | int day = 0; |
---|
397 | |
---|
398 | int hour = 0; |
---|
399 | int minute = 0; |
---|
400 | int seconds = 0; |
---|
401 | |
---|
402 | int nanos = 0; |
---|
403 | |
---|
404 | if (bits == null) { |
---|
405 | |
---|
406 | return null; |
---|
407 | } |
---|
408 | |
---|
409 | Calendar sessionCalendar = conn.getUseJDBCCompliantTimezoneShift() ? conn |
---|
410 | .getUtcCalendar() |
---|
411 | : rs.getCalendarInstanceForSessionOrNew(); |
---|
412 | |
---|
413 | boolean populatedFromDateTimeValue = false; |
---|
414 | |
---|
415 | switch (mysqlType) { |
---|
416 | case MysqlDefs.FIELD_TYPE_DATETIME: |
---|
417 | case MysqlDefs.FIELD_TYPE_TIMESTAMP: |
---|
418 | populatedFromDateTimeValue = true; |
---|
419 | |
---|
420 | if (length != 0) { |
---|
421 | year = (bits[offset + 0] & 0xff) |
---|
422 | | ((bits[offset + 1] & 0xff) << 8); |
---|
423 | month = bits[offset + 2]; |
---|
424 | day = bits[offset + 3]; |
---|
425 | |
---|
426 | if (length > 4) { |
---|
427 | hour = bits[offset + 4]; |
---|
428 | minute = bits[offset + 5]; |
---|
429 | seconds = bits[offset + 6]; |
---|
430 | } |
---|
431 | |
---|
432 | if (length > 7) { |
---|
433 | // MySQL uses microseconds |
---|
434 | nanos = ((bits[offset + 7] & 0xff) |
---|
435 | | ((bits[offset + 8] & 0xff) << 8) |
---|
436 | | ((bits[offset + 9] & 0xff) << 16) | ((bits[offset + 10] & 0xff) << 24)) * 1000; |
---|
437 | } |
---|
438 | } |
---|
439 | |
---|
440 | break; |
---|
441 | case MysqlDefs.FIELD_TYPE_DATE: |
---|
442 | populatedFromDateTimeValue = true; |
---|
443 | |
---|
444 | if (bits.length != 0) { |
---|
445 | year = (bits[offset + 0] & 0xff) |
---|
446 | | ((bits[offset + 1] & 0xff) << 8); |
---|
447 | month = bits[offset + 2]; |
---|
448 | day = bits[offset + 3]; |
---|
449 | } |
---|
450 | |
---|
451 | break; |
---|
452 | case MysqlDefs.FIELD_TYPE_TIME: |
---|
453 | populatedFromDateTimeValue = true; |
---|
454 | |
---|
455 | if (bits.length != 0) { |
---|
456 | // bits[0] // skip tm->neg |
---|
457 | // binaryData.readLong(); // skip daysPart |
---|
458 | hour = bits[offset + 5]; |
---|
459 | minute = bits[offset + 6]; |
---|
460 | seconds = bits[offset + 7]; |
---|
461 | } |
---|
462 | |
---|
463 | year = 1970; |
---|
464 | month = 1; |
---|
465 | day = 1; |
---|
466 | |
---|
467 | break; |
---|
468 | default: |
---|
469 | populatedFromDateTimeValue = false; |
---|
470 | } |
---|
471 | |
---|
472 | switch (jdbcType) { |
---|
473 | case Types.TIME: |
---|
474 | if (populatedFromDateTimeValue) { |
---|
475 | if (!rs.useLegacyDatetimeCode) { |
---|
476 | return TimeUtil.fastTimeCreate(hour, minute, seconds, targetCalendar, this.exceptionInterceptor); |
---|
477 | } |
---|
478 | |
---|
479 | Time time = TimeUtil.fastTimeCreate(rs |
---|
480 | .getCalendarInstanceForSessionOrNew(), hour, minute, |
---|
481 | seconds, this.exceptionInterceptor); |
---|
482 | |
---|
483 | Time adjustedTime = TimeUtil.changeTimezone(conn, |
---|
484 | sessionCalendar, targetCalendar, time, conn |
---|
485 | .getServerTimezoneTZ(), tz, rollForward); |
---|
486 | |
---|
487 | return adjustedTime; |
---|
488 | } |
---|
489 | |
---|
490 | return rs.getNativeTimeViaParseConversion(columnIndex + 1, |
---|
491 | targetCalendar, tz, rollForward); |
---|
492 | |
---|
493 | case Types.DATE: |
---|
494 | if (populatedFromDateTimeValue) { |
---|
495 | if ((year == 0) && (month == 0) && (day == 0)) { |
---|
496 | if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL |
---|
497 | .equals(conn.getZeroDateTimeBehavior())) { |
---|
498 | |
---|
499 | return null; |
---|
500 | } else if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_EXCEPTION |
---|
501 | .equals(conn.getZeroDateTimeBehavior())) { |
---|
502 | throw new SQLException( |
---|
503 | "Value '0000-00-00' can not be represented as java.sql.Date", |
---|
504 | SQLError.SQL_STATE_ILLEGAL_ARGUMENT); |
---|
505 | } |
---|
506 | |
---|
507 | year = 1; |
---|
508 | month = 1; |
---|
509 | day = 1; |
---|
510 | } |
---|
511 | |
---|
512 | if (!rs.useLegacyDatetimeCode) { |
---|
513 | return TimeUtil.fastDateCreate(year, month, day, targetCalendar); |
---|
514 | } |
---|
515 | |
---|
516 | return rs |
---|
517 | .fastDateCreate( |
---|
518 | rs.getCalendarInstanceForSessionOrNew(), year, |
---|
519 | month, day); |
---|
520 | } |
---|
521 | |
---|
522 | return rs.getNativeDateViaParseConversion(columnIndex + 1); |
---|
523 | case Types.TIMESTAMP: |
---|
524 | if (populatedFromDateTimeValue) { |
---|
525 | if ((year == 0) && (month == 0) && (day == 0)) { |
---|
526 | if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL |
---|
527 | .equals(conn.getZeroDateTimeBehavior())) { |
---|
528 | |
---|
529 | return null; |
---|
530 | } else if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_EXCEPTION |
---|
531 | .equals(conn.getZeroDateTimeBehavior())) { |
---|
532 | throw new SQLException( |
---|
533 | "Value '0000-00-00' can not be represented as java.sql.Timestamp", |
---|
534 | SQLError.SQL_STATE_ILLEGAL_ARGUMENT); |
---|
535 | } |
---|
536 | |
---|
537 | year = 1; |
---|
538 | month = 1; |
---|
539 | day = 1; |
---|
540 | } |
---|
541 | |
---|
542 | if (!rs.useLegacyDatetimeCode) { |
---|
543 | return TimeUtil.fastTimestampCreate(tz, year, month, day, hour, minute, |
---|
544 | seconds, nanos); |
---|
545 | } |
---|
546 | |
---|
547 | Timestamp ts = rs.fastTimestampCreate(rs |
---|
548 | .getCalendarInstanceForSessionOrNew(), year, month, |
---|
549 | day, hour, minute, seconds, nanos); |
---|
550 | |
---|
551 | Timestamp adjustedTs = TimeUtil.changeTimezone(conn, |
---|
552 | sessionCalendar, targetCalendar, ts, conn |
---|
553 | .getServerTimezoneTZ(), tz, rollForward); |
---|
554 | |
---|
555 | return adjustedTs; |
---|
556 | } |
---|
557 | |
---|
558 | return rs.getNativeTimestampViaParseConversion(columnIndex + 1, |
---|
559 | targetCalendar, tz, rollForward); |
---|
560 | |
---|
561 | default: |
---|
562 | throw new SQLException( |
---|
563 | "Internal error - conversion method doesn't support this type", |
---|
564 | SQLError.SQL_STATE_GENERAL_ERROR); |
---|
565 | } |
---|
566 | } |
---|
567 | |
---|
568 | public abstract Object getNativeDateTimeValue(int columnIndex, |
---|
569 | Calendar targetCalendar, int jdbcType, int mysqlType, |
---|
570 | TimeZone tz, boolean rollForward, MySQLConnection conn, ResultSetImpl rs) |
---|
571 | throws SQLException; |
---|
572 | |
---|
573 | protected double getNativeDouble(byte[] bits, int offset) { |
---|
574 | long valueAsLong = (bits[offset + 0] & 0xff) |
---|
575 | | ((long) (bits[offset + 1] & 0xff) << 8) |
---|
576 | | ((long) (bits[offset + 2] & 0xff) << 16) |
---|
577 | | ((long) (bits[offset + 3] & 0xff) << 24) |
---|
578 | | ((long) (bits[offset + 4] & 0xff) << 32) |
---|
579 | | ((long) (bits[offset + 5] & 0xff) << 40) |
---|
580 | | ((long) (bits[offset + 6] & 0xff) << 48) |
---|
581 | | ((long) (bits[offset + 7] & 0xff) << 56); |
---|
582 | |
---|
583 | return Double.longBitsToDouble(valueAsLong); |
---|
584 | } |
---|
585 | |
---|
586 | public abstract double getNativeDouble(int columnIndex) throws SQLException; |
---|
587 | |
---|
588 | protected float getNativeFloat(byte[] bits, int offset) { |
---|
589 | int asInt = (bits[offset + 0] & 0xff) |
---|
590 | | ((bits[offset + 1] & 0xff) << 8) |
---|
591 | | ((bits[offset + 2] & 0xff) << 16) |
---|
592 | | ((bits[offset + 3] & 0xff) << 24); |
---|
593 | |
---|
594 | return Float.intBitsToFloat(asInt); |
---|
595 | } |
---|
596 | |
---|
597 | public abstract float getNativeFloat(int columnIndex) throws SQLException; |
---|
598 | |
---|
599 | protected int getNativeInt(byte[] bits, int offset) { |
---|
600 | |
---|
601 | int valueAsInt = (bits[offset + 0] & 0xff) |
---|
602 | | ((bits[offset + 1] & 0xff) << 8) |
---|
603 | | ((bits[offset + 2] & 0xff) << 16) |
---|
604 | | ((bits[offset + 3] & 0xff) << 24); |
---|
605 | |
---|
606 | return valueAsInt; |
---|
607 | } |
---|
608 | |
---|
609 | public abstract int getNativeInt(int columnIndex) throws SQLException; |
---|
610 | |
---|
611 | protected long getNativeLong(byte[] bits, int offset) { |
---|
612 | long valueAsLong = (bits[offset + 0] & 0xff) |
---|
613 | | ((long) (bits[offset + 1] & 0xff) << 8) |
---|
614 | | ((long) (bits[offset + 2] & 0xff) << 16) |
---|
615 | | ((long) (bits[offset + 3] & 0xff) << 24) |
---|
616 | | ((long) (bits[offset + 4] & 0xff) << 32) |
---|
617 | | ((long) (bits[offset + 5] & 0xff) << 40) |
---|
618 | | ((long) (bits[offset + 6] & 0xff) << 48) |
---|
619 | | ((long) (bits[offset + 7] & 0xff) << 56); |
---|
620 | |
---|
621 | return valueAsLong; |
---|
622 | } |
---|
623 | |
---|
624 | public abstract long getNativeLong(int columnIndex) throws SQLException; |
---|
625 | |
---|
626 | protected short getNativeShort(byte[] bits, int offset) { |
---|
627 | short asShort = (short) ((bits[offset + 0] & 0xff) | ((bits[offset + 1] & 0xff) << 8)); |
---|
628 | |
---|
629 | return asShort; |
---|
630 | } |
---|
631 | |
---|
632 | public abstract short getNativeShort(int columnIndex) throws SQLException; |
---|
633 | |
---|
634 | /** |
---|
635 | * |
---|
636 | * @param columnIndex |
---|
637 | * @param bits |
---|
638 | * @param offset |
---|
639 | * @param length |
---|
640 | * @param targetCalendar |
---|
641 | * @param tz |
---|
642 | * @param rollForward |
---|
643 | * @param conn |
---|
644 | * @param rs |
---|
645 | * @return |
---|
646 | * @throws SQLException |
---|
647 | */ |
---|
648 | protected Time getNativeTime(int columnIndex, byte[] bits, int offset, |
---|
649 | int length, Calendar targetCalendar, TimeZone tz, |
---|
650 | boolean rollForward, MySQLConnection conn, ResultSetImpl rs) |
---|
651 | throws SQLException { |
---|
652 | |
---|
653 | int hour = 0; |
---|
654 | int minute = 0; |
---|
655 | int seconds = 0; |
---|
656 | |
---|
657 | if (length != 0) { |
---|
658 | // bits[0] // skip tm->neg |
---|
659 | // binaryData.readLong(); // skip daysPart |
---|
660 | hour = bits[offset + 5]; |
---|
661 | minute = bits[offset + 6]; |
---|
662 | seconds = bits[offset + 7]; |
---|
663 | } |
---|
664 | |
---|
665 | if (!rs.useLegacyDatetimeCode) { |
---|
666 | return TimeUtil.fastTimeCreate(hour, minute, seconds, targetCalendar, this.exceptionInterceptor); |
---|
667 | } |
---|
668 | |
---|
669 | Calendar sessionCalendar = rs.getCalendarInstanceForSessionOrNew(); |
---|
670 | |
---|
671 | synchronized (sessionCalendar) { |
---|
672 | Time time = TimeUtil.fastTimeCreate(sessionCalendar, hour, minute, |
---|
673 | seconds, this.exceptionInterceptor); |
---|
674 | |
---|
675 | Time adjustedTime = TimeUtil.changeTimezone(conn, sessionCalendar, |
---|
676 | targetCalendar, time, conn.getServerTimezoneTZ(), tz, |
---|
677 | rollForward); |
---|
678 | |
---|
679 | return adjustedTime; |
---|
680 | } |
---|
681 | } |
---|
682 | |
---|
683 | public abstract Time getNativeTime(int columnIndex, |
---|
684 | Calendar targetCalendar, TimeZone tz, boolean rollForward, |
---|
685 | MySQLConnection conn, ResultSetImpl rs) throws SQLException; |
---|
686 | |
---|
687 | protected Timestamp getNativeTimestamp(byte[] bits, int offset, int length, |
---|
688 | Calendar targetCalendar, TimeZone tz, boolean rollForward, |
---|
689 | MySQLConnection conn, ResultSetImpl rs) throws SQLException { |
---|
690 | int year = 0; |
---|
691 | int month = 0; |
---|
692 | int day = 0; |
---|
693 | |
---|
694 | int hour = 0; |
---|
695 | int minute = 0; |
---|
696 | int seconds = 0; |
---|
697 | |
---|
698 | int nanos = 0; |
---|
699 | |
---|
700 | if (length != 0) { |
---|
701 | year = (bits[offset + 0] & 0xff) | ((bits[offset + 1] & 0xff) << 8); |
---|
702 | month = bits[offset + 2]; |
---|
703 | day = bits[offset + 3]; |
---|
704 | |
---|
705 | if (length > 4) { |
---|
706 | hour = bits[offset + 4]; |
---|
707 | minute = bits[offset + 5]; |
---|
708 | seconds = bits[offset + 6]; |
---|
709 | } |
---|
710 | |
---|
711 | if (length > 7) { |
---|
712 | // MySQL uses microseconds |
---|
713 | nanos = ((bits[offset + 7] & 0xff) |
---|
714 | | ((bits[offset + 8] & 0xff) << 8) |
---|
715 | | ((bits[offset + 9] & 0xff) << 16) | ((bits[offset + 10] & 0xff) << 24)) * 1000; |
---|
716 | } |
---|
717 | } |
---|
718 | |
---|
719 | if (length == 0 || ((year == 0) && (month == 0) && (day == 0))) { |
---|
720 | if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL |
---|
721 | .equals(conn.getZeroDateTimeBehavior())) { |
---|
722 | |
---|
723 | return null; |
---|
724 | } else if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_EXCEPTION |
---|
725 | .equals(conn.getZeroDateTimeBehavior())) { |
---|
726 | throw SQLError |
---|
727 | .createSQLException( |
---|
728 | "Value '0000-00-00' can not be represented as java.sql.Timestamp", |
---|
729 | SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor); |
---|
730 | } |
---|
731 | |
---|
732 | year = 1; |
---|
733 | month = 1; |
---|
734 | day = 1; |
---|
735 | } |
---|
736 | |
---|
737 | if (!rs.useLegacyDatetimeCode) { |
---|
738 | return TimeUtil.fastTimestampCreate(tz, year, month, |
---|
739 | day, hour, minute, seconds, nanos); |
---|
740 | } |
---|
741 | |
---|
742 | Calendar sessionCalendar = conn.getUseJDBCCompliantTimezoneShift() ? conn |
---|
743 | .getUtcCalendar() |
---|
744 | : rs.getCalendarInstanceForSessionOrNew(); |
---|
745 | |
---|
746 | synchronized (sessionCalendar) { |
---|
747 | Timestamp ts = rs.fastTimestampCreate(sessionCalendar, year, month, |
---|
748 | day, hour, minute, seconds, nanos); |
---|
749 | |
---|
750 | Timestamp adjustedTs = TimeUtil.changeTimezone(conn, |
---|
751 | sessionCalendar, targetCalendar, ts, conn |
---|
752 | .getServerTimezoneTZ(), tz, rollForward); |
---|
753 | |
---|
754 | return adjustedTs; |
---|
755 | } |
---|
756 | } |
---|
757 | |
---|
758 | public abstract Timestamp getNativeTimestamp(int columnIndex, |
---|
759 | Calendar targetCalendar, TimeZone tz, boolean rollForward, |
---|
760 | MySQLConnection conn, ResultSetImpl rs) throws SQLException; |
---|
761 | |
---|
762 | public abstract Reader getReader(int columnIndex) throws SQLException; |
---|
763 | |
---|
764 | /** |
---|
765 | * Returns the value at the given column (index starts at 0) as a |
---|
766 | * java.lang.String with the requested encoding, using the given |
---|
767 | * MySQLConnection to find character converters. |
---|
768 | * |
---|
769 | * @param index |
---|
770 | * of the column value (starting at 0) to return. |
---|
771 | * @param encoding |
---|
772 | * the Java name for the character encoding |
---|
773 | * @param conn |
---|
774 | * the connection that created this result set row |
---|
775 | * |
---|
776 | * @return the value for the given column (including NULL if it is) as a |
---|
777 | * String |
---|
778 | * |
---|
779 | * @throws SQLException |
---|
780 | * if an error occurs while retrieving the value. |
---|
781 | */ |
---|
782 | public abstract String getString(int index, String encoding, |
---|
783 | MySQLConnection conn) throws SQLException; |
---|
784 | |
---|
785 | /** |
---|
786 | * Convenience method for turning a byte[] into a string with the given |
---|
787 | * encoding. |
---|
788 | * |
---|
789 | * @param encoding |
---|
790 | * the Java encoding name for the byte[] -> char conversion |
---|
791 | * @param conn |
---|
792 | * the MySQLConnection that created the result set |
---|
793 | * @param value |
---|
794 | * the String value as a series of bytes, encoded using |
---|
795 | * "encoding" |
---|
796 | * @param offset |
---|
797 | * where to start the decoding |
---|
798 | * @param length |
---|
799 | * how many bytes to decode |
---|
800 | * |
---|
801 | * @return the String as decoded from bytes with the given encoding |
---|
802 | * |
---|
803 | * @throws SQLException |
---|
804 | * if an error occurs |
---|
805 | */ |
---|
806 | protected String getString(String encoding, MySQLConnection conn, |
---|
807 | byte[] value, int offset, int length) throws SQLException { |
---|
808 | String stringVal = null; |
---|
809 | |
---|
810 | if ((conn != null) && conn.getUseUnicode()) { |
---|
811 | try { |
---|
812 | if (encoding == null) { |
---|
813 | stringVal = StringUtils.toString(value); |
---|
814 | } else { |
---|
815 | SingleByteCharsetConverter converter = conn |
---|
816 | .getCharsetConverter(encoding); |
---|
817 | |
---|
818 | if (converter != null) { |
---|
819 | stringVal = converter.toString(value, offset, length); |
---|
820 | } else { |
---|
821 | stringVal = StringUtils.toString(value, offset, length, encoding); |
---|
822 | } |
---|
823 | } |
---|
824 | } catch (java.io.UnsupportedEncodingException E) { |
---|
825 | throw SQLError |
---|
826 | .createSQLException( |
---|
827 | Messages |
---|
828 | .getString("ResultSet.Unsupported_character_encoding____101") //$NON-NLS-1$ |
---|
829 | + encoding + "'.", "0S100", this.exceptionInterceptor); |
---|
830 | } |
---|
831 | } else { |
---|
832 | stringVal = StringUtils.toAsciiString(value, offset, length); |
---|
833 | } |
---|
834 | |
---|
835 | return stringVal; |
---|
836 | } |
---|
837 | |
---|
838 | protected Time getTimeFast(int columnIndex, byte[] timeAsBytes, int offset, |
---|
839 | int length, Calendar targetCalendar, TimeZone tz, |
---|
840 | boolean rollForward, MySQLConnection conn, ResultSetImpl rs) |
---|
841 | throws SQLException { |
---|
842 | |
---|
843 | int hr = 0; |
---|
844 | int min = 0; |
---|
845 | int sec = 0; |
---|
846 | |
---|
847 | try { |
---|
848 | |
---|
849 | if (timeAsBytes == null) { |
---|
850 | return null; |
---|
851 | } |
---|
852 | |
---|
853 | boolean allZeroTime = true; |
---|
854 | boolean onlyTimePresent = false; |
---|
855 | |
---|
856 | for (int i = 0; i < length; i++) { |
---|
857 | if (timeAsBytes[offset + i] == ':') { |
---|
858 | onlyTimePresent = true; |
---|
859 | break; |
---|
860 | } |
---|
861 | } |
---|
862 | |
---|
863 | for (int i = 0; i < length; i++) { |
---|
864 | byte b = timeAsBytes[offset + i]; |
---|
865 | |
---|
866 | if (b == ' ' || b == '-' || b == '/') { |
---|
867 | onlyTimePresent = false; |
---|
868 | } |
---|
869 | |
---|
870 | if (b != '0' && b != ' ' && b != ':' && b != '-' && b != '/' |
---|
871 | && b != '.') { |
---|
872 | allZeroTime = false; |
---|
873 | |
---|
874 | break; |
---|
875 | } |
---|
876 | } |
---|
877 | |
---|
878 | if (!onlyTimePresent && allZeroTime) { |
---|
879 | if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL |
---|
880 | .equals(conn.getZeroDateTimeBehavior())) { |
---|
881 | return null; |
---|
882 | } else if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_EXCEPTION |
---|
883 | .equals(conn.getZeroDateTimeBehavior())) { |
---|
884 | throw SQLError.createSQLException("Value '" |
---|
885 | + StringUtils.toString(timeAsBytes) |
---|
886 | + "' can not be represented as java.sql.Time", |
---|
887 | SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor); |
---|
888 | } |
---|
889 | |
---|
890 | // We're left with the case of 'round' to a time Java _can_ |
---|
891 | // represent, which is '00:00:00' |
---|
892 | return rs.fastTimeCreate(targetCalendar, 0, 0, 0); |
---|
893 | } |
---|
894 | |
---|
895 | Field timeColField = this.metadata[columnIndex]; |
---|
896 | |
---|
897 | if (timeColField.getMysqlType() == MysqlDefs.FIELD_TYPE_TIMESTAMP) { |
---|
898 | |
---|
899 | switch (length) { |
---|
900 | case 19: { // YYYY-MM-DD hh:mm:ss |
---|
901 | |
---|
902 | hr = StringUtils.getInt(timeAsBytes, offset + length - 8, |
---|
903 | offset + length - 6); |
---|
904 | min = StringUtils.getInt(timeAsBytes, offset + length - 5, |
---|
905 | offset + length - 3); |
---|
906 | sec = StringUtils.getInt(timeAsBytes, offset + length - 2, |
---|
907 | offset + length); |
---|
908 | } |
---|
909 | |
---|
910 | break; |
---|
911 | case 14: |
---|
912 | case 12: { |
---|
913 | hr = StringUtils.getInt(timeAsBytes, offset + length - 6, |
---|
914 | offset + length - 4); |
---|
915 | min = StringUtils.getInt(timeAsBytes, offset + length - 4, |
---|
916 | offset + length - 2); |
---|
917 | sec = StringUtils.getInt(timeAsBytes, offset + length - 2, |
---|
918 | offset + length); |
---|
919 | } |
---|
920 | |
---|
921 | break; |
---|
922 | |
---|
923 | case 10: { |
---|
924 | hr = StringUtils |
---|
925 | .getInt(timeAsBytes, offset + 6, offset + 8); |
---|
926 | min = StringUtils.getInt(timeAsBytes, offset + 8, |
---|
927 | offset + 10); |
---|
928 | sec = 0; |
---|
929 | } |
---|
930 | |
---|
931 | break; |
---|
932 | |
---|
933 | default: |
---|
934 | throw SQLError |
---|
935 | .createSQLException( |
---|
936 | Messages |
---|
937 | .getString("ResultSet.Timestamp_too_small_to_convert_to_Time_value_in_column__257") //$NON-NLS-1$ |
---|
938 | + (columnIndex + 1) |
---|
939 | + "(" |
---|
940 | + timeColField + ").", |
---|
941 | SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor); |
---|
942 | } /* endswitch */ |
---|
943 | |
---|
944 | @SuppressWarnings("unused") |
---|
945 | SQLWarning precisionLost = new SQLWarning( |
---|
946 | Messages |
---|
947 | .getString("ResultSet.Precision_lost_converting_TIMESTAMP_to_Time_with_getTime()_on_column__261") //$NON-NLS-1$ |
---|
948 | + columnIndex + "(" + timeColField + ")."); |
---|
949 | /* |
---|
950 | * if (this.warningChain == null) { this.warningChain = |
---|
951 | * precisionLost; } else { |
---|
952 | * this.warningChain.setNextWarning(precisionLost); } |
---|
953 | */ |
---|
954 | } else if (timeColField.getMysqlType() == MysqlDefs.FIELD_TYPE_DATETIME) { |
---|
955 | hr = StringUtils.getInt(timeAsBytes, offset + 11, offset + 13); |
---|
956 | min = StringUtils.getInt(timeAsBytes, offset + 14, offset + 16); |
---|
957 | sec = StringUtils.getInt(timeAsBytes, offset + 17, offset + 19); |
---|
958 | |
---|
959 | @SuppressWarnings("unused") |
---|
960 | SQLWarning precisionLost = new SQLWarning( |
---|
961 | Messages |
---|
962 | .getString("ResultSet.Precision_lost_converting_DATETIME_to_Time_with_getTime()_on_column__264") //$NON-NLS-1$ |
---|
963 | + (columnIndex + 1) + "(" + timeColField + ")."); |
---|
964 | |
---|
965 | /* |
---|
966 | * if (this.warningChain == null) { this.warningChain = |
---|
967 | * precisionLost; } else { |
---|
968 | * this.warningChain.setNextWarning(precisionLost); } |
---|
969 | */ |
---|
970 | } else if (timeColField.getMysqlType() == MysqlDefs.FIELD_TYPE_DATE) { |
---|
971 | return rs.fastTimeCreate(null, 0, 0, 0); // midnight on the |
---|
972 | // given |
---|
973 | // date |
---|
974 | } else { |
---|
975 | // convert a String to a Time |
---|
976 | if ((length != 5) && (length != 8)) { |
---|
977 | throw SQLError.createSQLException(Messages |
---|
978 | .getString("ResultSet.Bad_format_for_Time____267") //$NON-NLS-1$ |
---|
979 | + StringUtils.toString(timeAsBytes) |
---|
980 | + Messages.getString("ResultSet.___in_column__268") |
---|
981 | + (columnIndex + 1), |
---|
982 | SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor); |
---|
983 | } |
---|
984 | |
---|
985 | hr = StringUtils.getInt(timeAsBytes, offset + 0, offset + 2); |
---|
986 | min = StringUtils.getInt(timeAsBytes, offset + 3, offset + 5); |
---|
987 | sec = (length == 5) ? 0 : StringUtils.getInt(timeAsBytes, |
---|
988 | offset + 6, offset + 8); |
---|
989 | } |
---|
990 | |
---|
991 | Calendar sessionCalendar = rs.getCalendarInstanceForSessionOrNew(); |
---|
992 | |
---|
993 | if (!rs.useLegacyDatetimeCode) { |
---|
994 | return rs.fastTimeCreate(targetCalendar, hr, min, sec); |
---|
995 | } |
---|
996 | |
---|
997 | synchronized (sessionCalendar) { |
---|
998 | return TimeUtil.changeTimezone(conn, sessionCalendar, |
---|
999 | targetCalendar, rs.fastTimeCreate(sessionCalendar, hr, |
---|
1000 | min, sec), conn.getServerTimezoneTZ(), tz, |
---|
1001 | rollForward); |
---|
1002 | } |
---|
1003 | } catch (RuntimeException ex) { |
---|
1004 | SQLException sqlEx = SQLError.createSQLException(ex.toString(), |
---|
1005 | SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor); |
---|
1006 | sqlEx.initCause(ex); |
---|
1007 | |
---|
1008 | throw sqlEx; |
---|
1009 | } |
---|
1010 | } |
---|
1011 | |
---|
1012 | public abstract Time getTimeFast(int columnIndex, Calendar targetCalendar, |
---|
1013 | TimeZone tz, boolean rollForward, MySQLConnection conn, |
---|
1014 | ResultSetImpl rs) throws SQLException; |
---|
1015 | |
---|
1016 | protected Timestamp getTimestampFast(int columnIndex, |
---|
1017 | byte[] timestampAsBytes, int offset, int length, |
---|
1018 | Calendar targetCalendar, TimeZone tz, boolean rollForward, |
---|
1019 | MySQLConnection conn, ResultSetImpl rs) throws SQLException { |
---|
1020 | |
---|
1021 | try { |
---|
1022 | Calendar sessionCalendar = conn.getUseJDBCCompliantTimezoneShift() ? conn |
---|
1023 | .getUtcCalendar() |
---|
1024 | : rs.getCalendarInstanceForSessionOrNew(); |
---|
1025 | |
---|
1026 | synchronized (sessionCalendar) { |
---|
1027 | boolean allZeroTimestamp = true; |
---|
1028 | |
---|
1029 | boolean onlyTimePresent = false; |
---|
1030 | |
---|
1031 | for (int i = 0; i < length; i++) { |
---|
1032 | if (timestampAsBytes[offset + i] == ':') { |
---|
1033 | onlyTimePresent = true; |
---|
1034 | break; |
---|
1035 | } |
---|
1036 | } |
---|
1037 | |
---|
1038 | for (int i = 0; i < length; i++) { |
---|
1039 | byte b = timestampAsBytes[offset + i]; |
---|
1040 | |
---|
1041 | if (b == ' ' || b == '-' || b == '/') { |
---|
1042 | onlyTimePresent = false; |
---|
1043 | } |
---|
1044 | |
---|
1045 | if (b != '0' && b != ' ' && b != ':' && b != '-' |
---|
1046 | && b != '/' && b != '.') { |
---|
1047 | allZeroTimestamp = false; |
---|
1048 | |
---|
1049 | break; |
---|
1050 | } |
---|
1051 | } |
---|
1052 | |
---|
1053 | if (!onlyTimePresent && allZeroTimestamp) { |
---|
1054 | |
---|
1055 | if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_CONVERT_TO_NULL |
---|
1056 | .equals(conn.getZeroDateTimeBehavior())) { |
---|
1057 | |
---|
1058 | return null; |
---|
1059 | } else if (ConnectionPropertiesImpl.ZERO_DATETIME_BEHAVIOR_EXCEPTION |
---|
1060 | .equals(conn.getZeroDateTimeBehavior())) { |
---|
1061 | throw SQLError |
---|
1062 | .createSQLException( |
---|
1063 | "Value '" |
---|
1064 | + StringUtils.toString(timestampAsBytes) |
---|
1065 | + "' can not be represented as java.sql.Timestamp", |
---|
1066 | SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor); |
---|
1067 | } |
---|
1068 | |
---|
1069 | if (!rs.useLegacyDatetimeCode) { |
---|
1070 | return TimeUtil.fastTimestampCreate(tz, 1, 1, 1, 0, 0, 0, 0); |
---|
1071 | } |
---|
1072 | // We're left with the case of 'round' to a date Java _can_ |
---|
1073 | // represent, which is '0001-01-01'. |
---|
1074 | return rs.fastTimestampCreate(null, 1, 1, 1, 0, 0, 0, 0); |
---|
1075 | |
---|
1076 | } else if (this.metadata[columnIndex].getMysqlType() == MysqlDefs.FIELD_TYPE_YEAR) { |
---|
1077 | |
---|
1078 | if (!rs.useLegacyDatetimeCode) { |
---|
1079 | return TimeUtil.fastTimestampCreate(tz, StringUtils |
---|
1080 | .getInt(timestampAsBytes, offset, 4), 1, 1, 0, |
---|
1081 | 0, 0, 0); |
---|
1082 | } |
---|
1083 | |
---|
1084 | return TimeUtil.changeTimezone(conn, sessionCalendar, |
---|
1085 | targetCalendar, rs.fastTimestampCreate( |
---|
1086 | sessionCalendar, StringUtils.getInt( |
---|
1087 | timestampAsBytes, offset, 4), 1, 1, |
---|
1088 | 0, 0, 0, 0), conn.getServerTimezoneTZ(), |
---|
1089 | tz, rollForward); |
---|
1090 | } else { |
---|
1091 | if (timestampAsBytes[offset + length - 1] == '.') { |
---|
1092 | length--; |
---|
1093 | } |
---|
1094 | |
---|
1095 | // Convert from TIMESTAMP or DATE |
---|
1096 | |
---|
1097 | int year = 0; |
---|
1098 | int month = 0; |
---|
1099 | int day = 0; |
---|
1100 | int hour = 0; |
---|
1101 | int minutes = 0; |
---|
1102 | int seconds = 0; |
---|
1103 | int nanos = 0; |
---|
1104 | |
---|
1105 | switch (length) { |
---|
1106 | case 29: |
---|
1107 | case 26: |
---|
1108 | case 25: |
---|
1109 | case 24: |
---|
1110 | case 23: |
---|
1111 | case 22: |
---|
1112 | case 21: |
---|
1113 | case 20: |
---|
1114 | case 19: { |
---|
1115 | year = StringUtils.getInt(timestampAsBytes, |
---|
1116 | offset + 0, offset + 4); |
---|
1117 | month = StringUtils.getInt(timestampAsBytes, |
---|
1118 | offset + 5, offset + 7); |
---|
1119 | day = StringUtils.getInt(timestampAsBytes, |
---|
1120 | offset + 8, offset + 10); |
---|
1121 | hour = StringUtils.getInt(timestampAsBytes, |
---|
1122 | offset + 11, offset + 13); |
---|
1123 | minutes = StringUtils.getInt(timestampAsBytes, |
---|
1124 | offset + 14, offset + 16); |
---|
1125 | seconds = StringUtils.getInt(timestampAsBytes, |
---|
1126 | offset + 17, offset + 19); |
---|
1127 | |
---|
1128 | nanos = 0; |
---|
1129 | |
---|
1130 | if (length > 19) { |
---|
1131 | int decimalIndex = -1; |
---|
1132 | |
---|
1133 | for (int i = 0; i < length; i++) { |
---|
1134 | if (timestampAsBytes[offset + i] == '.') { |
---|
1135 | decimalIndex = i; |
---|
1136 | } |
---|
1137 | } |
---|
1138 | |
---|
1139 | if (decimalIndex != -1) { |
---|
1140 | if ((decimalIndex + 2) <= length) { |
---|
1141 | nanos = StringUtils.getInt( |
---|
1142 | timestampAsBytes, offset + decimalIndex + 1, |
---|
1143 | offset + length); |
---|
1144 | |
---|
1145 | int numDigits = (length) - (decimalIndex + 1); |
---|
1146 | |
---|
1147 | if (numDigits < 9) { |
---|
1148 | int factor = (int)(Math.pow(10, 9 - numDigits)); |
---|
1149 | nanos = nanos * factor; |
---|
1150 | } |
---|
1151 | } else { |
---|
1152 | throw new IllegalArgumentException(); // re-thrown |
---|
1153 | // further |
---|
1154 | // down |
---|
1155 | // with |
---|
1156 | // a |
---|
1157 | // much better error message |
---|
1158 | } |
---|
1159 | } |
---|
1160 | } |
---|
1161 | |
---|
1162 | break; |
---|
1163 | } |
---|
1164 | |
---|
1165 | case 14: { |
---|
1166 | year = StringUtils.getInt(timestampAsBytes, |
---|
1167 | offset + 0, offset + 4); |
---|
1168 | month = StringUtils.getInt(timestampAsBytes, |
---|
1169 | offset + 4, offset + 6); |
---|
1170 | day = StringUtils.getInt(timestampAsBytes, |
---|
1171 | offset + 6, offset + 8); |
---|
1172 | hour = StringUtils.getInt(timestampAsBytes, |
---|
1173 | offset + 8, offset + 10); |
---|
1174 | minutes = StringUtils.getInt(timestampAsBytes, |
---|
1175 | offset + 10, offset + 12); |
---|
1176 | seconds = StringUtils.getInt(timestampAsBytes, |
---|
1177 | offset + 12, offset + 14); |
---|
1178 | |
---|
1179 | break; |
---|
1180 | } |
---|
1181 | |
---|
1182 | case 12: { |
---|
1183 | year = StringUtils.getInt(timestampAsBytes, |
---|
1184 | offset + 0, offset + 2); |
---|
1185 | |
---|
1186 | if (year <= 69) { |
---|
1187 | year = (year + 100); |
---|
1188 | } |
---|
1189 | |
---|
1190 | year += 1900; |
---|
1191 | |
---|
1192 | month = StringUtils.getInt(timestampAsBytes, |
---|
1193 | offset + 2, offset + 4); |
---|
1194 | day = StringUtils.getInt(timestampAsBytes, |
---|
1195 | offset + 4, offset + 6); |
---|
1196 | hour = StringUtils.getInt(timestampAsBytes, |
---|
1197 | offset + 6, offset + 8); |
---|
1198 | minutes = StringUtils.getInt(timestampAsBytes, |
---|
1199 | offset + 8, offset + 10); |
---|
1200 | seconds = StringUtils.getInt(timestampAsBytes, |
---|
1201 | offset + 10, offset + 12); |
---|
1202 | |
---|
1203 | break; |
---|
1204 | } |
---|
1205 | |
---|
1206 | case 10: { |
---|
1207 | boolean hasDash = false; |
---|
1208 | |
---|
1209 | for (int i = 0; i < length; i++) { |
---|
1210 | if (timestampAsBytes[offset + i] == '-') { |
---|
1211 | hasDash = true; |
---|
1212 | break; |
---|
1213 | } |
---|
1214 | } |
---|
1215 | |
---|
1216 | if ((this.metadata[columnIndex].getMysqlType() == MysqlDefs.FIELD_TYPE_DATE) |
---|
1217 | || hasDash) { |
---|
1218 | year = StringUtils.getInt(timestampAsBytes, |
---|
1219 | offset + 0, offset + 4); |
---|
1220 | month = StringUtils.getInt(timestampAsBytes, |
---|
1221 | offset + 5, offset + 7); |
---|
1222 | day = StringUtils.getInt(timestampAsBytes, |
---|
1223 | offset + 8, offset + 10); |
---|
1224 | hour = 0; |
---|
1225 | minutes = 0; |
---|
1226 | } else { |
---|
1227 | year = StringUtils.getInt(timestampAsBytes, |
---|
1228 | offset + 0, offset + 2); |
---|
1229 | |
---|
1230 | if (year <= 69) { |
---|
1231 | year = (year + 100); |
---|
1232 | } |
---|
1233 | |
---|
1234 | month = StringUtils.getInt(timestampAsBytes, |
---|
1235 | offset + 2, offset + 4); |
---|
1236 | day = StringUtils.getInt(timestampAsBytes, |
---|
1237 | offset + 4, offset + 6); |
---|
1238 | hour = StringUtils.getInt(timestampAsBytes, |
---|
1239 | offset + 6, offset + 8); |
---|
1240 | minutes = StringUtils.getInt(timestampAsBytes, |
---|
1241 | offset + 8, offset + 10); |
---|
1242 | |
---|
1243 | year += 1900; // two-digit year |
---|
1244 | } |
---|
1245 | |
---|
1246 | break; |
---|
1247 | } |
---|
1248 | |
---|
1249 | case 8: { |
---|
1250 | boolean hasColon = false; |
---|
1251 | |
---|
1252 | for (int i = 0; i < length; i++) { |
---|
1253 | if (timestampAsBytes[offset + i] == ':') { |
---|
1254 | hasColon = true; |
---|
1255 | break; |
---|
1256 | } |
---|
1257 | } |
---|
1258 | |
---|
1259 | if (hasColon) { |
---|
1260 | hour = StringUtils.getInt(timestampAsBytes, |
---|
1261 | offset + 0, offset + 2); |
---|
1262 | minutes = StringUtils.getInt(timestampAsBytes, |
---|
1263 | offset + 3, offset + 5); |
---|
1264 | seconds = StringUtils.getInt(timestampAsBytes, |
---|
1265 | offset + 6, offset + 8); |
---|
1266 | |
---|
1267 | year = 1970; |
---|
1268 | month = 1; |
---|
1269 | day = 1; |
---|
1270 | |
---|
1271 | break; |
---|
1272 | } |
---|
1273 | |
---|
1274 | year = StringUtils.getInt(timestampAsBytes, |
---|
1275 | offset + 0, offset + 4); |
---|
1276 | month = StringUtils.getInt(timestampAsBytes, |
---|
1277 | offset + 4, offset + 6); |
---|
1278 | day = StringUtils.getInt(timestampAsBytes, |
---|
1279 | offset + 6, offset + 8); |
---|
1280 | |
---|
1281 | year -= 1900; |
---|
1282 | month--; |
---|
1283 | |
---|
1284 | break; |
---|
1285 | } |
---|
1286 | |
---|
1287 | case 6: { |
---|
1288 | year = StringUtils.getInt(timestampAsBytes, |
---|
1289 | offset + 0, offset + 2); |
---|
1290 | |
---|
1291 | if (year <= 69) { |
---|
1292 | year = (year + 100); |
---|
1293 | } |
---|
1294 | |
---|
1295 | year += 1900; |
---|
1296 | |
---|
1297 | month = StringUtils.getInt(timestampAsBytes, |
---|
1298 | offset + 2, offset + 4); |
---|
1299 | day = StringUtils.getInt(timestampAsBytes, |
---|
1300 | offset + 4, offset + 6); |
---|
1301 | |
---|
1302 | break; |
---|
1303 | } |
---|
1304 | |
---|
1305 | case 4: { |
---|
1306 | year = StringUtils.getInt(timestampAsBytes, |
---|
1307 | offset + 0, offset + 2); |
---|
1308 | |
---|
1309 | if (year <= 69) { |
---|
1310 | year = (year + 100); |
---|
1311 | } |
---|
1312 | |
---|
1313 | month = StringUtils.getInt(timestampAsBytes, |
---|
1314 | offset + 2, offset + 4); |
---|
1315 | |
---|
1316 | day = 1; |
---|
1317 | |
---|
1318 | break; |
---|
1319 | } |
---|
1320 | |
---|
1321 | case 2: { |
---|
1322 | year = StringUtils.getInt(timestampAsBytes, |
---|
1323 | offset + 0, offset + 2); |
---|
1324 | |
---|
1325 | if (year <= 69) { |
---|
1326 | year = (year + 100); |
---|
1327 | } |
---|
1328 | |
---|
1329 | year += 1900; |
---|
1330 | month = 1; |
---|
1331 | day = 1; |
---|
1332 | |
---|
1333 | break; |
---|
1334 | } |
---|
1335 | |
---|
1336 | default: |
---|
1337 | throw new java.sql.SQLException( |
---|
1338 | "Bad format for Timestamp '" |
---|
1339 | + StringUtils.toString(timestampAsBytes) |
---|
1340 | + "' in column " + (columnIndex + 1) |
---|
1341 | + ".", |
---|
1342 | SQLError.SQL_STATE_ILLEGAL_ARGUMENT); |
---|
1343 | } |
---|
1344 | |
---|
1345 | if (!rs.useLegacyDatetimeCode) { |
---|
1346 | return TimeUtil.fastTimestampCreate(tz, |
---|
1347 | year, month, |
---|
1348 | day, hour, minutes, seconds, |
---|
1349 | nanos); |
---|
1350 | } |
---|
1351 | |
---|
1352 | return TimeUtil |
---|
1353 | .changeTimezone(conn, sessionCalendar, |
---|
1354 | targetCalendar, rs.fastTimestampCreate( |
---|
1355 | sessionCalendar, year, month, |
---|
1356 | day, hour, minutes, seconds, |
---|
1357 | nanos), conn |
---|
1358 | .getServerTimezoneTZ(), tz, |
---|
1359 | rollForward); |
---|
1360 | } |
---|
1361 | } |
---|
1362 | } catch (RuntimeException e) { |
---|
1363 | SQLException sqlEx = SQLError.createSQLException("Cannot convert value '" |
---|
1364 | + getString(columnIndex, "ISO8859_1", conn) |
---|
1365 | + "' from column " + (columnIndex + 1) + " to TIMESTAMP.", |
---|
1366 | SQLError.SQL_STATE_ILLEGAL_ARGUMENT, this.exceptionInterceptor); |
---|
1367 | sqlEx.initCause(e); |
---|
1368 | |
---|
1369 | throw sqlEx; |
---|
1370 | } |
---|
1371 | } |
---|
1372 | |
---|
1373 | public abstract Timestamp getTimestampFast(int columnIndex, |
---|
1374 | Calendar targetCalendar, TimeZone tz, boolean rollForward, |
---|
1375 | MySQLConnection conn, ResultSetImpl rs) throws SQLException; |
---|
1376 | |
---|
1377 | /** |
---|
1378 | * Could the column value at the given index (which starts at 0) be |
---|
1379 | * interpreted as a floating-point number (has +/-/E/e in it)? |
---|
1380 | * |
---|
1381 | * @param index |
---|
1382 | * of the column value (starting at 0) to check. |
---|
1383 | * |
---|
1384 | * @return true if the column value at the given index looks like it might |
---|
1385 | * be a floating-point number, false if not. |
---|
1386 | * |
---|
1387 | * @throws SQLException |
---|
1388 | * if an error occurs |
---|
1389 | */ |
---|
1390 | public abstract boolean isFloatingPointNumber(int index) |
---|
1391 | throws SQLException; |
---|
1392 | |
---|
1393 | /** |
---|
1394 | * Is the column value at the given index (which starts at 0) NULL? |
---|
1395 | * |
---|
1396 | * @param index |
---|
1397 | * of the column value (starting at 0) to check. |
---|
1398 | * |
---|
1399 | * @return true if the column value is NULL, false if not. |
---|
1400 | * |
---|
1401 | * @throws SQLException |
---|
1402 | * if an error occurs |
---|
1403 | */ |
---|
1404 | public abstract boolean isNull(int index) throws SQLException; |
---|
1405 | |
---|
1406 | /** |
---|
1407 | * Returns the length of the column at the given index (which starts at 0). |
---|
1408 | * |
---|
1409 | * @param index |
---|
1410 | * of the column value (starting at 0) for which to return the |
---|
1411 | * length. |
---|
1412 | * @return the length of the requested column, 0 if null (clients of this |
---|
1413 | * interface should use isNull() beforehand to determine status of |
---|
1414 | * NULL values in the column). |
---|
1415 | * |
---|
1416 | * @throws SQLException |
---|
1417 | */ |
---|
1418 | public abstract long length(int index) throws SQLException; |
---|
1419 | |
---|
1420 | /** |
---|
1421 | * Sets the given column value (only works currently with |
---|
1422 | * ByteArrayRowHolder). |
---|
1423 | * |
---|
1424 | * @param index |
---|
1425 | * index of the column value (starting at 0) to set. |
---|
1426 | * @param value |
---|
1427 | * the (raw) value to set |
---|
1428 | * |
---|
1429 | * @throws SQLException |
---|
1430 | * if an error occurs, or the concrete RowHolder doesn't support |
---|
1431 | * this operation. |
---|
1432 | */ |
---|
1433 | public abstract void setColumnValue(int index, byte[] value) |
---|
1434 | throws SQLException; |
---|
1435 | |
---|
1436 | public ResultSetRow setMetadata(Field[] f) throws SQLException { |
---|
1437 | this.metadata = f; |
---|
1438 | |
---|
1439 | return this; |
---|
1440 | } |
---|
1441 | |
---|
1442 | public abstract int getBytesSize(); |
---|
1443 | } |
---|