github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/tests/integration/query_regression_test.go (about) 1 //go:build integration 2 // +build integration 3 4 package integration 5 6 import ( 7 "os" 8 "strings" 9 "testing" 10 11 "github.com/google/uuid" 12 "github.com/stretchr/testify/require" 13 14 "github.com/ydb-platform/ydb-go-sdk/v3" 15 "github.com/ydb-platform/ydb-go-sdk/v3/internal/query/tx" 16 "github.com/ydb-platform/ydb-go-sdk/v3/internal/version" 17 "github.com/ydb-platform/ydb-go-sdk/v3/query" 18 "github.com/ydb-platform/ydb-go-sdk/v3/table/types" 19 ) 20 21 func TestUUIDSerializationQueryServiceIssue1501(t *testing.T) { 22 // https://github.com/ydb-platform/ydb-go-sdk/issues/1501 23 // test with special uuid - all bytes are different for check any byte swaps 24 25 t.Run("old-send-with-force-wrapper", func(t *testing.T) { 26 // test old behavior - for test way of safe work with data, written with bagged API version 27 var ( 28 scope = newScope(t) 29 ctx = scope.Ctx 30 db = scope.Driver() 31 ) 32 33 idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" 34 expectedResultWithBug := "2d9e498b-b746-9cfb-084d-de4e1cb4736e" 35 id := uuid.MustParse(idString) 36 row, err := db.Query().QueryRow(ctx, ` 37 DECLARE $val AS UUID; 38 39 SELECT CAST($val AS Utf8)`, 40 query.WithIdempotent(), 41 query.WithParameters(ydb.ParamsBuilder().Param("$val").UUIDWithIssue1501Value(id).Build()), 42 query.WithTxControl(tx.SerializableReadWriteTxControl()), 43 ) 44 45 require.NoError(t, err) 46 47 var res string 48 49 err = row.Scan(&res) 50 require.NoError(t, err) 51 require.Equal(t, expectedResultWithBug, res) 52 }) 53 t.Run("old-receive-to-bytes", func(t *testing.T) { 54 // test old behavior - for test way of safe work with data, written with bagged API version 55 var ( 56 scope = newScope(t) 57 ctx = scope.Ctx 58 db = scope.Driver() 59 ) 60 61 idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" 62 row, err := db.Query().QueryRow(ctx, ` 63 DECLARE $val AS Text; 64 65 SELECT CAST($val AS UUID)`, 66 query.WithIdempotent(), 67 query.WithParameters(ydb.ParamsBuilder().Param("$val").Text(idString).Build()), 68 query.WithTxControl(tx.SerializableReadWriteTxControl()), 69 ) 70 71 require.NoError(t, err) 72 73 var res [16]byte 74 75 err = row.Scan(&res) 76 require.ErrorIs(t, err, types.ErrIssue1501BadUUID) 77 }) 78 t.Run("old-receive-to-bytes-with-force-wrapper", func(t *testing.T) { 79 // test old behavior - for test way of safe work with data, written with bagged API version 80 var ( 81 scope = newScope(t) 82 ctx = scope.Ctx 83 db = scope.Driver() 84 ) 85 86 idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" 87 expectedResultWithBug := "8b499e2d-46b7-fb9c-4d08-4ede6e73b41c" 88 row, err := db.Query().QueryRow(ctx, ` 89 DECLARE $val AS Text; 90 91 SELECT CAST($val AS UUID)`, 92 query.WithIdempotent(), 93 query.WithParameters(ydb.ParamsBuilder().Param("$val").Text(idString).Build()), 94 query.WithTxControl(tx.SerializableReadWriteTxControl()), 95 ) 96 97 require.NoError(t, err) 98 99 var res types.UUIDBytesWithIssue1501Type 100 101 err = row.Scan(&res) 102 require.NoError(t, err) 103 104 resUUID := uuid.UUID(res.AsBytesArray()) 105 require.Equal(t, expectedResultWithBug, resUUID.String()) 106 }) 107 t.Run("old-receive-to-string", func(t *testing.T) { 108 // test old behavior - for test way of safe work with data, written with bagged API version 109 var ( 110 scope = newScope(t) 111 ctx = scope.Ctx 112 db = scope.Driver() 113 ) 114 115 idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" 116 row, err := db.Query().QueryRow(ctx, ` 117 DECLARE $val AS Text; 118 119 SELECT CAST($val AS UUID)`, 120 query.WithIdempotent(), 121 query.WithParameters(ydb.ParamsBuilder().Param("$val").Text(idString).Build()), 122 query.WithTxControl(tx.SerializableReadWriteTxControl()), 123 ) 124 125 require.NoError(t, err) 126 127 var res string 128 129 err = row.Scan(&res) 130 require.ErrorIs(t, err, types.ErrIssue1501BadUUID) 131 }) 132 t.Run("old-receive-to-string-with-force-wrapper", func(t *testing.T) { 133 // test old behavior - for test way of safe work with data, written with bagged API version 134 var ( 135 scope = newScope(t) 136 ctx = scope.Ctx 137 db = scope.Driver() 138 ) 139 140 idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" 141 expectedResultWithBug := []byte{0x8b, 0x49, 0x9e, 0x2d, 0x46, 0xb7, 0xfb, 0x9c, 0x4d, 0x8, 0x4e, 0xde, 0x6e, 0x73, 0xb4, 0x1c} 142 row, err := db.Query().QueryRow(ctx, ` 143 DECLARE $val AS Text; 144 145 SELECT CAST($val AS UUID)`, 146 query.WithIdempotent(), 147 query.WithParameters(ydb.ParamsBuilder().Param("$val").Text(idString).Build()), 148 query.WithTxControl(tx.SerializableReadWriteTxControl()), 149 ) 150 151 require.NoError(t, err) 152 153 var resFromDB types.UUIDBytesWithIssue1501Type 154 155 err = row.Scan(&resFromDB) 156 require.NoError(t, err) 157 158 res := resFromDB.AsBrokenString() 159 require.Equal(t, expectedResultWithBug, []byte(res)) 160 }) 161 t.Run("old-send-receive-with-force-wrapper", func(t *testing.T) { 162 // test old behavior - for test way of safe work with data, written with bagged API version 163 var ( 164 scope = newScope(t) 165 ctx = scope.Ctx 166 db = scope.Driver() 167 ) 168 169 idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" 170 id := uuid.MustParse(idString) 171 row, err := db.Query().QueryRow(ctx, ` 172 DECLARE $val AS UUID; 173 174 SELECT $val`, 175 query.WithIdempotent(), 176 query.WithParameters(ydb.ParamsBuilder().Param("$val").UUIDWithIssue1501Value(id).Build()), 177 query.WithTxControl(tx.SerializableReadWriteTxControl()), 178 ) 179 180 require.NoError(t, err) 181 182 var resWrapper types.UUIDBytesWithIssue1501Type 183 err = row.Scan(&resWrapper) 184 require.NoError(t, err) 185 186 resUUID := uuid.UUID(resWrapper.AsBytesArray()) 187 188 require.Equal(t, id, resUUID) 189 }) 190 t.Run("good-send", func(t *testing.T) { 191 var ( 192 scope = newScope(t) 193 ctx = scope.Ctx 194 db = scope.Driver() 195 ) 196 197 idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" 198 id := uuid.MustParse(idString) 199 row, err := db.Query().QueryRow(ctx, ` 200 DECLARE $val AS UUID; 201 202 SELECT CAST($val AS Utf8)`, 203 query.WithIdempotent(), 204 query.WithTxControl(query.SerializableReadWriteTxControl()), 205 query.WithParameters(ydb.ParamsBuilder().Param("$val").Uuid(id).Build()), 206 ) 207 208 require.NoError(t, err) 209 210 var res string 211 err = row.Scan(&res) 212 require.NoError(t, err) 213 require.Equal(t, id.String(), res) 214 }) 215 t.Run("good-receive", func(t *testing.T) { 216 // test old behavior - for test way of safe work with data, written with bagged API version 217 var ( 218 scope = newScope(t) 219 ctx = scope.Ctx 220 db = scope.Driver() 221 ) 222 223 idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" 224 row, err := db.Query().QueryRow(ctx, ` 225 DECLARE $val AS Utf8; 226 227 SELECT CAST($val AS UUID)`, 228 query.WithIdempotent(), 229 query.WithParameters(ydb.ParamsBuilder().Param("$val").Text(idString).Build()), 230 query.WithTxControl(query.SerializableReadWriteTxControl()), 231 ) 232 233 require.NoError(t, err) 234 235 var res uuid.UUID 236 237 err = row.Scan(&res) 238 require.NoError(t, err) 239 240 resString := strings.ToUpper(res.String()) 241 require.Equal(t, idString, resString) 242 }) 243 t.Run("good-send-receive", func(t *testing.T) { 244 var ( 245 scope = newScope(t) 246 ctx = scope.Ctx 247 db = scope.Driver() 248 ) 249 250 idString := "6E73B41C-4EDE-4D08-9CFB-B7462D9E498B" 251 id := uuid.MustParse(idString) 252 row, err := db.Query().QueryRow(ctx, ` 253 DECLARE $val AS UUID; 254 255 SELECT $val`, 256 query.WithIdempotent(), 257 query.WithParameters(ydb.ParamsBuilder().Param("$val").Uuid(id).Build()), 258 query.WithTxControl(query.SerializableReadWriteTxControl()), 259 ) 260 261 require.NoError(t, err) 262 263 var res uuid.UUID 264 err = row.Scan(&res) 265 require.NoError(t, err) 266 require.Equal(t, id.String(), res.String()) 267 }) 268 } 269 270 // https://github.com/ydb-platform/ydb-go-sdk/issues/1506 271 func TestIssue1506TypedNullPushdown(t *testing.T) { 272 if version.Lt(os.Getenv("YDB_VERSION"), "24.1") { 273 t.Skip("query service not allowed in YDB version '" + os.Getenv("YDB_VERSION") + "'") 274 } 275 276 scope := newScope(t) 277 ctx := scope.Ctx 278 db := scope.Driver() 279 280 val := int64(123) 281 row, err := db.Query().QueryRow(ctx, ` 282 DECLARE $arg1 AS Int64?; 283 DECLARE $arg2 AS Int64?; 284 285 SELECT CAST($arg1 AS Utf8) AS v1, CAST($arg2 AS Utf8) AS v2 286 `, query.WithParameters( 287 ydb.ParamsBuilder(). 288 Param("$arg1").BeginOptional().Int64(nil).EndOptional(). 289 Param("$arg2").BeginOptional().Int64(&val).EndOptional(). 290 Build(), 291 ), 292 ) 293 require.NoError(t, err) 294 295 var res struct { 296 V1 *string `sql:"v1"` 297 V2 *string `sql:"v2"` 298 } 299 err = row.ScanStruct(&res) 300 require.NoError(t, err) 301 302 require.Nil(t, res.V1) 303 require.Equal(t, "123", *res.V2) 304 }