Thread: Bug in getImportedExportedKeys(), DatabaseMetaData class

Bug in getImportedExportedKeys(), DatabaseMetaData class

From
Todd Cornett
Date:
All:

In our work with PostgreSQL 7.3.2 and the JDBC drivers, we have
discovered a bug in the DatabaseMetaData class, or more specifically the
AbstractJdbc1DatabaseMetaData class in the getImportedExportedKeys()
(about line number 3100) .  We found that the current use of the
StringTokenizer to parse out the response from the database acheieves
the desired result only when the returning column and table names do not
contain either '\' or '0'.  We believe that the intent was to treat the
string parameter as a literal string and not as a collection of
characters, as Java interprets it.

To fix this, we used the split function, available in JDK1.4, to split
the string. The sample of the code is attached below.   Unfortunately,
this fix only works in JDK1.4 but hopefully this will fix someone's
problem if they come across it or at least bring it to the attention of
the development team.

Thank you for your time,

Todd Cornett
The MITRE Corporation


/***********************************************/


   // args look like this
   //<unnamed>\000ww\000vv\000UNSPECIFIED\000m\000a\000n\000b\000
   // we are primarily interested in the column names which are the last
items in the string

//   StringTokenizer st = new StringTokenizer(targs, "\\000");

   String[] str_array = targs.split( "\\\\000" );

   int advance = 4 + (keySequence - 1) * 2;
/*

   for ( int i = 0; st.hasMoreTokens() && i < advance ; i++ ) {
    st.nextToken(); // advance to the key column of interest
   }
   if ( st.hasMoreTokens() )
   {
    fkeyColumn = st.nextToken();
   }
   if ( st.hasMoreTokens() )
   {
    pkeyColumn = st.nextToken();
   }
*/
   if( str_array.length >= advance ) {

    fkeyColumn = str_array[ advance ];

    if( str_array.length >= ( advance + 1 ) ) {

     pkeyColumn = str_array[ advance + 1 ];

    }
   }


   tuple[3] = pkeyColumn.getBytes(); //PKCOLUMN_NAME
   tuple[7] = fkeyColumn.getBytes(); //FKCOLUMN_NAME


Re: Bug in getImportedExportedKeys(), DatabaseMetaData class

From
Kris Jurka
Date:

On Tue, 8 Apr 2003, Todd Cornett wrote:

> All:
>
> We found that the current use of the StringTokenizer to parse out the
> response from the database acheieves the desired result only when the
> returning column and table names do not contain either '\' or '0'.

The attached patch fixes this for all JDK versions by using its own
tokenizing routine.

Kris Jurka


Attachment

Re: Bug in getImportedExportedKeys(), DatabaseMetaData class

From
Barry Lind
Date:
Patch applied to both head and 7.3 branch.

--Barry

Kris Jurka wrote:
>
> On Tue, 8 Apr 2003, Todd Cornett wrote:
>
>
>>All:
>>
>>We found that the current use of the StringTokenizer to parse out the
>>response from the database acheieves the desired result only when the
>>returning column and table names do not contain either '\' or '0'.
>
>
> The attached patch fixes this for all JDK versions by using its own
> tokenizing routine.
>
> Kris Jurka
>
>
>
> ------------------------------------------------------------------------
>
> Index: src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java
> ===================================================================
> RCS file:
/projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java,v
> retrieving revision 1.20
> diff -c -r1.20 AbstractJdbc1DatabaseMetaData.java
> *** src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java    2003/03/25 02:28:45    1.20
> --- src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1DatabaseMetaData.java    2003/04/16 07:17:29
> ***************
> *** 3143,3168 ****
>               //<unnamed>\000ww\000vv\000UNSPECIFIED\000m\000a\000n\000b\000
>               // we are primarily interested in the column names which are the last items in the string
>
> !             StringTokenizer st = new StringTokenizer(targs, "\\000");
> !             if (st.hasMoreTokens()) {
> !                 fkName = st.nextToken();
>               }
>
>               if (fkName.startsWith("<unnamed>")) {
>                   fkName = targs;
>               }
>
> !             int advance = 4 + (keySequence - 1) * 2;
> !             for ( int i = 1; st.hasMoreTokens() && i < advance ; i++ )
> !                 st.nextToken(); // advance to the key column of interest
> !
> !             if ( st.hasMoreTokens() )
> !             {
> !                 fkeyColumn = st.nextToken();
>               }
> !             if ( st.hasMoreTokens() )
> !             {
> !                 pkeyColumn = st.nextToken();
>               }
>
>               tuple[3] = pkeyColumn.getBytes(); //PKCOLUMN_NAME
> --- 3143,3165 ----
>               //<unnamed>\000ww\000vv\000UNSPECIFIED\000m\000a\000n\000b\000
>               // we are primarily interested in the column names which are the last items in the string
>
> !             Vector tokens = tokenize(targs, "\\000");
> !             if (tokens.size() > 0) {
> !                 fkName = (String)tokens.elementAt(0);
>               }
>
>               if (fkName.startsWith("<unnamed>")) {
>                   fkName = targs;
>               }
>
> !             int element = 4 + (keySequence - 1) * 2;
> !             if (tokens.size() > element) {
> !                 fkeyColumn = (String)tokens.elementAt(element);
>               }
> !
> !             element++;
> !             if (tokens.size() > element) {
> !                 pkeyColumn = (String)tokens.elementAt(element);
>               }
>
>               tuple[3] = pkeyColumn.getBytes(); //PKCOLUMN_NAME
> ***************
> *** 3571,3575 ****
> --- 3568,3597 ----
>           sql += " ORDER BY NON_UNIQUE, TYPE, INDEX_NAME ";
>           return connection.createStatement().executeQuery(sql);
>       }
> +
> +     /**
> +      * Tokenize based on words not on single characters.
> +      */
> +     private static Vector tokenize(String input, String delimiter) {
> +         Vector result = new Vector();
> +         int start = 0;
> +         int end = input.length();
> +         int delimiterSize = delimiter.length();
> +
> +         while (start < end) {
> +             int delimiterIndex = input.indexOf(delimiter,start);
> +             if (delimiterIndex < 0) {
> +                 result.addElement(input.substring(start));
> +                 break;
> +             } else {
> +                 String token = input.substring(start,delimiterIndex);
> +                 result.addElement(token);
> +                 start = delimiterIndex + delimiterSize;
> +             }
> +         }
> +         return result;
> +     }
> +
> +
>
>   }
>
>
> ------------------------------------------------------------------------
>
>
> ---------------------------(end of broadcast)---------------------------
> TIP 6: Have you searched our list archives?
>
> http://archives.postgresql.org