db-derby-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Mamta A. Satoor (JIRA)" <j...@apache.org>
Subject [jira] [Updated] (DERBY-5407) When run across the network, dblook produces unusable DDL for VARCHAR FOR BIT DATA columns.
Date Wed, 18 Jul 2012 03:11:35 GMT

     [ https://issues.apache.org/jira/browse/DERBY-5407?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]

Mamta A. Satoor updated DERBY-5407:
-----------------------------------

    Attachment: DERBY5407_patch1_diff.txt

Attaching a patch which has a fix for the issue and a new junit test fixture.

After debugging the issue, I have found that the serialization of object on the wire from
the network server end happens
correctly. The same serialized data is received by the client but when we try to instantiate
the TypeDescriptor based
on this serialized data, we get confused between "VARCHAR () FOR BIT DATA" and "VARCHAR FOR
BIT DATA".

Following is a brief explanation of the current logic and problem area.

Let's say, there is a database with following table
create table t2( a1 varchar( 30 ) for bit data, a2 varchar(25) ); 

When query below is run on top of the trunk in network server mode against the databse above,
we get following results
select columndatatype from sys.systables, sys.syscolumns where tablename='T2' and tableid=referenceid;
COLUMNDATATYPE
---------------
VARCHAR () FOR&
VARCHAR(25)

Notice the length of the column "A1" is missing in syscolumns.COLUMNDATATYPE


syscolumns.columndatatype is a UDT. On the server side, the TypeDescriptor associated with
it gets initialized as shown below
          case StoredFormatIds.VARBIT_TYPE_ID_IMPL:
              schemaName = null;
              unqualifiedName = TypeId.VARBIT_NAME;
              JDBCTypeId = Types.VARBINARY;
              break;
Note, that unqualifiedName has gotten "VARCHAR () FOR BIT DATA" assigned to it. Later on in
the server code, we associate
column width 30 with this TypeDescriptor for our specific example. So, the TypeDescriptor
has the correct information which will then be sent on the wire to the client.

Following stack trace shows were we write this "VARCHAR () FOR BIT DATA" onto the wire.
Thread [DRDAConnThread_2] (Suspended (breakpoint at line 323 in BaseTypeIdImpl))	
	BaseTypeIdImpl.writeExternal(ObjectOutput) line: 323	
	ObjectOutputStream.writeExternalData(Externalizable) line: 1449	
	ObjectOutputStream.writeOrdinaryObject(Object, ObjectStreamClass, boolean) line: 1418	
	ObjectOutputStream.writeObject0(Object, boolean) line: 1178	
	ObjectOutputStream.writeObject(Object) line: 347	
	TypeDescriptorImpl.writeExternal(ObjectOutput) line: 549	
	ObjectOutputStream.writeExternalData(Externalizable) line: 1449	
	ObjectOutputStream.writeOrdinaryObject(Object, ObjectStreamClass, boolean) line: 1418	
	ObjectOutputStream.writeObject0(Object, boolean) line: 1178	
	ObjectOutputStream.writeObject(Object) line: 347	
	DDMWriter.writeUDT(Object, int) line: 1181	
	DRDAConnThread.writeFdocaVal(int, Object, int, int, int, boolean, DRDAStatement, boolean)
line: 8053	
	DRDAConnThread.writeFDODTA(DRDAStatement) line: 7236	
	DRDAConnThread.writeQRYDTA(DRDAStatement) line: 6970	
	DRDAConnThread.processCommands() line: 894	
	DRDAConnThread.run() line: 288	
Subsequently, we also write the width 30 for the VARCHAR () FOR BIT DATA on the wire for our
example case.

Client goes through the deserialization of the UDT and during deserialization, it finds VARCHAR
() FOR BIT DATA and the width 
30 for it. So far, client is reading what server has sent and things are in sync. We use this
information to construct a
TypeDescriptor. This happens through BaseTypeIdImpl.getTypeFormatId(). Here, we look at the
string representation of the type descriptor that we received on the wire and choose the appropriate
format id based on that string. The problem is in this BaseTypeIdImpl.getTypeFormatId() code,
because the code looks for VARCHAR FOR BIT DATA rather than VARCHAR () FOR BIT DATA 
(notice the missing parentheses) as shown below.
            else if ( "VARCHAR FOR BIT DATA".equals( unqualifiedName ) ) { return StoredFormatIds.VARBIT_TYPE_ID_IMPL;
}
Since VARCHAR FOR BIT DATA and VARCHAR () FOR BIT DATA do not match, we do not use format
id VARBIT_TYPE_ID_IMPL
Later, we go through the following switch statement based on format id in BaseTypeIdlImpl.toParsableString(TypeDescriptor)
        switch (getTypeFormatId())
        {
          case StoredFormatIds.BIT_TYPE_ID_IMPL:
          case StoredFormatIds.VARBIT_TYPE_ID_IMPL:
			  int rparen = retval.indexOf(')');
			  String lead = retval.substring(0, rparen);
			  retval = lead + td.getMaximumWidth() + retval.substring(rparen);
			  break;

          case StoredFormatIds.CHAR_TYPE_ID_IMPL:
          case StoredFormatIds.VARCHAR_TYPE_ID_IMPL:
          case StoredFormatIds.BLOB_TYPE_ID_IMPL:
          case StoredFormatIds.CLOB_TYPE_ID_IMPL:
                retval += "(" + td.getMaximumWidth() + ")";
                break;

          case StoredFormatIds.DECIMAL_TYPE_ID_IMPL:
                retval += "(" + td.getPrecision() + "," + td.getScale() + ")";
                break;
        }
In the switch statement above, we are supposed to stuff in the width of the varchar for bit
data into the parentheses
ie VARCHAR () FOR BIT DATA should get converted into VARCHAR (30) FOR BIT DATA for our specific
example but we don't do it because of getTypeFormatd() code above..

To solve this, I have found that if I change code in BaseTypeIdImpl.getTypeFormatId() to look
for VARCHAR () FOR BIT DATA, as 
follows
            else if ( "VARCHAR () FOR BIT DATA".equals( unqualifiedName ) ) { return StoredFormatIds.VARBIT_TYPE_ID_IMPL;
}
the problem gets fixed. I have not yet run derbyall and junit suite to see if that change
can cause any problems. 

If there might be dependencies on the original "VARCHAR FOR BIT DATA" check, then we can add
additional check for 
VARCHAR () FOR BIT DATA along with existing check for "VARCHAR FOR BIT DATA" as shown below
            else if ( "VARCHAR FOR BIT DATA".equals( unqualifiedName ) ) { return StoredFormatIds.VARBIT_TYPE_ID_IMPL;
}
            else if ( "VARCHAR () FOR BIT DATA".equals( unqualifiedName ) ) { return StoredFormatIds.VARBIT_TYPE_ID_IMPL;
}
We will need to do similar thing for CHAR FOR BIT DATA. This will fix the jira issue and it
will also not break any dependencies
that might exist on "VARCHAR FOR BIT DATA" check.

The test that I have attached to the jira runs fine with my suggested changes. Next, I will
run derbyall and junit suite.
Please let me know if there is any feedback on the suggested fix.

                
> When run across the network, dblook produces unusable DDL for VARCHAR FOR BIT DATA columns.
> -------------------------------------------------------------------------------------------
>
>                 Key: DERBY-5407
>                 URL: https://issues.apache.org/jira/browse/DERBY-5407
>             Project: Derby
>          Issue Type: Bug
>          Components: Tools
>    Affects Versions: 10.8.1.2
>            Reporter: Rick Hillegas
>            Assignee: Mamta A. Satoor
>              Labels: derby_triage10_9
>         Attachments: DERBY5407_patch1_diff.txt, SystemCatalogTest.java
>
>
> In private correspondence, Mani Afschar Yazdi reports that dblook omits the length specification
for VARCHAR FOR BIT DATA columns when run across the network. Embedded dblook runs fine. I
can reproduce this problem as follows:
> 1) Bring up a server (here I am using port 8246).
> 2) Create a database with the following ij script:
> connect 'jdbc:derby://localhost:8246/memory:db;create=true';
> create table t( a varchar( 20 ) for bit data );
> 3) Now run dblook across the network:
> java -org.apache.derby.tools.dblook -d "jdbc:derby://localhost:8246/memory:db"
> This produces the following DDL for the table:
> CREATE TABLE "APP"."T" ("A" VARCHAR () FOR BIT DATA);
> A similar experiment using an embedded database produces usable DDL which includes a
length specification for the VARCHAR FOR BIT DATA column.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators: https://issues.apache.org/jira/secure/ContactAdministrators!default.jspa
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

Mime
View raw message