Skip to content

Commit

Permalink
fix: issue 716 getTypeInfo() may not return data in the order specifi…
Browse files Browse the repository at this point in the history
…ed in Oracle documentation (#1506)

this replaces PR #910 as it was stale and easier to replace than fix. Original work by @zemian
  • Loading branch information
davecramer committed Nov 12, 2019
1 parent c67b0b0 commit 9b8a3ff
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 1 deletion.
19 changes: 18 additions & 1 deletion pgjdbc/src/main/java/org/postgresql/jdbc/PgDatabaseMetaData.java
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -2247,14 +2252,18 @@ 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);

tuple[0] = connection.encodeString(typname);
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)));

Expand Down Expand Up @@ -2300,6 +2309,14 @@ public ResultSet getTypeInfo() throws SQLException {
rs.close();
stmt.close();

Collections.sort(v, new Comparator<byte[][]>() {
@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);
}

Expand Down
19 changes: 19 additions & 0 deletions pgjdbc/src/main/java/org/postgresql/util/ByteConverter.java
Expand Up @@ -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.
*
Expand Down
Expand Up @@ -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;
}
}
}

0 comments on commit 9b8a3ff

Please sign in to comment.