Mercurial > hg > monetdb-java
changeset 198:376a15ce49e3
Improve parsing negative years.
Also updated and extended test program for those cases.
author | Martin van Dinther <martin.van.dinther@monetdbsolutions.com> |
---|---|
date | Thu, 14 Dec 2017 17:24:38 +0100 (2017-12-14) |
parents | 95b48b249f68 |
children | e87d89d371f1 |
files | src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java tests/Test_Rtimedate.java |
diffstat | 2 files changed, 127 insertions(+), 110 deletions(-) [+] |
line wrap: on
line diff
--- a/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java +++ b/src/main/java/nl/cwi/monetdb/jdbc/MonetResultSet.java @@ -2638,12 +2638,14 @@ public class MonetResultSet if (cal == null) throw new IllegalArgumentException("No Calendar object given!"); + final String monetDateStr; final String monetDate; final String MonetDBType; int JdbcType; + boolean negativeYear = false; try { - monetDate = tlp.values[columnIndex - 1]; - if (monetDate == null) { + monetDateStr = tlp.values[columnIndex - 1]; + if (monetDateStr == null) { lastReadWasNull = true; return -1; } @@ -2659,6 +2661,14 @@ public class MonetResultSet { JdbcType = type; } + + if ((JdbcType == Types.DATE || JdbcType == Types.TIMESTAMP) && monetDateStr.startsWith("-")) { + // the SimpleDateFormat parsers do not support to parse negative year numbers, deal with it separately + negativeYear = true; + monetDate = monetDateStr.substring(1); + } else { + monetDate = monetDateStr; + } } catch (IndexOutOfBoundsException e) { throw newSQLInvalidColumnIndexException(columnIndex); } @@ -2702,35 +2712,47 @@ public class MonetResultSet } timestampFormat.setTimeZone(ptz); pdate = timestampFormat.parse(monetDate, ppos); + // if parsing with timestampFormat failed try to parse it in dateFormat + if (pdate == null && monetDate.length() <= 10 && monetDate.contains("-")) { + if (dateFormat == null) { + // first time usage, create and keep the dateFormat object for next usage + dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + } + dateFormat.setTimeZone(ptz); + pdate = dateFormat.parse(monetDate, ppos); + } break; default: - addWarning("unsupported data type", "01M03"); - cal.clear(); - return 0; + throw new SQLException("Internal error, unsupported data type: " + type, "01M03"); } if (pdate == null) { // parsing failed + String errMsg; int epos = ppos.getErrorIndex(); if (epos == -1) { - addWarning("parsing '" + monetDate + "' failed", "01M10"); + errMsg = "parsing '" + monetDateStr + "' failed"; } else if (epos < monetDate.length()) { - addWarning("parsing failed," + - " found: '" + monetDate.charAt(epos) + "'" + - " in: \"" + monetDate + "\"" + - " at pos: " + epos, "01M10"); + errMsg = "parsing failed," + + " found: '" + monetDate.charAt(epos) + "'" + + " in: \"" + monetDateStr + "\"" + + " at pos: " + (epos + (negativeYear ? 2 : 1)); } else { - addWarning("parsing failed, expected more data after '" + - monetDate + "'", "01M10"); + errMsg = "parsing failed, expected more data after '" + monetDateStr + "'"; } - // default value - cal.clear(); - return 0; + throw new SQLException(errMsg, "01M10"); } + cal.setTime(pdate); - - int nanos = 0; + if (negativeYear) { + // System.out.println("Current cal: " + cal.toString()); + // using cal.set(Calendar.YEAR, -(cal.get(Calendar.YEAR))); does not work. We must set the ERA instead + cal.set(Calendar.ERA, java.util.GregorianCalendar.BC); + // System.out.println("Corrected cal: " + cal.toString()); + } + if (JdbcType == Types.TIME || JdbcType == Types.TIMESTAMP) { // parse additional nanos (if any) + int nanos = 0; int pos = ppos.getIndex(); char[] monDate = monetDate.toCharArray(); if (pos < monDate.length && monDate[pos] == '.') { @@ -2760,12 +2782,13 @@ public class MonetResultSet " in: \"" + monetDate + "\"" + " at pos: " + e.getErrorOffset(), "01M10"); // default value - cal.clear(); nanos = 0; } } + return nanos; } - return nanos; + + return 0; } /**
--- a/tests/Test_Rtimedate.java +++ b/tests/Test_Rtimedate.java @@ -14,110 +14,67 @@ public class Test_Rtimedate { Connection con = DriverManager.getConnection(args[0]); Statement stmt = con.createStatement(); ResultSet rs = null; - //DatabaseMetaData dbmd = con.getMetaData(); con.setAutoCommit(false); // >> false: auto commit should be off now System.out.println("false\t" + con.getAutoCommit()); try { - stmt.executeUpdate("CREATE TABLE table_Test_Rtimedate ( id int, ts timestamp, t time, d date, vc varchar(30), PRIMARY KEY (id) )"); + stmt.executeUpdate("CREATE TABLE table_Test_Rtimedate ( id int PRIMARY KEY, ts timestamp, t time, d date, vc varchar(30) )"); - stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, ts) VALUES (1, timestamp '2004-04-24 11:43:53.000')"); - stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, t) VALUES (2, time '11:43:53.000')"); + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, ts) VALUES (1, timestamp '2004-04-24 11:43:53.123')"); + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, t) VALUES (2, time '11:43:53.123')"); stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, d) VALUES (3, date '2004-04-24')"); - - stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, vc) VALUES (4, '2004-04-24 11:43:53.000000')"); + // same values but now as strings to test string to timestamp / time / date object conversions + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, vc) VALUES (4, '2004-04-24 11:43:53.654321')"); stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, vc) VALUES (5, '11:43:53')"); stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, vc) VALUES (6, '2004-04-24')"); + // test also with small years (< 1000) (see bug 6468) + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, ts) VALUES (11, timestamp '904-04-24 11:43:53.567')"); + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, ts) VALUES (12, timestamp '74-04-24 11:43:53.567')"); + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, ts) VALUES (13, timestamp '4-04-24 11:43:53.567')"); + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, d) VALUES (14, date '904-04-24')"); + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, d) VALUES (15, date '74-04-24')"); + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, d) VALUES (16, date '4-04-24')"); + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, vc) VALUES (17, '904-04-24 11:43:53.567')"); + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, vc) VALUES (18, '74-04-24 11:43:53.567')"); + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, vc) VALUES (19, '4-04-24 11:43:53.567')"); + + // test also with negative years (see bug 6468) + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, ts) VALUES (21, timestamp '-4-04-24 11:43:53.567')"); // negative year + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, ts) VALUES (22, timestamp '-2004-04-24 11:43:53.567')"); // negative year + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, d) VALUES (23, date '-4-04-24')"); // negative year + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, d) VALUES (24, date '-3004-04-24')"); // negative year + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, vc) VALUES (25, '-2004-04-24 11:43:53.654321')"); // negative year + stmt.executeUpdate("INSERT INTO table_Test_Rtimedate(id, vc) VALUES (26, '-3004-04-24')"); // negative year + rs = stmt.executeQuery("SELECT * FROM table_Test_Rtimedate"); - rs.next(); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - // the next three should all go well - System.out.println("1. " + rs.getString("id") + ", " + rs.getString("ts") + ", " + rs.getTimestamp("ts")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - System.out.println("2. " + rs.getString("id") + ", " + rs.getString("ts") + ", " + rs.getTime("ts")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - System.out.println("3. " + rs.getString("id") + ", " + rs.getString("ts") + ", " + rs.getDate("ts")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - rs.next(); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - // the next two should go fine - System.out.println("4. " + rs.getString("id") + ", " + rs.getString("t") + ", " + rs.getTimestamp("t")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - System.out.println("5. " + rs.getString("id") + ", " + rs.getString("t") + ", " + rs.getTime("t")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - // this one should return 0 - System.out.println("6. " + rs.getString("id") + ", " + rs.getString("t") + ", " + rs.getDate("t")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - rs.next(); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - // the next one passes - System.out.println("7. " + rs.getString("id") + ", " + rs.getString("d") + ", " + rs.getTimestamp("d")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - // this one should return 0 - System.out.println("8. " + rs.getString("id") + ", " + rs.getString("d") + ", " + rs.getTime("d")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - // and this one should pass again - System.out.println("9. " + rs.getString("id") + ", " + rs.getString("d") + ", " + rs.getDate("d")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); + readNextRow(rs, 1, "ts"); + readNextRow(rs, 2, "t"); + readNextRow(rs, 3, "d"); + + readNextRow(rs, 4, "vc"); + readNextRow(rs, 5, "vc"); + readNextRow(rs, 6, "vc"); - // in the tests below a bare string is parsed - // everything will fail except the ones commented on - rs.next(); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - // timestamp -> timestamp should go - System.out.println("1. " + rs.getString("id") + ", " + rs.getString("vc") + ", " + rs.getTimestamp("vc")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - System.out.println("2. " + rs.getString("id") + ", " + rs.getString("vc") + ", " + rs.getTime("vc")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - // timestamp -> date goes because the begin is the same - System.out.println("3. " + rs.getString("id") + ", " + rs.getString("vc") + ", " + rs.getDate("vc")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - rs.next(); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - System.out.println("4. " + rs.getString("id") + ", " + rs.getString("vc") + ", " + rs.getTimestamp("vc")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - // time -> time should fit - System.out.println("5. " + rs.getString("id") + ", " + rs.getString("vc") + ", " + rs.getTime("vc")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - System.out.println("6. " + rs.getString("id") + ", " + rs.getString("vc") + ", " + rs.getDate("vc")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - rs.next(); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - System.out.println("7. " + rs.getString("id") + ", " + rs.getString("vc") + ", " + rs.getTimestamp("vc")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - System.out.println("8. " + rs.getString("id") + ", " + rs.getString("vc") + ", " + rs.getTime("vc")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); - // date -> date should be fine - System.out.println("9. " + rs.getString("id") + ", " + rs.getString("vc") + ", " + rs.getDate("vc")); - readWarnings(rs.getWarnings()); - rs.clearWarnings(); + readNextRow(rs, 11, "ts"); + readNextRow(rs, 12, "ts"); + readNextRow(rs, 13, "ts"); + readNextRow(rs, 14, "d"); + readNextRow(rs, 15, "d"); + readNextRow(rs, 16, "d"); + readNextRow(rs, 17, "vc"); + readNextRow(rs, 18, "vc"); + readNextRow(rs, 19, "vc"); + + readNextRow(rs, 21, "ts"); + readNextRow(rs, 22, "ts"); + readNextRow(rs, 23, "d"); + readNextRow(rs, 24, "d"); + readNextRow(rs, 25, "vc"); + readNextRow(rs, 26, "vc"); readWarnings(stmt.getWarnings()); readWarnings(con.getWarnings()); @@ -130,9 +87,46 @@ public class Test_Rtimedate { con.close(); } + private static void readNextRow(ResultSet rs, int rowseq, String colnm) throws SQLException { + rs.next(); + readWarnings(rs.getWarnings()); + rs.clearWarnings(); + + // fetch the column value using multiple methods: getString(), getTimestamp(), getTime() and getDate() + // to test proper conversion and error reporting + String data = rs.getString("id") + ". " + colnm + " " + rs.getString(colnm) + " to "; + + // getTimestamp() may raise a conversion warning when the value is of type Time or a String which doesn't match format yyyy-mm-dd hh:mm:ss + try { + System.out.println(data + "ts: " + rs.getTimestamp(colnm)); + } catch (SQLException e) { + System.out.println("rs.getTimestamp(colnm) failed with error: " + e.getMessage()); + } + readWarnings(rs.getWarnings()); + rs.clearWarnings(); + + // getTime() may raise a conversion warning when the value is of type Date or a String which doesn't match format hh:mm:ss + try { + System.out.println(data + "tm: " + rs.getTime(colnm)); + } catch (SQLException e) { + System.out.println("rs.getTime(colnm) failed with error: " + e.getMessage()); + } + readWarnings(rs.getWarnings()); + rs.clearWarnings(); + + // getDate() may raise a conversion warning when the value is of type Time or a String which doesn't match format yyyy-mm-dd + try { + System.out.println(data + "dt: " + rs.getDate(colnm)); + } catch (SQLException e) { + System.out.println("rs.getDate(colnm) failed with error: " + e.getMessage()); + } + readWarnings(rs.getWarnings()); + rs.clearWarnings(); + } + private static void readWarnings(SQLWarning w) { while (w != null) { - System.out.println("warning: " + w.toString()); + System.out.println("Warning: " + w.toString()); w = w.getNextWarning(); } }