diff --git a/google-cloud-bigquery/clirr-ignored-differences.xml b/google-cloud-bigquery/clirr-ignored-differences.xml
index 6c1fd8cd6..bebc7e25c 100644
--- a/google-cloud-bigquery/clirr-ignored-differences.xml
+++ b/google-cloud-bigquery/clirr-ignored-differences.xml
@@ -5,6 +5,6 @@
7013
com/google/cloud/bigquery/RoutineInfo$Builder
- com.google.cloud.bigquery.RoutineInfo$Builder setDeterminismLevel(java.lang.String)
+ com.google.cloud.bigquery.RoutineInfo$Builder setReturnTableType(com.google.cloud.bigquery.StandardSQLTableType)
\ No newline at end of file
diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Routine.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Routine.java
index 2fbf1d67d..a5232c3f9 100644
--- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Routine.java
+++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Routine.java
@@ -111,6 +111,12 @@ public Builder setReturnType(StandardSQLDataType returnType) {
return this;
}
+ @Override
+ public Builder setReturnTableType(StandardSQLTableType returnTableType) {
+ infoBuilder.setReturnTableType(returnTableType);
+ return this;
+ }
+
@Override
public Builder setImportedLibraries(List libraries) {
infoBuilder.setImportedLibraries(libraries);
diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineInfo.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineInfo.java
index 1f9c252d2..daa745577 100644
--- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineInfo.java
+++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineInfo.java
@@ -67,6 +67,7 @@ public Routine apply(RoutineInfo routineInfo) {
private final String language;
private final List argumentList;
private final StandardSQLDataType returnType;
+ private final StandardSQLTableType returnTableType;
private final List importedLibrariesList;
private final String body;
@@ -113,6 +114,9 @@ public abstract static class Builder {
*/
public abstract Builder setReturnType(StandardSQLDataType returnType);
+ /** Optional. Set only if Routine is a "TABLE_VALUED_FUNCTION". */
+ public abstract Builder setReturnTableType(StandardSQLTableType returnTableType);
+
/**
* Optional. If language = "JAVASCRIPT", this field stores the path of the imported JAVASCRIPT
* libraries as a list of gs:// URLs.
@@ -159,6 +163,7 @@ static class BuilderImpl extends Builder {
private String language;
private List argumentList;
private StandardSQLDataType returnType;
+ private StandardSQLTableType returnTableType;
private List importedLibrariesList;
private String body;
@@ -175,6 +180,7 @@ static class BuilderImpl extends Builder {
this.language = routineInfo.language;
this.argumentList = routineInfo.argumentList;
this.returnType = routineInfo.returnType;
+ this.returnTableType = routineInfo.returnTableType;
this.importedLibrariesList = routineInfo.importedLibrariesList;
this.body = routineInfo.body;
}
@@ -195,6 +201,9 @@ static class BuilderImpl extends Builder {
if (routinePb.getReturnType() != null) {
this.returnType = StandardSQLDataType.fromPb(routinePb.getReturnType());
}
+ if (routinePb.getReturnTableType() != null) {
+ this.returnTableType = StandardSQLTableType.fromPb(routinePb.getReturnTableType());
+ }
if (routinePb.getImportedLibraries() == null) {
this.importedLibrariesList = Collections.emptyList();
} else {
@@ -263,6 +272,12 @@ public Builder setReturnType(StandardSQLDataType returnType) {
return this;
}
+ @Override
+ public Builder setReturnTableType(StandardSQLTableType returnTableType) {
+ this.returnTableType = returnTableType;
+ return this;
+ }
+
@Override
public Builder setImportedLibraries(List importedLibrariesList) {
this.importedLibrariesList = importedLibrariesList;
@@ -292,6 +307,7 @@ public RoutineInfo build() {
this.language = builder.language;
this.argumentList = builder.argumentList;
this.returnType = builder.returnType;
+ this.returnTableType = builder.returnTableType;
this.importedLibrariesList = builder.importedLibrariesList;
this.body = builder.body;
}
@@ -350,6 +366,11 @@ public StandardSQLDataType getReturnType() {
return returnType;
}
+ /** If specified, returns the table type returned from the routine. */
+ public StandardSQLTableType getReturnTableType() {
+ return returnTableType;
+ }
+
/**
* Returns the list of imported libraries for the routine. Only relevant for routines implemented
* using the JAVASCRIPT language.
@@ -381,6 +402,7 @@ public String toString() {
.add("language", language)
.add("arguments", argumentList)
.add("returnType", returnType)
+ .add("returnTableType", returnTableType)
.add("importedLibrariesList", importedLibrariesList)
.add("body", body)
.toString();
@@ -399,6 +421,7 @@ public int hashCode() {
language,
argumentList,
returnType,
+ returnTableType,
importedLibrariesList,
body);
}
@@ -448,6 +471,9 @@ Routine toPb() {
if (getReturnType() != null) {
routinePb.setReturnType(getReturnType().toPb());
}
+ if (getReturnTableType() != null) {
+ routinePb.setReturnTableType(getReturnTableType().toPb());
+ }
return routinePb;
}
diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLTableType.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLTableType.java
new file mode 100644
index 000000000..d44f89f92
--- /dev/null
+++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLTableType.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.cloud.bigquery;
+
+import com.google.api.services.bigquery.model.StandardSqlTableType;
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.Lists;
+import java.io.Serializable;
+import java.util.List;
+
+/** Represents Standard SQL table type information. */
+@AutoValue
+public abstract class StandardSQLTableType implements Serializable {
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+
+ /** Sets the columns in this table type. */
+ public abstract Builder setColumns(List columns);
+
+ /** Creates a {@code StandardSQLTableType} object. */
+ public abstract StandardSQLTableType build();
+ }
+
+ /** Returns the columns in this table type. */
+ public abstract List getColumns();
+
+ public abstract Builder toBuilder();
+
+ /** Returns a builder for a {@code StandardSQLTableType} object. */
+ public static Builder newBuilder() {
+ return new AutoValue_StandardSQLTableType.Builder();
+ }
+
+ /** Returns a builder for a {@code StandardSQLTableType} object with the specified columns. */
+ public static StandardSQLTableType.Builder newBuilder(List columns) {
+ return newBuilder().setColumns(columns);
+ }
+
+ static StandardSQLTableType fromPb(
+ com.google.api.services.bigquery.model.StandardSqlTableType tableTypePb) {
+ StandardSQLTableType.Builder builder = newBuilder();
+ if (tableTypePb.getColumns() != null) {
+ builder.setColumns(
+ Lists.transform(tableTypePb.getColumns(), StandardSQLField.FROM_PB_FUNCTION));
+ }
+ return builder.build();
+ }
+
+ StandardSqlTableType toPb() {
+ StandardSqlTableType tableType = new StandardSqlTableType();
+ if (getColumns() != null) {
+ tableType.setColumns(Lists.transform(getColumns(), StandardSQLField.TO_PB_FUNCTION));
+ }
+ return tableType;
+ }
+}
diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/RoutineTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/RoutineTest.java
index f0e29410d..89bed602e 100644
--- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/RoutineTest.java
+++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/RoutineTest.java
@@ -38,9 +38,11 @@
public class RoutineTest {
private static final RoutineId ROUTINE_ID = RoutineId.of("dataset", "routine");
+ private static final RoutineId ROUTINE_ID_TVF = RoutineId.of("dataset", "tvf_routine");
private static final String DETERMINISM_LEVEL = "DETERMINISTIC";
private static final String ETAG = "etag";
private static final String ROUTINE_TYPE = "SCALAR_FUNCTION";
+ private static final String ROUTINE_TYPE_TVF = "TABLE_VALUED_FUNCTION";
private static final Long CREATION_TIME = 10L;
private static final Long LAST_MODIFIED_TIME = 20L;
private static final String LANGUAGE = "SQL";
@@ -56,6 +58,18 @@ public class RoutineTest {
private static final StandardSQLDataType RETURN_TYPE =
StandardSQLDataType.newBuilder("FLOAT64").build();
+ private static final StandardSQLField COLUMN_1 =
+ StandardSQLField.newBuilder("COLUMN_1", StandardSQLDataType.newBuilder("STRING").build())
+ .build();
+ private static final StandardSQLField COLUMN_2 =
+ StandardSQLField.newBuilder("COLUMN_2", StandardSQLDataType.newBuilder("FLOAT64").build())
+ .build();
+
+ private static final List COLUMN_LIST = ImmutableList.of(COLUMN_1, COLUMN_2);
+
+ private static final StandardSQLTableType RETURN_TABLE_TYPE =
+ StandardSQLTableType.newBuilder(COLUMN_LIST).build();
+
private static final List IMPORTED_LIBRARIES =
ImmutableList.of("gs://foo", "gs://bar", "gs://baz");
@@ -75,11 +89,19 @@ public class RoutineTest {
.setBody(BODY)
.build();
+ private static final RoutineInfo ROUTINE_INFO_TVF =
+ RoutineInfo.newBuilder(ROUTINE_ID_TVF)
+ .setBody(BODY)
+ .setRoutineType(ROUTINE_TYPE_TVF)
+ .setReturnTableType(RETURN_TABLE_TYPE)
+ .build();
+
@Rule public MockitoRule rule;
private BigQuery bigquery;
private BigQueryOptions mockOptions;
private Routine expectedRoutine;
+ private Routine expectedRoutineTvf;
private Routine routine;
@Before
@@ -88,6 +110,7 @@ public void setUp() {
mockOptions = mock(BigQueryOptions.class);
when(bigquery.getOptions()).thenReturn(mockOptions);
expectedRoutine = new Routine(bigquery, new RoutineInfo.BuilderImpl(ROUTINE_INFO));
+ expectedRoutineTvf = new Routine(bigquery, new RoutineInfo.BuilderImpl(ROUTINE_INFO_TVF));
routine = new Routine(bigquery, new RoutineInfo.BuilderImpl(ROUTINE_INFO));
}
@@ -114,6 +137,7 @@ public void testBuilder() {
@Test
public void testToBuilder() {
compareRoutineInfo(expectedRoutine, expectedRoutine.toBuilder().build());
+ compareRoutineInfo(expectedRoutineTvf, expectedRoutineTvf.toBuilder().build());
}
@Test
@@ -200,6 +224,7 @@ public void compareRoutineInfo(RoutineInfo expected, RoutineInfo value) {
assertEquals(expected.getLanguage(), value.getLanguage());
assertEquals(expected.getArguments(), value.getArguments());
assertEquals(expected.getReturnType(), value.getReturnType());
+ assertEquals(expected.getReturnTableType(), value.getReturnTableType());
assertEquals(expected.getImportedLibraries(), value.getImportedLibraries());
assertEquals(expected.getBody(), value.getBody());
assertEquals(expected.hashCode(), value.hashCode());
diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/StandardSQLTableTypeTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/StandardSQLTableTypeTest.java
new file mode 100644
index 000000000..2ed6e3535
--- /dev/null
+++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/StandardSQLTableTypeTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.bigquery;
+
+import static org.junit.Assert.*;
+
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+
+public class StandardSQLTableTypeTest {
+
+ private static final StandardSQLField COLUMN_1 =
+ StandardSQLField.newBuilder("COLUMN_1", StandardSQLDataType.newBuilder("STRING").build())
+ .build();
+ private static final StandardSQLField COLUMN_2 =
+ StandardSQLField.newBuilder("COLUMN_2", StandardSQLDataType.newBuilder("FLOAT64").build())
+ .build();
+
+ private static final List COLUMN_LIST = ImmutableList.of(COLUMN_1, COLUMN_2);
+ private static final StandardSQLTableType TABLE_TYPE =
+ StandardSQLTableType.newBuilder(COLUMN_LIST).build();
+
+ @Test
+ public void testToBuilder() {
+ compareStandardSQLTableType(TABLE_TYPE, TABLE_TYPE.toBuilder().build());
+ }
+
+ @Test
+ public void testBuilder() {
+ assertEquals(COLUMN_1, TABLE_TYPE.getColumns().get(0));
+ assertEquals(COLUMN_2, TABLE_TYPE.getColumns().get(1));
+ }
+
+ @Test
+ public void testToAndFromPb() {
+ compareStandardSQLTableType(TABLE_TYPE, StandardSQLTableType.fromPb(TABLE_TYPE.toPb()));
+ }
+
+ private void compareStandardSQLTableType(
+ StandardSQLTableType expected, StandardSQLTableType value) {
+ assertEquals(expected, value);
+ assertEquals(expected.getColumns(), value.getColumns());
+ assertEquals(expected.hashCode(), value.hashCode());
+ }
+}
diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java
index e123fa446..9b1374bc1 100644
--- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java
+++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java
@@ -87,6 +87,8 @@
import com.google.cloud.bigquery.RoutineInfo;
import com.google.cloud.bigquery.Schema;
import com.google.cloud.bigquery.StandardSQLDataType;
+import com.google.cloud.bigquery.StandardSQLField;
+import com.google.cloud.bigquery.StandardSQLTableType;
import com.google.cloud.bigquery.StandardTableDefinition;
import com.google.cloud.bigquery.Table;
import com.google.cloud.bigquery.TableDataWriteChannel;
@@ -1676,6 +1678,34 @@ public void testRoutineAPICreationJavascriptUDF() {
assertEquals(routine.getReturnType(), StandardSQLDataType.newBuilder("STRING").build());
}
+ @Test
+ public void testRoutineAPICreationTVF() {
+ String routineName = RemoteBigQueryHelper.generateRoutineName();
+ RoutineId routineId = RoutineId.of(ROUTINE_DATASET, routineName);
+ List columns =
+ ImmutableList.of(
+ StandardSQLField.newBuilder("x", StandardSQLDataType.newBuilder("INT64").build())
+ .build());
+ StandardSQLTableType returnTableType = StandardSQLTableType.newBuilder(columns).build();
+ RoutineInfo routineInfo =
+ RoutineInfo.newBuilder(routineId)
+ .setRoutineType("TABLE_VALUED_FUNCTION")
+ .setLanguage("SQL")
+ .setArguments(
+ ImmutableList.of(
+ RoutineArgument.newBuilder()
+ .setName("filter")
+ .setDataType(StandardSQLDataType.newBuilder("INT64").build())
+ .build()))
+ .setReturnTableType(returnTableType)
+ .setBody("SELECT x FROM UNNEST([1,2,3]) x WHERE x = filter")
+ .build();
+ Routine routine = bigquery.create(routineInfo);
+ assertNotNull(routine);
+ assertEquals(routine.getRoutineType(), "TABLE_VALUED_FUNCTION");
+ assertEquals(routine.getReturnTableType(), returnTableType);
+ }
+
@Test
public void testAuthorizeRoutine() {
String routineName = RemoteBigQueryHelper.generateRoutineName();