Skip to content

Instantly share code, notes, and snippets.

@ovr
Created March 10, 2026 11:55
Show Gist options
  • Select an option

  • Save ovr/f845f78549af8bcc9ed03a2a17b99df4 to your computer and use it in GitHub Desktop.

Select an option

Save ovr/f845f78549af8bcc9ed03a2a17b99df4 to your computer and use it in GitHub Desktop.
import java.sql.*;
import java.util.Properties;
public class Discover {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
props.setProperty("user", "ovr");
props.setProperty("password", "test");
try (Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost:5555/db", props)) {
// List public tables
ResultSet tables = conn.getMetaData().getTables(null, "public", "%", null);
System.out.println("=== PUBLIC TABLES ===");
while (tables.next()) {
System.out.println(" " + tables.getString("TABLE_NAME") + " (" + tables.getString("TABLE_TYPE") + ")");
}
// For each table, list columns
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(
"SELECT table_name, column_name, data_type FROM information_schema.columns WHERE table_schema = 'public' ORDER BY table_name, ordinal_position");
System.out.println("\n=== COLUMNS ===");
while (rs.next()) {
System.out.printf(" %s.%s (%s)%n", rs.getString(1), rs.getString(2), rs.getString(3));
}
}
}
}
import java.sql.*;
import java.util.Properties;
/**
* Reproducer for CubeSQL per-column format bug (GitHub issue #10418).
*
* Tableau and other JDBC clients use the Extended Query protocol which
* requests binary format for specific column types (int8, float8) and
* text format for others. This mix of per-column format codes in the
* Bind message exposes a bug in CubeSQL where RowDescription only sends
* a single format code instead of per-column format codes.
*
* Usage:
* cd rust/cubesql/java-reproducer
* curl -O https://jdbc.postgresql.org/download/postgresql-42.7.5.jar
* javac PgReproducer.java
* java -cp .:postgresql-42.7.5.jar PgReproducer
*/
public class PgReproducer {
public static void main(String[] args) {
String url = "jdbc:postgresql://localhost:5555/db";
Properties props = new Properties();
props.setProperty("user", "ovr");
props.setProperty("password", "test");
// After 1 execution the driver switches to server-prepared → binary transfer
props.setProperty("prepareThreshold", "1");
// Enable binary transfer only for int8 (OID 20) and float8 (OID 701)
// This creates a MIX of binary and text format codes in the Bind message,
// just like Tableau does.
props.setProperty("binaryTransfer", "true");
props.setProperty("binaryTransferEnable", "20,701");
props.setProperty("binaryTransferDisable", "");
System.out.println("Connecting to " + url + " ...");
try (Connection conn = DriverManager.getConnection(url, props)) {
System.out.println("Connected. Server version: "
+ conn.getMetaData().getDatabaseProductVersion());
// Query 1: orders without aggregation — mixed types
// id=float8(binary), status=text(text), order_sum=float8(binary), created=timestamp(text)
runQuery(conn, "Query 1: orders without SUM",
"SELECT id, status, order_sum, created FROM orders LIMIT 5");
// Query 2: orders with SUM aggregation — mixed types
// status=text(text), total=float8(binary), cnt=int8(binary)
runQuery(conn, "Query 2: orders with SUM",
"SELECT status, SUM(order_sum) AS total, COUNT(*) AS cnt FROM orders GROUP BY 1");
System.out.println("\nALL QUERIES SUCCEEDED — no errors.");
} catch (Exception e) {
System.err.println("\nFAILED:");
e.printStackTrace();
System.exit(1);
}
}
private static void runQuery(Connection conn, String label, String query) throws SQLException {
System.out.println("\n=== " + label + " ===");
System.out.println("SQL: " + query);
// Reuse the same PreparedStatement so the driver crosses prepareThreshold
// and switches to binary format on the 2nd+ execution.
try (PreparedStatement ps = conn.prepareStatement(query)) {
for (int attempt = 1; attempt <= 3; attempt++) {
System.out.println("\n --- Execution #" + attempt
+ (attempt == 1 ? " (text format)" : " (mixed binary/text format)") + " ---");
try (ResultSet rs = ps.executeQuery()) {
ResultSetMetaData meta = rs.getMetaData();
int cols = meta.getColumnCount();
System.out.println(" Columns (" + cols + "):");
for (int i = 1; i <= cols; i++) {
System.out.printf(" [%d] %s type=%s (%d)%n",
i,
meta.getColumnLabel(i),
meta.getColumnTypeName(i),
meta.getColumnType(i));
}
System.out.println(" Rows:");
int rowNum = 0;
while (rs.next()) {
rowNum++;
StringBuilder sb = new StringBuilder(" row " + rowNum + ": ");
for (int i = 1; i <= cols; i++) {
if (i > 1) sb.append(", ");
Object val = rs.getObject(i);
sb.append(meta.getColumnLabel(i))
.append("=")
.append(val)
.append(" (")
.append(val == null ? "null" : val.getClass().getSimpleName())
.append(")");
}
System.out.println(sb);
}
System.out.println(" Total rows: " + rowNum);
} catch (SQLException e) {
System.err.println(" ERROR on execution #" + attempt + ": " + e.getMessage());
throw e;
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment