Skip to content

Commit 796b052

Browse files
authored
Fixed NPE issue with Metadata calls in SEA (#1130)
## Description <!-- Provide a brief summary of the changes made and the issue they aim to address.--> Fixed NPE in metadata calls for SEA. ## Testing <!-- Describe how the changes have been tested--> Tested locally ## Additional Notes to the Reviewer <!-- Share any additional context or insights that may help the reviewer understand the changes better. This could include challenges faced, limitations, or compromises made during the development process. Also, mention any areas of the code that you would like the reviewer to focus on specifically. --> NO_CHANGELOG=true Fixes [PECOBLR-1372](https://databricks.atlassian.net/browse/PECOBLR-1372) [PECOBLR-1372]: https://databricks.atlassian.net/browse/PECOBLR-1372?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
1 parent ec9a2ff commit 796b052

2 files changed

Lines changed: 125 additions & 4 deletions

File tree

src/main/java/com/databricks/jdbc/dbclient/impl/sqlexec/DatabricksMetadataSdkClient.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public DatabricksResultSet listSchemas(
7979
return metadataResultSetBuilder.getSchemasResult(getResultSet(SQL, session), catalog);
8080
} catch (SQLException e) {
8181
if (WildcardUtil.isNullOrWildcard(catalog)
82-
&& e.getSQLState().equals(PARSE_SYNTAX_ERROR_SQL_STATE)) {
82+
&& PARSE_SYNTAX_ERROR_SQL_STATE.equals(e.getSQLState())) {
8383
// This is a fallback for the case where the SQL command fails with "syntax error at or near
8484
// "ALL CATALOGS""
8585
// This is a known issue for older DBR versions
@@ -115,7 +115,7 @@ public DatabricksResultSet listTables(
115115
return metadataResultSetBuilder.getTablesResult(
116116
getResultSet(SQL, session), validatedTableTypes);
117117
} catch (SQLException e) {
118-
if (e.getSQLState().equals(PARSE_SYNTAX_ERROR_SQL_STATE)
118+
if (PARSE_SYNTAX_ERROR_SQL_STATE.equals(e.getSQLState())
119119
&& (catalog == null || catalog.equals("*") || catalog.equals("%"))) {
120120
// Gracefully handles the case where an older DBSQL version doesn't support all catalogs in
121121
// the SHOW TABLES command.
@@ -247,7 +247,7 @@ public DatabricksResultSet listImportedKeys(
247247
try {
248248
return metadataResultSetBuilder.getImportedKeysResult(getResultSet(SQL, session));
249249
} catch (SQLException e) {
250-
if (e.getSQLState().equals(PARSE_SYNTAX_ERROR_SQL_STATE)) {
250+
if (PARSE_SYNTAX_ERROR_SQL_STATE.equals(e.getSQLState())) {
251251
// This is a workaround for the issue where the SQL command fails with "syntax error at or
252252
// near "foreign""
253253
LOGGER.debug("SQL command failed with syntax error. Returning empty result set.");
@@ -293,7 +293,7 @@ public DatabricksResultSet listCrossReferences(
293293
return metadataResultSetBuilder.getCrossReferenceKeysResult(
294294
getResultSet(SQL, session), parentCatalog, parentSchema, parentTable);
295295
} catch (SQLException e) {
296-
if (e.getSQLState().equals(PARSE_SYNTAX_ERROR_SQL_STATE)) {
296+
if (PARSE_SYNTAX_ERROR_SQL_STATE.equals(e.getSQLState())) {
297297
// This is a workaround for the issue where the SQL command fails with "syntax error at or
298298
// near "foreign""
299299
// This is a known issue in Databricks for older DBSQL versions

src/test/java/com/databricks/jdbc/dbclient/impl/sqlexec/DatabricksMetadataSdkClientTest.java

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,4 +964,125 @@ void testListSchemasWithMultipleCatalogSupportDisabled() throws SQLException {
964964
assertEquals(METADATA_STATEMENT_ID, actualResult.getStatementId());
965965
assertEquals(2, ((DatabricksResultSetMetaData) actualResult.getMetaData()).getTotalRows());
966966
}
967+
968+
/**
969+
* Test that listTables handles SQLException with null SQL state without NPE. This tests the fix
970+
* for the issue where e.getSQLState() could return null, causing NullPointerException when
971+
* calling .equals() on it.
972+
*/
973+
@Test
974+
void testListTables_handlesNullSqlStateWithoutNPE() throws Exception {
975+
// Create exception with null SQL state (simulating server response without structured SQL
976+
// state)
977+
DatabricksSQLException exception =
978+
new DatabricksSQLException(
979+
"[SCHEMA_NOT_FOUND] The schema cannot be found. SQLSTATE: 42704",
980+
(String) null); // null SQL state
981+
982+
when(session.getComputeResource()).thenReturn(WAREHOUSE_COMPUTE);
983+
IDatabricksConnectionContext mockContext = mock(IDatabricksConnectionContext.class);
984+
when(mockContext.getEnableMultipleCatalogSupport()).thenReturn(true);
985+
when(mockClient.getConnectionContext()).thenReturn(mockContext);
986+
987+
DatabricksMetadataSdkClient metadataClient = new DatabricksMetadataSdkClient(mockClient);
988+
when(mockClient.executeStatement(
989+
"SHOW TABLES IN CATALOG ",
990+
WAREHOUSE_COMPUTE,
991+
new HashMap<>(),
992+
StatementType.METADATA,
993+
session,
994+
null))
995+
.thenThrow(exception);
996+
997+
// This should throw the original exception, not NPE
998+
assertThrows(
999+
DatabricksSQLException.class,
1000+
() -> metadataClient.listTables(session, "", null, null, null));
1001+
}
1002+
1003+
@Test
1004+
void testListSchemas_handlesNullSqlStateWithoutNPE() throws Exception {
1005+
DatabricksSQLException exception =
1006+
new DatabricksSQLException(
1007+
"syntax error at or near \"ALL CATALOGS\"", (String) null); // null SQL state
1008+
1009+
when(session.getComputeResource()).thenReturn(WAREHOUSE_COMPUTE);
1010+
IDatabricksConnectionContext mockContext = mock(IDatabricksConnectionContext.class);
1011+
when(mockContext.getEnableMultipleCatalogSupport()).thenReturn(true);
1012+
when(mockClient.getConnectionContext()).thenReturn(mockContext);
1013+
1014+
DatabricksMetadataSdkClient metadataClient = new DatabricksMetadataSdkClient(mockClient);
1015+
when(mockClient.executeStatement(
1016+
"SHOW SCHEMAS IN ALL CATALOGS",
1017+
WAREHOUSE_COMPUTE,
1018+
new HashMap<>(),
1019+
StatementType.METADATA,
1020+
session,
1021+
null))
1022+
.thenThrow(exception);
1023+
1024+
// This should throw the original exception, not NPE
1025+
assertThrows(
1026+
DatabricksSQLException.class, () -> metadataClient.listSchemas(session, null, null));
1027+
}
1028+
1029+
@Test
1030+
void testListImportedKeys_handlesNullSqlStateWithoutNPE() throws Exception {
1031+
DatabricksSQLException exception =
1032+
new DatabricksSQLException(
1033+
"syntax error at or near \"foreign\"", (String) null); // null SQL state
1034+
1035+
when(session.getComputeResource()).thenReturn(WAREHOUSE_COMPUTE);
1036+
IDatabricksConnectionContext mockContext = mock(IDatabricksConnectionContext.class);
1037+
when(mockContext.getEnableMultipleCatalogSupport()).thenReturn(true);
1038+
when(mockClient.getConnectionContext()).thenReturn(mockContext);
1039+
1040+
DatabricksMetadataSdkClient metadataClient = new DatabricksMetadataSdkClient(mockClient);
1041+
when(mockClient.executeStatement(
1042+
"SHOW FOREIGN KEYS IN CATALOG catalog1 IN SCHEMA testSchema IN TABLE testTable",
1043+
WAREHOUSE_COMPUTE,
1044+
new HashMap<>(),
1045+
StatementType.METADATA,
1046+
session,
1047+
null))
1048+
.thenThrow(exception);
1049+
1050+
// This should throw the original exception, not NPE
1051+
assertThrows(
1052+
DatabricksSQLException.class,
1053+
() -> metadataClient.listImportedKeys(session, TEST_CATALOG, TEST_SCHEMA, TEST_TABLE));
1054+
}
1055+
1056+
@Test
1057+
void testListCrossReferences_handlesNullSqlStateWithoutNPE() throws Exception {
1058+
DatabricksSQLException exception =
1059+
new DatabricksSQLException(
1060+
"syntax error at or near \"foreign\"", (String) null); // null SQL state
1061+
1062+
when(session.getComputeResource()).thenReturn(WAREHOUSE_COMPUTE);
1063+
when(mockClient.getConnectionContext()).thenReturn(mock(IDatabricksConnectionContext.class));
1064+
1065+
DatabricksMetadataSdkClient metadataClient = new DatabricksMetadataSdkClient(mockClient);
1066+
when(mockClient.executeStatement(
1067+
"SHOW FOREIGN KEYS IN CATALOG catalog1 IN SCHEMA testSchema IN TABLE testTable",
1068+
WAREHOUSE_COMPUTE,
1069+
new HashMap<>(),
1070+
StatementType.METADATA,
1071+
session,
1072+
null))
1073+
.thenThrow(exception);
1074+
1075+
// This should throw the original exception, not NPE
1076+
assertThrows(
1077+
DatabricksSQLException.class,
1078+
() ->
1079+
metadataClient.listCrossReferences(
1080+
session,
1081+
"parentCatalog",
1082+
"parentSchema",
1083+
"parentTable",
1084+
TEST_CATALOG,
1085+
TEST_SCHEMA,
1086+
TEST_TABLE));
1087+
}
9671088
}

0 commit comments

Comments
 (0)