Skip to content

Commit bf7319c

Browse files
committed
throw error instead of logging warning for getDiscoveredProjects
1 parent 47a47ac commit bf7319c

4 files changed

Lines changed: 59 additions & 46 deletions

File tree

java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryConnection.java

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,7 +1324,7 @@ public boolean isEnableProjectDiscovery() {
13241324
return this.enableProjectDiscovery;
13251325
}
13261326

1327-
public synchronized List<String> getDiscoveredProjects() {
1327+
public synchronized List<String> getDiscoveredProjects() throws SQLException {
13281328
if (this.discoveredProjectsCache != null) {
13291329
return this.discoveredProjectsCache;
13301330
}
@@ -1339,16 +1339,10 @@ public synchronized List<String> getDiscoveredProjects() {
13391339
}
13401340
this.discoveredProjectsCache = ImmutableList.copyOf(projects);
13411341
} catch (BigQueryException e) {
1342-
LOG.warning(e, "Failed to list all accessible projects due to BigQuery error.");
1343-
int statusCode = e.getCode();
1344-
// Only cache empty list for non-transient auth/permission errors (400, 401, 403)
1345-
if (statusCode == 400 || statusCode == 401 || statusCode == 403) {
1346-
this.discoveredProjectsCache = ImmutableList.of();
1347-
}
1348-
return ImmutableList.of();
1342+
throw new BigQueryJdbcException(
1343+
"Failed to list all accessible projects due to BigQuery error.", e);
13491344
} catch (Exception e) {
1350-
LOG.warning(e, "Failed to list all accessible projects, falling back to connection default.");
1351-
return ImmutableList.of();
1345+
throw new BigQueryJdbcException("Failed to list all accessible projects.", e);
13521346
}
13531347
return this.discoveredProjectsCache;
13541348
}

java-bigquery-jdbc/src/main/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaData.java

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1996,14 +1996,14 @@ Comparator<FieldValueList> defineGetTablesComparator(FieldList resultSchemaField
19961996
}
19971997

19981998
@Override
1999-
public ResultSet getSchemas() {
1999+
public ResultSet getSchemas() throws SQLException {
20002000
LOG.info("getSchemas() called");
20012001

20022002
return getSchemas(null, null);
20032003
}
20042004

20052005
@Override
2006-
public ResultSet getCatalogs() {
2006+
public ResultSet getCatalogs() throws SQLException {
20072007
LOG.info("getCatalogs() called");
20082008

20092009
final List<String> accessibleCatalogs = getAccessibleCatalogNames();
@@ -3618,7 +3618,7 @@ public RowIdLifetime getRowIdLifetime() {
36183618
}
36193619

36203620
@Override
3621-
public ResultSet getSchemas(String catalog, String schemaPattern) {
3621+
public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException {
36223622
if ((catalog != null && catalog.isEmpty())
36233623
|| (schemaPattern != null && schemaPattern.isEmpty())) {
36243624
LOG.warning("Returning empty ResultSet as catalog or schemaPattern is an empty string.");
@@ -3641,20 +3641,20 @@ public ResultSet getSchemas(String catalog, String schemaPattern) {
36413641
final FieldList localResultSchemaFields = resultSchemaFields;
36423642
List<String> projectsToScanList = new ArrayList<>();
36433643

3644-
if (catalogParam != null) {
3645-
projectsToScanList.add(catalogParam);
3646-
} else {
3647-
projectsToScanList.addAll(getAccessibleCatalogNames());
3648-
}
3644+
try {
3645+
if (catalogParam != null) {
3646+
projectsToScanList.add(catalogParam);
3647+
} else {
3648+
projectsToScanList.addAll(getAccessibleCatalogNames());
3649+
}
36493650

3650-
if (projectsToScanList.isEmpty()) {
3651-
LOG.info(
3652-
"No valid projects to scan (primary, specified, or additional). Returning empty"
3653-
+ " resultset.");
3654-
return;
3655-
}
3651+
if (projectsToScanList.isEmpty()) {
3652+
LOG.info(
3653+
"No valid projects to scan (primary, specified, or additional). Returning empty"
3654+
+ " resultset.");
3655+
return;
3656+
}
36563657

3657-
try {
36583658
for (String currentProjectToScan : projectsToScanList) {
36593659
if (Thread.currentThread().isInterrupted()) {
36603660
LOG.warning(
@@ -3707,6 +3707,13 @@ public ResultSet getSchemas(String catalog, String schemaPattern) {
37073707

37083708
} catch (Throwable t) {
37093709
LOG.severe("Unexpected error in schema fetcher runnable: " + t.getMessage());
3710+
Exception ex = (t instanceof Exception) ? (Exception) t : new Exception(t);
3711+
try {
3712+
queue.put(BigQueryFieldValueListWrapper.ofError(ex));
3713+
} catch (InterruptedException ie) {
3714+
LOG.warning("Failed to put exception to queue due to interruption.");
3715+
Thread.currentThread().interrupt();
3716+
}
37103717
} finally {
37113718
signalEndOfData(queue, localResultSchemaFields);
37123719
LOG.info("Schema fetcher thread finished.");
@@ -5178,7 +5185,7 @@ private String getCurrentCatalogName() {
51785185
return this.connection.getCatalog();
51795186
}
51805187

5181-
private List<String> getAccessibleCatalogNames() {
5188+
private List<String> getAccessibleCatalogNames() throws SQLException {
51825189
Set<String> accessibleCatalogs = new HashSet<>();
51835190
String primaryCatalog = getCurrentCatalogName();
51845191
if (primaryCatalog != null && !primaryCatalog.isEmpty()) {

java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryConnectionTest.java

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -556,42 +556,54 @@ public void testGetDiscoveredProjects_Success() throws Exception {
556556
}
557557

558558
@Test
559-
public void testGetDiscoveredProjects_NonTransientError() throws Exception {
559+
public void testGetDiscoveredProjects_BigQueryExceptionThrown() throws Exception {
560560
try (BigQueryConnection connection = new BigQueryConnection(BASE_URL)) {
561561
BigQuery mockBigQuery = mock(BigQuery.class);
562562
connection.bigQuery = mockBigQuery;
563563

564-
// 403 Forbidden (Non-transient error)
565564
BigQueryException exception = new BigQueryException(403, "Access Denied");
566565
when(mockBigQuery.listProjects(any(BigQuery.ProjectListOption.class))).thenThrow(exception);
567566

568-
List<String> discovered = connection.getDiscoveredProjects();
569-
assertTrue(discovered.isEmpty());
570-
571-
// Verify that it caches the empty list for 403, so it does not retry.
572-
List<String> discoveredCached = connection.getDiscoveredProjects();
573-
assertTrue(discoveredCached.isEmpty());
574-
verify(mockBigQuery, times(1)).listProjects(any(BigQuery.ProjectListOption.class));
567+
// Verify that it throws BigQueryJdbcException
568+
BigQueryJdbcException ex =
569+
assertThrows(
570+
BigQueryJdbcException.class,
571+
() -> {
572+
connection.getDiscoveredProjects();
573+
});
574+
assertTrue(
575+
ex.getMessage()
576+
.contains("Failed to list all accessible projects due to BigQuery error."));
577+
assertEquals(exception, ex.getCause());
578+
579+
// Subsequent call should retry since no cache is set
580+
assertThrows(
581+
BigQueryJdbcException.class,
582+
() -> {
583+
connection.getDiscoveredProjects();
584+
});
585+
verify(mockBigQuery, times(2)).listProjects(any(BigQuery.ProjectListOption.class));
575586
}
576587
}
577588

578589
@Test
579-
public void testGetDiscoveredProjects_TransientError() throws Exception {
590+
public void testGetDiscoveredProjects_OtherExceptionThrown() throws Exception {
580591
try (BigQueryConnection connection = new BigQueryConnection(BASE_URL)) {
581592
BigQuery mockBigQuery = mock(BigQuery.class);
582593
connection.bigQuery = mockBigQuery;
583594

584-
// 500 Internal Error (Transient error, should not cache empty list)
585-
BigQueryException exception = new BigQueryException(500, "Internal Server Error");
595+
RuntimeException exception = new RuntimeException("Generic Network Failure");
586596
when(mockBigQuery.listProjects(any(BigQuery.ProjectListOption.class))).thenThrow(exception);
587597

588-
List<String> discovered = connection.getDiscoveredProjects();
589-
assertTrue(discovered.isEmpty());
590-
591-
// Since it's a transient error, it should NOT cache the empty list and should try again.
592-
List<String> discoveredCached = connection.getDiscoveredProjects();
593-
assertTrue(discoveredCached.isEmpty());
594-
verify(mockBigQuery, times(2)).listProjects(any(BigQuery.ProjectListOption.class));
598+
// Verify that it throws BigQueryJdbcException
599+
BigQueryJdbcException ex =
600+
assertThrows(
601+
BigQueryJdbcException.class,
602+
() -> {
603+
connection.getDiscoveredProjects();
604+
});
605+
assertTrue(ex.getMessage().contains("Failed to list all accessible projects."));
606+
assertEquals(exception, ex.getCause());
595607
}
596608
}
597609
}

java-bigquery-jdbc/src/test/java/com/google/cloud/bigquery/jdbc/BigQueryDatabaseMetaDataTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2955,7 +2955,7 @@ public void testPrepareGetCatalogsRows() {
29552955
}
29562956

29572957
@Test
2958-
public void testGetSchemas_NoArgs_DelegatesCorrectly() {
2958+
public void testGetSchemas_NoArgs_DelegatesCorrectly() throws SQLException {
29592959
BigQueryDatabaseMetaData spiedDbMetadata = spy(dbMetadata);
29602960
ResultSet mockResultSet = mock(ResultSet.class);
29612961
doReturn(mockResultSet).when(spiedDbMetadata).getSchemas(null, null);

0 commit comments

Comments
 (0)