Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with getting char NONE field for UTF8 connection [JDBC363] #405

Closed
firebird-automations opened this issue Sep 19, 2014 · 6 comments

Comments

@firebird-automations
Copy link

Submitted by: Tomasz Kujalow (tkujalow)

When I am getting field type: char(12) character set NONE, connection character set is UTF8 or UNICODE_FSS, and I fetching value by rs.getString(1), I'm receiving only 3 or 4 chars (3 for UTF8, 4 for UNICODE). Returning value is 12 character length. When I use rs.getBytes(1) , I'm receiving whole 12 chars.
I tested it for FB 2.0 and FB 2.5.

My program which show this problem:

1) Output:

Version: 2.2
ODS: 11.0
Dialect: 3
Firebird: Firebird 2.09LI LI-V2.0.7.13318

Encoding: UNICODE_FSS
rs.getString(1) returns: _|0010|_
rs.getBytes(1) returns: _|001000000001|_
rs.getString(1) returns: _|1111|_
rs.getBytes(1) returns: _|111111111111|_
rs.getString(1) returns: _|0000|_
rs.getBytes(1) returns: _|000000000000|_
rs.getString(1) returns: _|1010|_
rs.getBytes(1) returns: _|101010101010|_

Encoding: UTF8
rs.getString(1) returns: _|001|_
rs.getBytes(1) returns: _|001000000001|_
rs.getString(1) returns: _|111|_
rs.getBytes(1) returns: _|111111111111|_
rs.getString(1) returns: _|000|_
rs.getBytes(1) returns: _|000000000000|_
rs.getString(1) returns: _|101|_
rs.getBytes(1) returns: _|101010101010|_

Encoding: ASCII
rs.getString(1) returns: _|001000000001|_
rs.getBytes(1) returns: _|001000000001|_
rs.getString(1) returns: _|111111111111|_
rs.getBytes(1) returns: _|111111111111|_
rs.getString(1) returns: _|000000000000|_
rs.getBytes(1) returns: _|000000000000|_
rs.getString(1) returns: _|101010101010|_
rs.getBytes(1) returns: _|101010101010|_

Encoding: NONE
rs.getString(1) returns: _|001000000001|_
rs.getBytes(1) returns: _|001000000001|_
rs.getString(1) returns: _|111111111111|_
rs.getBytes(1) returns: _|111111111111|_
rs.getString(1) returns: _|000000000000|_
rs.getBytes(1) returns: _|000000000000|_
rs.getString(1) returns: _|101010101010|_
rs.getBytes(1) returns: _|101010101010|_

Encoding: WIN1250
rs.getString(1) returns: _|001000000001|_
rs.getBytes(1) returns: _|001000000001|_
rs.getString(1) returns: _|111111111111|_
rs.getBytes(1) returns: _|111111111111|_
rs.getString(1) returns: _|000000000000|_
rs.getBytes(1) returns: _|000000000000|_
rs.getString(1) returns: _|101010101010|_
rs.getBytes(1) returns: _|101010101010|_

2) SQL code:
create or alter procedure TMP_BUG_GET_CHAR_BY_ASSTRING
returns (
OUT char(12) character set NONE)
as
begin
--
out='001000000001';
suspend;
out='111111111111';
suspend;
out='000000000000';
suspend;
out='101010101010';
suspend;
--
end;

3) Application:

import org.firebirdsql.gds.DatabaseParameterBuffer;
import org.firebirdsql.gds.GDS;
import org.firebirdsql.gds.GDSException;
import org.firebirdsql.gds.ISCConstants;
import org.firebirdsql.gds.IscDbHandle;
import org.firebirdsql.gds.impl.GDSFactory;

public class FirebirdBugTest {
private static GDS gds=null;
private static String dbAddr="10.100.2.20/3050:/DATA/FIREBIRD/test_database.gdb";
private static String dbPass="masterkey";
public static void main(String[] args) {

	org\.firebirdsql\.jdbc\.FBDriver x=new org\.firebirdsql\.jdbc\.FBDriver\(\);
	System\.out\.println\(" Version: "\+x\.getMajorVersion\(\)\+"\."\+x\.getMinorVersion\(\)\);
	gds = GDSFactory\.getDefaultGDS\(\);
	DatabaseParameterBuffer c;
	c = gds\.createDatabaseParameterBuffer\(\);
	c\.addArgument\(ISCConstants\.isc\_dpb\_sql\_dialect, new byte\[\] \{3, 0, 0, 0\}\);
    c\.addArgument\(ISCConstants\.isc\_dpb\_user\_name, "sysdba" \);
    c\.addArgument\(ISCConstants\.isc\_dpb\_password, dbPass\);
	IscDbHandle db = gds\.createIscDbHandle\(\);				
	try \{
		gds\.iscAttachDatabase\(dbAddr, db, c\);
	\} catch \(GDSException e\) \{
		e\.printStackTrace\(\);
	\}
	System\.out\.println\("     ODS: "\+db\.getODSMajorVersion\(\)\+"\."\+db\.getODSMinorVersion\(\)\);
	System\.out\.println\(" Dialect: "\+db\.getDialect\(\)\);
	System\.out\.println\("Firebird: "\+db\.getDatabaseProductName\(\)\+" "\+db\.getDatabaseProductVersion\(\)\);
		
	testForCharset\("UNICODE\_FSS"\);
	testForCharset\("UTF8"\);
	testForCharset\("ASCII"\);
	testForCharset\("NONE"\);
	testForCharset\("WIN1250"\);
\}
private static void testForCharset\(String charset\) \{		
	try\{
		org\.firebirdsql\.pool\.FBWrappingDataSource dataSource = new org\.firebirdsql\.pool\.FBWrappingDataSource\(\);
		dataSource\.setDatabase \(dbAddr\);
	    dataSource\.setEncoding\(charset\);
	    java\.sql\.Connection c = dataSource\.getConnection \("sysdba", dbPass\);   
	    java\.sql\.Statement stmt = c\.createStatement\(\);
	    java\.sql\.ResultSet rs = stmt\.executeQuery\("      select \* from TMP\_BUG\_GET\_CHAR\_BY\_ASSTRING "\);
	    System\.out\.println\(""\);		    
	    System\.out\.println\("Encoding: "\+dataSource\.getEncoding\(\)\+" "  \);
	    while\(rs\.next\(\)\)\{
	    	  byte\[\] b=rs\.getBytes\(1\);
	    	  System\.out\.println\("rs\.getString\(1\) returns: \_\|"\+rs\.getString\(1\)\+"\|\_"\);
	    	  System\.out\.println\("rs\.getBytes\(1\)  returns: \_\|"\+new String\(b\)\+"\|\_"\);
	    \}
	    stmt\.close\(\);
	\}catch\(Exception e\)\{
		e\.printStackTrace\(\);
	\}
\}

}

@firebird-automations
Copy link
Author

Commented by: @mrotteveel

The main problem is that the current version of Jaybird always uses the connection character set for conversion, however NONE is sent as is. For CHAR fields it trims the field to the expected length. As UTF-8 is a max 4 byte character set, this means that a 12 byte string in NONE is converted to a three character string. See http://sourceforge.net/p/firebird/code/HEAD/tree/client-java/branches/Branch_2_2/src/main/org/firebirdsql/jdbc/field/FBWorkaroundStringField.java#l116

In Jaybird 3.0 the handling of character sets will be overhauled, which should solve this problem.

The workaround is to use VARCHAR instead.

PS Is there a reason that you are using the GDS API directly in your testcode?

@firebird-automations
Copy link
Author

Modified by: @mrotteveel

Fix Version: Jaybird 3.0 [ 10440 ]

@firebird-automations
Copy link
Author

Commented by: Tomasz Kujalow (tkujalow)

I used GDS only for showing such database information as: ODS, FB version, itd...
Is it wrong to use GDS API?
Will be it removed in future versions?

@firebird-automations
Copy link
Author

Commented by: @mrotteveel

The GDS API is going to be removed in Jaybird 3. You can obtain the information from the databasemetadata object. For the ODS version you need to unwrap or cast to FirebirdDatabaseMetaData. It looks like the dialect is missing from this info. I will check if I make this available in the new API in Jaybird 3.

@firebird-automations
Copy link
Author

Commented by: @mrotteveel

Problem itself is fixed with new character set handling.

I have exposed the dialect information in the FirebirdDatabaseMetaData interface.

@firebird-automations
Copy link
Author

Modified by: @mrotteveel

status: Open [ 1 ] => Closed [ 6 ]

resolution: Won't Fix [ 2 ]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants