Skip to content

Commit

Permalink
[CONJ-1019] DatabaseMetaData.getImportedKeys should return real value…
Browse files Browse the repository at this point in the history
… for PK_NAME column
  • Loading branch information
rusher committed Oct 31, 2022
1 parent 22388e6 commit 79eb340
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 13 deletions.
79 changes: 72 additions & 7 deletions src/main/java/org/mariadb/jdbc/DatabaseMetaData.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@
import java.sql.*;
import java.sql.Statement;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.*;
import org.mariadb.jdbc.client.DataType;
import org.mariadb.jdbc.client.result.CompleteResult;
import org.mariadb.jdbc.client.result.Result;
Expand Down Expand Up @@ -202,7 +199,10 @@ private int parseIdentifierList(char[] part, int startPos, List<Identifier> list
*/
private ResultSet getImportedKeys(
String tableDef, String tableName, String catalog, org.mariadb.jdbc.Connection connection)
throws ParseException {
throws Exception, SQLException {
boolean importedKeysWithConstraintNames =
Boolean.parseBoolean(
conf.nonMappedOptions().getProperty("importedKeysWithConstraintNames", "true"));
String[] columnNames = {
"PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME",
"PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM",
Expand Down Expand Up @@ -255,7 +255,7 @@ private ResultSet getImportedKeys(
onDeleteReferenceAction = getImportedKeyAction(referenceAction);
}
}

Map<String, Map<String[], String>> externalInfos = new HashMap<>();
for (int i = 0; i < primaryKeyCols.size(); i++) {

String[] row = new String[columnNames.length];
Expand All @@ -274,7 +274,37 @@ private ResultSet getImportedKeys(
row[9] = Integer.toString(onUpdateReferenceAction); // UPDATE_RULE
row[10] = Integer.toString(onDeleteReferenceAction); // DELETE_RULE
row[11] = constraintName.name; // FK_NAME
row[12] = null; // PK_NAME - unlike using information_schema, cannot know constraint name
if (importedKeysWithConstraintNames) {
String ext =
(pkTable.schema == null ? "" : quoteIdentifier(pkTable.schema) + ".")
+ quoteIdentifier(pkTable.name);
if (!externalInfos.containsKey(ext)) {
externalInfos.put(ext, getExtImportedKeys(ext, connection));
}
row[12] = null; // PK_NAME
Map<String[], String> externalInfo = externalInfos.get(ext);
if (externalInfo != null) {
for (Map.Entry<String[], String> entry : externalInfo.entrySet()) {
boolean foundAll = true;

for (String keyPart : entry.getKey()) {
boolean foundKey = false;
for (Identifier keyCol : primaryKeyCols) {
if (keyCol.name.equals(keyPart)) {
foundKey = true;
break;
}
}
if (!foundKey) foundAll = false;
}
if (foundAll) {
row[12] = entry.getValue();
}
}
}
} else {
row[12] = null; // PK_NAME
}
row[13] = Integer.toString(DatabaseMetaData.importedKeyNotDeferrable); // DEFERRABILITY
data.add(row);
}
Expand All @@ -301,6 +331,41 @@ private ResultSet getImportedKeys(
columnNames, dataTypes, arr, connection.getContext(), ColumnFlags.PRIMARY_KEY);
}

private Map<String[], String> getExtImportedKeys(
String tableName, org.mariadb.jdbc.Connection connection) throws SQLException {
ResultSet rs = connection.createStatement().executeQuery("SHOW CREATE TABLE " + tableName);
rs.next();
String refTableDef = rs.getString(2);
Map<String[], String> res = new HashMap<>();
String[] parts = refTableDef.split("\n");
for (int i = 1; i < parts.length - 1; i++) {
String part = parts[i].trim();
if (part.startsWith("`")) {
// field
continue;
}
if (part.startsWith("PRIMARY KEY") || part.startsWith("UNIQUE KEY")) {
String name = "PRIMARY";
if (part.indexOf("`") < part.indexOf("(")) {
int offset = part.indexOf("`");
name = part.substring(offset + 1, part.indexOf("`", offset + 1));
}

String subPart = part.substring(part.indexOf("(") + 1, part.lastIndexOf(")"));
List<String> cols = new ArrayList<>();
int pos = 0;
while (pos < subPart.length()) {
pos = subPart.indexOf("`", pos);
int endpos = subPart.indexOf("`", pos + 1);
cols.add(subPart.substring(pos + 1, endpos));
pos = endpos + 1;
}
res.put(cols.toArray(new String[0]), name);
}
}
return res;
}

/**
* Retrieves a description of the primary key columns that are referenced by the given table's
* foreign key columns (the primary keys imported by a table). They are ordered by PKTABLE_CAT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,15 +236,21 @@ public void functionColumns() throws SQLException {
/** Same as getImportedKeys, with one foreign key in a table in another catalog. */
@Test
public void getImportedKeys() throws Exception {
getImportedKeys(sharedConn);
getImportedKeys(sharedConn, true);
try (org.mariadb.jdbc.Connection con = createCon()) {
java.sql.Statement stmt = con.createStatement();
stmt.execute("SET sql_mode = concat(@@sql_mode,',NO_BACKSLASH_ESCAPES')");
getImportedKeys(con);
getImportedKeys(con, true);
}
try (org.mariadb.jdbc.Connection con = createCon("importedKeysWithConstraintNames=false")) {
java.sql.Statement stmt = con.createStatement();
stmt.execute("SET sql_mode = concat(@@sql_mode,',NO_BACKSLASH_ESCAPES')");
getImportedKeys(con, false);
}
}

private void getImportedKeys(org.mariadb.jdbc.Connection con) throws Exception {
private void getImportedKeys(
org.mariadb.jdbc.Connection con, boolean importedKeysWithConstraintNames) throws Exception {
// cancel for MySQL 8.0, since CASCADE with I_S give importedKeySetDefault, not
// importedKeyCascade
// Assumptions.assumeFalse(!isMariaDBServer() && minVersion(8, 0, 0));
Expand Down Expand Up @@ -349,7 +355,9 @@ Get result sets using either method and compare (ignore minor differences INT vs
assertEquals(DatabaseMetaData.importedKeyCascade, rs.getInt("DELETE_RULE"));
assertEquals("product order 1_ibfk_1", rs.getString("FK_NAME"));
// with show, meta don't know contraint name
assertEquals((i == 0) ? null : "unik_name", rs.getString("PK_NAME"));
assertEquals(
(i == 0 && !importedKeysWithConstraintNames) ? null : "unik_name",
rs.getString("PK_NAME"));
assertEquals(DatabaseMetaData.importedKeyNotDeferrable, rs.getInt("DEFERRABILITY"));

assertTrue(rs.next());
Expand All @@ -366,7 +374,9 @@ Get result sets using either method and compare (ignore minor differences INT vs
assertEquals(DatabaseMetaData.importedKeyCascade, rs.getInt("DELETE_RULE"));
assertEquals("product order 1_ibfk_1", rs.getString("FK_NAME"));
// with show, meta don't know contraint name
assertEquals((i == 0) ? null : "unik_name", rs.getString("PK_NAME"));
assertEquals(
(i == 0 && !importedKeysWithConstraintNames) ? null : "unik_name",
rs.getString("PK_NAME"));
assertEquals(DatabaseMetaData.importedKeyNotDeferrable, rs.getInt("DEFERRABILITY"));

assertTrue(rs.next());
Expand All @@ -388,7 +398,8 @@ Get result sets using either method and compare (ignore minor differences INT vs
}
assertEquals("product order 1_ibfk_2", rs.getString("FK_NAME"));
// with show, meta don't know contraint name
assertEquals((i == 0) ? null : "PRIMARY", rs.getString("PK_NAME"));
assertEquals(
(i == 0 && !importedKeysWithConstraintNames) ? null : "PRIMARY", rs.getString("PK_NAME"));
assertEquals(DatabaseMetaData.importedKeyNotDeferrable, rs.getInt("DEFERRABILITY"));
}

Expand Down

0 comments on commit 79eb340

Please sign in to comment.