Bug #664 JDBC Driver Connector/J DatabaseMetaData.getImportedKeys Error
Description:
DatabaseMetaData.getImportedKeys doesn't return the correct foreign key under InnoDB tables. The error is at com.mysql.jdbc.DatabaseMetaData.java
at method extractForeignKeyForTable(ArrayList, ResultSet, String)
The summary of getting foreign key is basically as follows:
* Invoke query "SHOW CREATE TABLE TABLE_NAME".
* Fetch the second column, which is basically the clause that create the table
* Parse it and look for the line that starts with "FOREIGN KEY".
The problem is:
* With InnoDB, "FOREIGN KEY" clause may not be the first two words. Rather, the declaration would look something like this:
CONSTRAINT '0_33' FOREIGN KEY ('COL_NAME') REFERENCE OTHER_TABLE ('OTHER_COL')
So, the parser in extractForeignKeyForTable failed to detect this situation.
How to repeat:
See above
Suggested fix:
Build a more robust parser.
Change the:
if (line.startsWith("FOREIGN KEY")) {
line with:
something that will detect CONSTRAINT stuff.
For me, since I'm only interested in reference key name, other table name, and other table's primary key, I did it this way:
--------------------------------------------------------
StringTokenizer tok = new StringTokenizer(createTableString,"\n");
while (tok.hasMoreTokens()) {
String lineToken = tok.nextToken().trim();
StringTokenizer lineTok = new StringTokenizer(lineToken, " ");
int state = 0;
String[] triplet = new String[3];
while (lineTok.hasMoreTokens()) {
String token = lineTok.nextToken();
switch (state) {
case 0:
if (token.equals("CONSTRAINT")) state = 1;
else if (token.equals("FOREIGN")) state = 3;
else state = -1; // INVALID
break;
case 1:
state = 2; // Skip constraint name, we're not interested
break;
case 2:
if (token.equals("FOREIGN")) state = 3;
else state = -1; // INVALID
break;
case 3:
if (token.equals("KEY")) state = 4;
else state = -1; // INVALID
break;
case 4:
// This is the foreign key name
token = token.substring(2, token.length()-2);
triplet[0] = token;
state = 5;
break;
case 5:
if (token.equals("REFERENCES")) state = 6;
else state = -1; // INVALID
break;
case 6:
// This is the primary referencing table
token = token.substring(1, token.length()-1);
triplet[1] = token;
state = 7;
break;
case 7:
// This is the primary referencing column
// Cut of trailling commas, if present
if (token.endsWith(","))
token = token.substring(0, token.length()-1);
token = token.substring(2, token.length()-2);
triplet[2] = token;
state = 8;
break;
case 8:
default:
state = -1; break;
} // end switch
if (state == -1) break;
} // end while (lineTok.hasMoreTokens())
if (state != -1) { // If no errors, then take care of the triplet
rows.add(triplet)
}
} // end while
--------------------------------------------------------
Note that: I'm not familiar with variations of Create table clauses. My suggestion is to build a custom parser like above to take care of all combinations.
Good luck.
Portions of this website are copyright © 2001, 2002 The PHP Group
Page generated in 0.039 sec. using MySQL 8.4.7-u6-cloud
Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the
respective copyright holders.
It is not reviewed in advance
by Oracle and does not necessarily represent the opinion of
Oracle or any other party.
Description: DatabaseMetaData.getImportedKeys doesn't return the correct foreign key under InnoDB tables. The error is at com.mysql.jdbc.DatabaseMetaData.java at method extractForeignKeyForTable(ArrayList, ResultSet, String) The summary of getting foreign key is basically as follows: * Invoke query "SHOW CREATE TABLE TABLE_NAME". * Fetch the second column, which is basically the clause that create the table * Parse it and look for the line that starts with "FOREIGN KEY". The problem is: * With InnoDB, "FOREIGN KEY" clause may not be the first two words. Rather, the declaration would look something like this: CONSTRAINT '0_33' FOREIGN KEY ('COL_NAME') REFERENCE OTHER_TABLE ('OTHER_COL') So, the parser in extractForeignKeyForTable failed to detect this situation. How to repeat: See above Suggested fix: Build a more robust parser. Change the: if (line.startsWith("FOREIGN KEY")) { line with: something that will detect CONSTRAINT stuff. For me, since I'm only interested in reference key name, other table name, and other table's primary key, I did it this way: -------------------------------------------------------- StringTokenizer tok = new StringTokenizer(createTableString,"\n"); while (tok.hasMoreTokens()) { String lineToken = tok.nextToken().trim(); StringTokenizer lineTok = new StringTokenizer(lineToken, " "); int state = 0; String[] triplet = new String[3]; while (lineTok.hasMoreTokens()) { String token = lineTok.nextToken(); switch (state) { case 0: if (token.equals("CONSTRAINT")) state = 1; else if (token.equals("FOREIGN")) state = 3; else state = -1; // INVALID break; case 1: state = 2; // Skip constraint name, we're not interested break; case 2: if (token.equals("FOREIGN")) state = 3; else state = -1; // INVALID break; case 3: if (token.equals("KEY")) state = 4; else state = -1; // INVALID break; case 4: // This is the foreign key name token = token.substring(2, token.length()-2); triplet[0] = token; state = 5; break; case 5: if (token.equals("REFERENCES")) state = 6; else state = -1; // INVALID break; case 6: // This is the primary referencing table token = token.substring(1, token.length()-1); triplet[1] = token; state = 7; break; case 7: // This is the primary referencing column // Cut of trailling commas, if present if (token.endsWith(",")) token = token.substring(0, token.length()-1); token = token.substring(2, token.length()-2); triplet[2] = token; state = 8; break; case 8: default: state = -1; break; } // end switch if (state == -1) break; } // end while (lineTok.hasMoreTokens()) if (state != -1) { // If no errors, then take care of the triplet rows.add(triplet) } } // end while -------------------------------------------------------- Note that: I'm not familiar with variations of Create table clauses. My suggestion is to build a custom parser like above to take care of all combinations. Good luck.