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; ...@@ -20,6 +20,7 @@ import java.net.Socket;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.sql.Connection; import java.sql.Connection;
import java.sql.Date;
import java.sql.ParameterMetaData; import java.sql.ParameterMetaData;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
...@@ -53,6 +54,8 @@ import org.h2.value.CaseInsensitiveMap; ...@@ -53,6 +54,8 @@ import org.h2.value.CaseInsensitiveMap;
* One server thread is opened for each client. * One server thread is opened for each client.
*/ */
public class PgServerThread implements Runnable { public class PgServerThread implements Runnable {
private static final boolean INTEGER_DATE_TYPES = false;
private final PgServer server; private final PgServer server;
private Socket socket; private Socket socket;
private Connection conn; private Connection conn;
...@@ -582,36 +585,61 @@ public class PgServerThread implements Runnable { ...@@ -582,36 +585,61 @@ public class PgServerThread implements Runnable {
break; break;
} }
case PgServer.PG_TYPE_DATE: { case PgServer.PG_TYPE_DATE: {
writeInt(4); Date d = rs.getDate(column);
long millis = rs.getDate(column).getTime(); if (d == null) {
millis += TimeZone.getDefault().getOffset(millis); writeInt(-1);
writeInt((int) (toPostgreSeconds(millis) / 86400)); } else {
writeInt(4);
long millis = d.getTime();
millis += TimeZone.getDefault().getOffset(millis);
writeInt((int) (toPostgreSeconds(millis) / 86400));
}
break; break;
} }
case PgServer.PG_TYPE_TIME: { case PgServer.PG_TYPE_TIME: {
writeInt(8);
Time t = rs.getTime(column); Time t = rs.getTime(column);
long m = t.getTime(); if (t == null) {
m += TimeZone.getDefault().getOffset(m); writeInt(-1);
// double format } else {
m /= 1000; writeInt(8);
m = Double.doubleToLongBits(m); long m = t.getTime();
// long format m += TimeZone.getDefault().getOffset(m);
// m *= 1000; if (INTEGER_DATE_TYPES) {
writeInt((int) (m >>> 32)); // long format
writeInt((int) m); m *= 1000;
} else {
// double format
m /= 1000;
m = Double.doubleToLongBits(m);
}
writeInt((int) (m >>> 32));
writeInt((int) m);
}
break; break;
} }
case PgServer.PG_TYPE_TIMESTAMP_NO_TMZONE: { case PgServer.PG_TYPE_TIMESTAMP_NO_TMZONE: {
writeInt(8);
Timestamp t = rs.getTimestamp(column); Timestamp t = rs.getTimestamp(column);
long m = t.getTime(); if (t == null) {
m += TimeZone.getDefault().getOffset(m); writeInt(-1);
// double format } else {
m = toPostgreSeconds(m); writeInt(8);
m = Double.doubleToLongBits(m + t.getNanos() * 0.000000001); long m = t.getTime();
writeInt((int) (m >>> 32)); m += TimeZone.getDefault().getOffset(m);
writeInt((int) 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; break;
} }
default: throw new IllegalStateException("output binary format is undefined"); default: throw new IllegalStateException("output binary format is undefined");
...@@ -949,6 +977,7 @@ public class PgServerThread implements Runnable { ...@@ -949,6 +977,7 @@ public class PgServerThread implements Runnable {
sendParameterStatus("standard_conforming_strings", "off"); sendParameterStatus("standard_conforming_strings", "off");
// TODO PostgreSQL TimeZone // TODO PostgreSQL TimeZone
sendParameterStatus("TimeZone", "CET"); sendParameterStatus("TimeZone", "CET");
sendParameterStatus("integer_datetimes", INTEGER_DATE_TYPES ? "on" : "off");
sendBackendKeyData(); sendBackendKeyData();
sendReadyForQuery(); sendReadyForQuery();
} }
......
...@@ -31,6 +31,7 @@ import java.text.DateFormat; ...@@ -31,6 +31,7 @@ import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Objects;
import java.util.SimpleTimeZone; import java.util.SimpleTimeZone;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.h2.jdbc.JdbcConnection; import org.h2.jdbc.JdbcConnection;
...@@ -641,11 +642,14 @@ public abstract class TestBase { ...@@ -641,11 +642,14 @@ public abstract class TestBase {
* @throws AssertionError if the values are not equal * @throws AssertionError if the values are not equal
*/ */
public void assertEquals(java.util.Date expected, java.util.Date actual) { 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"); DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
SimpleTimeZone gmt = new SimpleTimeZone(0, "Z"); SimpleTimeZone gmt = new SimpleTimeZone(0, "Z");
df.setTimeZone(gmt); 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 { ...@@ -56,6 +56,7 @@ public class TestPgServer extends TestBase {
testKeyAlias(); testKeyAlias();
testCancelQuery(); testCancelQuery();
testBinaryTypes(); testBinaryTypes();
testDateTime();
testPrepareWithUnspecifiedType(); testPrepareWithUnspecifiedType();
} }
...@@ -451,6 +452,62 @@ public class TestPgServer extends TestBase { ...@@ -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 { private void testPrepareWithUnspecifiedType() throws Exception {
if (!getPgJdbcDriver()) { if (!getPgJdbcDriver()) {
return; return;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论