提交 2fe774a1 authored 作者: Noel Grandin's avatar Noel Grandin

Merge pull request #244 from michaeltandy/master

Improve compatibility with oracle to_date RRRR
...@@ -37,10 +37,14 @@ class ToDateTokenizer { ...@@ -37,10 +37,14 @@ class ToDateTokenizer {
static final Pattern PATTERN_NUMBER = Pattern.compile("^([+-]?[0-9]+)"); static final Pattern PATTERN_NUMBER = Pattern.compile("^([+-]?[0-9]+)");
/** /**
* The pattern for for digits (typically a year). * The pattern for four digits (typically a year).
*/ */
static final Pattern PATTERN_FOUR_DIGITS = Pattern.compile("^([+-]?[0-9]{4})"); static final Pattern PATTERN_FOUR_DIGITS = Pattern.compile("^([+-]?[0-9]{4})");
/**
* The pattern 2-4 digits (e.g. for RRRR).
*/
static final Pattern PATTERN_TWO_TO_FOUR_DIGITS = Pattern.compile("^([+-]?[0-9]{2,4})");
/** /**
* The pattern for three digits. * The pattern for three digits.
*/ */
...@@ -142,6 +146,8 @@ class ToDateTokenizer { ...@@ -142,6 +146,8 @@ class ToDateTokenizer {
dateNr = Integer.parseInt(inputFragmentStr); dateNr = Integer.parseInt(inputFragmentStr);
// Gregorian calendar does not have a year 0. // Gregorian calendar does not have a year 0.
// 0 = 0001 BC, -1 = 0002 BC, ... so we adjust // 0 = 0001 BC, -1 = 0002 BC, ... so we adjust
if (dateNr==0)
throwException(params, "Year may not be zero");
result.set(Calendar.YEAR, dateNr >= 0 ? dateNr : dateNr + 1); result.set(Calendar.YEAR, dateNr >= 0 ? dateNr : dateNr + 1);
break; break;
case YYY: case YYY:
...@@ -155,9 +161,16 @@ class ToDateTokenizer { ...@@ -155,9 +161,16 @@ class ToDateTokenizer {
break; break;
case RRRR: case RRRR:
inputFragmentStr = matchStringOrThrow( inputFragmentStr = matchStringOrThrow(
PATTERN_TWO_DIGITS, params, formatTokenEnum); PATTERN_TWO_TO_FOUR_DIGITS, params, formatTokenEnum);
dateNr = Integer.parseInt(inputFragmentStr); dateNr = Integer.parseInt(inputFragmentStr);
dateNr += dateNr < 50 ? 2000 : 1900; if (inputFragmentStr.length() < 4) {
if (dateNr < 50)
dateNr += 2000;
else if (dateNr < 100)
dateNr += 1900;
}
if (dateNr==0)
throwException(params, "Year may not be zero");
result.set(Calendar.YEAR, dateNr); result.set(Calendar.YEAR, dateNr);
break; break;
case RR: case RR:
......
...@@ -11,6 +11,7 @@ import java.sql.ResultSet; ...@@ -11,6 +11,7 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.sql.Types; import java.sql.Types;
import java.text.SimpleDateFormat;
import java.util.Arrays; import java.util.Arrays;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.tools.SimpleResultSet; import org.h2.tools.SimpleResultSet;
...@@ -35,6 +36,7 @@ public class TestCompatibilityOracle extends TestBase { ...@@ -35,6 +36,7 @@ public class TestCompatibilityOracle extends TestBase {
testTreatEmptyStringsAsNull(); testTreatEmptyStringsAsNull();
testDecimalScale(); testDecimalScale();
testPoundSymbolInColumnName(); testPoundSymbolInColumnName();
testToDate();
} }
private void testTreatEmptyStringsAsNull() throws SQLException { private void testTreatEmptyStringsAsNull() throws SQLException {
...@@ -140,6 +142,31 @@ public class TestCompatibilityOracle extends TestBase { ...@@ -140,6 +142,31 @@ public class TestCompatibilityOracle extends TestBase {
conn.close(); conn.close();
} }
private void testToDate() throws SQLException {
deleteDb("oracle");
Connection conn = getConnection("oracle;MODE=Oracle");
Statement stat = conn.createStatement();
stat.execute("CREATE TABLE DATETABLE (ID NUMBER PRIMARY KEY, TESTVAL TIMESTAMP)");
stat.execute("INSERT INTO DATETABLE VALUES (1, to_date('31-DEC-9999 23:59:59','DD-MON-RRRR HH24:MI:SS'))");
stat.execute("INSERT INTO DATETABLE VALUES (2, to_date('01-JAN-0001 00:00:00','DD-MON-RRRR HH24:MI:SS'))");
assertResultDate("9999-12-31T23:59:59", stat, "SELECT TESTVAL FROM DATETABLE WHERE ID=1");
assertResultDate("0001-01-01T00:00:00", stat, "SELECT TESTVAL FROM DATETABLE WHERE ID=2");
conn.close();
}
private void assertResultDate(String expected, Statement stat, String sql) throws SQLException {
SimpleDateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
ResultSet rs = stat.executeQuery(sql);
if (rs.next()) {
assertEquals(expected, iso8601.format(rs.getTimestamp(1)));
} else {
assertEquals(expected, null);
}
}
private void assertResult(Object[][] expectedRowsOfValues, Statement stat, private void assertResult(Object[][] expectedRowsOfValues, Statement stat,
String sql) throws SQLException { String sql) throws SQLException {
assertResult(newSimpleResultSet(expectedRowsOfValues), stat, sql); assertResult(newSimpleResultSet(expectedRowsOfValues), stat, sql);
......
...@@ -1288,6 +1288,11 @@ public class TestFunctions extends TestBase implements AggregateFunction { ...@@ -1288,6 +1288,11 @@ public class TestFunctions extends TestBase implements AggregateFunction {
} catch (Exception e) { } catch (Exception e) {
assertEquals(DbException.class.getSimpleName(), e.getClass().getSimpleName()); assertEquals(DbException.class.getSimpleName(), e.getClass().getSimpleName());
} }
try {
ToDateParser.toDate("1-DEC-0000","DD-MON-RRRR");
fail("Oracle to_date should reject year 0 (ORA-01841)");
} catch (Exception e) { }
} }
private void testToDate() throws ParseException { private void testToDate() throws ParseException {
...@@ -1400,6 +1405,22 @@ public class TestFunctions extends TestBase implements AggregateFunction { ...@@ -1400,6 +1405,22 @@ public class TestFunctions extends TestBase implements AggregateFunction {
date = new SimpleDateFormat("yyyy-MM-dd").parse("2013-01-29"); date = new SimpleDateFormat("yyyy-MM-dd").parse("2013-01-29");
assertEquals(date, ToDateParser.toDate("113029", "J")); assertEquals(date, ToDateParser.toDate("113029", "J"));
date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss").parse("9999-12-31T23:59:59");
assertEquals(date, ToDateParser.toDate("31-DEC-9999 23:59:59","DD-MON-YYYY HH24:MI:SS"));
assertEquals(date, ToDateParser.toDate("31-DEC-9999 23:59:59","DD-MON-RRRR HH24:MI:SS"));
SimpleDateFormat ymd = new SimpleDateFormat("yyyy-MM-dd");
assertEquals(ymd.parse("0001-03-01"), ToDateParser.toDate("1-MAR-0001","DD-MON-RRRR"));
assertEquals(ymd.parse("9999-03-01"), ToDateParser.toDate("1-MAR-9999","DD-MON-RRRR"));
assertEquals(ymd.parse("2000-03-01"), ToDateParser.toDate("1-MAR-000","DD-MON-RRRR"));
assertEquals(ymd.parse("1999-03-01"), ToDateParser.toDate("1-MAR-099","DD-MON-RRRR"));
assertEquals(ymd.parse("0100-03-01"), ToDateParser.toDate("1-MAR-100","DD-MON-RRRR"));
assertEquals(ymd.parse("2000-03-01"), ToDateParser.toDate("1-MAR-00","DD-MON-RRRR"));
assertEquals(ymd.parse("2049-03-01"), ToDateParser.toDate("1-MAR-49","DD-MON-RRRR"));
assertEquals(ymd.parse("1950-03-01"), ToDateParser.toDate("1-MAR-50","DD-MON-RRRR"));
assertEquals(ymd.parse("1999-03-01"), ToDateParser.toDate("1-MAR-99","DD-MON-RRRR"));
} }
private static void setMonth(Date date, int month) { private static void setMonth(Date date, int month) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论