ydb-platform / ydb-go-sdk

Pure Go native and database/sql driver for YDB
https://ydb.tech
Apache License 2.0
132 stars 69 forks source link

bug: `Query().Do` doesn't up/insert when calling `Execute(...)` with `SerializableReadWriteTxControl()` #1316

Closed pelageech closed 6 days ago

pelageech commented 6 days ago

Bug Report

YDB GO SDK version: 3.74.5

Environment macOS Sonoma 14.2.1 amd64

Current behavior: Nothing happens after serializable Execute-call. ReadRow returns io.EOF.

Expected behavior: I expect either a correct up/insert operation and true in stdout or some error.

Steps to reproduce: Run the code.

Related code:

package main

import (
    "context"
    "errors"
    "fmt"
    "io"
    "log"
    "math/rand"
    "time"

    "github.com/ydb-platform/ydb-go-sdk/v3"
    "github.com/ydb-platform/ydb-go-sdk/v3/query"
)

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    driver, err := ydb.Open(ctx,
        "grpc://localhost:2136/local",
    )
    if err != nil {
        log.Fatal("open", err)
    }
    defer driver.Close(ctx)

    _, err = driver.Query().Execute(ctx, `CREATE TABLE IF NOT EXISTS example ( key UInt64, PRIMARY KEY (key) );`)
    if err != nil {
        log.Fatal("execute", err)
    }

    num := rand.Uint64()

    err = driver.Query().Do( // Do retry operation on errors with best effort
        ctx, // context manage exiting from Do
        func(ctx context.Context, s query.Session) (err error) { // retry operation
            _, _, err = s.Execute(ctx, `DECLARE $num AS Uint64; UPSERT INTO example (key) VALUES ($num)`,
                query.WithParameters(
                    ydb.ParamsBuilder().
                        Param("$num").Uint64(num).
                        Build(),
                ),
                query.WithTxControl(query.SerializableReadWriteTxControl()),
            )
            if err != nil {
                return err
            }

            return nil
        }, query.WithIdempotent(),
    )
    if err != nil {
        log.Fatal("query: ", err)
    }

    row, err := driver.Query().ReadRow(ctx, `DECLARE $num AS Uint64; SELECT key FROM example WHERE key=$num;`,
        query.WithParameters(
            ydb.ParamsBuilder().
                Param("$num").Uint64(num).
                Build(),
        ),
        query.WithTxControl(query.OnlineReadOnlyTxControl()),
    )
    if errors.Is(err, io.EOF) {
        log.Fatalf("the number %d is not presented", num)
    }
    if err != nil {
        log.Fatal("query read row: ", err)
    }

    var res uint64
    err = row.Scan(&res)
    if err != nil {
        log.Fatal("unmarshal row: ", err)
    }

    fmt.Println(res == num)
}

Other information:

pelageech commented 6 days ago

Sorry, found out the fact that I should commit transaction in order to see the difference.