[ 
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

        

Reply via email to