JDK-6335589 : REGRESSION: JdbcOdbc ResultSet.getString returning text and char(0) padding
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.sql:bridge
  • Affected Version: 6
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_2000,windows_xp
  • CPU: x86
  • Submitted: 2005-10-11
  • Updated: 2011-02-16
  • Resolved: 2006-06-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6
6 b86Fixed
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0-ea"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.6.0-ea-b53)
Java HotSpot(TM) Client VM (build 1.6.0-ea-b53, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
Attempting to get a String value from a ResultSet or DatabaseMetaData or ResultSetMetaData (with a Microsoft Access database at least), or calling getObject() on the ResultSet for String-type columns, returns the value of the string AND lots of extra characters, with the value char(0).  It looks like padding on VARCHAR columns might be the problem (being returned when it shouldn't), BUT this also affects ANY string column, including those from "MetaData" JDBC objects.

JDBC-ODBC regression has occurred in early-access versions of "Mustang" (Java 6).  The same code running against the same Access database on the same machine, under 1.5.0_04 works fine, but under 1.6.0_ea_b53 (and more than one previous early-access build of Mustang).

I can reproduce this on ANY MS-Access database here.  I am unable to test this using other databases accessible through ODBC, and have not yet had the opportunity to test other JDBC drivers.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create a simple Access database (one table with some fields of different types, some indexed, some not) should be ample.  I can provide one if necessary, but the bug-reporting form doesn't seem to provide any field for uploads.

Then run my source code below.  Try it with Java 5 AND Java 6.  For simplicity, I hard-coded the path to the Access database into the source code, so you may wish to adapt it to get the code running.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The code uses database metadata to get the names of all user tables in the database, and prints out their name and type.  Then, it selects all records from each table in turn, printing out the values of each field.  The procedure runs TWICE, with the difference being that the first attempt just dumps exactly what the driver is outputting, and the second attempt uses a cumbersome workaround to strip the junk -- if any -- from returned strings.

It is expected that each time the procedure runs, the exact same output is generated.
ACTUAL -
Under Java 6 (ea/b49), extra "things" appears on the JDBC-ODBC strings.  Under Java 5, it doesn't.  The result of running the code under Java 6 with my test database is show below (NOTE: I can't paste in char(0), so I was forced to replace that with the asterisk ("*") symbol):

Seeking MS-Access database:
C:\sandbox\db.mdb

Running test (skip trimming)...
Name: Table1***************************************************************************************************************************
Type: TABLE****************************************************************************************************************************

Querying Table1...
1:Table1.id = 1
1:Table1.uniqueText = apple***********************************************************************************************************************************************************************************************************************************************************
1:Table1.arbitraryText = braeburn********************************************************************************************************************************************************************************************************************************************************

2:Table1.id = 2
2:Table1.uniqueText = banana**********************************************************************************************************************************************************************************************************************************************************
2:Table1.arbitraryText = null

3:Table1.id = 3
3:Table1.uniqueText = melon***********************************************************************************************************************************************************************************************************************************************************
3:Table1.arbitraryText = watermelon******************************************************************************************************************************************************************************************************************************************************

4:Table1.id = 4
4:Table1.uniqueText = orange**********************************************************************************************************************************************************************************************************************************************************
4:Table1.arbitraryText = null

Running test (with trimming)...
Name: Table1
Type: TABLE

Querying Table1...
1:Table1.id = 1
1:Table1.uniqueText = apple
1:Table1.arbitraryText = braeburn

2:Table1.id = 2
2:Table1.uniqueText = banana
2:Table1.arbitraryText = null

3:Table1.id = 3
3:Table1.uniqueText = melon
3:Table1.arbitraryText = watermelon

4:Table1.id = 4
4:Table1.uniqueText = orange
4:Table1.arbitraryText = null

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package test;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.DriverManager;
import java.sql.ResultSetMetaData;
import java.io.File;
import java.util.Properties;
import java.util.List;
import java.util.ArrayList;



public class AccessTest implements Runnable
{
	public static void main(String[] args)
	{
		new Thread(new AccessTest()).start();
	}


	private boolean skipTrim;



	private AccessTest()
	{
		skipTrim = false;
	}


	public void run()
	{
		try
		{
			Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
		}
		catch (Exception e)
		{
			e.printStackTrace();
			return;
		}

		File mdbFile = new File("db.mdb");
		System.out.printf("Seeking MS-Access database:\n%s\n\n",mdbFile.getAbsolutePath());
		Properties jdbcProperties = new Properties();

		String           url  = "jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ="+mdbFile.getPath();
		Connection       conn = null;
		try
		{
			conn = DriverManager.getConnection(url,jdbcProperties);
			skipTrim = true;
			test(conn);
			skipTrim = false;
			test(conn);
		}
		catch (SQLException e)
		{
			e.printStackTrace();
		}
		finally
		{
			if (conn != null) try { conn.close(); } catch (Exception e) {}
		}
	}


	private void test(Connection conn) throws SQLException
	{
		System.out.printf("Running test (%s trimming)...\n",(skipTrim?"skip":"with"));

		List<String> tableNames = new ArrayList<String>();

		DatabaseMetaData dbmd = conn.getMetaData();
		ResultSet tables = dbmd.getTables(null, null, "%", new String[]{"TABLE","VIEW"});
		while (tables.next())
		{
			String tableName = trim(tables.getString("TABLE_NAME"));
			String tableType = trim(tables.getString("TABLE_TYPE"));
			System.out.printf("Name: %s\n",tableName);
			System.out.printf("Type: %s\n",tableType);
			System.out.println();

			if (skipTrim) tableName = trim(tableName,false);
			tableNames.add(tableName);
		}
		tables.close();

		for (String tableName : tableNames)
		{
			System.out.printf("Querying %s...\n",tableName);
			ResultSet records = conn.createStatement().executeQuery(
				"SELECT * FROM "+tableName
			);
			ResultSetMetaData rsmd = records.getMetaData();
			final int colCount = rsmd.getColumnCount();
			int r = 0;
			while (records.next())
			{
				r++;
				for (int i = 1; i <= colCount; i++)
				{
					Object field = records.getObject(i);
					if (field instanceof String)
					{
						field = trim((String)field);
					}
					System.out.printf("%d:%s.%s = %s\n",r,tableName,rsmd.getColumnName(i),field);
				}
				System.out.println();
			}
			records.close();
		}
	}


	private String trim(String text)
	{
		return trim(text,skipTrim);
	}


	private String trim(String text,boolean skip)
	{
		if (skip) return text;

		StringBuilder sb = new StringBuilder(text.length());
		char c;
		for (int i = 0; i < text.length(); i++)
		{
			c = text.charAt(i);
			if (c == (char)0) break;
			sb.append(c);
		}
		return sb.toString();
	}


//	private String trim(String text,boolean skip)
//	{
//		if (skip) return text;
//
//		StringBuilder sb = new StringBuilder(text.length());
//		char c;
//		for (int i = 0; i < text.length(); i++)
//		{
//			c = text.charAt(i);
//			if (c == (char)0 || (!skip && c == '*'))
//			{
//				if (!skip) break;
//				sb.append('*');
//				continue;
//			}
//			if (skip &&c == (char)0) break;
//			sb.append(c);
//		}
//		return sb.toString();
//	}
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Using the cumbersome "trim" method above.  That's not a practical option in many cases.

Release Regression From : mustang
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.

Comments
EVALUATION I investigated this more, the regression started in mustang-b26 for the first time. This has been caused by changes due to java.nio.charset changes(CR 4952588). The affected file is sun/jdbc/odbc/JdbcOdbcObject.java where the changes are causing such a thing to happen. I am working to fix this.
03-05-2006

EVALUATION There have been no changes to the bridge, irrespective it is not clear from the bugster which MS Access version ODBC driver has been used. I will investigate this more.
08-11-2005