Skip to content
Merged
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
5 changes: 0 additions & 5 deletions internal/rows/rows.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"database/sql"
"database/sql/driver"
"io"
"math"
"reflect"
"time"
Expand Down Expand Up @@ -456,10 +455,6 @@ func (r *rows) fetchResultPage() error {
r.RowScanner = nil
}

if !r.ResultPageIterator.HasNext() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

can you check the r.error and return r.error instead?

Copy link
Contributor

Choose a reason for hiding this comment

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

@jackyhu-db I think it is possible to do a check like that, but I would like to clarify what is the use of HasNext if Next itself can just return nil, io.EOF to signify an end of the stream?

My question is more structural: why the additional complexity of HasNext when Next itself can interface and encapsulate the concept of HasNext? It is possible to now check for the error in r.ResultPageIterator.err and bubble that up, but I'm afraid any divergence between Next's logic and HasNext's logic in the future can lead to similar problems

Copy link
Contributor

@mdibaiee mdibaiee Mar 14, 2025

Choose a reason for hiding this comment

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

I think it is worth considering whether HasNext can be simply rewritten as: r.ResultPageIterator.Next() == (nil, io.EOF), and if so, it is not really useful to keep it, any consumer of ResultPageIterator can use Next for the purpose of checking whether there are any items left or not

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@jackyhu-db, we would also need to update the function signature to return (bool, error) and also make changes to https://github.com/databricks/databricks-sql-go/blob/main/internal/rows/arrowbased/arrowRecordIterator.go#L86 to also return the error, do we want to go down that route?

return io.EOF
}

fetchResult, err1 := r.ResultPageIterator.Next()
if err1 != nil {
return err1
Expand Down
27 changes: 27 additions & 0 deletions internal/rows/rows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1506,3 +1506,30 @@ func getSimpleClient(fetchResults []cli_service.TFetchResultsResp) cli_service.T

return client
}

func getErroringClient(err error) cli_service.TCLIService {
fetchResultsFn := func(ctx context.Context, req *cli_service.TFetchResultsReq) (_r *cli_service.TFetchResultsResp, _err error) {
return nil, err
}

client := &client.TestClient{
FnFetchResults: fetchResultsFn,
}

return client
}

func TestFetchResultPage_PropagatesGetNextPageError(t *testing.T) {
errorMsg := "Error thrown while calling TFetchResults in getNextPage"
expectedErr := errors.New(errorMsg)

client := getErroringClient(expectedErr)

executeStatementResp := cli_service.TExecuteStatementResp{}
cfg := config.WithDefaults()
rows, _ := NewRows("connId", "corrId", nil, client, cfg, executeStatementResp.DirectResults)
// Call Next and ensure it propagates the error from getNextPage
actualErr := rows.Next(nil)

assert.ErrorContains(t, actualErr, errorMsg)
}
Loading