severe jdbc metadata problem

From: Tim Holloway <mtsinc(at)southeast(dot)net>
To: pgsql-bugs(at)postgresql(dot)org
Subject: severe jdbc metadata problem
Date: 2000-02-04 00:50:44
Message-ID: 389A2263.AF1E791B@southeast.net
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

If PostgreSQL failed to compile on your computer or you found a bug that
is likely to be specific to one platform then please fill out this form
and e-mail it to pgsql-ports(at)postgresql(dot)org(dot)

To report any other bug, fill out the form below and e-mail it to
pgsql-bugs(at)postgresql(dot)org(dot)

If you not only found the problem but solved it and generated a patch
then e-mail it to pgsql-patches(at)postgresql(dot)org instead. Please use the
command "diff -c" to generate the patch.

You may also enter a bug report at http://www.postgresql.org/ instead of
e-mail-ing this form.

============================================================================
POSTGRESQL BUG REPORT TEMPLATE
============================================================================

Your name : Tim Holloway
Your email address : mtsinc(at)leading(dot)nete

System Configuration
---------------------
Architecture (example: Intel Pentium) : Intel Pentium

Operating System (example: Linux 2.0.26 ELF) : Linux 2.2

PostgreSQL version (example: PostgreSQL-6.5) : PostgreSQL-6.5.2

Compiler used (example: gcc 2.8.0) : N/A

Please enter a FULL description of your problem:
------------------------------------------------

jdbc: postgresql.Driver - Invalid column width returned from
resultsetmetadata getColumnDisplaySize() method.

Please describe a way to repeat the problem. Please try to provide a
concise reproducible example, if at all possible:
----------------------------------------------------------------------

Sun, in their infinite wisdom, did not provide a way to get abstract
metadata from a resultset without actually issuing a query. Symantec's
Visual Cafe finesses this issue by modifying the model query with "WHERE 1 > 2"
to return an empty resultset (I can appreciate this - one of my tables would
return over 5 MB everytime the metadata changed if data was actually retrieved
wholesale).

As near as I can read from the driver source, however, the postgresql jdbc driver
doesn't return abstract metadata - it returns metadata based on the
actual results OF THAT QUERY. The algorithm appears to compute the widest display(?)
value of each column counting down through the rows and then taking either that
number OR the column's name length in characters, whichever is greater. For an
mpty resultset, this means that the "column display widths" are always returned as
the widths of the column names.

While the above mentioned algorithm has its uses - e.g.: it works well for \dt-type
displays - I believe it is not the appropriate one for jdbc. The metadata is "impure"
in that it varies with the results of the query. The column name's length is not
neccesarily going to be displayed in the same location as the colum data in a Java
app. Scanning each otem to determine display width is potentially expensive,

Most importantly, one of the most popular Internet database application
generators in the industry is rendered almost completey useless.

Model code:
========== tear here

// The following code can be used as a template. Simply
// substitute the appropriate url, login, and password, and then substitute the
// SQL statement you want to send to the database.

//----------------------------------------------------------------------------
//
// Module: SimpleSelect.java
//
// Description: Test program for ODBC API interface. This java application
// will connect to a JDBC driver, issue a select statement
// and display all result columns and rows
//
// Product: JDBC to ODBC Bridge
//
// Author: Karl Moss
//
// Date: February, 1996
//
// Copyright: 1990-1996 INTERSOLV, Inc.
// This software contains confidential and proprietary
// information of INTERSOLV, Inc.
//----------------------------------------------------------------------------

// NOTE: Adapted for postgresql jdbc Driver - tfh

import java.applet.*;
import java.net.URL;
import java.sql.*;

public class SimpleSelect extends java.applet.Applet {

public static void main (String args[]) {
//public void init() {
//super.init();

String url = "jdbc:postgresql://master/RandyScott";
String query = "SELECT * FROM ARTISTS";
try {
Class.forName("postgresql.Driver");
} catch ( ClassNotFoundException e ) {
System.out.println("ERROR: postgresql.Driver not found!\n");
return;
}
System.out.println("Got class.forName");
try {
System.out.println("Trying for connection A" );
Connection con;
DriverManager.setLogStream(System.out);
System.out.println("Trying for connection B");
con = DriverManager.getConnection (
url, "apache", "HSD9511");
System.out.println("Didn't fault on connection.");

// Attempt to connect to a driver. Each one
// of the registered drivers will be loaded until
// one is found that can process this URL

// If we were unable to connect, an exception
// would have been thrown. So, if we get here,
// we are successfully connected to the URL

// Check for, and display and warnings generated
// by the connect.

checkForWarning (con.getWarnings ());

// Get the DatabaseMetaData object and display
// some information about the connection

DatabaseMetaData dma = con.getMetaData ();

System.out.println("\nConnected to " + dma.getURL());
System.out.println("Driver " +
dma.getDriverName());
System.out.println("Version " +
dma.getDriverVersion());
System.out.println("");

// Create a Statement object so we can submit
// SQL statements to the driver

Statement stmt = con.createStatement ();

// Submit a query, creating a ResultSet object

ResultSet rs = stmt.executeQuery (query);

// Display all columns and rows from the result set

dispResultSet (rs);

// Close the result set

rs.close();

// Close the statement

stmt.close();

// Close the connection

con.close();
}
catch (SQLException ex) {

// A SQLException was generated. Catch it and
// display the error information. Note that there
// could be multiple error objects chained
// together

System.out.println ("\n*** SQLException caught ***\n");

while (ex != null) {
System.out.println ("SQLState: " +
ex.getSQLState ());
System.out.println ("Message: " + ex.getMessage ());
System.out.println ("Vendor: " +
ex.getErrorCode ());
ex = ex.getNextException ();
System.out.println ("");
}
}
catch (java.lang.Exception ex) {

// Got some other type of exception. Dump it.

ex.printStackTrace ();
}
}

//-------------------------------------------------------------------
// checkForWarning
// Checks for and displays warnings. Returns true if a warning
// existed
//-------------------------------------------------------------------

private static boolean checkForWarning (SQLWarning warn)
throws SQLException {
boolean rc = false;

// If a SQLWarning object was given, display the
// warning messages. Note that there could be
// multiple warnings chained together

if (warn != null) {
System.out.println ("\n *** Warning ***\n");
rc = true;
while (warn != null) {
System.out.println ("SQLState: " +
warn.getSQLState ());
System.out.println ("Message: " +
warn.getMessage ());
System.out.println ("Vendor: " +
warn.getErrorCode ());
System.out.println ("");
warn = warn.getNextWarning ();
}
}
return rc;
}

//-------------------------------------------------------------------
// dispResultSet
// Displays all columns and rows in the given result set
//-------------------------------------------------------------------

private static void dispResultSet (ResultSet rs)
throws SQLException
{
int i;

// Get the ResultSetMetaData. This will be used for
// the column headings

ResultSetMetaData rsmd = rs.getMetaData ();

// Get the number of columns in the result set

int numCols = rsmd.getColumnCount ();

// Display column headings

for (i=1; i<=numCols; i++) {
if (i > 1) System.out.print(",");
System.out.print(rsmd.getColumnLabel(i));
/// Display COLUMN WIDTH ////
System.out.print("(" + String.valueOf(rsmd.getColumnDisplayWidth(i)) + ") ");
}
System.out.println("");

// Display data, fetching until end of the result set

boolean more = rs.next ();
while (more) {

// Loop through each column, getting the
// column data and displaying

for (i=1; i<=numCols; i++) {
if (i > 1) System.out.print(",");
System.out.print(rs.getString(i));
}
System.out.println("");

// Fetch the next result set row

more = rs.next ();
}
}

}

========== tear here

If you know how this problem might be fixed, list the solution below:
---------------------------------------------------------------------

Apparently Java's definition of metadata is not the same as other querents.
Thus a Java-conforming type of metadata needs to be sent back from the
server when so requested.

Browse pgsql-bugs by date

  From Date Subject
Next Message WHarms 2000-02-04 17:04:23 configure
Previous Message Franz Korntner 2000-02-01 15:27:11 'SELECT DISTINCT' and 'ORDER BY' dont combine