diff --git a/pgjdbc/src/main/java/org/postgresql/jdbc/PgDatabaseMetaData.java b/pgjdbc/src/main/java/org/postgresql/jdbc/PgDatabaseMetaData.java index 56d135065c..ef3ac75000 100644 --- a/pgjdbc/src/main/java/org/postgresql/jdbc/PgDatabaseMetaData.java +++ b/pgjdbc/src/main/java/org/postgresql/jdbc/PgDatabaseMetaData.java @@ -9,11 +9,13 @@ import org.postgresql.core.Field; import org.postgresql.core.Oid; import org.postgresql.core.ServerVersion; +import org.postgresql.util.ByteConverter; import org.postgresql.util.GT; import org.postgresql.util.JdbcBlackHole; import org.postgresql.util.PSQLException; import org.postgresql.util.PSQLState; +import java.math.BigInteger; import java.sql.Array; import java.sql.Connection; import java.sql.DatabaseMetaData; @@ -24,6 +26,9 @@ import java.sql.Types; import java.util.ArrayList; import java.util.Arrays; + +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -2247,7 +2252,7 @@ public ResultSet getTypeInfo() throws SQLException { connection.encodeString(Integer.toString(java.sql.DatabaseMetaData.typeSearchable)); while (rs.next()) { - byte[][] tuple = new byte[18][]; + byte[][] tuple = new byte[19][]; String typname = rs.getString(1); int typeOid = (int) rs.getLong(2); @@ -2255,6 +2260,10 @@ public ResultSet getTypeInfo() throws SQLException { int sqlType = connection.getTypeInfo().getSQLType(typname); tuple[1] = connection.encodeString(Integer.toString(sqlType)); + + /* this is just for sorting below, the result set never sees this */ + tuple[18] = BigInteger.valueOf(sqlType).toByteArray(); + tuple[2] = connection .encodeString(Integer.toString(connection.getTypeInfo().getMaximumPrecision(typeOid))); @@ -2300,6 +2309,14 @@ public ResultSet getTypeInfo() throws SQLException { rs.close(); stmt.close(); + Collections.sort(v, new Comparator() { + @Override + public int compare(byte[][] o1, byte[][] o2) { + int i1 = ByteConverter.bytesToInt(o1[18]); + int i2 = ByteConverter.bytesToInt(o2[18]); + return (i1 < i2) ? -1 : ((i1 == i2) ? 0 : 1); + } + }); return ((BaseStatement) createMetaDataStatement()).createDriverResultSet(f, v); } diff --git a/pgjdbc/src/main/java/org/postgresql/util/ByteConverter.java b/pgjdbc/src/main/java/org/postgresql/util/ByteConverter.java index 5464236cb9..f118897781 100644 --- a/pgjdbc/src/main/java/org/postgresql/util/ByteConverter.java +++ b/pgjdbc/src/main/java/org/postgresql/util/ByteConverter.java @@ -16,6 +16,25 @@ private ByteConverter() { // prevent instantiation of static helper class } + /** + * Convert a variable length array of bytes to an integer + * @param bytes array of bytes that can be decoded as an integer + * @return integer + */ + public static int bytesToInt(byte []bytes) { + if ( bytes.length == 1 ) { + return (int)bytes[0]; + } + if ( bytes.length == 2 ) { + return int2(bytes, 0); + } + if ( bytes.length == 4 ) { + return int4(bytes, 0); + } else { + throw new IllegalArgumentException("Argument bytes is empty"); + } + } + /** * Parses a long value from the byte array. * diff --git a/pgjdbc/src/test/java/org/postgresql/test/jdbc4/DatabaseMetaDataTest.java b/pgjdbc/src/test/java/org/postgresql/test/jdbc4/DatabaseMetaDataTest.java index 813a777f2e..a22f42ae72 100644 --- a/pgjdbc/src/test/java/org/postgresql/test/jdbc4/DatabaseMetaDataTest.java +++ b/pgjdbc/src/test/java/org/postgresql/test/jdbc4/DatabaseMetaDataTest.java @@ -232,4 +232,17 @@ public void testGetFunctionsWithSpecificTypes() throws SQLException { stmt.execute("DROP FUNCTION getfunc_f3(int, varchar)"); } } + + @Test + public void testSortedDataTypes() throws SQLException { + // https://github.com/pgjdbc/pgjdbc/issues/716 + DatabaseMetaData dbmd = conn.getMetaData(); + ResultSet rs = dbmd.getTypeInfo(); + int lastType = Integer.MIN_VALUE; + while (rs.next()) { + int type = rs.getInt("DATA_TYPE"); + assertTrue(lastType <= type); + lastType = type; + } + } }