Unverified 提交 8b2f4739 authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #798 from katzyn/PgServer

Add partial support of DATE, TIME, and TIMESTAMP data types to PgServer
......@@ -26,10 +26,14 @@ import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Properties;
import java.util.TimeZone;
import org.h2.command.CommandInterface;
import org.h2.engine.ConnectionInfo;
import org.h2.engine.SysProperties;
......@@ -520,6 +524,11 @@ public class PgServerThread implements Runnable {
sendMessage();
}
private static long toPostgreSeconds(long millis) {
// TODO handle Julian/Gregorian transitions
return millis / 1000 - 946684800L;
}
private void writeDataColumn(ResultSet rs, int column, int pgType, boolean text)
throws Exception {
if (text) {
......@@ -562,7 +571,7 @@ public class PgServerThread implements Runnable {
writeInt(8);
dataOut.writeDouble(rs.getDouble(column));
break;
case PgServer.PG_TYPE_BYTEA:
case PgServer.PG_TYPE_BYTEA: {
byte[] data = rs.getBytes(column);
if (data == null) {
writeInt(-1);
......@@ -571,7 +580,40 @@ public class PgServerThread implements Runnable {
write(data);
}
break;
}
case PgServer.PG_TYPE_DATE: {
writeInt(4);
long millis = rs.getDate(column).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);
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);
break;
}
default: throw new IllegalStateException("output binary format is undefined");
}
}
......@@ -595,7 +637,28 @@ public class PgServerThread implements Runnable {
// plain text
byte[] data = DataUtils.newBytes(paramLen);
readFully(data);
prep.setString(col, new String(data, getEncoding()));
String str = new String(data, getEncoding());
switch (pgType) {
case PgServer.PG_TYPE_DATE: {
// Strip timezone offset
int idx = str.indexOf(' ');
if (idx > 0) {
str = str.substring(0, idx);
}
break;
}
case PgServer.PG_TYPE_TIME: {
// Strip timezone offset
int idx = str.indexOf('+');
if (idx <= 0)
idx = str.indexOf('-');
if (idx > 0) {
str = str.substring(0, idx);
}
break;
}
}
prep.setString(col, str);
} else {
// binary
switch (pgType) {
......
......@@ -6,7 +6,6 @@
package org.h2.test;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
......
......@@ -7,6 +7,7 @@ package org.h2.test.unit;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
......@@ -14,6 +15,7 @@ import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Properties;
......@@ -22,6 +24,8 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.h2.api.ErrorCode;
import org.h2.test.TestBase;
import org.h2.tools.Server;
......@@ -45,19 +49,13 @@ public class TestPgServer extends TestBase {
config.memory = true;
config.mvStore = true;
config.mvcc = true;
// the sleeps are too mitigate "port in use" exceptions on Jenkins
testLowerCaseIdentifiers();
Thread.sleep(100);
// testPgAdapter() starts server by itself without a wait so run it first
testPgAdapter();
Thread.sleep(100);
testLowerCaseIdentifiers();
testKeyAlias();
Thread.sleep(100);
testKeyAlias();
Thread.sleep(100);
testCancelQuery();
Thread.sleep(100);
testBinaryTypes();
Thread.sleep(100);
testPrepareWithUnspecifiedType();
}
......@@ -70,10 +68,9 @@ public class TestPgServer extends TestBase {
"mem:pgserver;DATABASE_TO_UPPER=false", "sa", "sa");
Statement stat = conn.createStatement();
stat.execute("create table test(id int, name varchar(255))");
Server server = Server.createPgServer("-baseDir", getBaseDir(),
Server server = createPgServer("-baseDir", getBaseDir(),
"-pgPort", "5535", "-pgDaemon", "-key", "pgserver",
"mem:pgserver");
server.start();
try {
Connection conn2;
conn2 = DriverManager.getConnection(
......@@ -98,6 +95,28 @@ public class TestPgServer extends TestBase {
}
}
private Server createPgServer(String... args) throws SQLException {
Server server = Server.createPgServer(args);
int failures = 0;
for (;;) {
try {
server.start();
return server;
} catch (SQLException e) {
// the sleeps are too mitigate "port in use" exceptions on Jenkins
if (e.getErrorCode() != ErrorCode.EXCEPTION_OPENING_PORT_2 || ++failures > 10) {
throw e;
}
println("Sleeping");
try {
Thread.sleep(100);
} catch (InterruptedException e2) {
throw new RuntimeException(e2);
}
}
}
}
private void testPgAdapter() throws SQLException {
deleteDb("pgserver");
Server server = Server.createPgServer(
......@@ -120,9 +139,8 @@ public class TestPgServer extends TestBase {
return;
}
Server server = Server.createPgServer(
Server server = createPgServer(
"-pgPort", "5535", "-pgDaemon", "-key", "pgserver", "mem:pgserver");
server.start();
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
......@@ -347,9 +365,8 @@ public class TestPgServer extends TestBase {
if (!getPgJdbcDriver()) {
return;
}
Server server = Server.createPgServer(
Server server = createPgServer(
"-pgPort", "5535", "-pgDaemon", "-key", "pgserver", "mem:pgserver");
server.start();
try {
Connection conn = DriverManager.getConnection(
"jdbc:postgresql://localhost:5535/pgserver", "sa", "sa");
......@@ -375,13 +392,8 @@ public class TestPgServer extends TestBase {
return;
}
// Sometimes the previous pg server has not finished shutting and we get
// "port in use", so sleep for a bit.
Thread.sleep(100);
Server server = Server.createPgServer(
Server server = createPgServer(
"-pgPort", "5535", "-pgDaemon", "-key", "pgserver", "mem:pgserver");
server.start();
try {
Properties props = new Properties();
props.setProperty("user", "sa");
......@@ -396,10 +408,11 @@ public class TestPgServer extends TestBase {
stat.execute(
"create table test(x1 varchar, x2 int, " +
"x3 smallint, x4 bigint, x5 double, x6 float, " +
"x7 real, x8 boolean, x9 char, x10 bytea)");
"x7 real, x8 boolean, x9 char, x10 bytea, " +
"x11 date, x12 time, x13 timestamp)");
PreparedStatement ps = conn.prepareStatement(
"insert into test values (?,?,?,?,?,?,?,?,?,?)");
"insert into test values (?,?,?,?,?,?,?,?,?,?,?,?,?)");
ps.setString(1, "test");
ps.setInt(2, 12345678);
ps.setShort(3, (short) 12345);
......@@ -410,6 +423,9 @@ public class TestPgServer extends TestBase {
ps.setBoolean(8, true);
ps.setByte(9, (byte) 0xfe);
ps.setBytes(10, new byte[] { 'a', (byte) 0xfe, '\127' });
ps.setDate(11, Date.valueOf("2015-01-31"));
ps.setTime(12, Time.valueOf("20:11:15"));
ps.setTimestamp(13, Timestamp.valueOf("2001-10-30 14:16:10.111"));
ps.execute();
ResultSet rs = stat.executeQuery("select * from test");
......@@ -425,6 +441,9 @@ public class TestPgServer extends TestBase {
assertEquals((byte) 0xfe, rs.getByte(9));
assertEquals(new byte[] { 'a', (byte) 0xfe, '\127' },
rs.getBytes(10));
assertEquals(Date.valueOf("2015-01-31"), rs.getDate(11));
assertEquals(Time.valueOf("20:11:15"), rs.getTime(12));
assertEquals(Timestamp.valueOf("2001-10-30 14:16:10.111"), rs.getTimestamp(13));
conn.close();
} finally {
......@@ -437,9 +456,8 @@ public class TestPgServer extends TestBase {
return;
}
Server server = Server.createPgServer(
Server server = createPgServer(
"-pgPort", "5535", "-pgDaemon", "-key", "pgserver", "mem:pgserver");
server.start();
try {
Properties props = new Properties();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论