pg: respect format codes from Bind message when sending results

From https://www.postgresql.org/docs/9.1/static/protocol-message-formats.html:

  Bind (F)

  ...

  After the last parameter, the following fields appear:

  Int16

    The number of result-column format codes that follow (denoted R
    below). This can be zero to indicate that there are no result
    columns or that the result columns should all use the default
    format (text); or one, in which case the specified format code is
    applied to all result columns (if any); or it can equal the actual
    number of result columns of the query.

  Int16[R]

    The result-column format codes. Each must presently be zero (text)
    or one (binary).

Also fix testBinaryTypes test:

- force binary by setting prepareThreshold to -1
- handle REAL type as float

Without the fix the corrected test testBinaryTypes fails:

  05:25:02 21:55:02.666 org.h2.test.unit.TestPgServer Expected: 12345678 actual: 825373492
  Exception in thread "main" java.lang.AssertionError: Expected: 12345678 actual: 825373492
      at org.h2.test.TestBase.fail(TestBase.java:464)
      at org.h2.test.TestBase.assertEquals(TestBase.java:617)
      at org.h2.test.unit.TestPgServer.testBinaryTypes(TestPgServer.java:404)
      at org.h2.test.unit.TestPgServer.test(TestPgServer.java:51)
      at org.h2.test.unit.TestPgServer.main(TestPgServer.java:41)
上级 89c07ea5
...@@ -368,7 +368,7 @@ public class PgServerThread implements Runnable { ...@@ -368,7 +368,7 @@ public class PgServerThread implements Runnable {
ResultSet rs = prep.getResultSet(); ResultSet rs = prep.getResultSet();
// the meta-data is sent in the prior 'Describe' // the meta-data is sent in the prior 'Describe'
while (rs.next()) { while (rs.next()) {
sendDataRow(rs); sendDataRow(rs, p.resultColumnFormat);
} }
sendCommandComplete(prep, 0); sendCommandComplete(prep, 0);
} catch (Exception e) { } catch (Exception e) {
...@@ -414,7 +414,7 @@ public class PgServerThread implements Runnable { ...@@ -414,7 +414,7 @@ public class PgServerThread implements Runnable {
try { try {
sendRowDescription(meta); sendRowDescription(meta);
while (rs.next()) { while (rs.next()) {
sendDataRow(rs); sendDataRow(rs, null);
} }
sendCommandComplete(stat, 0); sendCommandComplete(stat, 0);
} catch (Exception e) { } catch (Exception e) {
...@@ -495,20 +495,31 @@ public class PgServerThread implements Runnable { ...@@ -495,20 +495,31 @@ public class PgServerThread implements Runnable {
sendMessage(); sendMessage();
} }
private void sendDataRow(ResultSet rs) throws Exception { private void sendDataRow(ResultSet rs, int[] formatCodes) throws Exception {
ResultSetMetaData metaData = rs.getMetaData(); ResultSetMetaData metaData = rs.getMetaData();
int columns = metaData.getColumnCount(); int columns = metaData.getColumnCount();
startMessage('D'); startMessage('D');
writeShort(columns); writeShort(columns);
for (int i = 1; i <= columns; i++) { for (int i = 1; i <= columns; i++) {
writeDataColumn(rs, i, PgServer.convertType(metaData.getColumnType(i))); int pgType = PgServer.convertType(metaData.getColumnType(i));
boolean text = formatAsText(pgType);
if (formatCodes != null) {
if (formatCodes.length == 0) {
text = true;
} else if (formatCodes.length == 1) {
text = formatCodes[0] == 0;
} else if (i - 1 < formatCodes.length) {
text = formatCodes[i - 1] == 0;
}
}
writeDataColumn(rs, i, pgType, text);
} }
sendMessage(); sendMessage();
} }
private void writeDataColumn(ResultSet rs, int column, int pgType) private void writeDataColumn(ResultSet rs, int column, int pgType, boolean text)
throws Exception { throws Exception {
if (formatAsText(pgType)) { if (text) {
// plain text // plain text
switch (pgType) { switch (pgType) {
case PgServer.PG_TYPE_BOOL: case PgServer.PG_TYPE_BOOL:
......
...@@ -369,8 +369,14 @@ public class TestPgServer extends TestBase { ...@@ -369,8 +369,14 @@ public class TestPgServer extends TestBase {
"-pgPort", "5535", "-pgDaemon", "-key", "test", "mem:test"); "-pgPort", "5535", "-pgDaemon", "-key", "test", "mem:test");
server.start(); server.start();
try { try {
Properties props = new Properties();
props.setProperty("user", "sa");
props.setProperty("password", "sa");
// force binary
props.setProperty("prepareThreshold", "-1");
Connection conn = DriverManager.getConnection( Connection conn = DriverManager.getConnection(
"jdbc:postgresql://localhost:5535/test", "sa", "sa"); "jdbc:postgresql://localhost:5535/test", props);
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute( stat.execute(
...@@ -386,7 +392,7 @@ public class TestPgServer extends TestBase { ...@@ -386,7 +392,7 @@ public class TestPgServer extends TestBase {
ps.setLong(4, 1234567890123L); ps.setLong(4, 1234567890123L);
ps.setDouble(5, 123.456); ps.setDouble(5, 123.456);
ps.setFloat(6, 123.456f); ps.setFloat(6, 123.456f);
ps.setDouble(7, 123.456); ps.setFloat(7, 123.456f);
ps.setBoolean(8, true); ps.setBoolean(8, true);
ps.setByte(9, (byte) 0xfe); ps.setByte(9, (byte) 0xfe);
ps.setBytes(10, new byte[] { 'a', (byte) 0xfe, '\127' }); ps.setBytes(10, new byte[] { 'a', (byte) 0xfe, '\127' });
...@@ -400,7 +406,7 @@ public class TestPgServer extends TestBase { ...@@ -400,7 +406,7 @@ public class TestPgServer extends TestBase {
assertEquals(1234567890123L, rs.getLong(4)); assertEquals(1234567890123L, rs.getLong(4));
assertEquals(123.456, rs.getDouble(5)); assertEquals(123.456, rs.getDouble(5));
assertEquals(123.456f, rs.getFloat(6)); assertEquals(123.456f, rs.getFloat(6));
assertEquals(123.456, rs.getDouble(7)); assertEquals(123.456f, rs.getFloat(7));
assertEquals(true, rs.getBoolean(8)); assertEquals(true, rs.getBoolean(8));
assertEquals((byte) 0xfe, rs.getByte(9)); assertEquals((byte) 0xfe, rs.getByte(9));
assertEquals(new byte[] { 'a', (byte) 0xfe, '\127' }, assertEquals(new byte[] { 'a', (byte) 0xfe, '\127' },
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论