/
githubmirror
/
ydb-go-sdk
Обзор
Документация
Войти
/
githubmirror
/
ydb-go-sdk
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
tests/integration/database_sql_regression_test.go
445 строк
11 KB
Aleksey Myasnikov
* Added public package `github.com/ydb-platform/ydb-go-sdk/v3/types` and marked as deprecated all public API in `github.com/ydb-platform/ydb-go-sdk/v3/table/types` as deprecated (#2217)
30 июн 2026, 13:52
Не верифицирован
30 июн 2026, 13:52
419b93a
Код
Авторство
О чём код?
//go:build integration // +build integration package integration import ( "context" "database/sql" "database/sql/driver" "errors" "fmt" "math/rand" "strings" "testing" "time" "github.com/google/uuid" "github.com/stretchr/testify/require" "github.com/ydb-platform/ydb-go-genproto/protos/Ydb" "github.com/ydb-platform/ydb-go-sdk/v3" "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors" "github.com/ydb-platform/ydb-go-sdk/v3/internal/xsql/badconn" "github.com/ydb-platform/ydb-go-sdk/v3/pkg/xtest" "github.com/ydb-platform/ydb-go-sdk/v3/retry" "github.com/ydb-platform/ydb-go-sdk/v3/table" "github.com/ydb-platform/ydb-go-sdk/v3/types" ) func TestRegressionCloud109307(t *testing.T) { var ( ctx = xtest.Context(t) scope = newScope(t) db = scope.SQLDriverWithFolder( ydb.WithTablePathPrefix(scope.Folder()), ydb.WithAutoDeclare(), ) ) ctx, cancel := context.WithTimeout(ctx, 42*time.Second) defer cancel() for i := int64(1); ; i++ { if ctx.Err() != nil { break } err := retry.DoTx(ctx, db, func(ctx context.Context, tx *sql.Tx) error { //nolint:gosec if rand.Int31n(3) == 0 { return badconn.Map(xerrors.Operation(xerrors.WithStatusCode(Ydb.StatusIds_BAD_SESSION))) } var rows *sql.Rows rows, err := tx.QueryContext(ctx, `SELECT $i`, sql.Named("i", i)) if err != nil { return err } defer rows.Close() if !rows.Next() { return errors.New("no rows") } var result interface{} if err = rows.Scan(&result); err != nil { return err } if result.(int64)%100 == 0 { t.Logf("result: %+v\n", result) } return rows.Err() }, retry.WithTxOptions(&sql.TxOptions{ Isolation: sql.LevelSnapshot, ReadOnly: true, }), retry.WithIdempotent(true)) if ctx.Err() == nil { require.NoError(t, err) } } } func TestRegressionKikimr17104(t *testing.T) { var ( ctx = xtest.Context(t) scope = newScope(t) db = scope.SQLDriverWithFolder( ydb.WithTablePathPrefix(scope.Folder()), ydb.WithAutoDeclare(), ) tableName = t.Name() upsertRowsCount = 100000 upsertChecksum uint64 ) t.Run("data", func(t *testing.T) { t.Run("prepare", func(t *testing.T) { t.Run("scheme", func(t *testing.T) { err := retry.Do(ydb.WithQueryMode(ctx, ydb.SchemeQueryMode), db, func(ctx context.Context, cc *sql.Conn) (err error) { _, err = cc.ExecContext(ctx, fmt.Sprintf("CREATE TABLE %s (val Int32, PRIMARY KEY (val))", tableName), ) if err != nil { return err } return nil }, retry.WithIdempotent(true), ) require.NoError(t, err) }) t.Run("data", func(t *testing.T) { // - upsert data t.Logf("> preparing values to upsert...\n") values := make([]types.Value, 0, upsertRowsCount) for i := 0; i < upsertRowsCount; i++ { upsertChecksum += uint64(i) values = append(values, types.StructValue( types.StructFieldValue("val", types.Int32Value(int32(i))), ), ) } t.Logf("> upsert data\n") err := retry.Do(ydb.WithQueryMode(ctx, ydb.DataQueryMode), db, func(ctx context.Context, cc *sql.Conn) (err error) { _, err = cc.ExecContext(ctx, fmt.Sprintf("UPSERT INTO %s SELECT val FROM AS_TABLE($values);", tableName), table.NewQueryParameters(table.ValueParam("$values", types.ListValue(values...))), ) if err != nil { return err } return nil }, retry.WithIdempotent(true), ) require.NoError(t, err) }) }) t.Run("scan", func(t *testing.T) { t.Run("query", func(t *testing.T) { var ( rowsCount int checkSum uint64 ) err := retry.Do(ydb.WithQueryMode(ctx, ydb.ScanQueryMode), db, func(ctx context.Context, cc *sql.Conn) (err error) { var rows *sql.Rows rowsCount = 0 checkSum = 0 rows, err = cc.QueryContext(ctx, fmt.Sprintf("SELECT val FROM %s", tableName)) if err != nil { return err } for rows.NextResultSet() { for rows.Next() { rowsCount++ var val uint64 err = rows.Scan(&val) if err != nil { return err } checkSum += val } } return rows.Err() }, retry.WithIdempotent(true), ) require.NoError(t, err) require.Equal(t, upsertRowsCount, rowsCount) require.Equal(t, upsertChecksum, checkSum) }) }) }) } func TestUUIDSerializationDatabaseSQLIssue1501(t *testing.T) { // https://github.com/ydb-platform/ydb-go-sdk/issues/1501 // test with special uuid - all bytes are different for check any byte swaps t.Run("old-send", func(t *testing.T) { // test old behavior - for test way of safe work with data, written with bagged API version var ( scope = newScope(t) db = scope.SQLDriver() ) idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" id := [16]byte(uuid.MustParse(idString)) row := db.QueryRow(` DECLARE $val AS UUID; SELECT CAST($val AS Utf8)`, sql.Named("val", id), ) require.ErrorIs(t, row.Err(), types.ErrIssue1501BadUUID) }) t.Run("old-send-with-force-wrapper", func(t *testing.T) { // test old behavior - for test way of safe work with data, written with bagged API version var ( scope = newScope(t) db = scope.SQLDriver() ) idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" expectedResultWithBug := "2d9e498b-b746-9cfb-084d-de4e1cb4736e" id := [16]byte(uuid.MustParse(idString)) row := db.QueryRow(` DECLARE $val AS UUID; SELECT CAST($val AS Utf8)`, sql.Named("val", types.NewUUIDBytesWithIssue1501(id)), ) require.NoError(t, row.Err()) var res string err := row.Scan(&res) require.NoError(t, err) require.Equal(t, expectedResultWithBug, res) }) t.Run("old-receive-to-bytes", func(t *testing.T) { // test old behavior - for test way of safe work with data, written with bagged API version var ( scope = newScope(t) db = scope.SQLDriver() ) idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" row := db.QueryRow(` DECLARE $val AS Text; SELECT CAST($val AS UUID)`, sql.Named("val", idString), ) require.NoError(t, row.Err()) var res [16]byte err := row.Scan(&res) require.Error(t, err) }) t.Run("old-receive-to-bytes-with-force-wrapper", func(t *testing.T) { // test old behavior - for test way of safe work with data, written with bagged API version var ( scope = newScope(t) db = scope.SQLDriver() ) idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" expectedResultWithBug := "8b499e2d-46b7-fb9c-4d08-4ede6e73b41c" row := db.QueryRow(` DECLARE $val AS Text; SELECT CAST($val AS UUID)`, sql.Named("val", idString), ) require.NoError(t, row.Err()) var res types.UUIDBytesWithIssue1501Type err := row.Scan(&res) require.NoError(t, err) resUUID := uuid.UUID(res.AsBytesArray()) require.Equal(t, expectedResultWithBug, resUUID.String()) }) t.Run("old-send-receive", func(t *testing.T) { // test old behavior - for test way of safe work with data, written with bagged API version var ( scope = newScope(t) db = scope.SQLDriver() ) idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" id := uuid.MustParse(idString) idParam := [16]byte(id) row := db.QueryRow(` DECLARE $val AS UUID; SELECT $val`, sql.Named("val", idParam), ) require.ErrorIs(t, row.Err(), types.ErrIssue1501BadUUID) }) t.Run("old-send-receive-with-force-wrapper", func(t *testing.T) { // test old behavior - for test way of safe work with data, written with bagged API version var ( scope = newScope(t) db = scope.SQLDriver() ) idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" id := uuid.MustParse(idString) row := db.QueryRow(` DECLARE $val AS UUID; SELECT $val`, sql.Named("val", types.UUIDWithIssue1501Value(id)), ) require.NoError(t, row.Err()) var resBytes types.UUIDBytesWithIssue1501Type err := row.Scan(&resBytes) require.NoError(t, err) resUUID := uuid.UUID(resBytes.AsBytesArray()) require.Equal(t, id, resUUID) }) t.Run("old-send-uuid-receive-error-bad-request", func(t *testing.T) { var ( scope = newScope(t) db = scope.SQLDriver() ) idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" id := uuid.MustParse(idString) row := db.QueryRow(` DECLARE $val AS Utf8; SELECT $val`, sql.Named("val", id), // send as string because uuid implements Value() (driver.Value, error) ) require.Error(t, row.Err()) require.True(t, xerrors.IsOperationError(row.Err(), Ydb.StatusIds_BAD_REQUEST)) require.ErrorContains(t, row.Err(), "Parameter $val type mismatch") }) t.Run("good-send", func(t *testing.T) { var ( scope = newScope(t) db = scope.SQLDriver() ) idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" id := uuid.MustParse(idString) row := db.QueryRow(` DECLARE $val AS Utf8; SELECT $val`, sql.Named("val", id.String()), // send as string because uuid implements Value() (driver.Value, error) ) require.NoError(t, row.Err()) var res string err := row.Scan(&res) require.NoError(t, err) require.Equal(t, id.String(), res) }) t.Run("good-receive", func(t *testing.T) { // test old behavior - for test way of safe work with data, written with bagged API version var ( scope = newScope(t) db = scope.SQLDriver() ) idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" row := db.QueryRow(` DECLARE $val AS Utf8; SELECT CAST($val AS UUID)`, sql.Named("val", idString), ) require.NoError(t, row.Err()) var resFromDB types.UUIDBytesWithIssue1501Type err := row.Scan(&resFromDB) require.NoError(t, err) resUUID := resFromDB.PublicRevertReorderForIssue1501() resString := strings.ToUpper(resUUID.String()) require.Equal(t, idString, resString) }) t.Run("good-send-receive", func(t *testing.T) { var ( scope = newScope(t) db = scope.SQLDriver() ) idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" id := uuid.MustParse(idString) row := db.QueryRow(` DECLARE $val AS Utf8; SELECT $val`, sql.Named("val", id.String()), ) require.NoError(t, row.Err()) var res uuid.UUID err := row.Scan(&res) require.NoError(t, err) require.Equal(t, id.String(), res.String()) }) t.Run("good-receive-as-uuid", func(t *testing.T) { // Regression test for https://github.com/ydb-platform/ydb-go-sdk/issues/1515 // Before fix: scanning UUID into uuid.UUID (which implements sql.Scanner) would fail // After fix: should work correctly var ( scope = newScope(t) db = scope.SQLDriver() ) idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" row := db.QueryRow(` DECLARE $val AS Utf8; SELECT CAST($val AS UUID)`, sql.Named("val", idString), ) require.NoError(t, row.Err()) var res uuid.UUID err := row.Scan(&res) require.NoError(t, err) require.Equal(t, strings.ToLower(idString), res.String()) }) t.Run("good-receive-uuid-as-string", func(t *testing.T) { // Regression test for https://github.com/ydb-platform/ydb-go-sdk/issues/1515 // Before fix: scanning UUID into string would fail // After fix: should work correctly var ( scope = newScope(t) db = scope.SQLDriver() ) idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" row := db.QueryRow(` DECLARE $val AS Utf8; SELECT CAST($val AS UUID)`, sql.Named("val", idString), ) require.NoError(t, row.Err()) var res string err := row.Scan(&res) require.NoError(t, err) require.Equal(t, strings.ToLower(idString), res) }) } type testValuer struct { value driver.Value } func (v *testValuer) Value() (driver.Value, error) { return v.value, nil }