From 4cfe74ef780f57747ea1dfef1a7098f809bcb300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Knut=20Olav=20L=C3=B8ite?= Date: Wed, 16 Feb 2022 07:58:57 +0100 Subject: [PATCH] fix: allow getting metadata without calling next() (#1691) * fix: allow getting metadata without calling next() DirectExecuteResultSet, which is used in the Connection API, directly executes any query that it is given without the need to call ResultSet.next() first. This also makes it possible to get the ResultSet metadata from the result without the need to calling ResultSet.next() first. * fix: add methods to exclude list for test --- .../connection/DirectExecuteResultSet.java | 5 ---- .../DirectExecuteResultSetTest.java | 12 ++++++++- .../connection/it/ITReadOnlySpannerTest.java | 25 +++++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DirectExecuteResultSet.java b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DirectExecuteResultSet.java index cf577cbc361..21c3dae7ec9 100644 --- a/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DirectExecuteResultSet.java +++ b/google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/DirectExecuteResultSet.java @@ -96,31 +96,26 @@ public ResultSetStats getStats() { @Override public Type getType() { - Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); return delegate.getType(); } @Override public int getColumnCount() { - Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); return delegate.getColumnCount(); } @Override public int getColumnIndex(String columnName) { - Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); return delegate.getColumnIndex(columnName); } @Override public Type getColumnType(int columnIndex) { - Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); return delegate.getColumnType(columnIndex); } @Override public Type getColumnType(String columnName) { - Preconditions.checkState(nextCalledByClient, MISSING_NEXT_CALL); return delegate.getColumnType(columnName); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DirectExecuteResultSetTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DirectExecuteResultSetTest.java index 7145ccdf743..896055ee9a8 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DirectExecuteResultSetTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/DirectExecuteResultSetTest.java @@ -53,7 +53,17 @@ private DirectExecuteResultSet createSubject() { public void testMethodCallBeforeNext() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { List excludedMethods = - Arrays.asList("getStats", "next", "close", "ofResultSet", "equals", "hashCode"); + Arrays.asList( + "getStats", + "next", + "close", + "ofResultSet", + "equals", + "hashCode", + "getType", + "getColumnCount", + "getColumnIndex", + "getColumnType"); DirectExecuteResultSet subject = createSubject(); callMethods(subject, excludedMethods, IllegalStateException.class); } diff --git a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java index fd5df07954e..5e626d50ebf 100644 --- a/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java +++ b/google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITReadOnlySpannerTest.java @@ -33,6 +33,7 @@ import com.google.cloud.spanner.ResultSet; import com.google.cloud.spanner.SpannerException; import com.google.cloud.spanner.Statement; +import com.google.cloud.spanner.Type; import com.google.cloud.spanner.connection.ITAbstractSpannerTest; import com.google.cloud.spanner.connection.SqlScriptVerifier; import java.math.BigInteger; @@ -213,4 +214,28 @@ public void testMultipleOpenResultSets() throws InterruptedException { rs2.close(); } } + + @Test + public void testGetMetadataFromAnalyzeQuery() { + assumeFalse("analyze query is not supported on the emulator", isUsingEmulator()); + try (ITConnection connection = createConnection()) { + // Request a query plan without executing the query and verify that we can get the column + // metadata of the query without calling resultSet.next() first. + try (ResultSet resultSet = + connection.analyzeQuery( + Statement.of("SELECT number, name FROM NUMBERS"), QueryAnalyzeMode.PLAN)) { + assertEquals(2, resultSet.getColumnCount()); + + assertEquals(0, resultSet.getColumnIndex("number")); + assertEquals("number", resultSet.getType().getStructFields().get(0).getName()); + assertEquals(Type.int64(), resultSet.getColumnType(0)); + assertEquals(Type.int64(), resultSet.getColumnType("number")); + + assertEquals(1, resultSet.getColumnIndex("name")); + assertEquals("name", resultSet.getType().getStructFields().get(1).getName()); + assertEquals(Type.string(), resultSet.getColumnType(1)); + assertEquals(Type.string(), resultSet.getColumnType("name")); + } + } + } }