Unverified 提交 0295a962 authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #800 from katzyn/PgServer

More fixes in date-time types for ODBC drivers
......@@ -20,6 +20,7 @@ import java.net.Socket;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.sql.Connection;
import java.sql.Date;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
......@@ -53,6 +54,8 @@ import org.h2.value.CaseInsensitiveMap;
* One server thread is opened for each client.
*/
public class PgServerThread implements Runnable {
private static final boolean INTEGER_DATE_TYPES = false;
private final PgServer server;
private Socket socket;
private Connection conn;
......@@ -582,36 +585,61 @@ public class PgServerThread implements Runnable {
break;
}
case PgServer.PG_TYPE_DATE: {
writeInt(4);
long millis = rs.getDate(column).getTime();
millis += TimeZone.getDefault().getOffset(millis);
writeInt((int) (toPostgreSeconds(millis) / 86400));
Date d = rs.getDate(column);
if (d == null) {
writeInt(-1);
} else {
writeInt(4);
long millis = d.getTime();
millis += TimeZone.getDefault().getOffset(millis);
writeInt((int) (toPostgreSeconds(millis) / 86400));
}
break;
}
case PgServer.PG_TYPE_TIME: {
writeInt(8);
Time t = rs.getTime(column);
long m = t.getTime();
m += TimeZone.getDefault().getOffset(m);
// double format
m /= 1000;
m = Double.doubleToLongBits(m);
// long format
// m *= 1000;
writeInt((int) (m >>> 32));
writeInt((int) m);
if (t == null) {
writeInt(-1);
} else {
writeInt(8);
long m = t.getTime();
m += TimeZone.getDefault().getOffset(m);
if (INTEGER_DATE_TYPES) {
// long format
m *= 1000;
} else {
// double format
m /= 1000;
m = Double.doubleToLongBits(m);
}
writeInt((int) (m >>> 32));
writeInt((int) m);
}
break;
}
case PgServer.PG_TYPE_TIMESTAMP_NO_TMZONE: {
writeInt(8);
Timestamp t = rs.getTimestamp(column);
long m = t.getTime();
m += TimeZone.getDefault().getOffset(m);
// double format
m = toPostgreSeconds(m);
m = Double.doubleToLongBits(m + t.getNanos() * 0.000000001);
writeInt((int) (m >>> 32));
writeInt((int) m);
if (t == null) {
writeInt(-1);
} else {
writeInt(8);
long m = t.getTime();
m += TimeZone.getDefault().getOffset(m);
m = toPostgreSeconds(m);
int nanos = t.getNanos();
if (m < 0 && nanos != 0) {
m--;
}
if (INTEGER_DATE_TYPES) {
// long format
m = m * 1000000 + nanos / 1000;
} else {
// double format
m = Double.doubleToLongBits(m + nanos * 0.000000001);
}
writeInt((int) (m >>> 32));
writeInt((int) m);
}
break;
}
default: throw new IllegalStateException("output binary format is undefined");
......@@ -949,6 +977,7 @@ public class PgServerThread implements Runnable {
sendParameterStatus("standard_conforming_strings", "off");
// TODO PostgreSQL TimeZone
sendParameterStatus("TimeZone", "CET");
sendParameterStatus("integer_datetimes", INTEGER_DATE_TYPES ? "on" : "off");
sendBackendKeyData();
sendReadyForQuery();
}
......
......@@ -31,6 +31,7 @@ import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Objects;
import java.util.SimpleTimeZone;
import java.util.concurrent.TimeUnit;
import org.h2.jdbc.JdbcConnection;
......@@ -641,11 +642,14 @@ public abstract class TestBase {
* @throws AssertionError if the values are not equal
*/
public void assertEquals(java.util.Date expected, java.util.Date actual) {
if (expected != actual && !expected.equals(actual)) {
if (!Objects.equals(expected, actual)) {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
SimpleTimeZone gmt = new SimpleTimeZone(0, "Z");
df.setTimeZone(gmt);
fail("Expected: " + df.format(expected) + " actual: " + df.format(actual));
fail("Expected: " +
(expected != null ? df.format(expected) : "null") +
" actual: " +
(actual != null ? df.format(actual) : "null"));
}
}
......
......@@ -56,6 +56,7 @@ public class TestPgServer extends TestBase {
testKeyAlias();
testCancelQuery();
testBinaryTypes();
testDateTime();
testPrepareWithUnspecifiedType();
}
......@@ -451,6 +452,62 @@ public class TestPgServer extends TestBase {
}
}
private void testDateTime() throws SQLException, InterruptedException {
if (!getPgJdbcDriver()) {
return;
}
Server server = createPgServer(
"-pgPort", "5535", "-pgDaemon", "-key", "pgserver", "mem:pgserver");
try {
Properties props = new Properties();
props.setProperty("user", "sa");
props.setProperty("password", "sa");
// force binary
props.setProperty("prepareThreshold", "-1");
Connection conn = DriverManager.getConnection(
"jdbc:postgresql://localhost:5535/pgserver", props);
Statement stat = conn.createStatement();
stat.execute(
"create table test(x1 date, x2 time, x3 timestamp)");
Date[] dates = { null, Date.valueOf("2017-02-20"),
Date.valueOf("1970-01-01"), Date.valueOf("1969-12-31"),
Date.valueOf("1940-01-10"), Date.valueOf("1950-11-10") };
Time[] times = { null, Time.valueOf("14:15:16"),
Time.valueOf("00:00:00"), Time.valueOf("23:59:59"),
Time.valueOf("00:10:59"), Time.valueOf("08:30:42") };
Timestamp[] timestamps = { null, Timestamp.valueOf("2017-02-20 14:15:16.763"),
Timestamp.valueOf("1970-01-01 00:00:00"), Timestamp.valueOf("1969-12-31 23:59:59"),
Timestamp.valueOf("1940-01-10 00:10:59"), Timestamp.valueOf("1950-11-10 08:30:42.12") };
int count = dates.length;
PreparedStatement ps = conn.prepareStatement(
"insert into test values (?,?,?)");
for (int i = 0; i < count; i++) {
ps.setDate(1, dates[i]);
ps.setTime(2, times[i]);
ps.setTimestamp(3, timestamps[i]);
ps.execute();
}
ResultSet rs = stat.executeQuery("select * from test");
for (int i = 0; i < count; i++) {
assertTrue(rs.next());
assertEquals(dates[i], rs.getDate(1));
assertEquals(times[i], rs.getTime(2));
assertEquals(timestamps[i], rs.getTimestamp(3));
}
assertFalse(rs.next());
conn.close();
} finally {
server.stop();
}
}
private void testPrepareWithUnspecifiedType() throws Exception {
if (!getPgJdbcDriver()) {
return;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论