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

Merge pull request #849 from katzyn/pgserver

Encode date and time in fast and proper way in PgServerThread
......@@ -3222,7 +3222,14 @@ public class JdbcResultSet extends TraceObject implements ResultSet, JdbcResultS
}
}
private Value get(int columnIndex) {
/**
* INTERNAL
*
* @param columnIndex
* index of a column
* @return internal representation of the value in the specified column
*/
public Value get(int columnIndex) {
checkColumnIndex(columnIndex);
checkOnValidRow();
Value[] list;
......
......@@ -20,35 +20,38 @@ 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;
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;
import org.h2.jdbc.JdbcConnection;
import org.h2.jdbc.JdbcPreparedStatement;
import org.h2.jdbc.JdbcResultSet;
import org.h2.jdbc.JdbcStatement;
import org.h2.message.DbException;
import org.h2.mvstore.DataUtils;
import org.h2.util.DateTimeUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.MathUtils;
import org.h2.util.ScriptReader;
import org.h2.util.StringUtils;
import org.h2.util.Utils;
import org.h2.value.CaseInsensitiveMap;
import org.h2.value.Value;
import org.h2.value.ValueDate;
import org.h2.value.ValueNull;
import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp;
/**
* One server thread is opened for each client.
......@@ -527,153 +530,91 @@ public class PgServerThread implements Runnable {
sendMessage();
}
private static long toPostgreSeconds(long millis) {
// TODO handle Julian/Gregorian transitions
return millis / 1000 - 946684800L;
private static long toPostgreDays(long dateValue) {
return DateTimeUtils.prolepticGregorianAbsoluteDayFromDateValue(dateValue) - 10_957;
}
private void writeDataColumn(ResultSet rs, int column, int pgType, boolean text)
throws Exception {
Value v = ((JdbcResultSet) rs).get(column);
if (v == ValueNull.INSTANCE) {
writeInt(-1);
return;
}
if (text) {
// plain text
switch (pgType) {
case PgServer.PG_TYPE_BOOL: {
boolean b = rs.getBoolean(column);
if (rs.wasNull()) {
writeInt(-1);
} else {
writeInt(1);
dataOut.writeByte(b ? 't' : 'f');
}
case PgServer.PG_TYPE_BOOL:
writeInt(1);
dataOut.writeByte(v.getBoolean() ? 't' : 'f');
break;
}
default:
String s = rs.getString(column);
if (s == null) {
writeInt(-1);
} else {
byte[] data = s.getBytes(getEncoding());
writeInt(data.length);
write(data);
}
byte[] data = v.getString().getBytes(getEncoding());
writeInt(data.length);
write(data);
}
} else {
// binary
switch (pgType) {
case PgServer.PG_TYPE_INT2: {
short s = rs.getShort(column);
if (rs.wasNull()) {
writeInt(-1);
} else {
writeInt(2);
writeShort(s);
}
case PgServer.PG_TYPE_INT2:
writeInt(2);
writeShort(v.getShort());
break;
}
case PgServer.PG_TYPE_INT4: {
int i = rs.getInt(column);
if (rs.wasNull()) {
writeInt(-1);
} else {
writeInt(4);
writeInt(i);
}
case PgServer.PG_TYPE_INT4:
writeInt(4);
writeInt(v.getInt());
break;
}
case PgServer.PG_TYPE_INT8: {
long l = rs.getLong(column);
if (rs.wasNull()) {
writeInt(-1);
} else {
writeInt(8);
dataOut.writeLong(l);
}
case PgServer.PG_TYPE_INT8:
writeInt(8);
dataOut.writeLong(v.getLong());
break;
}
case PgServer.PG_TYPE_FLOAT4: {
float f = rs.getFloat(column);
if (rs.wasNull()) {
writeInt(-1);
} else {
writeInt(4);
dataOut.writeFloat(f);
}
case PgServer.PG_TYPE_FLOAT4:
writeInt(4);
dataOut.writeFloat(v.getFloat());
break;
}
case PgServer.PG_TYPE_FLOAT8: {
double d = rs.getDouble(column);
if (rs.wasNull()) {
writeInt(-1);
} else {
writeInt(8);
dataOut.writeDouble(d);
}
case PgServer.PG_TYPE_FLOAT8:
writeInt(8);
dataOut.writeDouble(v.getDouble());
break;
}
case PgServer.PG_TYPE_BYTEA: {
byte[] data = rs.getBytes(column);
if (data == null) {
writeInt(-1);
} else {
writeInt(data.length);
write(data);
}
byte[] data = v.getBytesNoCopy();
writeInt(data.length);
write(data);
break;
}
case PgServer.PG_TYPE_DATE: {
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));
}
ValueDate d = (ValueDate) v.convertTo(Value.DATE);
writeInt(4);
writeInt((int) (toPostgreDays(d.getDateValue())));
break;
}
case PgServer.PG_TYPE_TIME: {
Time t = rs.getTime(column);
if (t == null) {
writeInt(-1);
ValueTime t = (ValueTime) v.convertTo(Value.TIME);
writeInt(8);
long m = t.getNanos();
if (INTEGER_DATE_TYPES) {
// long format
m /= 1_000;
} 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);
}
dataOut.writeLong(m);
// double format
m = Double.doubleToLongBits(m * 0.000_000_001);
}
dataOut.writeLong(m);
break;
}
case PgServer.PG_TYPE_TIMESTAMP_NO_TMZONE: {
Timestamp t = rs.getTimestamp(column);
if (t == null) {
writeInt(-1);
ValueTimestamp t = (ValueTimestamp) v.convertTo(Value.TIMESTAMP);
writeInt(8);
long m = toPostgreDays(t.getDateValue()) * 86_400;
long nanos = t.getTimeNanos();
if (INTEGER_DATE_TYPES) {
// long format
m = m * 1_000_000 + nanos / 1_000;
} 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);
}
dataOut.writeLong(m);
// double format
m = Double.doubleToLongBits(m + nanos * 0.000_000_001);
}
dataOut.writeLong(m);
break;
}
default: throw new IllegalStateException("output binary format is undefined");
......
......@@ -1120,6 +1120,29 @@ public class DateTimeUtils {
return a;
}
/**
* Calculate the absolute day from an encoded date value in proleptic Gregorian
* calendar.
*
* @param dateValue the date value
* @return the absolute day in proleptic Gregorian calendar
*/
public static long prolepticGregorianAbsoluteDayFromDateValue(long dateValue) {
long y = yearFromDateValue(dateValue);
int m = monthFromDateValue(dateValue);
int d = dayFromDateValue(dateValue);
if (m <= 2) {
y--;
m += 12;
}
long a = ((y * 2922L) >> 3) + DAYS_OFFSET[m - 3] + d - 719484;
if (y < 1901 || y > 2099) {
// Slow mode
a += (y / 400) - (y / 100) + 15;
}
return a;
}
/**
* Calculate the encoded date value from an absolute day.
*
......
......@@ -487,13 +487,16 @@ public class TestPgServer extends TestBase {
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") };
Date.valueOf("1940-01-10"), Date.valueOf("1950-11-10"),
Date.valueOf("1500-01-01")};
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") };
Time.valueOf("00:10:59"), Time.valueOf("08:30:42"),
Time.valueOf("10:00:00")};
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") };
Timestamp.valueOf("1940-01-10 00:10:59"), Timestamp.valueOf("1950-11-10 08:30:42.12"),
Timestamp.valueOf("1500-01-01 10:00:10")};
int count = dates.length;
PreparedStatement ps = conn.prepareStatement(
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论