Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,7 @@ monorepo
*.tfstate.lock.info

.jqwik-database

# Agent configuration and local skills
.agent/
.agents/
Comment on lines +89 to +92
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

qq, is this intended to be added?

Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,9 @@ private boolean meetsReadRatio(TableResult results) {
return false;
}

long pageSize = querySettings.getMaxResultPerPage();
Long rowsInPage = results.getRowsInPage();
long pageSize =
(rowsInPage != null && rowsInPage > 0) ? rowsInPage : querySettings.getMaxResultPerPage();

// Prevent division by zero due to potential overflows/empty sets:
if (pageSize <= 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1685,6 +1685,7 @@ && getOptions().getOpenTelemetryTracer() != null) {
.setSchema(schema)
.setTotalRows(data.y())
.setPageNoSchema(data.x())
.setRowsInPage(data.x() != null ? (long) Iterables.size(data.x().getValues()) : 0L)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we guarantee somehow that it would be using .size() to avoid O(N) here?

Copy link
Copy Markdown
Contributor Author

@Neenu1995 Neenu1995 May 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can guarantee $O(1)$ performance because the row values in TableResult pages are always materialized into an ImmutableList under the hood. Since ImmutableList implements Collection, any size check—whether through our explicit instanceof check or Guava's Iterables.size—calls the list's size() method directly. This allows Java to look up the count instantly instead of looping through each row one by one.

But if we want we can add an explicit instanceof check here. Should I add it?

.build();
} finally {
if (tableDataList != null) {
Expand Down Expand Up @@ -2016,6 +2017,7 @@ public com.google.api.services.bigquery.model.QueryResponse call()
.setJobId(jobId)
.setQueryId(results.getQueryId())
.setJobCreationReason(JobCreationReason.fromPb(results.getJobCreationReason()))
.setRowsInPage(results.getRows() != null ? (long) results.getRows().size() : 0L)
.build();
}
// only 1 page of result
Expand All @@ -2035,6 +2037,7 @@ public com.google.api.services.bigquery.model.QueryResponse call()
results.getJobReference() != null ? JobId.fromPb(results.getJobReference()) : null)
.setQueryId(results.getQueryId())
.setJobCreationReason(JobCreationReason.fromPb(results.getJobCreationReason()))
.setRowsInPage(results.getRows() != null ? (long) results.getRows().size() : 0L)
.build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ public TableResult getQueryResults(QueryResultsOption... options)
.setJobId(job.getJobId())
.setTotalRows(0L)
.setPageNoSchema(new PageImpl<FieldValueList>(null, "", null))
.setRowsInPage(0L)
.build();
return emptyTableResult;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public abstract static class Builder {

public abstract TableResult.Builder setJobCreationReason(JobCreationReason jobCreationReason);

public abstract TableResult.Builder setRowsInPage(Long rowsInPage);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Is is possible to keep this setter package-private for now? I think it's only used internally and we can make it public if there is a need.


/** Creates a @code TableResult} object. */
public abstract TableResult build();
}
Expand Down Expand Up @@ -81,6 +83,10 @@ public static Builder newBuilder() {
@Nullable
public abstract JobCreationReason getJobCreationReason();

/** Returns the number of rows in the current page of results. */
@Nullable
public abstract Long getRowsInPage();

@Override
public boolean hasNextPage() {
return getPageNoSchema().hasNextPage();
Expand All @@ -94,12 +100,18 @@ public String getNextPageToken() {
@Override
public TableResult getNextPage() {
if (getPageNoSchema().hasNextPage()) {
Page<FieldValueList> nextPageNoSchema = getPageNoSchema().getNextPage();
long nextRows =
nextPageNoSchema.getValues() != null
? (long) Iterables.size(nextPageNoSchema.getValues())
: 0L;
Comment on lines +103 to +107
Copy link
Copy Markdown
Member

@lqiu96 lqiu96 May 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

qq, similar to the question Kirill mentioned above. If Page.getValues() is not a Collection, this would be O(n) time instead of O(1) right?

Would that end up increasing the overall time? For example O(n) here in the getNextPage() call and then O(n) again as the user iterates through the page?

return TableResult.newBuilder()
.setSchema(getSchema())
.setTotalRows(getTotalRows())
.setPageNoSchema(getPageNoSchema().getNextPage())
.setPageNoSchema(nextPageNoSchema)
.setQueryId(getQueryId())
.setJobCreationReason(getJobCreationReason())
.setRowsInPage(nextRows)
.build();
}
return null;
Expand Down Expand Up @@ -137,12 +149,14 @@ public String toString() {
.add("totalRows", getTotalRows())
.add("cursor", getNextPageToken())
.add("queryId", getQueryId())
.add("rowsInPage", getRowsInPage())
.toString();
}

@Override
public final int hashCode() {
return Objects.hash(getPageNoSchema(), getSchema(), getTotalRows(), getQueryId());
return Objects.hash(
getPageNoSchema(), getSchema(), getTotalRows(), getQueryId(), getRowsInPage());
}

@Override
Expand All @@ -158,6 +172,7 @@ public final boolean equals(Object obj) {
&& Iterators.elementsEqual(getValues().iterator(), response.getValues().iterator())
&& Objects.equals(getSchema(), response.getSchema())
&& getTotalRows() == response.getTotalRows()
&& getQueryId() == response.getQueryId();
&& Objects.equals(getQueryId(), response.getQueryId())
&& Objects.equals(getRowsInPage(), response.getRowsInPage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ public class SerializationTest extends BaseSerializationTest {
.setSchema(Schema.of())
.setTotalRows(0L)
.setPageNoSchema(new PageImpl(null, "", ImmutableList.of()))
.setRowsInPage(0L)
.build();
private static final BigQuery BIGQUERY =
BigQueryOptions.newBuilder().setProjectId("p1").build().getService();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,15 @@ private static FieldValueList newFieldValueList(String s) {
@Test
void testNullSchema() {
TableResult result =
TableResult.newBuilder().setTotalRows(3L).setPageNoSchema(INNER_PAGE_0).build();
TableResult.newBuilder()
.setTotalRows(3L)
.setPageNoSchema(INNER_PAGE_0)
.setRowsInPage(2L)
.build();
assertThat(result.getSchema()).isNull();
assertThat(result.hasNextPage()).isTrue();
assertThat(result.getNextPageToken()).isNotNull();
assertThat(result.getRowsInPage()).isEqualTo(2L);
assertThat(result.getValues())
.containsExactly(newFieldValueList("0"), newFieldValueList("1"))
.inOrder();
Expand All @@ -66,6 +71,7 @@ void testNullSchema() {
assertThat(next.getSchema()).isNull();
assertThat(next.hasNextPage()).isFalse();
assertThat(next.getNextPageToken()).isNull();
assertThat(next.getRowsInPage()).isEqualTo(1L);
assertThat(next.getValues()).containsExactly(newFieldValueList("2"));
assertThat(next.getNextPage()).isNull();

Expand All @@ -81,10 +87,12 @@ void testSchema() {
.setSchema(SCHEMA)
.setTotalRows(3L)
.setPageNoSchema(INNER_PAGE_0)
.setRowsInPage(2L)
.build();
assertThat(result.getSchema()).isEqualTo(SCHEMA);
assertThat(result.hasNextPage()).isTrue();
assertThat(result.getNextPageToken()).isNotNull();
assertThat(result.getRowsInPage()).isEqualTo(2L);
assertThat(result.getValues())
.containsExactly(
newFieldValueList("0").withSchema(SCHEMA.getFields()),
Expand All @@ -95,6 +103,7 @@ void testSchema() {
assertThat(next.getSchema()).isEqualTo(SCHEMA);
assertThat(next.hasNextPage()).isFalse();
assertThat(next.getNextPageToken()).isNull();
assertThat(next.getRowsInPage()).isEqualTo(1L);
assertThat(next.getValues())
.containsExactly(newFieldValueList("2").withSchema(SCHEMA.getFields()));
assertThat(next.getNextPage()).isNull();
Expand Down
Loading