Skip to content

Commit 253b404

Browse files
NO-SNOW: Fix StreamLoader vector metadata detection error handling
1 parent b3f35ea commit 253b404

File tree

4 files changed

+64
-3
lines changed

4 files changed

+64
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
# Changelog
44
- Upcoming release (TBD)
5+
- Fix StreamLoader vector metadata detection to handle empty metadata result sets safely and avoid aborting load jobs on non-critical metadata lookup failures.
56
- Fix expired session token renewal when polling results (snowflakedb/snowflake-jdbc#2489)
67
- Fix missing minicore async initialization that was dropped during public API restructuring in v4.0.0
78
- Adjust level of logging during Driver initialization

src/main/java/net/snowflake/client/internal/api/implementation/metadata/SnowflakeDatabaseMetaDataImpl.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3722,9 +3722,27 @@ private ResultSet executeAndReturnEmptyResultIfNotFound(
37223722
try {
37233723
resultSet = statement.executeQuery(sql);
37243724
} catch (SnowflakeSQLException e) {
3725+
if (metadataType == GET_COLUMNS) {
3726+
logger.warn(
3727+
"DatabaseMetaData.getColumns received SQL exception and may return empty result: "
3728+
+ "sqlState={}, errorCode={}, queryId={}, message={}, sql={}",
3729+
e.getSQLState(),
3730+
e.getErrorCode(),
3731+
e.getQueryId(),
3732+
e.getMessage(),
3733+
sql);
3734+
}
37253735
if (e.getSQLState().equals(SqlState.NO_DATA)
37263736
|| e.getSQLState().equals(SqlState.BASE_TABLE_OR_VIEW_NOT_FOUND)
37273737
|| e.getMessage().contains("Operation is not supported in reader account")) {
3738+
if (metadataType == GET_COLUMNS) {
3739+
logger.warn(
3740+
"DatabaseMetaData.getColumns normalized SQL exception to empty result set: "
3741+
+ "sqlState={}, queryId={}, sql={}",
3742+
e.getSQLState(),
3743+
e.getQueryId(),
3744+
sql);
3745+
}
37283746
return SnowflakeDatabaseMetaDataResultSet.getEmptyResult(
37293747
metadataType, statement, e.getQueryId());
37303748
}

src/main/java/net/snowflake/client/internal/loader/StreamLoader.java

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ public class StreamLoader implements Loader, Runnable {
5757
/** Default batch row size */
5858
private static final long DEFAULT_BATCH_ROW_SIZE = -1L;
5959

60+
private static final String FAIL_ON_MISSING_COLUMN_METADATA_KEY =
61+
SYSTEM_PARAMETER_PREFIX + "failOnMissingColumnMetadata";
62+
6063
public static DatabaseMetaData metadata;
6164

6265
private BufferStage _stage = null;
@@ -632,26 +635,49 @@ public void setVectorColumnType(String vectorType) {
632635
}
633636

634637
public void setVectorColumns() {
638+
_vectorColumnsNameAndSize.clear();
639+
if (_columns == null || _columns.isEmpty()) {
640+
return;
641+
}
642+
635643
try {
636644
DatabaseMetaData dbmd = _processConn.getMetaData();
637645
for (String col : _columns) {
638646
try (ResultSet rs = dbmd.getColumns(_database, _schema, _table, col)) {
639-
rs.next();
647+
if (!rs.next()) {
648+
String message =
649+
String.format(
650+
"No metadata row returned for column %s.%s.%s.%s",
651+
_database, _schema, _table, col);
652+
logger.warn(message);
653+
if (shouldFailOnMissingColumnMetadata()) {
654+
throw new Loader.ConnectionError(message);
655+
}
656+
continue;
657+
}
640658
if (isColumnTypeVector(rs.getString(6))) {
641659
_vectorColumnsNameAndSize.put(col, rs.getInt(7));
642660
}
643661
}
644662
}
645663
} catch (SQLException e) {
646-
logger.error(e.getMessage(), e);
647-
abort(new Loader.ConnectionError(Utils.getCause(e)));
664+
logger.warn(
665+
"Failed to detect vector columns via metadata query. "
666+
+ "Vector column type casting will be skipped. Error: {}",
667+
e.getMessage());
668+
logger.debug("setVectorColumns metadata query failure details", e);
669+
_vectorColumnsNameAndSize.clear();
648670
}
649671
}
650672

651673
private boolean isColumnTypeVector(String col) {
652674
return col != null && col.equalsIgnoreCase("vector");
653675
}
654676

677+
private boolean shouldFailOnMissingColumnMetadata() {
678+
return Boolean.parseBoolean(systemGetProperty(FAIL_ON_MISSING_COLUMN_METADATA_KEY));
679+
}
680+
655681
@Override
656682
public void run() {
657683
try {

src/test/java/net/snowflake/client/internal/loader/FlatfileReadMultithreadIT.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.sql.Statement;
1010
import java.util.ArrayList;
1111
import java.util.Arrays;
12+
import java.util.Collections;
1213
import java.util.Date;
1314
import java.util.HashMap;
1415
import java.util.List;
@@ -30,6 +31,8 @@
3031
@Tag(TestTags.LOADER)
3132
public class FlatfileReadMultithreadIT {
3233
private final int NUM_RECORDS = 100000;
34+
private static final String FAIL_ON_MISSING_COLUMN_METADATA_KEY =
35+
"net.snowflake.client.loader.failOnMissingColumnMetadata";
3336

3437
private static final String TARGET_STAGE = "STAGE_MULTITHREAD_LOADER";
3538
private static String TARGET_SCHEMA;
@@ -64,6 +67,9 @@ public static void tearDownClass() throws Throwable {
6467
@Test
6568
public void testIssueSimpleDateFormat() throws Throwable {
6669
final String targetTable = "TABLE_ISSUE_SIMPLEDATEFORMAT";
70+
String originalFailOnMissingMetadataValue =
71+
System.getProperty(FAIL_ON_MISSING_COLUMN_METADATA_KEY);
72+
System.setProperty(FAIL_ON_MISSING_COLUMN_METADATA_KEY, "true");
6773
try (Connection testConnection = AbstractDriverIT.getConnection();
6874
Statement statement = testConnection.createStatement()) {
6975
try {
@@ -77,11 +83,15 @@ public void testIssueSimpleDateFormat() throws Throwable {
7783
Thread t2 =
7884
new Thread(
7985
new FlatfileRead(NUM_RECORDS, TARGET_DB, TARGET_SCHEMA, TARGET_STAGE, targetTable));
86+
List<Throwable> threadFailures = Collections.synchronizedList(new ArrayList<>());
87+
t1.setUncaughtExceptionHandler((thread, throwable) -> threadFailures.add(throwable));
88+
t2.setUncaughtExceptionHandler((thread, throwable) -> threadFailures.add(throwable));
8089

8190
t1.start();
8291
t2.start();
8392
t1.join();
8493
t2.join();
94+
assertThat("worker thread failures", threadFailures.isEmpty(), equalTo(true));
8595
try (ResultSet rs =
8696
statement.executeQuery(
8797
String.format(
@@ -93,6 +103,12 @@ public void testIssueSimpleDateFormat() throws Throwable {
93103
} finally {
94104
statement.execute(
95105
String.format("DROP TABLE IF EXISTS %s.%s.%s", TARGET_DB, TARGET_SCHEMA, targetTable));
106+
if (originalFailOnMissingMetadataValue == null) {
107+
System.clearProperty(FAIL_ON_MISSING_COLUMN_METADATA_KEY);
108+
} else {
109+
System.setProperty(
110+
FAIL_ON_MISSING_COLUMN_METADATA_KEY, originalFailOnMissingMetadataValue);
111+
}
96112
}
97113
}
98114
}

0 commit comments

Comments
 (0)