提交 e4760bbd authored 作者: Thomas Mueller's avatar Thomas Mueller

PgServer: incorrect SQL types were returned in result set meta data.

上级 481585be
...@@ -45,9 +45,14 @@ public class PgServer implements Service { ...@@ -45,9 +45,14 @@ public class PgServer implements Service {
*/ */
public static final int DEFAULT_PORT = 5435; public static final int DEFAULT_PORT = 5435;
/**
* The VARCHAR type.
*/
public static final int PG_TYPE_VARCHAR = 1043;
private static final int PG_TYPE_BOOL = 16; private static final int PG_TYPE_BOOL = 16;
private static final int PG_TYPE_BYTEA = 17; private static final int PG_TYPE_BYTEA = 17;
private static final int PG_TYPE_CHAR = 18; private static final int PG_TYPE_BPCHAR = 1042;
private static final int PG_TYPE_INT8 = 20; private static final int PG_TYPE_INT8 = 20;
private static final int PG_TYPE_INT2 = 21; private static final int PG_TYPE_INT2 = 21;
private static final int PG_TYPE_INT4 = 23; private static final int PG_TYPE_INT4 = 23;
...@@ -57,12 +62,13 @@ public class PgServer implements Service { ...@@ -57,12 +62,13 @@ public class PgServer implements Service {
private static final int PG_TYPE_FLOAT8 = 701; private static final int PG_TYPE_FLOAT8 = 701;
private static final int PG_TYPE_UNKNOWN = 705; private static final int PG_TYPE_UNKNOWN = 705;
private static final int PG_TYPE_TEXTARRAY = 1009; private static final int PG_TYPE_TEXTARRAY = 1009;
private static final int PG_TYPE_VARCHAR = 1043;
private static final int PG_TYPE_DATE = 1082; private static final int PG_TYPE_DATE = 1082;
private static final int PG_TYPE_TIME = 1083; private static final int PG_TYPE_TIME = 1083;
private static final int PG_TYPE_TIMESTAMP_NO_TMZONE = 1114; private static final int PG_TYPE_TIMESTAMP_NO_TMZONE = 1114;
private static final int PG_TYPE_NUMERIC = 1700; private static final int PG_TYPE_NUMERIC = 1700;
private HashSet<Integer> typeSet = New.hashSet();
private int port = PgServer.DEFAULT_PORT; private int port = PgServer.DEFAULT_PORT;
private boolean stop; private boolean stop;
private boolean trace; private boolean trace;
...@@ -102,8 +108,8 @@ public class PgServer implements Service { ...@@ -102,8 +108,8 @@ public class PgServer implements Service {
} }
} }
org.h2.Driver.load(); org.h2.Driver.load();
// int testing; // int testing;
// log = true; // trace = true;
} }
boolean getTrace() { boolean getTrace() {
...@@ -410,7 +416,7 @@ public class PgServer implements Service { ...@@ -410,7 +416,7 @@ public class PgServer implements Service {
case Types.CLOB: case Types.CLOB:
return PG_TYPE_TEXT; return PG_TYPE_TEXT;
case Types.CHAR: case Types.CHAR:
return PG_TYPE_CHAR; return PG_TYPE_BPCHAR;
case Types.SMALLINT: case Types.SMALLINT:
return PG_TYPE_INT2; return PG_TYPE_INT2;
case Types.INTEGER: case Types.INTEGER:
...@@ -440,4 +446,25 @@ public class PgServer implements Service { ...@@ -440,4 +446,25 @@ public class PgServer implements Service {
} }
} }
/**
* Get the type hash set.
*
* @return the type set
*/
HashSet<Integer> getTypeSet() {
return typeSet;
}
/**
* Check whether a data type is supported.
* A warning is logged if not.
*
* @param type the type
*/
void checkType(int type) {
if (!typeSet.contains(type)) {
trace("Unsupported type: " + type);
}
}
} }
...@@ -43,7 +43,6 @@ import org.h2.util.ScriptReader; ...@@ -43,7 +43,6 @@ import org.h2.util.ScriptReader;
* 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 int TYPE_STRING = Types.VARCHAR;
private PgServer server; private PgServer server;
private Socket socket; private Socket socket;
private Connection conn; private Connection conn;
...@@ -63,7 +62,6 @@ public class PgServerThread implements Runnable { ...@@ -63,7 +62,6 @@ public class PgServerThread implements Runnable {
private String dateStyle = "ISO"; private String dateStyle = "ISO";
private HashMap<String, Prepared> prepared = New.hashMap(); private HashMap<String, Prepared> prepared = New.hashMap();
private HashMap<String, Portal> portals = New.hashMap(); private HashMap<String, Portal> portals = New.hashMap();
private HashSet<Integer> typeSet = New.hashSet();
PgServerThread(Socket socket, PgServer server) { PgServerThread(Socket socket, PgServer server) {
this.server = server; this.server = server;
...@@ -163,7 +161,7 @@ public class PgServerThread implements Runnable { ...@@ -163,7 +161,7 @@ public class PgServerThread implements Runnable {
} else if ("DateStyle".equals(param)) { } else if ("DateStyle".equals(param)) {
dateStyle = value; dateStyle = value;
} }
// server.log(" param " + param + "=" + value); server.trace(" param " + param + "=" + value);
} }
sendAuthenticationCleartextPassword(); sendAuthenticationCleartextPassword();
initDone = true; initDone = true;
...@@ -210,7 +208,7 @@ public class PgServerThread implements Runnable { ...@@ -210,7 +208,7 @@ public class PgServerThread implements Runnable {
p.paramType = new int[count]; p.paramType = new int[count];
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
int type = readInt(); int type = readInt();
checkType(type); server.checkType(type);
p.paramType[i] = type; p.paramType[i] = type;
} }
try { try {
...@@ -373,12 +371,6 @@ public class PgServerThread implements Runnable { ...@@ -373,12 +371,6 @@ public class PgServerThread implements Runnable {
} }
} }
private void checkType(int type) {
if (typeSet.contains(type)) {
server.trace("Unsupported type: " + type);
}
}
private String getSQL(String s) { private String getSQL(String s) {
String lower = s.toLowerCase(); String lower = s.toLowerCase();
if (lower.startsWith("show max_identifier_length")) { if (lower.startsWith("show max_identifier_length")) {
...@@ -495,9 +487,9 @@ public class PgServerThread implements Runnable { ...@@ -495,9 +487,9 @@ public class PgServerThread implements Runnable {
if (p.paramType != null && p.paramType[i] != 0) { if (p.paramType != null && p.paramType[i] != 0) {
type = p.paramType[i]; type = p.paramType[i];
} else { } else {
type = TYPE_STRING; type = PgServer.PG_TYPE_VARCHAR;
} }
checkType(type); server.checkType(type);
writeInt(type); writeInt(type);
} }
sendMessage(); sendMessage();
...@@ -523,8 +515,9 @@ public class PgServerThread implements Runnable { ...@@ -523,8 +515,9 @@ public class PgServerThread implements Runnable {
for (int i = 0; i < columns; i++) { for (int i = 0; i < columns; i++) {
names[i] = meta.getColumnName(i + 1); names[i] = meta.getColumnName(i + 1);
int type = meta.getColumnType(i + 1); int type = meta.getColumnType(i + 1);
type = PgServer.convertType(type);
precision[i] = meta.getColumnDisplaySize(i + 1); precision[i] = meta.getColumnDisplaySize(i + 1);
checkType(type); server.checkType(type);
types[i] = type; types[i] = type;
} }
startMessage('T'); startMessage('T');
...@@ -588,37 +581,42 @@ public class PgServerThread implements Runnable { ...@@ -588,37 +581,42 @@ public class PgServerThread implements Runnable {
ResultSet rs = null; ResultSet rs = null;
Reader r = null; Reader r = null;
try { try {
rs = conn.getMetaData().getTables(null, "PG_CATALOG", "PG_VERSION", null); synchronized (server) {
boolean tableFound = rs.next(); // better would be: set the database to exclusive mode
stat = conn.createStatement(); rs = conn.getMetaData().getTables(null, "PG_CATALOG", "PG_VERSION", null);
if (tableFound) { boolean tableFound = rs.next();
rs = stat.executeQuery("SELECT VERSION FROM PG_CATALOG.PG_VERSION"); stat = conn.createStatement();
if (rs.next()) { if (!tableFound) {
if (rs.getInt(1) == 1) { try {
// already installed r = new InputStreamReader(new ByteArrayInputStream(Resources
stat.execute("set search_path = PUBLIC, pg_catalog"); .get("/org/h2/server/pg/pg_catalog.sql")));
return; } catch (IOException e) {
throw Message.convertIOException(e, "Can not read pg_catalog resource");
}
ScriptReader reader = new ScriptReader(r);
while (true) {
String sql = reader.readStatement();
if (sql == null) {
break;
}
stat.execute(sql);
} }
reader.close();
} }
} }
try {
r = new InputStreamReader(new ByteArrayInputStream(Resources.get("/org/h2/server/pg/pg_catalog.sql"))); rs = stat.executeQuery("SELECT VERSION FROM PG_CATALOG.PG_VERSION");
} catch (IOException e) { if (!rs.next() || rs.getInt(1) != 1) {
throw Message.convertIOException(e, "Can not read pg_catalog resource"); throw Message.throwInternalError("Invalid PG_VERSION");
}
ScriptReader reader = new ScriptReader(r);
while (true) {
String sql = reader.readStatement();
if (sql == null) {
break;
}
stat.execute(sql);
} }
reader.close(); stat.execute("set search_path = PUBLIC, pg_catalog");
rs = stat.executeQuery("SELECT OID FROM PG_CATALOG.PG_TYPE"); HashSet<Integer> typeSet = server.getTypeSet();
while (rs.next()) { if (typeSet.size() == 0) {
typeSet.add(rs.getInt(1)); rs = stat.executeQuery("SELECT OID FROM PG_CATALOG.PG_TYPE");
while (rs.next()) {
typeSet.add(rs.getInt(1));
}
} }
} finally { } finally {
JdbcUtils.closeSilently(stat); JdbcUtils.closeSilently(stat);
......
...@@ -12,8 +12,10 @@ import java.sql.DriverManager; ...@@ -12,8 +12,10 @@ import java.sql.DriverManager;
import java.sql.ParameterMetaData; import java.sql.ParameterMetaData;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.sql.Types;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.tools.Server; import org.h2.tools.Server;
...@@ -68,6 +70,11 @@ public class TestPgServer extends TestBase { ...@@ -68,6 +70,11 @@ public class TestPgServer extends TestBase {
prep.execute(); prep.execute();
ResultSet rs = stat.executeQuery("select * from test"); ResultSet rs = stat.executeQuery("select * from test");
rs.next(); rs.next();
ResultSetMetaData rsMeta = rs.getMetaData();
assertEquals(Types.INTEGER, rsMeta.getColumnType(1));
assertEquals(Types.VARCHAR, rsMeta.getColumnType(2));
prep.close(); prep.close();
assertEquals(1, rs.getInt(1)); assertEquals(1, rs.getInt(1));
assertEquals("Hello", rs.getString(2)); assertEquals("Hello", rs.getString(2));
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论