提交 3c0bc6c0 authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #534 from httpdigest/Issue-89

Add DB2 timestamp format compatibility
......@@ -21,7 +21,9 @@ Change Log
<h2>Next Version (unreleased)</h2>
<ul>
<li>Add padding for CHAR(N) values in PostgreSQL mode
<li>Add padding for CHAR(N) values in PostgreSQL mode
</li>
<li>Issue #89: Add DB2 timestamp format compatibility
</li>
<li>
</li>
......
......@@ -2907,7 +2907,7 @@ public class Parser {
String timestamp = currentValue.getString();
read();
r = ValueExpression
.get(ValueTimestamp.parse(timestamp));
.get(ValueTimestamp.parse(timestamp, session.getDatabase().getMode()));
} else if (equalsToken("X", name)) {
read();
byte[] buffer = StringUtils
......
......@@ -439,7 +439,7 @@ public class FunctionAlias extends SchemaObjectBase {
}
o = objArray;
} else {
v = v.convertTo(type);
v = v.convertTo(type, -1, session.getDatabase().getMode());
o = v.getObject();
}
if (o == null) {
......
......@@ -165,6 +165,11 @@ public class Mode {
*/
public boolean padFixedLengthStrings;
/**
* Whether DB2 TIMESTAMP formats are allowed.
*/
public boolean allowDB2TimestampFormat;
private final String name;
static {
......@@ -184,6 +189,7 @@ public class Mode {
Pattern.compile("ApplicationName|ClientAccountingInformation|" +
"ClientUser|ClientCorrelationToken");
mode.prohibitEmptyInPredicate = true;
mode.allowDB2TimestampFormat = true;
add(mode);
mode = new Mode("Derby");
......
......@@ -1263,7 +1263,7 @@ public class Function extends Expression implements FunctionCall {
} else if (v0.getType() == Value.STRING) {
ValueString vd = (ValueString) v0;
Calendar c = Calendar.getInstance();
c.setTime(ValueTimestamp.parse(vd.getString()).getDate());
c.setTime(ValueTimestamp.parse(vd.getString(), session.getDatabase().getMode()).getDate());
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
......
......@@ -963,7 +963,7 @@ public abstract class Value {
case DATE:
return ValueDate.parse(s.trim());
case TIMESTAMP:
return ValueTimestamp.parse(s.trim());
return ValueTimestamp.parse(s.trim(), mode);
case TIMESTAMP_TZ:
return ValueTimestampTimeZone.parse(s.trim());
case BYTES:
......
......@@ -13,6 +13,7 @@ import java.sql.Timestamp;
import java.util.Calendar;
import java.util.TimeZone;
import org.h2.api.ErrorCode;
import org.h2.engine.Mode;
import org.h2.message.DbException;
import org.h2.util.DateTimeUtils;
import org.h2.util.MathUtils;
......@@ -109,26 +110,53 @@ public class ValueTimestamp extends Value {
/**
* Parse a string to a ValueTimestamp. This method supports the format
* +/-year-month-day hour:minute:seconds.fractional and an optional timezone
* +/-year-month-day hour[:.]minute[:.]seconds.fractional and an optional timezone
* part.
*
* @param s the string to parse
* @return the date
*/
public static ValueTimestamp parse(String s) {
return parse(s, null);
}
/**
* Parse a string to a ValueTimestamp, using the given {@link Mode}.
* This method supports the format +/-year-month-day[ -]hour[:.]minute[:.]seconds.fractional
* and an optional timezone part.
*
* @param s the string to parse
* @param mode the database {@link Mode}
* @return the date
*/
public static ValueTimestamp parse(String s, Mode mode) {
try {
return parseTry(s);
return parseTry(s, mode);
} catch (Exception e) {
throw DbException.get(ErrorCode.INVALID_DATETIME_CONSTANT_2,
e, "TIMESTAMP", s);
}
}
private static ValueTimestamp parseTry(String s) {
/**
* See: https://stackoverflow.com/questions/3976616/how-to-find-nth-occurrence-of-character-in-a-string#answer-3976656
*/
private static int findNthIndexOf(String str, char chr, int n) {
int pos = str.indexOf(chr);
while (--n > 0 && pos != -1)
pos = str.indexOf(chr, pos + 1);
return pos;
}
private static ValueTimestamp parseTry(String s, Mode mode) {
int dateEnd = s.indexOf(' ');
if (dateEnd < 0) {
// ISO 8601 compatibility
dateEnd = s.indexOf('T');
if (dateEnd < 0 && mode != null && mode.allowDB2TimestampFormat) {
// DB2 also allows dash between date and time
dateEnd = findNthIndexOf(s, '-', 3);
}
}
int timeStart;
if (dateEnd < 0) {
......@@ -148,9 +176,9 @@ public class ValueTimestamp extends Value {
tz = TimeZone.getTimeZone("UTC");
timeEnd--;
} else {
int timeZoneStart = s.indexOf('+', dateEnd);
int timeZoneStart = s.indexOf('+', dateEnd + 1);
if (timeZoneStart < 0) {
timeZoneStart = s.indexOf('-', dateEnd);
timeZoneStart = s.indexOf('-', dateEnd + 1);
}
if (timeZoneStart >= 0) {
String tzName = "GMT" + s.substring(timeZoneStart);
......
......@@ -497,6 +497,14 @@ public class TestCompatibility extends TestBase {
"fetch next 2 rows only with rs use and keep update locks");
res = stat.executeQuery("select * from test order by id " +
"fetch next 2 rows only with rr use and keep exclusive locks");
// Test DB2 TIMESTAMP format with dash separating date and time
stat.execute("drop table test if exists");
stat.execute("create table test(date TIMESTAMP)");
stat.executeUpdate("insert into test (date) values ('2014-04-05-09.48.28.020005')");
assertResult("2014-04-05 09:48:28.020005", stat, "select date from test"); // <- result is always H2 format timestamp!
assertResult("2014-04-05 09:48:28.020005", stat, "select date from test where date = '2014-04-05-09.48.28.020005'");
assertResult("2014-04-05 09:48:28.020005", stat, "select date from test where date = '2014-04-05 09:48:28.020005'");
}
private void testDerby() throws SQLException {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论