1// +build go1.9 2 3package mssql 4 5import ( 6 "context" 7 "database/sql" 8 "log" 9 "reflect" 10 "testing" 11 "time" 12) 13 14const ( 15 crateSchema = `create schema TestTVPSchema;` 16 17 dropSchema = `drop schema TestTVPSchema;` 18 19 createTVP = ` 20 CREATE TYPE TestTVPSchema.exempleTVP AS TABLE 21 ( 22 message NVARCHAR(100) 23 )` 24 25 dropTVP = `DROP TYPE TestTVPSchema.exempleTVP;` 26 27 procedureWithTVP = ` 28 CREATE PROCEDURE ExecTVP 29 @param1 TestTVPSchema.exempleTVP READONLY 30 AS 31 BEGIN 32 SET NOCOUNT ON; 33 SELECT * FROM @param1; 34 END; 35 ` 36 37 dropProcedure = `drop PROCEDURE ExecTVP` 38 39 execTvp = `exec ExecTVP @param1;` 40) 41 42type TvptableRow struct { 43 PBinary []byte `db:"p_binary"` 44 PVarchar string `db:"p_varchar"` 45 PVarcharNull *string `db:"p_varcharNull"` 46 PNvarchar string `db:"p_nvarchar"` 47 PNvarcharNull *string `db:"p_nvarcharNull"` 48 PID UniqueIdentifier `db:"p_id"` 49 PIDNull *UniqueIdentifier `db:"p_idNull"` 50 PVarbinary []byte `db:"p_varbinary"` 51 PTinyint int8 `db:"p_tinyint"` 52 PTinyintNull *int8 `db:"p_tinyintNull"` 53 PSmallint int16 `db:"p_smallint"` 54 PSmallintNull *int16 `db:"p_smallintNull"` 55 PInt int32 `db:"p_int"` 56 PIntNull *int32 `db:"p_intNull"` 57 PBigint int64 `db:"p_bigint"` 58 PBigintNull *int64 `db:"p_bigintNull"` 59 PBit bool `db:"p_bit"` 60 PBitNull *bool `db:"p_bitNull"` 61 PFloat32 float32 `db:"p_float32"` 62 PFloatNull32 *float32 `db:"p_floatNull32"` 63 PFloat64 float64 `db:"p_float64"` 64 PFloatNull64 *float64 `db:"p_floatNull64"` 65 DTime time.Time `db:"p_timeNull"` 66 DTimeNull *time.Time `db:"p_time"` 67 Pint int `db:"pInt"` 68 PintNull *int `db:"pIntNull"` 69} 70 71type TvptableRowWithSkipTag struct { 72 PBinary []byte `db:"p_binary"` 73 SkipPBinary []byte `json:"-"` 74 PVarchar string `db:"p_varchar"` 75 SkipPVarchar string `tvp:"-"` 76 PVarcharNull *string `db:"p_varcharNull"` 77 SkipPVarcharNull *string `json:"-" tvp:"-"` 78 PNvarchar string `db:"p_nvarchar"` 79 SkipPNvarchar string `json:"-"` 80 PNvarcharNull *string `db:"p_nvarcharNull"` 81 SkipPNvarcharNull *string `json:"-"` 82 PID UniqueIdentifier `db:"p_id"` 83 SkipPID UniqueIdentifier `json:"-"` 84 PIDNull *UniqueIdentifier `db:"p_idNull"` 85 SkipPIDNull *UniqueIdentifier `tvp:"-"` 86 PVarbinary []byte `db:"p_varbinary"` 87 SkipPVarbinary []byte `json:"-" tvp:"-"` 88 PTinyint int8 `db:"p_tinyint"` 89 SkipPTinyint int8 `tvp:"-"` 90 PTinyintNull *int8 `db:"p_tinyintNull"` 91 SkipPTinyintNull *int8 `tvp:"-" json:"any"` 92 PSmallint int16 `db:"p_smallint"` 93 SkipPSmallint int16 `json:"-"` 94 PSmallintNull *int16 `db:"p_smallintNull"` 95 SkipPSmallintNull *int16 `tvp:"-"` 96 PInt int32 `db:"p_int"` 97 SkipPInt int32 `json:"-"` 98 PIntNull *int32 `db:"p_intNull"` 99 SkipPIntNull *int32 `tvp:"-"` 100 PBigint int64 `db:"p_bigint"` 101 SkipPBigint int64 `tvp:"-"` 102 PBigintNull *int64 `db:"p_bigintNull"` 103 SkipPBigintNull *int64 `json:"any" tvp:"-"` 104 PBit bool `db:"p_bit"` 105 SkipPBit bool `json:"-"` 106 PBitNull *bool `db:"p_bitNull"` 107 SkipPBitNull *bool `json:"-"` 108 PFloat32 float32 `db:"p_float32"` 109 SkipPFloat32 float32 `tvp:"-"` 110 PFloatNull32 *float32 `db:"p_floatNull32"` 111 SkipPFloatNull32 *float32 `tvp:"-"` 112 PFloat64 float64 `db:"p_float64"` 113 SkipPFloat64 float64 `tvp:"-"` 114 PFloatNull64 *float64 `db:"p_floatNull64"` 115 SkipPFloatNull64 *float64 `tvp:"-"` 116 DTime time.Time `db:"p_timeNull"` 117 SkipDTime time.Time `tvp:"-"` 118 DTimeNull *time.Time `db:"p_time"` 119 SkipDTimeNull *time.Time `tvp:"-"` 120 Pint int `db:"p_int_null"` 121 SkipPint int `tvp:"-"` 122 PintNull *int `db:"p_int_"` 123 SkipPintNull *int `tvp:"-"` 124} 125 126func TestTVP(t *testing.T) { 127 checkConnStr(t) 128 SetLogger(testLogger{t}) 129 130 db, err := sql.Open("sqlserver", makeConnStr(t).String()) 131 if err != nil { 132 t.Fatalf("failed to open driver sqlserver") 133 } 134 defer db.Close() 135 136 ctx, cancel := context.WithCancel(context.Background()) 137 defer cancel() 138 139 sqltextcreatetable := ` 140 CREATE TYPE tvptable AS TABLE 141 ( 142 p_binary BINARY(3), 143 p_varchar VARCHAR(500), 144 p_varcharNull VARCHAR(500), 145 p_nvarchar NVARCHAR(100), 146 p_nvarcharNull NVARCHAR(100), 147 p_id UNIQUEIDENTIFIER, 148 p_idNull UNIQUEIDENTIFIER, 149 p_varbinary VARBINARY(MAX), 150 p_tinyint TINYINT, 151 p_tinyintNull TINYINT, 152 p_smallint SMALLINT, 153 p_smallintNull SMALLINT, 154 p_int INT, 155 p_intNull INT, 156 p_bigint BIGINT, 157 p_bigintNull BIGINT, 158 p_bit BIT, 159 p_bitNull BIT, 160 p_float32 FLOAT, 161 p_floatNull32 FLOAT, 162 p_float64 FLOAT, 163 p_floatNull64 FLOAT, 164 p_time datetime2, 165 p_timeNull datetime2, 166 pInt INT, 167 pIntNull INT 168 ); ` 169 170 sqltextdroptable := `DROP TYPE tvptable;` 171 172 sqltextcreatesp := ` 173 CREATE PROCEDURE spwithtvp 174 @param1 tvptable READONLY, 175 @param2 tvptable READONLY, 176 @param3 NVARCHAR(10) 177 AS 178 BEGIN 179 SET NOCOUNT ON; 180 SELECT * FROM @param1; 181 SELECT * FROM @param2; 182 SELECT @param3; 183 END;` 184 185 sqltextdropsp := `DROP PROCEDURE spwithtvp;` 186 187 db.ExecContext(ctx, sqltextdropsp) 188 db.ExecContext(ctx, sqltextdroptable) 189 190 _, err = db.ExecContext(ctx, sqltextcreatetable) 191 if err != nil { 192 t.Fatal(err) 193 } 194 defer db.ExecContext(ctx, sqltextdroptable) 195 196 _, err = db.ExecContext(ctx, sqltextcreatesp) 197 if err != nil { 198 t.Fatal(err) 199 } 200 defer db.ExecContext(ctx, sqltextdropsp) 201 varcharNull := "aaa" 202 nvarchar := "bbb" 203 bytesMock := []byte("ddd") 204 i8 := int8(1) 205 i16 := int16(2) 206 i32 := int32(3) 207 i64 := int64(4) 208 i := int(5) 209 bFalse := false 210 floatValue64 := 0.123 211 floatValue32 := float32(-10.123) 212 timeNow := time.Now().UTC() 213 param1 := []TvptableRow{ 214 { 215 PBinary: []byte("ccc"), 216 PVarchar: varcharNull, 217 PNvarchar: nvarchar, 218 PID: UniqueIdentifier{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, 219 PVarbinary: bytesMock, 220 PTinyint: i8, 221 PSmallint: i16, 222 PInt: i32, 223 PBigint: i64, 224 PBit: bFalse, 225 PFloat32: floatValue32, 226 PFloat64: floatValue64, 227 DTime: timeNow, 228 Pint: 355, 229 }, 230 { 231 PBinary: []byte("www"), 232 PVarchar: "eee", 233 PNvarchar: "lll", 234 PID: UniqueIdentifier{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, 235 PVarbinary: []byte("zzz"), 236 PTinyint: 5, 237 PSmallint: 16000, 238 PInt: 20000000, 239 PBigint: 2000000020000000, 240 PBit: true, 241 PFloat32: -123.45, 242 PFloat64: -123.45, 243 DTime: time.Date(2001, 11, 16, 23, 59, 39, 0, time.UTC), 244 Pint: 455, 245 }, 246 { 247 PBinary: nil, 248 PVarcharNull: &varcharNull, 249 PNvarcharNull: &nvarchar, 250 PIDNull: &UniqueIdentifier{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, 251 PTinyintNull: &i8, 252 PSmallintNull: &i16, 253 PIntNull: &i32, 254 PBigintNull: &i64, 255 PBitNull: &bFalse, 256 PFloatNull32: &floatValue32, 257 PFloatNull64: &floatValue64, 258 DTime: timeNow, 259 DTimeNull: &timeNow, 260 PintNull: &i, 261 }, 262 { 263 PBinary: []byte("www"), 264 PVarchar: "eee", 265 PNvarchar: "lll", 266 PIDNull: &UniqueIdentifier{}, 267 PVarbinary: []byte("zzz"), 268 PTinyint: 5, 269 PSmallint: 16000, 270 PInt: 20000000, 271 PBigint: 2000000020000000, 272 PBit: true, 273 PFloat64: 123.45, 274 DTime: time.Date(2001, 11, 16, 23, 59, 39, 0, time.UTC), 275 PVarcharNull: &varcharNull, 276 PNvarcharNull: &nvarchar, 277 PTinyintNull: &i8, 278 PSmallintNull: &i16, 279 PIntNull: &i32, 280 PBigintNull: &i64, 281 PBitNull: &bFalse, 282 PFloatNull32: &floatValue32, 283 PFloatNull64: &floatValue64, 284 DTimeNull: &timeNow, 285 PintNull: &i, 286 }, 287 } 288 289 tvpType := TVP{ 290 TypeName: "tvptable", 291 Value: param1, 292 } 293 tvpTypeEmpty := TVP{ 294 TypeName: "tvptable", 295 Value: []TvptableRow{}, 296 } 297 298 rows, err := db.QueryContext(ctx, 299 "exec spwithtvp @param1, @param2, @param3", 300 sql.Named("param1", tvpType), 301 sql.Named("param2", tvpTypeEmpty), 302 sql.Named("param3", "test"), 303 ) 304 305 if err != nil { 306 t.Fatal(err) 307 } 308 309 var result1 []TvptableRow 310 for rows.Next() { 311 var val TvptableRow 312 err := rows.Scan( 313 &val.PBinary, 314 &val.PVarchar, 315 &val.PVarcharNull, 316 &val.PNvarchar, 317 &val.PNvarcharNull, 318 &val.PID, 319 &val.PIDNull, 320 &val.PVarbinary, 321 &val.PTinyint, 322 &val.PTinyintNull, 323 &val.PSmallint, 324 &val.PSmallintNull, 325 &val.PInt, 326 &val.PIntNull, 327 &val.PBigint, 328 &val.PBigintNull, 329 &val.PBit, 330 &val.PBitNull, 331 &val.PFloat32, 332 &val.PFloatNull32, 333 &val.PFloat64, 334 &val.PFloatNull64, 335 &val.DTime, 336 &val.DTimeNull, 337 &val.Pint, 338 &val.PintNull, 339 ) 340 if err != nil { 341 t.Fatalf("scan failed with error: %s", err) 342 } 343 344 result1 = append(result1, val) 345 } 346 347 if !reflect.DeepEqual(param1, result1) { 348 t.Logf("expected: %+v", param1) 349 t.Logf("actual: %+v", result1) 350 t.Errorf("first resultset did not match param1") 351 } 352 353 if !rows.NextResultSet() { 354 t.Errorf("second resultset did not exist") 355 } 356 357 if rows.Next() { 358 t.Errorf("second resultset was not empty") 359 } 360 361 if !rows.NextResultSet() { 362 t.Errorf("third resultset did not exist") 363 } 364 365 if !rows.Next() { 366 t.Errorf("third resultset was empty") 367 } 368 369 var result3 string 370 if err := rows.Scan(&result3); err != nil { 371 t.Errorf("error scanning third result set: %s", err) 372 } 373 if result3 != "test" { 374 t.Errorf("third result set had wrong value expected: %s actual: %s", "test", result3) 375 } 376} 377 378func TestTVP_WithTag(t *testing.T) { 379 checkConnStr(t) 380 SetLogger(testLogger{t}) 381 382 db, err := sql.Open("sqlserver", makeConnStr(t).String()) 383 if err != nil { 384 t.Fatalf("failed to open driver sqlserver") 385 } 386 defer db.Close() 387 388 ctx, cancel := context.WithCancel(context.Background()) 389 defer cancel() 390 391 sqltextcreatetable := ` 392 CREATE TYPE tvptable AS TABLE 393 ( 394 p_binary BINARY(3), 395 p_varchar VARCHAR(500), 396 p_varcharNull VARCHAR(500), 397 p_nvarchar NVARCHAR(100), 398 p_nvarcharNull NVARCHAR(100), 399 p_id UNIQUEIDENTIFIER, 400 p_idNull UNIQUEIDENTIFIER, 401 p_varbinary VARBINARY(MAX), 402 p_tinyint TINYINT, 403 p_tinyintNull TINYINT, 404 p_smallint SMALLINT, 405 p_smallintNull SMALLINT, 406 p_int INT, 407 p_intNull INT, 408 p_bigint BIGINT, 409 p_bigintNull BIGINT, 410 p_bit BIT, 411 p_bitNull BIT, 412 p_float32 FLOAT, 413 p_floatNull32 FLOAT, 414 p_float64 FLOAT, 415 p_floatNull64 FLOAT, 416 p_time datetime2, 417 p_timeNull datetime2, 418 pInt INT, 419 pIntNull INT 420 ); ` 421 422 sqltextdroptable := `DROP TYPE tvptable;` 423 424 sqltextcreatesp := ` 425 CREATE PROCEDURE spwithtvp 426 @param1 tvptable READONLY, 427 @param2 tvptable READONLY, 428 @param3 NVARCHAR(10) 429 AS 430 BEGIN 431 SET NOCOUNT ON; 432 SELECT * FROM @param1; 433 SELECT * FROM @param2; 434 SELECT @param3; 435 END;` 436 437 sqltextdropsp := `DROP PROCEDURE spwithtvp;` 438 439 db.ExecContext(ctx, sqltextdropsp) 440 db.ExecContext(ctx, sqltextdroptable) 441 442 _, err = db.ExecContext(ctx, sqltextcreatetable) 443 if err != nil { 444 t.Fatal(err) 445 } 446 defer db.ExecContext(ctx, sqltextdroptable) 447 448 _, err = db.ExecContext(ctx, sqltextcreatesp) 449 if err != nil { 450 t.Fatal(err) 451 } 452 defer db.ExecContext(ctx, sqltextdropsp) 453 454 varcharNull := "aaa" 455 nvarchar := "bbb" 456 bytesMock := []byte("ddd") 457 i8 := int8(1) 458 i16 := int16(2) 459 i32 := int32(3) 460 i64 := int64(4) 461 i := int(355) 462 bFalse := false 463 floatValue64 := 0.123 464 floatValue32 := float32(-10.123) 465 timeNow := time.Now().UTC() 466 param1 := []TvptableRowWithSkipTag{ 467 { 468 PBinary: []byte("ccc"), 469 PVarchar: varcharNull, 470 PNvarchar: nvarchar, 471 PID: UniqueIdentifier{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, 472 PVarbinary: bytesMock, 473 PTinyint: i8, 474 PSmallint: i16, 475 PInt: i32, 476 PBigint: i64, 477 PBit: bFalse, 478 PFloat32: floatValue32, 479 PFloat64: floatValue64, 480 DTime: timeNow, 481 Pint: i, 482 PintNull: &i, 483 }, 484 { 485 PBinary: []byte("www"), 486 PVarchar: "eee", 487 PNvarchar: "lll", 488 PID: UniqueIdentifier{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, 489 PVarbinary: []byte("zzz"), 490 PTinyint: 5, 491 PSmallint: 16000, 492 PInt: 20000000, 493 PBigint: 2000000020000000, 494 PBit: true, 495 PFloat32: -123.45, 496 PFloat64: -123.45, 497 DTime: time.Date(2001, 11, 16, 23, 59, 39, 0, time.UTC), 498 Pint: 3669, 499 PintNull: &i, 500 }, 501 { 502 PBinary: nil, 503 PVarcharNull: &varcharNull, 504 PNvarcharNull: &nvarchar, 505 PIDNull: &UniqueIdentifier{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, 506 PTinyintNull: &i8, 507 PSmallintNull: &i16, 508 PIntNull: &i32, 509 PBigintNull: &i64, 510 PBitNull: &bFalse, 511 PFloatNull32: &floatValue32, 512 PFloatNull64: &floatValue64, 513 DTime: timeNow, 514 DTimeNull: &timeNow, 515 Pint: 969, 516 }, 517 { 518 PBinary: []byte("www"), 519 PVarchar: "eee", 520 PNvarchar: "lll", 521 PIDNull: &UniqueIdentifier{}, 522 PVarbinary: []byte("zzz"), 523 PTinyint: 5, 524 PSmallint: 16000, 525 PInt: 20000000, 526 PBigint: 2000000020000000, 527 PBit: true, 528 PFloat64: 123.45, 529 DTime: time.Date(2001, 11, 16, 23, 59, 39, 0, time.UTC), 530 PVarcharNull: &varcharNull, 531 PNvarcharNull: &nvarchar, 532 PTinyintNull: &i8, 533 PSmallintNull: &i16, 534 PIntNull: &i32, 535 PBigintNull: &i64, 536 PBitNull: &bFalse, 537 PFloatNull32: &floatValue32, 538 PFloatNull64: &floatValue64, 539 DTimeNull: &timeNow, 540 PintNull: &i, 541 }, 542 } 543 544 tvpType := TVP{ 545 TypeName: "tvptable", 546 Value: param1, 547 } 548 tvpTypeEmpty := TVP{ 549 TypeName: "tvptable", 550 Value: []TvptableRowWithSkipTag{}, 551 } 552 553 rows, err := db.QueryContext(ctx, 554 "exec spwithtvp @param1, @param2, @param3", 555 sql.Named("param1", tvpType), 556 sql.Named("param2", tvpTypeEmpty), 557 sql.Named("param3", "test"), 558 ) 559 560 if err != nil { 561 t.Fatal(err) 562 } 563 564 var result1 []TvptableRowWithSkipTag 565 for rows.Next() { 566 var val TvptableRowWithSkipTag 567 err := rows.Scan( 568 &val.PBinary, 569 &val.PVarchar, 570 &val.PVarcharNull, 571 &val.PNvarchar, 572 &val.PNvarcharNull, 573 &val.PID, 574 &val.PIDNull, 575 &val.PVarbinary, 576 &val.PTinyint, 577 &val.PTinyintNull, 578 &val.PSmallint, 579 &val.PSmallintNull, 580 &val.PInt, 581 &val.PIntNull, 582 &val.PBigint, 583 &val.PBigintNull, 584 &val.PBit, 585 &val.PBitNull, 586 &val.PFloat32, 587 &val.PFloatNull32, 588 &val.PFloat64, 589 &val.PFloatNull64, 590 &val.DTime, 591 &val.DTimeNull, 592 &val.Pint, 593 &val.PintNull, 594 ) 595 if err != nil { 596 t.Fatalf("scan failed with error: %s", err) 597 } 598 599 result1 = append(result1, val) 600 } 601 602 if !reflect.DeepEqual(param1, result1) { 603 t.Logf("expected: %+v", param1) 604 t.Logf("actual: %+v", result1) 605 t.Errorf("first resultset did not match param1") 606 } 607 608 if !rows.NextResultSet() { 609 t.Errorf("second resultset did not exist") 610 } 611 612 if rows.Next() { 613 t.Errorf("second resultset was not empty") 614 } 615 616 if !rows.NextResultSet() { 617 t.Errorf("third resultset did not exist") 618 } 619 620 if !rows.Next() { 621 t.Errorf("third resultset was empty") 622 } 623 624 var result3 string 625 if err := rows.Scan(&result3); err != nil { 626 t.Errorf("error scanning third result set: %s", err) 627 } 628 if result3 != "test" { 629 t.Errorf("third result set had wrong value expected: %s actual: %s", "test", result3) 630 } 631} 632 633type TvpExample struct { 634 Message string 635} 636 637func TestTVPSchema(t *testing.T) { 638 checkConnStr(t) 639 SetLogger(testLogger{t}) 640 641 conn, err := sql.Open("sqlserver", makeConnStr(t).String()) 642 if err != nil { 643 log.Fatal("Open connection failed:", err.Error()) 644 } 645 defer conn.Close() 646 647 _, err = conn.Exec(crateSchema) 648 if err != nil { 649 log.Println(err) 650 return 651 } 652 defer conn.Exec(dropSchema) 653 654 _, err = conn.Exec(createTVP) 655 if err != nil { 656 log.Println(err) 657 return 658 } 659 defer conn.Exec(dropTVP) 660 661 _, err = conn.Exec(procedureWithTVP) 662 if err != nil { 663 log.Println(err) 664 return 665 } 666 defer conn.Exec(dropProcedure) 667 668 exempleData := []TvpExample{ 669 { 670 Message: "Hello", 671 }, 672 { 673 Message: "World", 674 }, 675 { 676 Message: "TVP", 677 }, 678 } 679 680 tvpType := TVP{ 681 TypeName: "TestTVPSchema.exempleTVP", 682 Value: exempleData, 683 } 684 685 rows, err := conn.Query(execTvp, 686 sql.Named("param1", tvpType), 687 ) 688 if err != nil { 689 log.Println(err) 690 return 691 } 692 693 tvpResult := make([]TvpExample, 0) 694 for rows.Next() { 695 tvpExemple := TvpExample{} 696 err = rows.Scan(&tvpExemple.Message) 697 if err != nil { 698 log.Println(err) 699 return 700 } 701 tvpResult = append(tvpResult, tvpExemple) 702 } 703 log.Println(tvpResult) 704} 705 706func TestTVPObject(t *testing.T) { 707 checkConnStr(t) 708 SetLogger(testLogger{t}) 709 710 conn, err := sql.Open("sqlserver", makeConnStr(t).String()) 711 if err != nil { 712 log.Fatal("Open connection failed:", err.Error()) 713 } 714 defer conn.Close() 715 716 tests := []struct { 717 name string 718 tvp TVP 719 wantErr bool 720 }{ 721 { 722 name: "empty name", 723 wantErr: true, 724 tvp: TVP{TypeName: ""}, 725 }, 726 { 727 name: "value is wrong type", 728 wantErr: true, 729 tvp: TVP{TypeName: "type", Value: "wrong type"}, 730 }, 731 { 732 name: "tvp type is wrong", 733 wantErr: true, 734 tvp: TVP{TypeName: "[type", Value: []TvpExample{{}}}, 735 }, 736 { 737 name: "tvp type is wrong", 738 wantErr: true, 739 tvp: TVP{TypeName: "[type", Value: []TestFieldsUnsupportedTypes{{}}}, 740 }, 741 } 742 for _, tt := range tests { 743 t.Run(tt.name, func(t *testing.T) { 744 _, err := conn.Exec("somequery", tt.tvp) 745 if (err != nil) != tt.wantErr { 746 t.Errorf("TVP.encode() error = %v, wantErr %v", err, tt.wantErr) 747 return 748 } 749 }) 750 } 751} 752