github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/internal/query/result_test.go (about) 1 package query 2 3 import ( 4 "context" 5 "errors" 6 "io" 7 "testing" 8 "time" 9 10 "github.com/stretchr/testify/require" 11 "github.com/ydb-platform/ydb-go-genproto/Ydb_Query_V1" 12 "github.com/ydb-platform/ydb-go-genproto/protos/Ydb" 13 "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query" 14 "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_TableStats" 15 "go.uber.org/mock/gomock" 16 17 "github.com/ydb-platform/ydb-go-sdk/v3/internal/stats" 18 "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors" 19 "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest" 20 "github.com/ydb-platform/ydb-go-sdk/v3/query" 21 "github.com/ydb-platform/ydb-go-sdk/v3/trace" 22 ) 23 24 func TestResultNextResultSet(t *testing.T) { 25 t.Run("HappyWay", func(t *testing.T) { 26 ctx, cancel := context.WithCancel(xtest.Context(t)) 27 defer cancel() 28 ctrl := gomock.NewController(t) 29 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 30 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 31 Status: Ydb.StatusIds_SUCCESS, 32 ResultSetIndex: 0, 33 ResultSet: &Ydb.ResultSet{ 34 Columns: []*Ydb.Column{ 35 { 36 Name: "a", 37 Type: &Ydb.Type{ 38 Type: &Ydb.Type_TypeId{ 39 TypeId: Ydb.Type_UINT64, 40 }, 41 }, 42 }, 43 { 44 Name: "b", 45 Type: &Ydb.Type{ 46 Type: &Ydb.Type_TypeId{ 47 TypeId: Ydb.Type_UTF8, 48 }, 49 }, 50 }, 51 }, 52 Rows: []*Ydb.Value{ 53 { 54 Items: []*Ydb.Value{{ 55 Value: &Ydb.Value_Uint64Value{ 56 Uint64Value: 1, 57 }, 58 }, { 59 Value: &Ydb.Value_TextValue{ 60 TextValue: "1", 61 }, 62 }}, 63 }, 64 { 65 Items: []*Ydb.Value{{ 66 Value: &Ydb.Value_Uint64Value{ 67 Uint64Value: 2, 68 }, 69 }, { 70 Value: &Ydb.Value_TextValue{ 71 TextValue: "2", 72 }, 73 }}, 74 }, 75 { 76 Items: []*Ydb.Value{{ 77 Value: &Ydb.Value_Uint64Value{ 78 Uint64Value: 3, 79 }, 80 }, { 81 Value: &Ydb.Value_TextValue{ 82 TextValue: "3", 83 }, 84 }}, 85 }, 86 }, 87 }, 88 }, nil) 89 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 90 Status: Ydb.StatusIds_SUCCESS, 91 ResultSetIndex: 0, 92 ResultSet: &Ydb.ResultSet{ 93 Rows: []*Ydb.Value{ 94 { 95 Items: []*Ydb.Value{{ 96 Value: &Ydb.Value_Uint64Value{ 97 Uint64Value: 4, 98 }, 99 }, { 100 Value: &Ydb.Value_TextValue{ 101 TextValue: "4", 102 }, 103 }}, 104 }, 105 { 106 Items: []*Ydb.Value{{ 107 Value: &Ydb.Value_Uint64Value{ 108 Uint64Value: 5, 109 }, 110 }, { 111 Value: &Ydb.Value_TextValue{ 112 TextValue: "5", 113 }, 114 }}, 115 }, 116 }, 117 }, 118 }, nil) 119 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 120 Status: Ydb.StatusIds_SUCCESS, 121 ResultSetIndex: 1, 122 ResultSet: &Ydb.ResultSet{ 123 Columns: []*Ydb.Column{ 124 { 125 Name: "c", 126 Type: &Ydb.Type{ 127 Type: &Ydb.Type_TypeId{ 128 TypeId: Ydb.Type_UINT64, 129 }, 130 }, 131 }, 132 { 133 Name: "d", 134 Type: &Ydb.Type{ 135 Type: &Ydb.Type_TypeId{ 136 TypeId: Ydb.Type_UTF8, 137 }, 138 }, 139 }, 140 { 141 Name: "e", 142 Type: &Ydb.Type{ 143 Type: &Ydb.Type_TypeId{ 144 TypeId: Ydb.Type_BOOL, 145 }, 146 }, 147 }, 148 }, 149 Rows: []*Ydb.Value{ 150 { 151 Items: []*Ydb.Value{{ 152 Value: &Ydb.Value_Uint64Value{ 153 Uint64Value: 1, 154 }, 155 }, { 156 Value: &Ydb.Value_TextValue{ 157 TextValue: "1", 158 }, 159 }, { 160 Value: &Ydb.Value_BoolValue{ 161 BoolValue: true, 162 }, 163 }}, 164 }, 165 { 166 Items: []*Ydb.Value{{ 167 Value: &Ydb.Value_Uint64Value{ 168 Uint64Value: 2, 169 }, 170 }, { 171 Value: &Ydb.Value_TextValue{ 172 TextValue: "2", 173 }, 174 }, { 175 Value: &Ydb.Value_BoolValue{ 176 BoolValue: false, 177 }, 178 }}, 179 }, 180 }, 181 }, 182 }, nil) 183 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 184 Status: Ydb.StatusIds_SUCCESS, 185 ResultSetIndex: 1, 186 ResultSet: &Ydb.ResultSet{ 187 Rows: []*Ydb.Value{ 188 { 189 Items: []*Ydb.Value{{ 190 Value: &Ydb.Value_Uint64Value{ 191 Uint64Value: 3, 192 }, 193 }, { 194 Value: &Ydb.Value_TextValue{ 195 TextValue: "3", 196 }, 197 }, { 198 Value: &Ydb.Value_BoolValue{ 199 BoolValue: true, 200 }, 201 }}, 202 }, 203 { 204 Items: []*Ydb.Value{{ 205 Value: &Ydb.Value_Uint64Value{ 206 Uint64Value: 4, 207 }, 208 }, { 209 Value: &Ydb.Value_TextValue{ 210 TextValue: "4", 211 }, 212 }, { 213 Value: &Ydb.Value_BoolValue{ 214 BoolValue: false, 215 }, 216 }}, 217 }, 218 { 219 Items: []*Ydb.Value{{ 220 Value: &Ydb.Value_Uint64Value{ 221 Uint64Value: 5, 222 }, 223 }, { 224 Value: &Ydb.Value_TextValue{ 225 TextValue: "5", 226 }, 227 }, { 228 Value: &Ydb.Value_BoolValue{ 229 BoolValue: false, 230 }, 231 }}, 232 }, 233 }, 234 }, 235 }, nil) 236 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 237 Status: Ydb.StatusIds_SUCCESS, 238 ResultSetIndex: 2, 239 ResultSet: &Ydb.ResultSet{ 240 Columns: []*Ydb.Column{ 241 { 242 Name: "c", 243 Type: &Ydb.Type{ 244 Type: &Ydb.Type_TypeId{ 245 TypeId: Ydb.Type_UINT64, 246 }, 247 }, 248 }, 249 { 250 Name: "d", 251 Type: &Ydb.Type{ 252 Type: &Ydb.Type_TypeId{ 253 TypeId: Ydb.Type_UTF8, 254 }, 255 }, 256 }, 257 { 258 Name: "e", 259 Type: &Ydb.Type{ 260 Type: &Ydb.Type_TypeId{ 261 TypeId: Ydb.Type_BOOL, 262 }, 263 }, 264 }, 265 }, 266 Rows: []*Ydb.Value{ 267 { 268 Items: []*Ydb.Value{{ 269 Value: &Ydb.Value_Uint64Value{ 270 Uint64Value: 1, 271 }, 272 }, { 273 Value: &Ydb.Value_TextValue{ 274 TextValue: "1", 275 }, 276 }, { 277 Value: &Ydb.Value_BoolValue{ 278 BoolValue: true, 279 }, 280 }}, 281 }, 282 { 283 Items: []*Ydb.Value{{ 284 Value: &Ydb.Value_Uint64Value{ 285 Uint64Value: 2, 286 }, 287 }, { 288 Value: &Ydb.Value_TextValue{ 289 TextValue: "2", 290 }, 291 }, { 292 Value: &Ydb.Value_BoolValue{ 293 BoolValue: false, 294 }, 295 }}, 296 }, 297 }, 298 }, 299 }, nil) 300 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 301 Status: Ydb.StatusIds_SUCCESS, 302 ResultSetIndex: 2, 303 ResultSet: &Ydb.ResultSet{ 304 Rows: []*Ydb.Value{ 305 { 306 Items: []*Ydb.Value{{ 307 Value: &Ydb.Value_Uint64Value{ 308 Uint64Value: 3, 309 }, 310 }, { 311 Value: &Ydb.Value_TextValue{ 312 TextValue: "3", 313 }, 314 }, { 315 Value: &Ydb.Value_BoolValue{ 316 BoolValue: true, 317 }, 318 }}, 319 }, 320 { 321 Items: []*Ydb.Value{{ 322 Value: &Ydb.Value_Uint64Value{ 323 Uint64Value: 4, 324 }, 325 }, { 326 Value: &Ydb.Value_TextValue{ 327 TextValue: "4", 328 }, 329 }, { 330 Value: &Ydb.Value_BoolValue{ 331 BoolValue: false, 332 }, 333 }}, 334 }, 335 { 336 Items: []*Ydb.Value{{ 337 Value: &Ydb.Value_Uint64Value{ 338 Uint64Value: 5, 339 }, 340 }, { 341 Value: &Ydb.Value_TextValue{ 342 TextValue: "5", 343 }, 344 }, { 345 Value: &Ydb.Value_BoolValue{ 346 BoolValue: false, 347 }, 348 }}, 349 }, 350 }, 351 }, 352 }, nil) 353 stream.EXPECT().Recv().Return(nil, io.EOF) 354 r, err := newResult(ctx, stream, nil) 355 require.NoError(t, err) 356 defer r.Close(ctx) 357 { 358 t.Log("nextResultSet") 359 rs, err := r.nextResultSet(ctx) 360 require.NoError(t, err) 361 require.EqualValues(t, 0, rs.Index()) 362 { 363 t.Log("next (row=1)") 364 _, err := rs.nextRow(ctx) 365 require.NoError(t, err) 366 require.EqualValues(t, 0, rs.rowIndex) 367 } 368 { 369 t.Log("next (row=2)") 370 _, err := rs.nextRow(ctx) 371 require.NoError(t, err) 372 require.EqualValues(t, 1, rs.rowIndex) 373 } 374 { 375 t.Log("next (row=3)") 376 _, err := rs.nextRow(ctx) 377 require.NoError(t, err) 378 require.EqualValues(t, 2, rs.rowIndex) 379 } 380 { 381 t.Log("next (row=4)") 382 _, err := rs.nextRow(ctx) 383 require.NoError(t, err) 384 require.EqualValues(t, 0, rs.rowIndex) 385 } 386 { 387 t.Log("next (row=5)") 388 _, err := rs.nextRow(ctx) 389 require.NoError(t, err) 390 require.EqualValues(t, 1, rs.rowIndex) 391 } 392 { 393 t.Log("next (row=6)") 394 _, err := rs.nextRow(ctx) 395 require.ErrorIs(t, err, io.EOF) 396 } 397 } 398 { 399 t.Log("nextResultSet") 400 rs, err := r.nextResultSet(ctx) 401 require.NoError(t, err) 402 require.EqualValues(t, 1, rs.Index()) 403 } 404 { 405 t.Log("nextResultSet") 406 rs, err := r.nextResultSet(ctx) 407 require.NoError(t, err) 408 require.EqualValues(t, 2, rs.Index()) 409 { 410 t.Log("next (row=1)") 411 _, err := rs.nextRow(ctx) 412 require.NoError(t, err) 413 require.EqualValues(t, 0, rs.rowIndex) 414 } 415 { 416 t.Log("next (row=2)") 417 _, err := rs.nextRow(ctx) 418 require.NoError(t, err) 419 require.EqualValues(t, 1, rs.rowIndex) 420 } 421 { 422 t.Log("next (row=3)") 423 _, err := rs.nextRow(ctx) 424 require.NoError(t, err) 425 require.EqualValues(t, 0, rs.rowIndex) 426 } 427 { 428 t.Log("next (row=4)") 429 _, err := rs.nextRow(ctx) 430 require.NoError(t, err) 431 require.EqualValues(t, 1, rs.rowIndex) 432 } 433 { 434 t.Log("next (row=5)") 435 _, err := rs.nextRow(ctx) 436 require.NoError(t, err) 437 require.EqualValues(t, 2, rs.rowIndex) 438 } 439 { 440 t.Log("next (row=6)") 441 _, err := rs.nextRow(ctx) 442 require.ErrorIs(t, err, io.EOF) 443 } 444 } 445 { 446 t.Log("close result") 447 r.Close(context.Background()) 448 } 449 { 450 t.Log("nextResultSet") 451 rs, err := r.nextResultSet(context.Background()) 452 require.ErrorIs(t, err, io.EOF) 453 require.Nil(t, rs) 454 require.Equal(t, -1, rs.Index()) 455 } 456 }) 457 t.Run("InterruptStream", func(t *testing.T) { 458 ctx, cancel := context.WithCancel(xtest.Context(t)) 459 defer cancel() 460 ctrl := gomock.NewController(t) 461 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 462 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 463 Status: Ydb.StatusIds_SUCCESS, 464 ResultSetIndex: 0, 465 ResultSet: &Ydb.ResultSet{ 466 Columns: []*Ydb.Column{ 467 { 468 Name: "a", 469 Type: &Ydb.Type{ 470 Type: &Ydb.Type_TypeId{ 471 TypeId: Ydb.Type_UINT64, 472 }, 473 }, 474 }, 475 { 476 Name: "b", 477 Type: &Ydb.Type{ 478 Type: &Ydb.Type_TypeId{ 479 TypeId: Ydb.Type_UTF8, 480 }, 481 }, 482 }, 483 }, 484 Rows: []*Ydb.Value{ 485 { 486 Items: []*Ydb.Value{{ 487 Value: &Ydb.Value_Uint64Value{ 488 Uint64Value: 1, 489 }, 490 }, { 491 Value: &Ydb.Value_TextValue{ 492 TextValue: "1", 493 }, 494 }}, 495 }, 496 { 497 Items: []*Ydb.Value{{ 498 Value: &Ydb.Value_Uint64Value{ 499 Uint64Value: 2, 500 }, 501 }, { 502 Value: &Ydb.Value_TextValue{ 503 TextValue: "2", 504 }, 505 }}, 506 }, 507 { 508 Items: []*Ydb.Value{{ 509 Value: &Ydb.Value_Uint64Value{ 510 Uint64Value: 3, 511 }, 512 }, { 513 Value: &Ydb.Value_TextValue{ 514 TextValue: "3", 515 }, 516 }}, 517 }, 518 }, 519 }, 520 }, nil) 521 r, err := newResult(ctx, stream, nil) 522 require.NoError(t, err) 523 defer r.Close(ctx) 524 { 525 t.Log("nextResultSet") 526 rs, err := r.nextResultSet(ctx) 527 require.NoError(t, err) 528 require.EqualValues(t, 0, rs.Index()) 529 { 530 t.Log("next (row=1)") 531 _, err := rs.nextRow(ctx) 532 require.NoError(t, err) 533 require.EqualValues(t, 0, rs.rowIndex) 534 } 535 { 536 t.Log("next (row=2)") 537 _, err := rs.nextRow(ctx) 538 require.NoError(t, err) 539 require.EqualValues(t, 1, rs.rowIndex) 540 } 541 t.Log("explicit interrupt stream") 542 r.closeOnce() 543 { 544 t.Log("next (row=3)") 545 _, err := rs.nextRow(context.Background()) 546 require.NoError(t, err) 547 require.EqualValues(t, 2, rs.rowIndex) 548 } 549 { 550 t.Log("next (row=4)") 551 _, err := rs.nextRow(context.Background()) 552 require.ErrorIs(t, err, io.EOF) 553 } 554 } 555 { 556 t.Log("nextResultSet") 557 _, err := r.nextResultSet(context.Background()) 558 require.ErrorIs(t, err, io.EOF) 559 } 560 }) 561 t.Run("WrongResultSetIndex", func(t *testing.T) { 562 ctx, cancel := context.WithCancel(xtest.Context(t)) 563 defer cancel() 564 ctrl := gomock.NewController(t) 565 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 566 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 567 Status: Ydb.StatusIds_SUCCESS, 568 ResultSetIndex: 0, 569 ResultSet: &Ydb.ResultSet{ 570 Columns: []*Ydb.Column{ 571 { 572 Name: "a", 573 Type: &Ydb.Type{ 574 Type: &Ydb.Type_TypeId{ 575 TypeId: Ydb.Type_UINT64, 576 }, 577 }, 578 }, 579 { 580 Name: "b", 581 Type: &Ydb.Type{ 582 Type: &Ydb.Type_TypeId{ 583 TypeId: Ydb.Type_UTF8, 584 }, 585 }, 586 }, 587 }, 588 Rows: []*Ydb.Value{ 589 { 590 Items: []*Ydb.Value{{ 591 Value: &Ydb.Value_Uint64Value{ 592 Uint64Value: 1, 593 }, 594 }, { 595 Value: &Ydb.Value_TextValue{ 596 TextValue: "1", 597 }, 598 }}, 599 }, 600 { 601 Items: []*Ydb.Value{{ 602 Value: &Ydb.Value_Uint64Value{ 603 Uint64Value: 2, 604 }, 605 }, { 606 Value: &Ydb.Value_TextValue{ 607 TextValue: "2", 608 }, 609 }}, 610 }, 611 { 612 Items: []*Ydb.Value{{ 613 Value: &Ydb.Value_Uint64Value{ 614 Uint64Value: 3, 615 }, 616 }, { 617 Value: &Ydb.Value_TextValue{ 618 TextValue: "3", 619 }, 620 }}, 621 }, 622 }, 623 }, 624 }, nil) 625 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 626 Status: Ydb.StatusIds_SUCCESS, 627 ResultSetIndex: 0, 628 ResultSet: &Ydb.ResultSet{ 629 Rows: []*Ydb.Value{ 630 { 631 Items: []*Ydb.Value{{ 632 Value: &Ydb.Value_Uint64Value{ 633 Uint64Value: 4, 634 }, 635 }, { 636 Value: &Ydb.Value_TextValue{ 637 TextValue: "4", 638 }, 639 }}, 640 }, 641 { 642 Items: []*Ydb.Value{{ 643 Value: &Ydb.Value_Uint64Value{ 644 Uint64Value: 5, 645 }, 646 }, { 647 Value: &Ydb.Value_TextValue{ 648 TextValue: "5", 649 }, 650 }}, 651 }, 652 }, 653 }, 654 }, nil) 655 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 656 Status: Ydb.StatusIds_SUCCESS, 657 ResultSetIndex: 2, 658 ResultSet: &Ydb.ResultSet{ 659 Columns: []*Ydb.Column{ 660 { 661 Name: "c", 662 Type: &Ydb.Type{ 663 Type: &Ydb.Type_TypeId{ 664 TypeId: Ydb.Type_UINT64, 665 }, 666 }, 667 }, 668 { 669 Name: "d", 670 Type: &Ydb.Type{ 671 Type: &Ydb.Type_TypeId{ 672 TypeId: Ydb.Type_UTF8, 673 }, 674 }, 675 }, 676 { 677 Name: "e", 678 Type: &Ydb.Type{ 679 Type: &Ydb.Type_TypeId{ 680 TypeId: Ydb.Type_BOOL, 681 }, 682 }, 683 }, 684 }, 685 Rows: []*Ydb.Value{ 686 { 687 Items: []*Ydb.Value{{ 688 Value: &Ydb.Value_Uint64Value{ 689 Uint64Value: 1, 690 }, 691 }, { 692 Value: &Ydb.Value_TextValue{ 693 TextValue: "1", 694 }, 695 }, { 696 Value: &Ydb.Value_BoolValue{ 697 BoolValue: true, 698 }, 699 }}, 700 }, 701 { 702 Items: []*Ydb.Value{{ 703 Value: &Ydb.Value_Uint64Value{ 704 Uint64Value: 2, 705 }, 706 }, { 707 Value: &Ydb.Value_TextValue{ 708 TextValue: "2", 709 }, 710 }, { 711 Value: &Ydb.Value_BoolValue{ 712 BoolValue: false, 713 }, 714 }}, 715 }, 716 }, 717 }, 718 }, nil) 719 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 720 Status: Ydb.StatusIds_SUCCESS, 721 ResultSetIndex: 2, 722 ResultSet: &Ydb.ResultSet{ 723 Rows: []*Ydb.Value{ 724 { 725 Items: []*Ydb.Value{{ 726 Value: &Ydb.Value_Uint64Value{ 727 Uint64Value: 3, 728 }, 729 }, { 730 Value: &Ydb.Value_TextValue{ 731 TextValue: "3", 732 }, 733 }, { 734 Value: &Ydb.Value_BoolValue{ 735 BoolValue: true, 736 }, 737 }}, 738 }, 739 { 740 Items: []*Ydb.Value{{ 741 Value: &Ydb.Value_Uint64Value{ 742 Uint64Value: 4, 743 }, 744 }, { 745 Value: &Ydb.Value_TextValue{ 746 TextValue: "4", 747 }, 748 }, { 749 Value: &Ydb.Value_BoolValue{ 750 BoolValue: false, 751 }, 752 }}, 753 }, 754 { 755 Items: []*Ydb.Value{{ 756 Value: &Ydb.Value_Uint64Value{ 757 Uint64Value: 5, 758 }, 759 }, { 760 Value: &Ydb.Value_TextValue{ 761 TextValue: "5", 762 }, 763 }, { 764 Value: &Ydb.Value_BoolValue{ 765 BoolValue: false, 766 }, 767 }}, 768 }, 769 }, 770 }, 771 }, nil) 772 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 773 Status: Ydb.StatusIds_SUCCESS, 774 ResultSetIndex: 1, 775 ResultSet: &Ydb.ResultSet{ 776 Columns: []*Ydb.Column{ 777 { 778 Name: "c", 779 Type: &Ydb.Type{ 780 Type: &Ydb.Type_TypeId{ 781 TypeId: Ydb.Type_UINT64, 782 }, 783 }, 784 }, 785 { 786 Name: "d", 787 Type: &Ydb.Type{ 788 Type: &Ydb.Type_TypeId{ 789 TypeId: Ydb.Type_UTF8, 790 }, 791 }, 792 }, 793 { 794 Name: "e", 795 Type: &Ydb.Type{ 796 Type: &Ydb.Type_TypeId{ 797 TypeId: Ydb.Type_BOOL, 798 }, 799 }, 800 }, 801 }, 802 Rows: []*Ydb.Value{ 803 { 804 Items: []*Ydb.Value{{ 805 Value: &Ydb.Value_Uint64Value{ 806 Uint64Value: 1, 807 }, 808 }, { 809 Value: &Ydb.Value_TextValue{ 810 TextValue: "1", 811 }, 812 }, { 813 Value: &Ydb.Value_BoolValue{ 814 BoolValue: true, 815 }, 816 }}, 817 }, 818 { 819 Items: []*Ydb.Value{{ 820 Value: &Ydb.Value_Uint64Value{ 821 Uint64Value: 2, 822 }, 823 }, { 824 Value: &Ydb.Value_TextValue{ 825 TextValue: "2", 826 }, 827 }, { 828 Value: &Ydb.Value_BoolValue{ 829 BoolValue: false, 830 }, 831 }}, 832 }, 833 }, 834 }, 835 }, nil) 836 r, err := newResult(ctx, stream, nil) 837 require.NoError(t, err) 838 defer r.Close(ctx) 839 { 840 t.Log("nextResultSet") 841 rs, err := r.nextResultSet(ctx) 842 require.NoError(t, err) 843 require.EqualValues(t, 0, rs.Index()) 844 { 845 t.Log("next (row=1)") 846 _, err := rs.nextRow(ctx) 847 require.NoError(t, err) 848 require.EqualValues(t, 0, rs.rowIndex) 849 } 850 { 851 t.Log("next (row=2)") 852 _, err := rs.nextRow(ctx) 853 require.NoError(t, err) 854 require.EqualValues(t, 1, rs.rowIndex) 855 } 856 { 857 t.Log("next (row=3)") 858 _, err := rs.nextRow(ctx) 859 require.NoError(t, err) 860 require.EqualValues(t, 2, rs.rowIndex) 861 } 862 { 863 t.Log("next (row=4)") 864 _, err := rs.nextRow(ctx) 865 require.NoError(t, err) 866 require.EqualValues(t, 0, rs.rowIndex) 867 } 868 { 869 t.Log("next (row=5)") 870 _, err := rs.nextRow(ctx) 871 require.NoError(t, err) 872 require.EqualValues(t, 1, rs.rowIndex) 873 } 874 { 875 t.Log("next (row=6)") 876 _, err := rs.nextRow(ctx) 877 require.ErrorIs(t, err, io.EOF) 878 } 879 } 880 { 881 t.Log("nextResultSet") 882 rs, err := r.nextResultSet(ctx) 883 require.NoError(t, err) 884 require.EqualValues(t, 2, rs.Index()) 885 } 886 { 887 t.Log("nextResultSet") 888 _, err := r.nextResultSet(ctx) 889 require.ErrorIs(t, err, errWrongNextResultSetIndex) 890 } 891 }) 892 } 893 894 func TestExactlyOneRowFromResult(t *testing.T) { 895 ctx := xtest.Context(t) 896 t.Run("HappyWay", func(t *testing.T) { 897 ctrl := gomock.NewController(t) 898 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 899 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 900 Status: Ydb.StatusIds_SUCCESS, 901 TxMeta: &Ydb_Query.TransactionMeta{ 902 Id: "456", 903 }, 904 ResultSetIndex: 0, 905 ResultSet: &Ydb.ResultSet{ 906 Columns: []*Ydb.Column{ 907 { 908 Name: "a", 909 Type: &Ydb.Type{ 910 Type: &Ydb.Type_TypeId{ 911 TypeId: Ydb.Type_UINT64, 912 }, 913 }, 914 }, 915 { 916 Name: "b", 917 Type: &Ydb.Type{ 918 Type: &Ydb.Type_TypeId{ 919 TypeId: Ydb.Type_UTF8, 920 }, 921 }, 922 }, 923 }, 924 Rows: []*Ydb.Value{ 925 { 926 Items: []*Ydb.Value{{ 927 Value: &Ydb.Value_Uint64Value{ 928 Uint64Value: 1, 929 }, 930 }, { 931 Value: &Ydb.Value_TextValue{ 932 TextValue: "1", 933 }, 934 }}, 935 }, 936 }, 937 }, 938 }, nil) 939 stream.EXPECT().Recv().Return(nil, io.EOF) 940 r, err := newResult(ctx, stream, nil) 941 require.NoError(t, err) 942 943 row, err := exactlyOneRowFromResult(ctx, r) 944 require.NoError(t, err) 945 var ( 946 a uint64 947 b string 948 ) 949 err = row.Scan(&a, &b) 950 require.NoError(t, err) 951 require.EqualValues(t, 1, a) 952 require.EqualValues(t, "1", b) 953 }) 954 t.Run("MoreThanOneRow", func(t *testing.T) { 955 ctrl := gomock.NewController(t) 956 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 957 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 958 Status: Ydb.StatusIds_SUCCESS, 959 TxMeta: &Ydb_Query.TransactionMeta{ 960 Id: "456", 961 }, 962 ResultSetIndex: 0, 963 ResultSet: &Ydb.ResultSet{ 964 Columns: []*Ydb.Column{ 965 { 966 Name: "a", 967 Type: &Ydb.Type{ 968 Type: &Ydb.Type_TypeId{ 969 TypeId: Ydb.Type_UINT64, 970 }, 971 }, 972 }, 973 { 974 Name: "b", 975 Type: &Ydb.Type{ 976 Type: &Ydb.Type_TypeId{ 977 TypeId: Ydb.Type_UTF8, 978 }, 979 }, 980 }, 981 }, 982 Rows: []*Ydb.Value{ 983 { 984 Items: []*Ydb.Value{{ 985 Value: &Ydb.Value_Uint64Value{ 986 Uint64Value: 1, 987 }, 988 }, { 989 Value: &Ydb.Value_TextValue{ 990 TextValue: "1", 991 }, 992 }}, 993 }, 994 { 995 Items: []*Ydb.Value{{ 996 Value: &Ydb.Value_Uint64Value{ 997 Uint64Value: 2, 998 }, 999 }, { 1000 Value: &Ydb.Value_TextValue{ 1001 TextValue: "2", 1002 }, 1003 }}, 1004 }, 1005 }, 1006 }, 1007 }, nil) 1008 r, err := newResult(ctx, stream, nil) 1009 require.NoError(t, err) 1010 1011 row, err := exactlyOneRowFromResult(ctx, r) 1012 require.ErrorIs(t, err, errMoreThanOneRow) 1013 require.Nil(t, row) 1014 }) 1015 t.Run("MoreThanOneRowErrorOnNextRow", func(t *testing.T) { 1016 ctrl := gomock.NewController(t) 1017 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 1018 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1019 Status: Ydb.StatusIds_SUCCESS, 1020 TxMeta: &Ydb_Query.TransactionMeta{ 1021 Id: "456", 1022 }, 1023 ResultSetIndex: 0, 1024 ResultSet: &Ydb.ResultSet{ 1025 Columns: []*Ydb.Column{ 1026 { 1027 Name: "a", 1028 Type: &Ydb.Type{ 1029 Type: &Ydb.Type_TypeId{ 1030 TypeId: Ydb.Type_UINT64, 1031 }, 1032 }, 1033 }, 1034 { 1035 Name: "b", 1036 Type: &Ydb.Type{ 1037 Type: &Ydb.Type_TypeId{ 1038 TypeId: Ydb.Type_UTF8, 1039 }, 1040 }, 1041 }, 1042 }, 1043 Rows: []*Ydb.Value{ 1044 { 1045 Items: []*Ydb.Value{{ 1046 Value: &Ydb.Value_Uint64Value{ 1047 Uint64Value: 1, 1048 }, 1049 }, { 1050 Value: &Ydb.Value_TextValue{ 1051 TextValue: "1", 1052 }, 1053 }}, 1054 }, 1055 }, 1056 }, 1057 }, nil) 1058 testErr := errors.New("test-err") 1059 stream.EXPECT().Recv().Return(nil, testErr) 1060 r, err := newResult(ctx, stream, nil) 1061 require.NoError(t, err) 1062 1063 row, err := exactlyOneRowFromResult(ctx, r) 1064 require.ErrorIs(t, err, testErr) 1065 require.Nil(t, row) 1066 }) 1067 t.Run("MoreThanOneResultSet", func(t *testing.T) { 1068 ctrl := gomock.NewController(t) 1069 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 1070 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1071 Status: Ydb.StatusIds_SUCCESS, 1072 TxMeta: &Ydb_Query.TransactionMeta{ 1073 Id: "456", 1074 }, 1075 ResultSetIndex: 0, 1076 ResultSet: &Ydb.ResultSet{ 1077 Columns: []*Ydb.Column{ 1078 { 1079 Name: "a", 1080 Type: &Ydb.Type{ 1081 Type: &Ydb.Type_TypeId{ 1082 TypeId: Ydb.Type_UINT64, 1083 }, 1084 }, 1085 }, 1086 { 1087 Name: "b", 1088 Type: &Ydb.Type{ 1089 Type: &Ydb.Type_TypeId{ 1090 TypeId: Ydb.Type_UTF8, 1091 }, 1092 }, 1093 }, 1094 }, 1095 Rows: []*Ydb.Value{ 1096 { 1097 Items: []*Ydb.Value{{ 1098 Value: &Ydb.Value_Uint64Value{ 1099 Uint64Value: 1, 1100 }, 1101 }, { 1102 Value: &Ydb.Value_TextValue{ 1103 TextValue: "1", 1104 }, 1105 }}, 1106 }, 1107 }, 1108 }, 1109 }, nil) 1110 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1111 Status: Ydb.StatusIds_SUCCESS, 1112 TxMeta: &Ydb_Query.TransactionMeta{ 1113 Id: "456", 1114 }, 1115 ResultSetIndex: 1, 1116 ResultSet: &Ydb.ResultSet{ 1117 Columns: []*Ydb.Column{ 1118 { 1119 Name: "a", 1120 Type: &Ydb.Type{ 1121 Type: &Ydb.Type_TypeId{ 1122 TypeId: Ydb.Type_UINT64, 1123 }, 1124 }, 1125 }, 1126 { 1127 Name: "b", 1128 Type: &Ydb.Type{ 1129 Type: &Ydb.Type_TypeId{ 1130 TypeId: Ydb.Type_UTF8, 1131 }, 1132 }, 1133 }, 1134 }, 1135 Rows: []*Ydb.Value{ 1136 { 1137 Items: []*Ydb.Value{{ 1138 Value: &Ydb.Value_Uint64Value{ 1139 Uint64Value: 1, 1140 }, 1141 }, { 1142 Value: &Ydb.Value_TextValue{ 1143 TextValue: "1", 1144 }, 1145 }}, 1146 }, 1147 }, 1148 }, 1149 }, nil) 1150 r, err := newResult(ctx, stream, nil) 1151 require.NoError(t, err) 1152 1153 row, err := exactlyOneResultSetFromResult(ctx, r) 1154 require.ErrorIs(t, err, errMoreThanOneResultSet) 1155 require.Nil(t, row) 1156 }) 1157 t.Run("MoreThanOneResultSetErrorOnNextResultSet", func(t *testing.T) { 1158 ctrl := gomock.NewController(t) 1159 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 1160 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1161 Status: Ydb.StatusIds_SUCCESS, 1162 TxMeta: &Ydb_Query.TransactionMeta{ 1163 Id: "456", 1164 }, 1165 ResultSetIndex: 0, 1166 ResultSet: &Ydb.ResultSet{ 1167 Columns: []*Ydb.Column{ 1168 { 1169 Name: "a", 1170 Type: &Ydb.Type{ 1171 Type: &Ydb.Type_TypeId{ 1172 TypeId: Ydb.Type_UINT64, 1173 }, 1174 }, 1175 }, 1176 { 1177 Name: "b", 1178 Type: &Ydb.Type{ 1179 Type: &Ydb.Type_TypeId{ 1180 TypeId: Ydb.Type_UTF8, 1181 }, 1182 }, 1183 }, 1184 }, 1185 Rows: []*Ydb.Value{ 1186 { 1187 Items: []*Ydb.Value{{ 1188 Value: &Ydb.Value_Uint64Value{ 1189 Uint64Value: 1, 1190 }, 1191 }, { 1192 Value: &Ydb.Value_TextValue{ 1193 TextValue: "1", 1194 }, 1195 }}, 1196 }, 1197 }, 1198 }, 1199 }, nil) 1200 testErr := errors.New("test-err") 1201 stream.EXPECT().Recv().Return(nil, testErr) 1202 r, err := newResult(ctx, stream, nil) 1203 require.NoError(t, err) 1204 1205 row, err := exactlyOneRowFromResult(ctx, r) 1206 require.ErrorIs(t, err, testErr) 1207 require.Nil(t, row) 1208 }) 1209 } 1210 1211 func TestExactlyOneResultSetFromResult(t *testing.T) { 1212 ctx := xtest.Context(t) 1213 t.Run("HappyWay", func(t *testing.T) { 1214 ctrl := gomock.NewController(t) 1215 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 1216 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1217 Status: Ydb.StatusIds_SUCCESS, 1218 TxMeta: &Ydb_Query.TransactionMeta{ 1219 Id: "456", 1220 }, 1221 ResultSetIndex: 0, 1222 ResultSet: &Ydb.ResultSet{ 1223 Columns: []*Ydb.Column{ 1224 { 1225 Name: "a", 1226 Type: &Ydb.Type{ 1227 Type: &Ydb.Type_TypeId{ 1228 TypeId: Ydb.Type_UINT64, 1229 }, 1230 }, 1231 }, 1232 { 1233 Name: "b", 1234 Type: &Ydb.Type{ 1235 Type: &Ydb.Type_TypeId{ 1236 TypeId: Ydb.Type_UTF8, 1237 }, 1238 }, 1239 }, 1240 }, 1241 Rows: []*Ydb.Value{ 1242 { 1243 Items: []*Ydb.Value{{ 1244 Value: &Ydb.Value_Uint64Value{ 1245 Uint64Value: 1, 1246 }, 1247 }, { 1248 Value: &Ydb.Value_TextValue{ 1249 TextValue: "1", 1250 }, 1251 }}, 1252 }, 1253 { 1254 Items: []*Ydb.Value{{ 1255 Value: &Ydb.Value_Uint64Value{ 1256 Uint64Value: 2, 1257 }, 1258 }, { 1259 Value: &Ydb.Value_TextValue{ 1260 TextValue: "2", 1261 }, 1262 }}, 1263 }, 1264 }, 1265 }, 1266 }, nil) 1267 stream.EXPECT().Recv().Return(nil, io.EOF) 1268 r, err := newResult(ctx, stream, nil) 1269 require.NoError(t, err) 1270 1271 rs, err := exactlyOneResultSetFromResult(ctx, r) 1272 require.NoError(t, err) 1273 var ( 1274 a uint64 1275 b string 1276 ) 1277 r1, err1 := rs.NextRow(ctx) 1278 require.NoError(t, err1) 1279 require.NotNil(t, r1) 1280 scanErr1 := r1.Scan(&a, &b) 1281 require.NoError(t, scanErr1) 1282 require.EqualValues(t, 1, a) 1283 require.EqualValues(t, "1", b) 1284 r2, err2 := rs.NextRow(ctx) 1285 require.NoError(t, err2) 1286 require.NotNil(t, r2) 1287 scanErr2 := r2.Scan(&a, &b) 1288 require.NoError(t, scanErr2) 1289 require.EqualValues(t, 2, a) 1290 require.EqualValues(t, "2", b) 1291 r3, err3 := rs.NextRow(ctx) 1292 require.ErrorIs(t, err3, io.EOF) 1293 require.Nil(t, r3) 1294 }) 1295 t.Run("MoreThanOneResultSet", func(t *testing.T) { 1296 ctrl := gomock.NewController(t) 1297 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 1298 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1299 Status: Ydb.StatusIds_SUCCESS, 1300 TxMeta: &Ydb_Query.TransactionMeta{ 1301 Id: "456", 1302 }, 1303 ResultSetIndex: 0, 1304 ResultSet: &Ydb.ResultSet{ 1305 Columns: []*Ydb.Column{ 1306 { 1307 Name: "a", 1308 Type: &Ydb.Type{ 1309 Type: &Ydb.Type_TypeId{ 1310 TypeId: Ydb.Type_UINT64, 1311 }, 1312 }, 1313 }, 1314 { 1315 Name: "b", 1316 Type: &Ydb.Type{ 1317 Type: &Ydb.Type_TypeId{ 1318 TypeId: Ydb.Type_UTF8, 1319 }, 1320 }, 1321 }, 1322 }, 1323 Rows: []*Ydb.Value{ 1324 { 1325 Items: []*Ydb.Value{{ 1326 Value: &Ydb.Value_Uint64Value{ 1327 Uint64Value: 1, 1328 }, 1329 }, { 1330 Value: &Ydb.Value_TextValue{ 1331 TextValue: "1", 1332 }, 1333 }}, 1334 }, 1335 }, 1336 }, 1337 }, nil) 1338 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1339 Status: Ydb.StatusIds_SUCCESS, 1340 TxMeta: &Ydb_Query.TransactionMeta{ 1341 Id: "456", 1342 }, 1343 ResultSetIndex: 1, 1344 ResultSet: &Ydb.ResultSet{ 1345 Columns: []*Ydb.Column{ 1346 { 1347 Name: "a", 1348 Type: &Ydb.Type{ 1349 Type: &Ydb.Type_TypeId{ 1350 TypeId: Ydb.Type_UINT64, 1351 }, 1352 }, 1353 }, 1354 { 1355 Name: "b", 1356 Type: &Ydb.Type{ 1357 Type: &Ydb.Type_TypeId{ 1358 TypeId: Ydb.Type_UTF8, 1359 }, 1360 }, 1361 }, 1362 }, 1363 Rows: []*Ydb.Value{ 1364 { 1365 Items: []*Ydb.Value{{ 1366 Value: &Ydb.Value_Uint64Value{ 1367 Uint64Value: 1, 1368 }, 1369 }, { 1370 Value: &Ydb.Value_TextValue{ 1371 TextValue: "1", 1372 }, 1373 }}, 1374 }, 1375 }, 1376 }, 1377 }, nil) 1378 r, err := newResult(ctx, stream, nil) 1379 require.NoError(t, err) 1380 1381 rs, err := exactlyOneResultSetFromResult(ctx, r) 1382 require.ErrorIs(t, err, errMoreThanOneResultSet) 1383 require.Nil(t, rs) 1384 }) 1385 t.Run("MoreThanOneResultSetErrorOnNextResultSet", func(t *testing.T) { 1386 ctrl := gomock.NewController(t) 1387 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 1388 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1389 Status: Ydb.StatusIds_SUCCESS, 1390 TxMeta: &Ydb_Query.TransactionMeta{ 1391 Id: "456", 1392 }, 1393 ResultSetIndex: 0, 1394 ResultSet: &Ydb.ResultSet{ 1395 Columns: []*Ydb.Column{ 1396 { 1397 Name: "a", 1398 Type: &Ydb.Type{ 1399 Type: &Ydb.Type_TypeId{ 1400 TypeId: Ydb.Type_UINT64, 1401 }, 1402 }, 1403 }, 1404 { 1405 Name: "b", 1406 Type: &Ydb.Type{ 1407 Type: &Ydb.Type_TypeId{ 1408 TypeId: Ydb.Type_UTF8, 1409 }, 1410 }, 1411 }, 1412 }, 1413 Rows: []*Ydb.Value{ 1414 { 1415 Items: []*Ydb.Value{{ 1416 Value: &Ydb.Value_Uint64Value{ 1417 Uint64Value: 1, 1418 }, 1419 }, { 1420 Value: &Ydb.Value_TextValue{ 1421 TextValue: "1", 1422 }, 1423 }}, 1424 }, 1425 }, 1426 }, 1427 }, nil) 1428 testErr := errors.New("test-err") 1429 stream.EXPECT().Recv().Return(nil, testErr) 1430 r, err := newResult(ctx, stream, nil) 1431 require.NoError(t, err) 1432 1433 rs, err := exactlyOneResultSetFromResult(ctx, r) 1434 require.ErrorIs(t, err, testErr) 1435 require.Nil(t, rs) 1436 }) 1437 } 1438 1439 func TestCloseResultOnCloseClosableResultSet(t *testing.T) { 1440 ctx := xtest.Context(t) 1441 ctrl := gomock.NewController(t) 1442 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 1443 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1444 Status: Ydb.StatusIds_SUCCESS, 1445 TxMeta: &Ydb_Query.TransactionMeta{ 1446 Id: "456", 1447 }, 1448 ResultSetIndex: 0, 1449 ResultSet: &Ydb.ResultSet{ 1450 Columns: []*Ydb.Column{ 1451 { 1452 Name: "a", 1453 Type: &Ydb.Type{ 1454 Type: &Ydb.Type_TypeId{ 1455 TypeId: Ydb.Type_UINT64, 1456 }, 1457 }, 1458 }, 1459 { 1460 Name: "b", 1461 Type: &Ydb.Type{ 1462 Type: &Ydb.Type_TypeId{ 1463 TypeId: Ydb.Type_UTF8, 1464 }, 1465 }, 1466 }, 1467 }, 1468 Rows: []*Ydb.Value{ 1469 { 1470 Items: []*Ydb.Value{{ 1471 Value: &Ydb.Value_Uint64Value{ 1472 Uint64Value: 1, 1473 }, 1474 }, { 1475 Value: &Ydb.Value_TextValue{ 1476 TextValue: "1", 1477 }, 1478 }}, 1479 }, 1480 { 1481 Items: []*Ydb.Value{{ 1482 Value: &Ydb.Value_Uint64Value{ 1483 Uint64Value: 2, 1484 }, 1485 }, { 1486 Value: &Ydb.Value_TextValue{ 1487 TextValue: "2", 1488 }, 1489 }}, 1490 }, 1491 }, 1492 }, 1493 }, nil) 1494 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1495 Status: Ydb.StatusIds_SUCCESS, 1496 TxMeta: &Ydb_Query.TransactionMeta{ 1497 Id: "456", 1498 }, 1499 ResultSetIndex: 0, 1500 ResultSet: &Ydb.ResultSet{ 1501 Columns: []*Ydb.Column{ 1502 { 1503 Name: "a", 1504 Type: &Ydb.Type{ 1505 Type: &Ydb.Type_TypeId{ 1506 TypeId: Ydb.Type_UINT64, 1507 }, 1508 }, 1509 }, 1510 { 1511 Name: "b", 1512 Type: &Ydb.Type{ 1513 Type: &Ydb.Type_TypeId{ 1514 TypeId: Ydb.Type_UTF8, 1515 }, 1516 }, 1517 }, 1518 }, 1519 Rows: []*Ydb.Value{ 1520 { 1521 Items: []*Ydb.Value{{ 1522 Value: &Ydb.Value_Uint64Value{ 1523 Uint64Value: 1, 1524 }, 1525 }, { 1526 Value: &Ydb.Value_TextValue{ 1527 TextValue: "1", 1528 }, 1529 }}, 1530 }, 1531 { 1532 Items: []*Ydb.Value{{ 1533 Value: &Ydb.Value_Uint64Value{ 1534 Uint64Value: 2, 1535 }, 1536 }, { 1537 Value: &Ydb.Value_TextValue{ 1538 TextValue: "2", 1539 }, 1540 }}, 1541 }, 1542 }, 1543 }, 1544 }, nil) 1545 stream.EXPECT().Recv().Return(nil, io.EOF) 1546 var closed bool 1547 r, err := newResult(ctx, stream, withTrace(&trace.Query{ 1548 OnResultClose: func(info trace.QueryResultCloseStartInfo) func(info trace.QueryResultCloseDoneInfo) { 1549 require.False(t, closed) 1550 closed = true 1551 1552 return nil 1553 }, 1554 })) 1555 1556 require.NoError(t, err) 1557 1558 rs, err := readResultSet(ctx, r) 1559 require.NoError(t, err) 1560 var ( 1561 a uint64 1562 b string 1563 ) 1564 r1, err1 := rs.NextRow(ctx) 1565 require.NoError(t, err1) 1566 require.NotNil(t, r1) 1567 scanErr1 := r1.Scan(&a, &b) 1568 require.NoError(t, scanErr1) 1569 require.EqualValues(t, 1, a) 1570 require.EqualValues(t, "1", b) 1571 r2, err2 := rs.NextRow(ctx) 1572 require.NoError(t, err2) 1573 require.NotNil(t, r2) 1574 scanErr2 := r2.Scan(&a, &b) 1575 require.NoError(t, scanErr2) 1576 require.EqualValues(t, 2, a) 1577 require.EqualValues(t, "2", b) 1578 r3, err3 := rs.NextRow(ctx) 1579 require.ErrorIs(t, err3, io.EOF) 1580 require.Nil(t, r3) 1581 err = rs.Close(ctx) 1582 require.NoError(t, err) 1583 require.True(t, closed) 1584 } 1585 1586 func TestResultStats(t *testing.T) { 1587 t.Run("Stats", func(t *testing.T) { 1588 t.Run("Never", func(t *testing.T) { 1589 ctx, cancel := context.WithCancel(xtest.Context(t)) 1590 defer cancel() 1591 ctrl := gomock.NewController(t) 1592 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 1593 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1594 Status: Ydb.StatusIds_SUCCESS, 1595 ResultSetIndex: 0, 1596 ResultSet: &Ydb.ResultSet{ 1597 Columns: []*Ydb.Column{ 1598 { 1599 Name: "a", 1600 Type: &Ydb.Type{ 1601 Type: &Ydb.Type_TypeId{ 1602 TypeId: Ydb.Type_UINT64, 1603 }, 1604 }, 1605 }, 1606 { 1607 Name: "b", 1608 Type: &Ydb.Type{ 1609 Type: &Ydb.Type_TypeId{ 1610 TypeId: Ydb.Type_UTF8, 1611 }, 1612 }, 1613 }, 1614 }, 1615 Rows: []*Ydb.Value{ 1616 { 1617 Items: []*Ydb.Value{{ 1618 Value: &Ydb.Value_Uint64Value{ 1619 Uint64Value: 1, 1620 }, 1621 }, { 1622 Value: &Ydb.Value_TextValue{ 1623 TextValue: "1", 1624 }, 1625 }}, 1626 }, 1627 { 1628 Items: []*Ydb.Value{{ 1629 Value: &Ydb.Value_Uint64Value{ 1630 Uint64Value: 2, 1631 }, 1632 }, { 1633 Value: &Ydb.Value_TextValue{ 1634 TextValue: "2", 1635 }, 1636 }}, 1637 }, 1638 { 1639 Items: []*Ydb.Value{{ 1640 Value: &Ydb.Value_Uint64Value{ 1641 Uint64Value: 3, 1642 }, 1643 }, { 1644 Value: &Ydb.Value_TextValue{ 1645 TextValue: "3", 1646 }, 1647 }}, 1648 }, 1649 }, 1650 }, 1651 }, nil) 1652 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1653 Status: Ydb.StatusIds_SUCCESS, 1654 ResultSetIndex: 0, 1655 ResultSet: &Ydb.ResultSet{ 1656 Rows: []*Ydb.Value{ 1657 { 1658 Items: []*Ydb.Value{{ 1659 Value: &Ydb.Value_Uint64Value{ 1660 Uint64Value: 4, 1661 }, 1662 }, { 1663 Value: &Ydb.Value_TextValue{ 1664 TextValue: "4", 1665 }, 1666 }}, 1667 }, 1668 { 1669 Items: []*Ydb.Value{{ 1670 Value: &Ydb.Value_Uint64Value{ 1671 Uint64Value: 5, 1672 }, 1673 }, { 1674 Value: &Ydb.Value_TextValue{ 1675 TextValue: "5", 1676 }, 1677 }}, 1678 }, 1679 }, 1680 }, 1681 }, nil) 1682 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1683 Status: Ydb.StatusIds_SUCCESS, 1684 ResultSetIndex: 1, 1685 ResultSet: &Ydb.ResultSet{ 1686 Columns: []*Ydb.Column{ 1687 { 1688 Name: "c", 1689 Type: &Ydb.Type{ 1690 Type: &Ydb.Type_TypeId{ 1691 TypeId: Ydb.Type_UINT64, 1692 }, 1693 }, 1694 }, 1695 { 1696 Name: "d", 1697 Type: &Ydb.Type{ 1698 Type: &Ydb.Type_TypeId{ 1699 TypeId: Ydb.Type_UTF8, 1700 }, 1701 }, 1702 }, 1703 { 1704 Name: "e", 1705 Type: &Ydb.Type{ 1706 Type: &Ydb.Type_TypeId{ 1707 TypeId: Ydb.Type_BOOL, 1708 }, 1709 }, 1710 }, 1711 }, 1712 Rows: []*Ydb.Value{ 1713 { 1714 Items: []*Ydb.Value{{ 1715 Value: &Ydb.Value_Uint64Value{ 1716 Uint64Value: 1, 1717 }, 1718 }, { 1719 Value: &Ydb.Value_TextValue{ 1720 TextValue: "1", 1721 }, 1722 }, { 1723 Value: &Ydb.Value_BoolValue{ 1724 BoolValue: true, 1725 }, 1726 }}, 1727 }, 1728 { 1729 Items: []*Ydb.Value{{ 1730 Value: &Ydb.Value_Uint64Value{ 1731 Uint64Value: 2, 1732 }, 1733 }, { 1734 Value: &Ydb.Value_TextValue{ 1735 TextValue: "2", 1736 }, 1737 }, { 1738 Value: &Ydb.Value_BoolValue{ 1739 BoolValue: false, 1740 }, 1741 }}, 1742 }, 1743 }, 1744 }, 1745 }, nil) 1746 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1747 Status: Ydb.StatusIds_SUCCESS, 1748 ResultSetIndex: 1, 1749 ResultSet: &Ydb.ResultSet{ 1750 Rows: []*Ydb.Value{ 1751 { 1752 Items: []*Ydb.Value{{ 1753 Value: &Ydb.Value_Uint64Value{ 1754 Uint64Value: 3, 1755 }, 1756 }, { 1757 Value: &Ydb.Value_TextValue{ 1758 TextValue: "3", 1759 }, 1760 }, { 1761 Value: &Ydb.Value_BoolValue{ 1762 BoolValue: true, 1763 }, 1764 }}, 1765 }, 1766 { 1767 Items: []*Ydb.Value{{ 1768 Value: &Ydb.Value_Uint64Value{ 1769 Uint64Value: 4, 1770 }, 1771 }, { 1772 Value: &Ydb.Value_TextValue{ 1773 TextValue: "4", 1774 }, 1775 }, { 1776 Value: &Ydb.Value_BoolValue{ 1777 BoolValue: false, 1778 }, 1779 }}, 1780 }, 1781 { 1782 Items: []*Ydb.Value{{ 1783 Value: &Ydb.Value_Uint64Value{ 1784 Uint64Value: 5, 1785 }, 1786 }, { 1787 Value: &Ydb.Value_TextValue{ 1788 TextValue: "5", 1789 }, 1790 }, { 1791 Value: &Ydb.Value_BoolValue{ 1792 BoolValue: false, 1793 }, 1794 }}, 1795 }, 1796 }, 1797 }, 1798 }, nil) 1799 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1800 Status: Ydb.StatusIds_SUCCESS, 1801 ResultSetIndex: 2, 1802 ResultSet: &Ydb.ResultSet{ 1803 Columns: []*Ydb.Column{ 1804 { 1805 Name: "c", 1806 Type: &Ydb.Type{ 1807 Type: &Ydb.Type_TypeId{ 1808 TypeId: Ydb.Type_UINT64, 1809 }, 1810 }, 1811 }, 1812 { 1813 Name: "d", 1814 Type: &Ydb.Type{ 1815 Type: &Ydb.Type_TypeId{ 1816 TypeId: Ydb.Type_UTF8, 1817 }, 1818 }, 1819 }, 1820 { 1821 Name: "e", 1822 Type: &Ydb.Type{ 1823 Type: &Ydb.Type_TypeId{ 1824 TypeId: Ydb.Type_BOOL, 1825 }, 1826 }, 1827 }, 1828 }, 1829 Rows: []*Ydb.Value{ 1830 { 1831 Items: []*Ydb.Value{{ 1832 Value: &Ydb.Value_Uint64Value{ 1833 Uint64Value: 1, 1834 }, 1835 }, { 1836 Value: &Ydb.Value_TextValue{ 1837 TextValue: "1", 1838 }, 1839 }, { 1840 Value: &Ydb.Value_BoolValue{ 1841 BoolValue: true, 1842 }, 1843 }}, 1844 }, 1845 { 1846 Items: []*Ydb.Value{{ 1847 Value: &Ydb.Value_Uint64Value{ 1848 Uint64Value: 2, 1849 }, 1850 }, { 1851 Value: &Ydb.Value_TextValue{ 1852 TextValue: "2", 1853 }, 1854 }, { 1855 Value: &Ydb.Value_BoolValue{ 1856 BoolValue: false, 1857 }, 1858 }}, 1859 }, 1860 }, 1861 }, 1862 }, nil) 1863 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1864 Status: Ydb.StatusIds_SUCCESS, 1865 ResultSetIndex: 2, 1866 ResultSet: &Ydb.ResultSet{ 1867 Rows: []*Ydb.Value{ 1868 { 1869 Items: []*Ydb.Value{{ 1870 Value: &Ydb.Value_Uint64Value{ 1871 Uint64Value: 3, 1872 }, 1873 }, { 1874 Value: &Ydb.Value_TextValue{ 1875 TextValue: "3", 1876 }, 1877 }, { 1878 Value: &Ydb.Value_BoolValue{ 1879 BoolValue: true, 1880 }, 1881 }}, 1882 }, 1883 { 1884 Items: []*Ydb.Value{{ 1885 Value: &Ydb.Value_Uint64Value{ 1886 Uint64Value: 4, 1887 }, 1888 }, { 1889 Value: &Ydb.Value_TextValue{ 1890 TextValue: "4", 1891 }, 1892 }, { 1893 Value: &Ydb.Value_BoolValue{ 1894 BoolValue: false, 1895 }, 1896 }}, 1897 }, 1898 { 1899 Items: []*Ydb.Value{{ 1900 Value: &Ydb.Value_Uint64Value{ 1901 Uint64Value: 5, 1902 }, 1903 }, { 1904 Value: &Ydb.Value_TextValue{ 1905 TextValue: "5", 1906 }, 1907 }, { 1908 Value: &Ydb.Value_BoolValue{ 1909 BoolValue: false, 1910 }, 1911 }}, 1912 }, 1913 }, 1914 }, 1915 }, nil) 1916 stream.EXPECT().Recv().Return(nil, io.EOF) 1917 var s stats.QueryStats 1918 result, err := newResult(ctx, stream, withStatsCallback(func(queryStats stats.QueryStats) { 1919 s = queryStats 1920 })) 1921 require.NoError(t, err) 1922 require.NotNil(t, result) 1923 defer result.Close(ctx) 1924 for { 1925 resultSet, err := result.nextResultSet(ctx) 1926 if err != nil && xerrors.Is(err, io.EOF) { 1927 break 1928 } 1929 for { 1930 _, err := resultSet.nextRow(ctx) 1931 if err != nil && xerrors.Is(err, io.EOF) { 1932 break 1933 } 1934 } 1935 } 1936 require.Nil(t, s) 1937 }) 1938 t.Run("SeparatedLastPart", func(t *testing.T) { 1939 ctx, cancel := context.WithCancel(xtest.Context(t)) 1940 defer cancel() 1941 ctrl := gomock.NewController(t) 1942 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 1943 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 1944 Status: Ydb.StatusIds_SUCCESS, 1945 ResultSetIndex: 0, 1946 ResultSet: &Ydb.ResultSet{ 1947 Columns: []*Ydb.Column{ 1948 { 1949 Name: "a", 1950 Type: &Ydb.Type{ 1951 Type: &Ydb.Type_TypeId{ 1952 TypeId: Ydb.Type_UINT64, 1953 }, 1954 }, 1955 }, 1956 { 1957 Name: "b", 1958 Type: &Ydb.Type{ 1959 Type: &Ydb.Type_TypeId{ 1960 TypeId: Ydb.Type_UTF8, 1961 }, 1962 }, 1963 }, 1964 }, 1965 Rows: []*Ydb.Value{ 1966 { 1967 Items: []*Ydb.Value{{ 1968 Value: &Ydb.Value_Uint64Value{ 1969 Uint64Value: 1, 1970 }, 1971 }, { 1972 Value: &Ydb.Value_TextValue{ 1973 TextValue: "1", 1974 }, 1975 }}, 1976 }, 1977 { 1978 Items: []*Ydb.Value{{ 1979 Value: &Ydb.Value_Uint64Value{ 1980 Uint64Value: 2, 1981 }, 1982 }, { 1983 Value: &Ydb.Value_TextValue{ 1984 TextValue: "2", 1985 }, 1986 }}, 1987 }, 1988 { 1989 Items: []*Ydb.Value{{ 1990 Value: &Ydb.Value_Uint64Value{ 1991 Uint64Value: 3, 1992 }, 1993 }, { 1994 Value: &Ydb.Value_TextValue{ 1995 TextValue: "3", 1996 }, 1997 }}, 1998 }, 1999 }, 2000 }, 2001 }, nil) 2002 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2003 Status: Ydb.StatusIds_SUCCESS, 2004 ResultSetIndex: 0, 2005 ResultSet: &Ydb.ResultSet{ 2006 Rows: []*Ydb.Value{ 2007 { 2008 Items: []*Ydb.Value{{ 2009 Value: &Ydb.Value_Uint64Value{ 2010 Uint64Value: 4, 2011 }, 2012 }, { 2013 Value: &Ydb.Value_TextValue{ 2014 TextValue: "4", 2015 }, 2016 }}, 2017 }, 2018 { 2019 Items: []*Ydb.Value{{ 2020 Value: &Ydb.Value_Uint64Value{ 2021 Uint64Value: 5, 2022 }, 2023 }, { 2024 Value: &Ydb.Value_TextValue{ 2025 TextValue: "5", 2026 }, 2027 }}, 2028 }, 2029 }, 2030 }, 2031 }, nil) 2032 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2033 Status: Ydb.StatusIds_SUCCESS, 2034 ResultSetIndex: 1, 2035 ResultSet: &Ydb.ResultSet{ 2036 Columns: []*Ydb.Column{ 2037 { 2038 Name: "c", 2039 Type: &Ydb.Type{ 2040 Type: &Ydb.Type_TypeId{ 2041 TypeId: Ydb.Type_UINT64, 2042 }, 2043 }, 2044 }, 2045 { 2046 Name: "d", 2047 Type: &Ydb.Type{ 2048 Type: &Ydb.Type_TypeId{ 2049 TypeId: Ydb.Type_UTF8, 2050 }, 2051 }, 2052 }, 2053 { 2054 Name: "e", 2055 Type: &Ydb.Type{ 2056 Type: &Ydb.Type_TypeId{ 2057 TypeId: Ydb.Type_BOOL, 2058 }, 2059 }, 2060 }, 2061 }, 2062 Rows: []*Ydb.Value{ 2063 { 2064 Items: []*Ydb.Value{{ 2065 Value: &Ydb.Value_Uint64Value{ 2066 Uint64Value: 1, 2067 }, 2068 }, { 2069 Value: &Ydb.Value_TextValue{ 2070 TextValue: "1", 2071 }, 2072 }, { 2073 Value: &Ydb.Value_BoolValue{ 2074 BoolValue: true, 2075 }, 2076 }}, 2077 }, 2078 { 2079 Items: []*Ydb.Value{{ 2080 Value: &Ydb.Value_Uint64Value{ 2081 Uint64Value: 2, 2082 }, 2083 }, { 2084 Value: &Ydb.Value_TextValue{ 2085 TextValue: "2", 2086 }, 2087 }, { 2088 Value: &Ydb.Value_BoolValue{ 2089 BoolValue: false, 2090 }, 2091 }}, 2092 }, 2093 }, 2094 }, 2095 }, nil) 2096 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2097 Status: Ydb.StatusIds_SUCCESS, 2098 ResultSetIndex: 1, 2099 ResultSet: &Ydb.ResultSet{ 2100 Rows: []*Ydb.Value{ 2101 { 2102 Items: []*Ydb.Value{{ 2103 Value: &Ydb.Value_Uint64Value{ 2104 Uint64Value: 3, 2105 }, 2106 }, { 2107 Value: &Ydb.Value_TextValue{ 2108 TextValue: "3", 2109 }, 2110 }, { 2111 Value: &Ydb.Value_BoolValue{ 2112 BoolValue: true, 2113 }, 2114 }}, 2115 }, 2116 { 2117 Items: []*Ydb.Value{{ 2118 Value: &Ydb.Value_Uint64Value{ 2119 Uint64Value: 4, 2120 }, 2121 }, { 2122 Value: &Ydb.Value_TextValue{ 2123 TextValue: "4", 2124 }, 2125 }, { 2126 Value: &Ydb.Value_BoolValue{ 2127 BoolValue: false, 2128 }, 2129 }}, 2130 }, 2131 { 2132 Items: []*Ydb.Value{{ 2133 Value: &Ydb.Value_Uint64Value{ 2134 Uint64Value: 5, 2135 }, 2136 }, { 2137 Value: &Ydb.Value_TextValue{ 2138 TextValue: "5", 2139 }, 2140 }, { 2141 Value: &Ydb.Value_BoolValue{ 2142 BoolValue: false, 2143 }, 2144 }}, 2145 }, 2146 }, 2147 }, 2148 }, nil) 2149 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2150 Status: Ydb.StatusIds_SUCCESS, 2151 ResultSetIndex: 2, 2152 ResultSet: &Ydb.ResultSet{ 2153 Columns: []*Ydb.Column{ 2154 { 2155 Name: "c", 2156 Type: &Ydb.Type{ 2157 Type: &Ydb.Type_TypeId{ 2158 TypeId: Ydb.Type_UINT64, 2159 }, 2160 }, 2161 }, 2162 { 2163 Name: "d", 2164 Type: &Ydb.Type{ 2165 Type: &Ydb.Type_TypeId{ 2166 TypeId: Ydb.Type_UTF8, 2167 }, 2168 }, 2169 }, 2170 { 2171 Name: "e", 2172 Type: &Ydb.Type{ 2173 Type: &Ydb.Type_TypeId{ 2174 TypeId: Ydb.Type_BOOL, 2175 }, 2176 }, 2177 }, 2178 }, 2179 Rows: []*Ydb.Value{ 2180 { 2181 Items: []*Ydb.Value{{ 2182 Value: &Ydb.Value_Uint64Value{ 2183 Uint64Value: 1, 2184 }, 2185 }, { 2186 Value: &Ydb.Value_TextValue{ 2187 TextValue: "1", 2188 }, 2189 }, { 2190 Value: &Ydb.Value_BoolValue{ 2191 BoolValue: true, 2192 }, 2193 }}, 2194 }, 2195 { 2196 Items: []*Ydb.Value{{ 2197 Value: &Ydb.Value_Uint64Value{ 2198 Uint64Value: 2, 2199 }, 2200 }, { 2201 Value: &Ydb.Value_TextValue{ 2202 TextValue: "2", 2203 }, 2204 }, { 2205 Value: &Ydb.Value_BoolValue{ 2206 BoolValue: false, 2207 }, 2208 }}, 2209 }, 2210 }, 2211 }, 2212 }, nil) 2213 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2214 Status: Ydb.StatusIds_SUCCESS, 2215 ResultSetIndex: 2, 2216 ResultSet: &Ydb.ResultSet{ 2217 Rows: []*Ydb.Value{ 2218 { 2219 Items: []*Ydb.Value{{ 2220 Value: &Ydb.Value_Uint64Value{ 2221 Uint64Value: 3, 2222 }, 2223 }, { 2224 Value: &Ydb.Value_TextValue{ 2225 TextValue: "3", 2226 }, 2227 }, { 2228 Value: &Ydb.Value_BoolValue{ 2229 BoolValue: true, 2230 }, 2231 }}, 2232 }, 2233 { 2234 Items: []*Ydb.Value{{ 2235 Value: &Ydb.Value_Uint64Value{ 2236 Uint64Value: 4, 2237 }, 2238 }, { 2239 Value: &Ydb.Value_TextValue{ 2240 TextValue: "4", 2241 }, 2242 }, { 2243 Value: &Ydb.Value_BoolValue{ 2244 BoolValue: false, 2245 }, 2246 }}, 2247 }, 2248 { 2249 Items: []*Ydb.Value{{ 2250 Value: &Ydb.Value_Uint64Value{ 2251 Uint64Value: 5, 2252 }, 2253 }, { 2254 Value: &Ydb.Value_TextValue{ 2255 TextValue: "5", 2256 }, 2257 }, { 2258 Value: &Ydb.Value_BoolValue{ 2259 BoolValue: false, 2260 }, 2261 }}, 2262 }, 2263 }, 2264 }, 2265 }, nil) 2266 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2267 Status: Ydb.StatusIds_SUCCESS, 2268 ResultSetIndex: 0, 2269 ExecStats: &Ydb_TableStats.QueryStats{ 2270 ProcessCpuTimeUs: 300, 2271 QueryPlan: "123", 2272 QueryAst: "456", 2273 TotalDurationUs: 100, 2274 TotalCpuTimeUs: 200, 2275 }, 2276 }, nil) 2277 stream.EXPECT().Recv().Return(nil, io.EOF) 2278 var s stats.QueryStats 2279 result, err := newResult(ctx, stream, withStatsCallback(func(queryStats stats.QueryStats) { 2280 s = queryStats 2281 })) 2282 require.NoError(t, err) 2283 require.NotNil(t, result) 2284 defer result.Close(ctx) 2285 for { 2286 resultSet, err := result.nextResultSet(ctx) 2287 if err != nil && xerrors.Is(err, io.EOF) { 2288 break 2289 } 2290 for { 2291 _, err := resultSet.nextRow(ctx) 2292 if err != nil && xerrors.Is(err, io.EOF) { 2293 break 2294 } 2295 } 2296 } 2297 require.NotNil(t, s) 2298 require.Equal(t, "123", s.QueryPlan()) 2299 require.Equal(t, "456", s.QueryAST()) 2300 require.Equal(t, time.Microsecond*100, s.TotalDuration()) 2301 require.Equal(t, time.Microsecond*200, s.TotalCPUTime()) 2302 require.Equal(t, time.Microsecond*300, s.ProcessCPUTime()) 2303 }) 2304 t.Run("WithLastPart", func(t *testing.T) { 2305 ctx, cancel := context.WithCancel(xtest.Context(t)) 2306 defer cancel() 2307 ctrl := gomock.NewController(t) 2308 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 2309 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2310 Status: Ydb.StatusIds_SUCCESS, 2311 ResultSetIndex: 0, 2312 ResultSet: &Ydb.ResultSet{ 2313 Columns: []*Ydb.Column{ 2314 { 2315 Name: "a", 2316 Type: &Ydb.Type{ 2317 Type: &Ydb.Type_TypeId{ 2318 TypeId: Ydb.Type_UINT64, 2319 }, 2320 }, 2321 }, 2322 { 2323 Name: "b", 2324 Type: &Ydb.Type{ 2325 Type: &Ydb.Type_TypeId{ 2326 TypeId: Ydb.Type_UTF8, 2327 }, 2328 }, 2329 }, 2330 }, 2331 Rows: []*Ydb.Value{ 2332 { 2333 Items: []*Ydb.Value{{ 2334 Value: &Ydb.Value_Uint64Value{ 2335 Uint64Value: 1, 2336 }, 2337 }, { 2338 Value: &Ydb.Value_TextValue{ 2339 TextValue: "1", 2340 }, 2341 }}, 2342 }, 2343 { 2344 Items: []*Ydb.Value{{ 2345 Value: &Ydb.Value_Uint64Value{ 2346 Uint64Value: 2, 2347 }, 2348 }, { 2349 Value: &Ydb.Value_TextValue{ 2350 TextValue: "2", 2351 }, 2352 }}, 2353 }, 2354 { 2355 Items: []*Ydb.Value{{ 2356 Value: &Ydb.Value_Uint64Value{ 2357 Uint64Value: 3, 2358 }, 2359 }, { 2360 Value: &Ydb.Value_TextValue{ 2361 TextValue: "3", 2362 }, 2363 }}, 2364 }, 2365 }, 2366 }, 2367 }, nil) 2368 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2369 Status: Ydb.StatusIds_SUCCESS, 2370 ResultSetIndex: 0, 2371 ResultSet: &Ydb.ResultSet{ 2372 Rows: []*Ydb.Value{ 2373 { 2374 Items: []*Ydb.Value{{ 2375 Value: &Ydb.Value_Uint64Value{ 2376 Uint64Value: 4, 2377 }, 2378 }, { 2379 Value: &Ydb.Value_TextValue{ 2380 TextValue: "4", 2381 }, 2382 }}, 2383 }, 2384 { 2385 Items: []*Ydb.Value{{ 2386 Value: &Ydb.Value_Uint64Value{ 2387 Uint64Value: 5, 2388 }, 2389 }, { 2390 Value: &Ydb.Value_TextValue{ 2391 TextValue: "5", 2392 }, 2393 }}, 2394 }, 2395 }, 2396 }, 2397 }, nil) 2398 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2399 Status: Ydb.StatusIds_SUCCESS, 2400 ResultSetIndex: 1, 2401 ResultSet: &Ydb.ResultSet{ 2402 Columns: []*Ydb.Column{ 2403 { 2404 Name: "c", 2405 Type: &Ydb.Type{ 2406 Type: &Ydb.Type_TypeId{ 2407 TypeId: Ydb.Type_UINT64, 2408 }, 2409 }, 2410 }, 2411 { 2412 Name: "d", 2413 Type: &Ydb.Type{ 2414 Type: &Ydb.Type_TypeId{ 2415 TypeId: Ydb.Type_UTF8, 2416 }, 2417 }, 2418 }, 2419 { 2420 Name: "e", 2421 Type: &Ydb.Type{ 2422 Type: &Ydb.Type_TypeId{ 2423 TypeId: Ydb.Type_BOOL, 2424 }, 2425 }, 2426 }, 2427 }, 2428 Rows: []*Ydb.Value{ 2429 { 2430 Items: []*Ydb.Value{{ 2431 Value: &Ydb.Value_Uint64Value{ 2432 Uint64Value: 1, 2433 }, 2434 }, { 2435 Value: &Ydb.Value_TextValue{ 2436 TextValue: "1", 2437 }, 2438 }, { 2439 Value: &Ydb.Value_BoolValue{ 2440 BoolValue: true, 2441 }, 2442 }}, 2443 }, 2444 { 2445 Items: []*Ydb.Value{{ 2446 Value: &Ydb.Value_Uint64Value{ 2447 Uint64Value: 2, 2448 }, 2449 }, { 2450 Value: &Ydb.Value_TextValue{ 2451 TextValue: "2", 2452 }, 2453 }, { 2454 Value: &Ydb.Value_BoolValue{ 2455 BoolValue: false, 2456 }, 2457 }}, 2458 }, 2459 }, 2460 }, 2461 }, nil) 2462 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2463 Status: Ydb.StatusIds_SUCCESS, 2464 ResultSetIndex: 1, 2465 ResultSet: &Ydb.ResultSet{ 2466 Rows: []*Ydb.Value{ 2467 { 2468 Items: []*Ydb.Value{{ 2469 Value: &Ydb.Value_Uint64Value{ 2470 Uint64Value: 3, 2471 }, 2472 }, { 2473 Value: &Ydb.Value_TextValue{ 2474 TextValue: "3", 2475 }, 2476 }, { 2477 Value: &Ydb.Value_BoolValue{ 2478 BoolValue: true, 2479 }, 2480 }}, 2481 }, 2482 { 2483 Items: []*Ydb.Value{{ 2484 Value: &Ydb.Value_Uint64Value{ 2485 Uint64Value: 4, 2486 }, 2487 }, { 2488 Value: &Ydb.Value_TextValue{ 2489 TextValue: "4", 2490 }, 2491 }, { 2492 Value: &Ydb.Value_BoolValue{ 2493 BoolValue: false, 2494 }, 2495 }}, 2496 }, 2497 { 2498 Items: []*Ydb.Value{{ 2499 Value: &Ydb.Value_Uint64Value{ 2500 Uint64Value: 5, 2501 }, 2502 }, { 2503 Value: &Ydb.Value_TextValue{ 2504 TextValue: "5", 2505 }, 2506 }, { 2507 Value: &Ydb.Value_BoolValue{ 2508 BoolValue: false, 2509 }, 2510 }}, 2511 }, 2512 }, 2513 }, 2514 }, nil) 2515 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2516 Status: Ydb.StatusIds_SUCCESS, 2517 ResultSetIndex: 2, 2518 ResultSet: &Ydb.ResultSet{ 2519 Columns: []*Ydb.Column{ 2520 { 2521 Name: "c", 2522 Type: &Ydb.Type{ 2523 Type: &Ydb.Type_TypeId{ 2524 TypeId: Ydb.Type_UINT64, 2525 }, 2526 }, 2527 }, 2528 { 2529 Name: "d", 2530 Type: &Ydb.Type{ 2531 Type: &Ydb.Type_TypeId{ 2532 TypeId: Ydb.Type_UTF8, 2533 }, 2534 }, 2535 }, 2536 { 2537 Name: "e", 2538 Type: &Ydb.Type{ 2539 Type: &Ydb.Type_TypeId{ 2540 TypeId: Ydb.Type_BOOL, 2541 }, 2542 }, 2543 }, 2544 }, 2545 Rows: []*Ydb.Value{ 2546 { 2547 Items: []*Ydb.Value{{ 2548 Value: &Ydb.Value_Uint64Value{ 2549 Uint64Value: 1, 2550 }, 2551 }, { 2552 Value: &Ydb.Value_TextValue{ 2553 TextValue: "1", 2554 }, 2555 }, { 2556 Value: &Ydb.Value_BoolValue{ 2557 BoolValue: true, 2558 }, 2559 }}, 2560 }, 2561 { 2562 Items: []*Ydb.Value{{ 2563 Value: &Ydb.Value_Uint64Value{ 2564 Uint64Value: 2, 2565 }, 2566 }, { 2567 Value: &Ydb.Value_TextValue{ 2568 TextValue: "2", 2569 }, 2570 }, { 2571 Value: &Ydb.Value_BoolValue{ 2572 BoolValue: false, 2573 }, 2574 }}, 2575 }, 2576 }, 2577 }, 2578 }, nil) 2579 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2580 Status: Ydb.StatusIds_SUCCESS, 2581 ResultSetIndex: 2, 2582 ResultSet: &Ydb.ResultSet{ 2583 Rows: []*Ydb.Value{ 2584 { 2585 Items: []*Ydb.Value{{ 2586 Value: &Ydb.Value_Uint64Value{ 2587 Uint64Value: 3, 2588 }, 2589 }, { 2590 Value: &Ydb.Value_TextValue{ 2591 TextValue: "3", 2592 }, 2593 }, { 2594 Value: &Ydb.Value_BoolValue{ 2595 BoolValue: true, 2596 }, 2597 }}, 2598 }, 2599 { 2600 Items: []*Ydb.Value{{ 2601 Value: &Ydb.Value_Uint64Value{ 2602 Uint64Value: 4, 2603 }, 2604 }, { 2605 Value: &Ydb.Value_TextValue{ 2606 TextValue: "4", 2607 }, 2608 }, { 2609 Value: &Ydb.Value_BoolValue{ 2610 BoolValue: false, 2611 }, 2612 }}, 2613 }, 2614 { 2615 Items: []*Ydb.Value{{ 2616 Value: &Ydb.Value_Uint64Value{ 2617 Uint64Value: 5, 2618 }, 2619 }, { 2620 Value: &Ydb.Value_TextValue{ 2621 TextValue: "5", 2622 }, 2623 }, { 2624 Value: &Ydb.Value_BoolValue{ 2625 BoolValue: false, 2626 }, 2627 }}, 2628 }, 2629 }, 2630 }, 2631 ExecStats: &Ydb_TableStats.QueryStats{ 2632 ProcessCpuTimeUs: 300, 2633 QueryPlan: "123", 2634 QueryAst: "456", 2635 TotalDurationUs: 100, 2636 TotalCpuTimeUs: 200, 2637 }, 2638 }, nil) 2639 stream.EXPECT().Recv().Return(nil, io.EOF) 2640 var s stats.QueryStats 2641 result, err := newResult(ctx, stream, withStatsCallback(func(queryStats stats.QueryStats) { 2642 s = queryStats 2643 })) 2644 require.NoError(t, err) 2645 require.NotNil(t, result) 2646 defer result.Close(ctx) 2647 for { 2648 resultSet, err := result.nextResultSet(ctx) 2649 if err != nil && xerrors.Is(err, io.EOF) { 2650 break 2651 } 2652 for { 2653 _, err := resultSet.nextRow(ctx) 2654 if err != nil && xerrors.Is(err, io.EOF) { 2655 break 2656 } 2657 } 2658 } 2659 require.NotNil(t, s) 2660 require.Equal(t, "123", s.QueryPlan()) 2661 require.Equal(t, "456", s.QueryAST()) 2662 require.Equal(t, time.Microsecond*100, s.TotalDuration()) 2663 require.Equal(t, time.Microsecond*200, s.TotalCPUTime()) 2664 require.Equal(t, time.Microsecond*300, s.ProcessCPUTime()) 2665 }) 2666 t.Run("EveryPart", func(t *testing.T) { 2667 ctx, cancel := context.WithCancel(xtest.Context(t)) 2668 defer cancel() 2669 ctrl := gomock.NewController(t) 2670 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 2671 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2672 Status: Ydb.StatusIds_SUCCESS, 2673 ResultSetIndex: 0, 2674 ResultSet: &Ydb.ResultSet{ 2675 Columns: []*Ydb.Column{ 2676 { 2677 Name: "a", 2678 Type: &Ydb.Type{ 2679 Type: &Ydb.Type_TypeId{ 2680 TypeId: Ydb.Type_UINT64, 2681 }, 2682 }, 2683 }, 2684 { 2685 Name: "b", 2686 Type: &Ydb.Type{ 2687 Type: &Ydb.Type_TypeId{ 2688 TypeId: Ydb.Type_UTF8, 2689 }, 2690 }, 2691 }, 2692 }, 2693 Rows: []*Ydb.Value{ 2694 { 2695 Items: []*Ydb.Value{{ 2696 Value: &Ydb.Value_Uint64Value{ 2697 Uint64Value: 1, 2698 }, 2699 }, { 2700 Value: &Ydb.Value_TextValue{ 2701 TextValue: "1", 2702 }, 2703 }}, 2704 }, 2705 { 2706 Items: []*Ydb.Value{{ 2707 Value: &Ydb.Value_Uint64Value{ 2708 Uint64Value: 2, 2709 }, 2710 }, { 2711 Value: &Ydb.Value_TextValue{ 2712 TextValue: "2", 2713 }, 2714 }}, 2715 }, 2716 { 2717 Items: []*Ydb.Value{{ 2718 Value: &Ydb.Value_Uint64Value{ 2719 Uint64Value: 3, 2720 }, 2721 }, { 2722 Value: &Ydb.Value_TextValue{ 2723 TextValue: "3", 2724 }, 2725 }}, 2726 }, 2727 }, 2728 }, 2729 ExecStats: &Ydb_TableStats.QueryStats{ 2730 ProcessCpuTimeUs: 1, 2731 QueryPlan: "sdsd", 2732 QueryAst: "sdffds", 2733 TotalDurationUs: 2, 2734 TotalCpuTimeUs: 3, 2735 }, 2736 }, nil) 2737 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2738 Status: Ydb.StatusIds_SUCCESS, 2739 ResultSetIndex: 0, 2740 ResultSet: &Ydb.ResultSet{ 2741 Rows: []*Ydb.Value{ 2742 { 2743 Items: []*Ydb.Value{{ 2744 Value: &Ydb.Value_Uint64Value{ 2745 Uint64Value: 4, 2746 }, 2747 }, { 2748 Value: &Ydb.Value_TextValue{ 2749 TextValue: "4", 2750 }, 2751 }}, 2752 }, 2753 { 2754 Items: []*Ydb.Value{{ 2755 Value: &Ydb.Value_Uint64Value{ 2756 Uint64Value: 5, 2757 }, 2758 }, { 2759 Value: &Ydb.Value_TextValue{ 2760 TextValue: "5", 2761 }, 2762 }}, 2763 }, 2764 }, 2765 }, 2766 ExecStats: &Ydb_TableStats.QueryStats{ 2767 ProcessCpuTimeUs: 332400, 2768 QueryPlan: "12wesfse3", 2769 QueryAst: "sedfefs", 2770 TotalDurationUs: 10324320, 2771 TotalCpuTimeUs: 234, 2772 }, 2773 }, nil) 2774 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2775 Status: Ydb.StatusIds_SUCCESS, 2776 ResultSetIndex: 1, 2777 ResultSet: &Ydb.ResultSet{ 2778 Columns: []*Ydb.Column{ 2779 { 2780 Name: "c", 2781 Type: &Ydb.Type{ 2782 Type: &Ydb.Type_TypeId{ 2783 TypeId: Ydb.Type_UINT64, 2784 }, 2785 }, 2786 }, 2787 { 2788 Name: "d", 2789 Type: &Ydb.Type{ 2790 Type: &Ydb.Type_TypeId{ 2791 TypeId: Ydb.Type_UTF8, 2792 }, 2793 }, 2794 }, 2795 { 2796 Name: "e", 2797 Type: &Ydb.Type{ 2798 Type: &Ydb.Type_TypeId{ 2799 TypeId: Ydb.Type_BOOL, 2800 }, 2801 }, 2802 }, 2803 }, 2804 Rows: []*Ydb.Value{ 2805 { 2806 Items: []*Ydb.Value{{ 2807 Value: &Ydb.Value_Uint64Value{ 2808 Uint64Value: 1, 2809 }, 2810 }, { 2811 Value: &Ydb.Value_TextValue{ 2812 TextValue: "1", 2813 }, 2814 }, { 2815 Value: &Ydb.Value_BoolValue{ 2816 BoolValue: true, 2817 }, 2818 }}, 2819 }, 2820 { 2821 Items: []*Ydb.Value{{ 2822 Value: &Ydb.Value_Uint64Value{ 2823 Uint64Value: 2, 2824 }, 2825 }, { 2826 Value: &Ydb.Value_TextValue{ 2827 TextValue: "2", 2828 }, 2829 }, { 2830 Value: &Ydb.Value_BoolValue{ 2831 BoolValue: false, 2832 }, 2833 }}, 2834 }, 2835 }, 2836 }, 2837 ExecStats: &Ydb_TableStats.QueryStats{ 2838 ProcessCpuTimeUs: 323400, 2839 QueryPlan: "sdfgrdg", 2840 QueryAst: "sdgsrg", 2841 TotalDurationUs: 43554, 2842 TotalCpuTimeUs: 235643, 2843 }, 2844 }, nil) 2845 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2846 Status: Ydb.StatusIds_SUCCESS, 2847 ResultSetIndex: 1, 2848 ResultSet: &Ydb.ResultSet{ 2849 Rows: []*Ydb.Value{ 2850 { 2851 Items: []*Ydb.Value{{ 2852 Value: &Ydb.Value_Uint64Value{ 2853 Uint64Value: 3, 2854 }, 2855 }, { 2856 Value: &Ydb.Value_TextValue{ 2857 TextValue: "3", 2858 }, 2859 }, { 2860 Value: &Ydb.Value_BoolValue{ 2861 BoolValue: true, 2862 }, 2863 }}, 2864 }, 2865 { 2866 Items: []*Ydb.Value{{ 2867 Value: &Ydb.Value_Uint64Value{ 2868 Uint64Value: 4, 2869 }, 2870 }, { 2871 Value: &Ydb.Value_TextValue{ 2872 TextValue: "4", 2873 }, 2874 }, { 2875 Value: &Ydb.Value_BoolValue{ 2876 BoolValue: false, 2877 }, 2878 }}, 2879 }, 2880 { 2881 Items: []*Ydb.Value{{ 2882 Value: &Ydb.Value_Uint64Value{ 2883 Uint64Value: 5, 2884 }, 2885 }, { 2886 Value: &Ydb.Value_TextValue{ 2887 TextValue: "5", 2888 }, 2889 }, { 2890 Value: &Ydb.Value_BoolValue{ 2891 BoolValue: false, 2892 }, 2893 }}, 2894 }, 2895 }, 2896 }, 2897 ExecStats: &Ydb_TableStats.QueryStats{ 2898 ProcessCpuTimeUs: 3034564570, 2899 QueryPlan: "sdgsrgsg", 2900 QueryAst: "dghytjf", 2901 TotalDurationUs: 45676, 2902 TotalCpuTimeUs: 4562342, 2903 }, 2904 }, nil) 2905 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 2906 Status: Ydb.StatusIds_SUCCESS, 2907 ResultSetIndex: 2, 2908 ResultSet: &Ydb.ResultSet{ 2909 Columns: []*Ydb.Column{ 2910 { 2911 Name: "c", 2912 Type: &Ydb.Type{ 2913 Type: &Ydb.Type_TypeId{ 2914 TypeId: Ydb.Type_UINT64, 2915 }, 2916 }, 2917 }, 2918 { 2919 Name: "d", 2920 Type: &Ydb.Type{ 2921 Type: &Ydb.Type_TypeId{ 2922 TypeId: Ydb.Type_UTF8, 2923 }, 2924 }, 2925 }, 2926 { 2927 Name: "e", 2928 Type: &Ydb.Type{ 2929 Type: &Ydb.Type_TypeId{ 2930 TypeId: Ydb.Type_BOOL, 2931 }, 2932 }, 2933 }, 2934 }, 2935 Rows: []*Ydb.Value{ 2936 { 2937 Items: []*Ydb.Value{{ 2938 Value: &Ydb.Value_Uint64Value{ 2939 Uint64Value: 1, 2940 }, 2941 }, { 2942 Value: &Ydb.Value_TextValue{ 2943 TextValue: "1", 2944 }, 2945 }, { 2946 Value: &Ydb.Value_BoolValue{ 2947 BoolValue: true, 2948 }, 2949 }}, 2950 }, 2951 { 2952 Items: []*Ydb.Value{{ 2953 Value: &Ydb.Value_Uint64Value{ 2954 Uint64Value: 2, 2955 }, 2956 }, { 2957 Value: &Ydb.Value_TextValue{ 2958 TextValue: "2", 2959 }, 2960 }, { 2961 Value: &Ydb.Value_BoolValue{ 2962 BoolValue: false, 2963 }, 2964 }}, 2965 }, 2966 }, 2967 }, 2968 ExecStats: &Ydb_TableStats.QueryStats{ 2969 ProcessCpuTimeUs: 300, 2970 QueryPlan: "123", 2971 QueryAst: "456", 2972 TotalDurationUs: 100, 2973 TotalCpuTimeUs: 200, 2974 }, 2975 }, nil) 2976 stream.EXPECT().Recv().Return(nil, io.EOF) 2977 var s stats.QueryStats 2978 result, err := newResult(ctx, stream, withStatsCallback(func(queryStats stats.QueryStats) { 2979 s = queryStats 2980 })) 2981 require.NoError(t, err) 2982 require.NotNil(t, result) 2983 defer result.Close(ctx) 2984 for { 2985 resultSet, err := result.nextResultSet(ctx) 2986 if err != nil && xerrors.Is(err, io.EOF) { 2987 break 2988 } 2989 for { 2990 _, err := resultSet.nextRow(ctx) 2991 if err != nil && xerrors.Is(err, io.EOF) { 2992 break 2993 } 2994 } 2995 } 2996 require.NotNil(t, s) 2997 require.Equal(t, "123", s.QueryPlan()) 2998 require.Equal(t, "456", s.QueryAST()) 2999 require.Equal(t, time.Microsecond*100, s.TotalDuration()) 3000 require.Equal(t, time.Microsecond*200, s.TotalCPUTime()) 3001 require.Equal(t, time.Microsecond*300, s.ProcessCPUTime()) 3002 }) 3003 }) 3004 } 3005 3006 func TestMaterializedResultStats(t *testing.T) { 3007 newResult := func( 3008 ctx context.Context, 3009 stream Ydb_Query_V1.QueryService_ExecuteQueryClient, 3010 opts ...resultOption, 3011 ) (query.Result, error) { 3012 r, err := newResult(ctx, stream, opts...) 3013 if err != nil { 3014 return nil, err 3015 } 3016 3017 return r, nil 3018 } 3019 t.Run("Stats", func(t *testing.T) { 3020 t.Run("Never", func(t *testing.T) { 3021 ctx, cancel := context.WithCancel(xtest.Context(t)) 3022 defer cancel() 3023 ctrl := gomock.NewController(t) 3024 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 3025 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3026 Status: Ydb.StatusIds_SUCCESS, 3027 ResultSetIndex: 0, 3028 ResultSet: &Ydb.ResultSet{ 3029 Columns: []*Ydb.Column{ 3030 { 3031 Name: "a", 3032 Type: &Ydb.Type{ 3033 Type: &Ydb.Type_TypeId{ 3034 TypeId: Ydb.Type_UINT64, 3035 }, 3036 }, 3037 }, 3038 { 3039 Name: "b", 3040 Type: &Ydb.Type{ 3041 Type: &Ydb.Type_TypeId{ 3042 TypeId: Ydb.Type_UTF8, 3043 }, 3044 }, 3045 }, 3046 }, 3047 Rows: []*Ydb.Value{ 3048 { 3049 Items: []*Ydb.Value{{ 3050 Value: &Ydb.Value_Uint64Value{ 3051 Uint64Value: 1, 3052 }, 3053 }, { 3054 Value: &Ydb.Value_TextValue{ 3055 TextValue: "1", 3056 }, 3057 }}, 3058 }, 3059 { 3060 Items: []*Ydb.Value{{ 3061 Value: &Ydb.Value_Uint64Value{ 3062 Uint64Value: 2, 3063 }, 3064 }, { 3065 Value: &Ydb.Value_TextValue{ 3066 TextValue: "2", 3067 }, 3068 }}, 3069 }, 3070 { 3071 Items: []*Ydb.Value{{ 3072 Value: &Ydb.Value_Uint64Value{ 3073 Uint64Value: 3, 3074 }, 3075 }, { 3076 Value: &Ydb.Value_TextValue{ 3077 TextValue: "3", 3078 }, 3079 }}, 3080 }, 3081 }, 3082 }, 3083 }, nil) 3084 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3085 Status: Ydb.StatusIds_SUCCESS, 3086 ResultSetIndex: 0, 3087 ResultSet: &Ydb.ResultSet{ 3088 Rows: []*Ydb.Value{ 3089 { 3090 Items: []*Ydb.Value{{ 3091 Value: &Ydb.Value_Uint64Value{ 3092 Uint64Value: 4, 3093 }, 3094 }, { 3095 Value: &Ydb.Value_TextValue{ 3096 TextValue: "4", 3097 }, 3098 }}, 3099 }, 3100 { 3101 Items: []*Ydb.Value{{ 3102 Value: &Ydb.Value_Uint64Value{ 3103 Uint64Value: 5, 3104 }, 3105 }, { 3106 Value: &Ydb.Value_TextValue{ 3107 TextValue: "5", 3108 }, 3109 }}, 3110 }, 3111 }, 3112 }, 3113 }, nil) 3114 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3115 Status: Ydb.StatusIds_SUCCESS, 3116 ResultSetIndex: 1, 3117 ResultSet: &Ydb.ResultSet{ 3118 Columns: []*Ydb.Column{ 3119 { 3120 Name: "c", 3121 Type: &Ydb.Type{ 3122 Type: &Ydb.Type_TypeId{ 3123 TypeId: Ydb.Type_UINT64, 3124 }, 3125 }, 3126 }, 3127 { 3128 Name: "d", 3129 Type: &Ydb.Type{ 3130 Type: &Ydb.Type_TypeId{ 3131 TypeId: Ydb.Type_UTF8, 3132 }, 3133 }, 3134 }, 3135 { 3136 Name: "e", 3137 Type: &Ydb.Type{ 3138 Type: &Ydb.Type_TypeId{ 3139 TypeId: Ydb.Type_BOOL, 3140 }, 3141 }, 3142 }, 3143 }, 3144 Rows: []*Ydb.Value{ 3145 { 3146 Items: []*Ydb.Value{{ 3147 Value: &Ydb.Value_Uint64Value{ 3148 Uint64Value: 1, 3149 }, 3150 }, { 3151 Value: &Ydb.Value_TextValue{ 3152 TextValue: "1", 3153 }, 3154 }, { 3155 Value: &Ydb.Value_BoolValue{ 3156 BoolValue: true, 3157 }, 3158 }}, 3159 }, 3160 { 3161 Items: []*Ydb.Value{{ 3162 Value: &Ydb.Value_Uint64Value{ 3163 Uint64Value: 2, 3164 }, 3165 }, { 3166 Value: &Ydb.Value_TextValue{ 3167 TextValue: "2", 3168 }, 3169 }, { 3170 Value: &Ydb.Value_BoolValue{ 3171 BoolValue: false, 3172 }, 3173 }}, 3174 }, 3175 }, 3176 }, 3177 }, nil) 3178 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3179 Status: Ydb.StatusIds_SUCCESS, 3180 ResultSetIndex: 1, 3181 ResultSet: &Ydb.ResultSet{ 3182 Rows: []*Ydb.Value{ 3183 { 3184 Items: []*Ydb.Value{{ 3185 Value: &Ydb.Value_Uint64Value{ 3186 Uint64Value: 3, 3187 }, 3188 }, { 3189 Value: &Ydb.Value_TextValue{ 3190 TextValue: "3", 3191 }, 3192 }, { 3193 Value: &Ydb.Value_BoolValue{ 3194 BoolValue: true, 3195 }, 3196 }}, 3197 }, 3198 { 3199 Items: []*Ydb.Value{{ 3200 Value: &Ydb.Value_Uint64Value{ 3201 Uint64Value: 4, 3202 }, 3203 }, { 3204 Value: &Ydb.Value_TextValue{ 3205 TextValue: "4", 3206 }, 3207 }, { 3208 Value: &Ydb.Value_BoolValue{ 3209 BoolValue: false, 3210 }, 3211 }}, 3212 }, 3213 { 3214 Items: []*Ydb.Value{{ 3215 Value: &Ydb.Value_Uint64Value{ 3216 Uint64Value: 5, 3217 }, 3218 }, { 3219 Value: &Ydb.Value_TextValue{ 3220 TextValue: "5", 3221 }, 3222 }, { 3223 Value: &Ydb.Value_BoolValue{ 3224 BoolValue: false, 3225 }, 3226 }}, 3227 }, 3228 }, 3229 }, 3230 }, nil) 3231 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3232 Status: Ydb.StatusIds_SUCCESS, 3233 ResultSetIndex: 2, 3234 ResultSet: &Ydb.ResultSet{ 3235 Columns: []*Ydb.Column{ 3236 { 3237 Name: "c", 3238 Type: &Ydb.Type{ 3239 Type: &Ydb.Type_TypeId{ 3240 TypeId: Ydb.Type_UINT64, 3241 }, 3242 }, 3243 }, 3244 { 3245 Name: "d", 3246 Type: &Ydb.Type{ 3247 Type: &Ydb.Type_TypeId{ 3248 TypeId: Ydb.Type_UTF8, 3249 }, 3250 }, 3251 }, 3252 { 3253 Name: "e", 3254 Type: &Ydb.Type{ 3255 Type: &Ydb.Type_TypeId{ 3256 TypeId: Ydb.Type_BOOL, 3257 }, 3258 }, 3259 }, 3260 }, 3261 Rows: []*Ydb.Value{ 3262 { 3263 Items: []*Ydb.Value{{ 3264 Value: &Ydb.Value_Uint64Value{ 3265 Uint64Value: 1, 3266 }, 3267 }, { 3268 Value: &Ydb.Value_TextValue{ 3269 TextValue: "1", 3270 }, 3271 }, { 3272 Value: &Ydb.Value_BoolValue{ 3273 BoolValue: true, 3274 }, 3275 }}, 3276 }, 3277 { 3278 Items: []*Ydb.Value{{ 3279 Value: &Ydb.Value_Uint64Value{ 3280 Uint64Value: 2, 3281 }, 3282 }, { 3283 Value: &Ydb.Value_TextValue{ 3284 TextValue: "2", 3285 }, 3286 }, { 3287 Value: &Ydb.Value_BoolValue{ 3288 BoolValue: false, 3289 }, 3290 }}, 3291 }, 3292 }, 3293 }, 3294 }, nil) 3295 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3296 Status: Ydb.StatusIds_SUCCESS, 3297 ResultSetIndex: 2, 3298 ResultSet: &Ydb.ResultSet{ 3299 Rows: []*Ydb.Value{ 3300 { 3301 Items: []*Ydb.Value{{ 3302 Value: &Ydb.Value_Uint64Value{ 3303 Uint64Value: 3, 3304 }, 3305 }, { 3306 Value: &Ydb.Value_TextValue{ 3307 TextValue: "3", 3308 }, 3309 }, { 3310 Value: &Ydb.Value_BoolValue{ 3311 BoolValue: true, 3312 }, 3313 }}, 3314 }, 3315 { 3316 Items: []*Ydb.Value{{ 3317 Value: &Ydb.Value_Uint64Value{ 3318 Uint64Value: 4, 3319 }, 3320 }, { 3321 Value: &Ydb.Value_TextValue{ 3322 TextValue: "4", 3323 }, 3324 }, { 3325 Value: &Ydb.Value_BoolValue{ 3326 BoolValue: false, 3327 }, 3328 }}, 3329 }, 3330 { 3331 Items: []*Ydb.Value{{ 3332 Value: &Ydb.Value_Uint64Value{ 3333 Uint64Value: 5, 3334 }, 3335 }, { 3336 Value: &Ydb.Value_TextValue{ 3337 TextValue: "5", 3338 }, 3339 }, { 3340 Value: &Ydb.Value_BoolValue{ 3341 BoolValue: false, 3342 }, 3343 }}, 3344 }, 3345 }, 3346 }, 3347 }, nil) 3348 stream.EXPECT().Recv().Return(nil, io.EOF) 3349 var s stats.QueryStats 3350 result, err := newResult(ctx, stream, withStatsCallback(func(queryStats stats.QueryStats) { 3351 s = queryStats 3352 })) 3353 require.NoError(t, err) 3354 require.NotNil(t, result) 3355 defer result.Close(ctx) 3356 for { 3357 resultSet, err := result.NextResultSet(ctx) 3358 if err != nil && xerrors.Is(err, io.EOF) { 3359 break 3360 } 3361 for { 3362 _, err := resultSet.NextRow(ctx) 3363 if err != nil && xerrors.Is(err, io.EOF) { 3364 break 3365 } 3366 } 3367 } 3368 require.Nil(t, s) 3369 }) 3370 t.Run("SeparatedLastPart", func(t *testing.T) { 3371 ctx, cancel := context.WithCancel(xtest.Context(t)) 3372 defer cancel() 3373 ctrl := gomock.NewController(t) 3374 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 3375 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3376 Status: Ydb.StatusIds_SUCCESS, 3377 ResultSetIndex: 0, 3378 ResultSet: &Ydb.ResultSet{ 3379 Columns: []*Ydb.Column{ 3380 { 3381 Name: "a", 3382 Type: &Ydb.Type{ 3383 Type: &Ydb.Type_TypeId{ 3384 TypeId: Ydb.Type_UINT64, 3385 }, 3386 }, 3387 }, 3388 { 3389 Name: "b", 3390 Type: &Ydb.Type{ 3391 Type: &Ydb.Type_TypeId{ 3392 TypeId: Ydb.Type_UTF8, 3393 }, 3394 }, 3395 }, 3396 }, 3397 Rows: []*Ydb.Value{ 3398 { 3399 Items: []*Ydb.Value{{ 3400 Value: &Ydb.Value_Uint64Value{ 3401 Uint64Value: 1, 3402 }, 3403 }, { 3404 Value: &Ydb.Value_TextValue{ 3405 TextValue: "1", 3406 }, 3407 }}, 3408 }, 3409 { 3410 Items: []*Ydb.Value{{ 3411 Value: &Ydb.Value_Uint64Value{ 3412 Uint64Value: 2, 3413 }, 3414 }, { 3415 Value: &Ydb.Value_TextValue{ 3416 TextValue: "2", 3417 }, 3418 }}, 3419 }, 3420 { 3421 Items: []*Ydb.Value{{ 3422 Value: &Ydb.Value_Uint64Value{ 3423 Uint64Value: 3, 3424 }, 3425 }, { 3426 Value: &Ydb.Value_TextValue{ 3427 TextValue: "3", 3428 }, 3429 }}, 3430 }, 3431 }, 3432 }, 3433 }, nil) 3434 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3435 Status: Ydb.StatusIds_SUCCESS, 3436 ResultSetIndex: 0, 3437 ResultSet: &Ydb.ResultSet{ 3438 Rows: []*Ydb.Value{ 3439 { 3440 Items: []*Ydb.Value{{ 3441 Value: &Ydb.Value_Uint64Value{ 3442 Uint64Value: 4, 3443 }, 3444 }, { 3445 Value: &Ydb.Value_TextValue{ 3446 TextValue: "4", 3447 }, 3448 }}, 3449 }, 3450 { 3451 Items: []*Ydb.Value{{ 3452 Value: &Ydb.Value_Uint64Value{ 3453 Uint64Value: 5, 3454 }, 3455 }, { 3456 Value: &Ydb.Value_TextValue{ 3457 TextValue: "5", 3458 }, 3459 }}, 3460 }, 3461 }, 3462 }, 3463 }, nil) 3464 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3465 Status: Ydb.StatusIds_SUCCESS, 3466 ResultSetIndex: 1, 3467 ResultSet: &Ydb.ResultSet{ 3468 Columns: []*Ydb.Column{ 3469 { 3470 Name: "c", 3471 Type: &Ydb.Type{ 3472 Type: &Ydb.Type_TypeId{ 3473 TypeId: Ydb.Type_UINT64, 3474 }, 3475 }, 3476 }, 3477 { 3478 Name: "d", 3479 Type: &Ydb.Type{ 3480 Type: &Ydb.Type_TypeId{ 3481 TypeId: Ydb.Type_UTF8, 3482 }, 3483 }, 3484 }, 3485 { 3486 Name: "e", 3487 Type: &Ydb.Type{ 3488 Type: &Ydb.Type_TypeId{ 3489 TypeId: Ydb.Type_BOOL, 3490 }, 3491 }, 3492 }, 3493 }, 3494 Rows: []*Ydb.Value{ 3495 { 3496 Items: []*Ydb.Value{{ 3497 Value: &Ydb.Value_Uint64Value{ 3498 Uint64Value: 1, 3499 }, 3500 }, { 3501 Value: &Ydb.Value_TextValue{ 3502 TextValue: "1", 3503 }, 3504 }, { 3505 Value: &Ydb.Value_BoolValue{ 3506 BoolValue: true, 3507 }, 3508 }}, 3509 }, 3510 { 3511 Items: []*Ydb.Value{{ 3512 Value: &Ydb.Value_Uint64Value{ 3513 Uint64Value: 2, 3514 }, 3515 }, { 3516 Value: &Ydb.Value_TextValue{ 3517 TextValue: "2", 3518 }, 3519 }, { 3520 Value: &Ydb.Value_BoolValue{ 3521 BoolValue: false, 3522 }, 3523 }}, 3524 }, 3525 }, 3526 }, 3527 }, nil) 3528 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3529 Status: Ydb.StatusIds_SUCCESS, 3530 ResultSetIndex: 1, 3531 ResultSet: &Ydb.ResultSet{ 3532 Rows: []*Ydb.Value{ 3533 { 3534 Items: []*Ydb.Value{{ 3535 Value: &Ydb.Value_Uint64Value{ 3536 Uint64Value: 3, 3537 }, 3538 }, { 3539 Value: &Ydb.Value_TextValue{ 3540 TextValue: "3", 3541 }, 3542 }, { 3543 Value: &Ydb.Value_BoolValue{ 3544 BoolValue: true, 3545 }, 3546 }}, 3547 }, 3548 { 3549 Items: []*Ydb.Value{{ 3550 Value: &Ydb.Value_Uint64Value{ 3551 Uint64Value: 4, 3552 }, 3553 }, { 3554 Value: &Ydb.Value_TextValue{ 3555 TextValue: "4", 3556 }, 3557 }, { 3558 Value: &Ydb.Value_BoolValue{ 3559 BoolValue: false, 3560 }, 3561 }}, 3562 }, 3563 { 3564 Items: []*Ydb.Value{{ 3565 Value: &Ydb.Value_Uint64Value{ 3566 Uint64Value: 5, 3567 }, 3568 }, { 3569 Value: &Ydb.Value_TextValue{ 3570 TextValue: "5", 3571 }, 3572 }, { 3573 Value: &Ydb.Value_BoolValue{ 3574 BoolValue: false, 3575 }, 3576 }}, 3577 }, 3578 }, 3579 }, 3580 }, nil) 3581 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3582 Status: Ydb.StatusIds_SUCCESS, 3583 ResultSetIndex: 2, 3584 ResultSet: &Ydb.ResultSet{ 3585 Columns: []*Ydb.Column{ 3586 { 3587 Name: "c", 3588 Type: &Ydb.Type{ 3589 Type: &Ydb.Type_TypeId{ 3590 TypeId: Ydb.Type_UINT64, 3591 }, 3592 }, 3593 }, 3594 { 3595 Name: "d", 3596 Type: &Ydb.Type{ 3597 Type: &Ydb.Type_TypeId{ 3598 TypeId: Ydb.Type_UTF8, 3599 }, 3600 }, 3601 }, 3602 { 3603 Name: "e", 3604 Type: &Ydb.Type{ 3605 Type: &Ydb.Type_TypeId{ 3606 TypeId: Ydb.Type_BOOL, 3607 }, 3608 }, 3609 }, 3610 }, 3611 Rows: []*Ydb.Value{ 3612 { 3613 Items: []*Ydb.Value{{ 3614 Value: &Ydb.Value_Uint64Value{ 3615 Uint64Value: 1, 3616 }, 3617 }, { 3618 Value: &Ydb.Value_TextValue{ 3619 TextValue: "1", 3620 }, 3621 }, { 3622 Value: &Ydb.Value_BoolValue{ 3623 BoolValue: true, 3624 }, 3625 }}, 3626 }, 3627 { 3628 Items: []*Ydb.Value{{ 3629 Value: &Ydb.Value_Uint64Value{ 3630 Uint64Value: 2, 3631 }, 3632 }, { 3633 Value: &Ydb.Value_TextValue{ 3634 TextValue: "2", 3635 }, 3636 }, { 3637 Value: &Ydb.Value_BoolValue{ 3638 BoolValue: false, 3639 }, 3640 }}, 3641 }, 3642 }, 3643 }, 3644 }, nil) 3645 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3646 Status: Ydb.StatusIds_SUCCESS, 3647 ResultSetIndex: 2, 3648 ResultSet: &Ydb.ResultSet{ 3649 Rows: []*Ydb.Value{ 3650 { 3651 Items: []*Ydb.Value{{ 3652 Value: &Ydb.Value_Uint64Value{ 3653 Uint64Value: 3, 3654 }, 3655 }, { 3656 Value: &Ydb.Value_TextValue{ 3657 TextValue: "3", 3658 }, 3659 }, { 3660 Value: &Ydb.Value_BoolValue{ 3661 BoolValue: true, 3662 }, 3663 }}, 3664 }, 3665 { 3666 Items: []*Ydb.Value{{ 3667 Value: &Ydb.Value_Uint64Value{ 3668 Uint64Value: 4, 3669 }, 3670 }, { 3671 Value: &Ydb.Value_TextValue{ 3672 TextValue: "4", 3673 }, 3674 }, { 3675 Value: &Ydb.Value_BoolValue{ 3676 BoolValue: false, 3677 }, 3678 }}, 3679 }, 3680 { 3681 Items: []*Ydb.Value{{ 3682 Value: &Ydb.Value_Uint64Value{ 3683 Uint64Value: 5, 3684 }, 3685 }, { 3686 Value: &Ydb.Value_TextValue{ 3687 TextValue: "5", 3688 }, 3689 }, { 3690 Value: &Ydb.Value_BoolValue{ 3691 BoolValue: false, 3692 }, 3693 }}, 3694 }, 3695 }, 3696 }, 3697 }, nil) 3698 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3699 Status: Ydb.StatusIds_SUCCESS, 3700 ResultSetIndex: 0, 3701 ExecStats: &Ydb_TableStats.QueryStats{ 3702 ProcessCpuTimeUs: 300, 3703 QueryPlan: "123", 3704 QueryAst: "456", 3705 TotalDurationUs: 100, 3706 TotalCpuTimeUs: 200, 3707 }, 3708 }, nil) 3709 stream.EXPECT().Recv().Return(nil, io.EOF) 3710 var s stats.QueryStats 3711 result, err := newResult(ctx, stream, withStatsCallback(func(queryStats stats.QueryStats) { 3712 s = queryStats 3713 })) 3714 require.NoError(t, err) 3715 require.NotNil(t, result) 3716 defer result.Close(ctx) 3717 for { 3718 resultSet, err := result.NextResultSet(ctx) 3719 if err != nil && xerrors.Is(err, io.EOF) { 3720 break 3721 } 3722 for { 3723 _, err := resultSet.NextRow(ctx) 3724 if err != nil && xerrors.Is(err, io.EOF) { 3725 break 3726 } 3727 } 3728 } 3729 require.NotNil(t, s) 3730 require.Equal(t, "123", s.QueryPlan()) 3731 require.Equal(t, "456", s.QueryAST()) 3732 require.Equal(t, time.Microsecond*100, s.TotalDuration()) 3733 require.Equal(t, time.Microsecond*200, s.TotalCPUTime()) 3734 require.Equal(t, time.Microsecond*300, s.ProcessCPUTime()) 3735 }) 3736 t.Run("WithLastPart", func(t *testing.T) { 3737 ctx, cancel := context.WithCancel(xtest.Context(t)) 3738 defer cancel() 3739 ctrl := gomock.NewController(t) 3740 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 3741 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3742 Status: Ydb.StatusIds_SUCCESS, 3743 ResultSetIndex: 0, 3744 ResultSet: &Ydb.ResultSet{ 3745 Columns: []*Ydb.Column{ 3746 { 3747 Name: "a", 3748 Type: &Ydb.Type{ 3749 Type: &Ydb.Type_TypeId{ 3750 TypeId: Ydb.Type_UINT64, 3751 }, 3752 }, 3753 }, 3754 { 3755 Name: "b", 3756 Type: &Ydb.Type{ 3757 Type: &Ydb.Type_TypeId{ 3758 TypeId: Ydb.Type_UTF8, 3759 }, 3760 }, 3761 }, 3762 }, 3763 Rows: []*Ydb.Value{ 3764 { 3765 Items: []*Ydb.Value{{ 3766 Value: &Ydb.Value_Uint64Value{ 3767 Uint64Value: 1, 3768 }, 3769 }, { 3770 Value: &Ydb.Value_TextValue{ 3771 TextValue: "1", 3772 }, 3773 }}, 3774 }, 3775 { 3776 Items: []*Ydb.Value{{ 3777 Value: &Ydb.Value_Uint64Value{ 3778 Uint64Value: 2, 3779 }, 3780 }, { 3781 Value: &Ydb.Value_TextValue{ 3782 TextValue: "2", 3783 }, 3784 }}, 3785 }, 3786 { 3787 Items: []*Ydb.Value{{ 3788 Value: &Ydb.Value_Uint64Value{ 3789 Uint64Value: 3, 3790 }, 3791 }, { 3792 Value: &Ydb.Value_TextValue{ 3793 TextValue: "3", 3794 }, 3795 }}, 3796 }, 3797 }, 3798 }, 3799 }, nil) 3800 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3801 Status: Ydb.StatusIds_SUCCESS, 3802 ResultSetIndex: 0, 3803 ResultSet: &Ydb.ResultSet{ 3804 Rows: []*Ydb.Value{ 3805 { 3806 Items: []*Ydb.Value{{ 3807 Value: &Ydb.Value_Uint64Value{ 3808 Uint64Value: 4, 3809 }, 3810 }, { 3811 Value: &Ydb.Value_TextValue{ 3812 TextValue: "4", 3813 }, 3814 }}, 3815 }, 3816 { 3817 Items: []*Ydb.Value{{ 3818 Value: &Ydb.Value_Uint64Value{ 3819 Uint64Value: 5, 3820 }, 3821 }, { 3822 Value: &Ydb.Value_TextValue{ 3823 TextValue: "5", 3824 }, 3825 }}, 3826 }, 3827 }, 3828 }, 3829 }, nil) 3830 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3831 Status: Ydb.StatusIds_SUCCESS, 3832 ResultSetIndex: 1, 3833 ResultSet: &Ydb.ResultSet{ 3834 Columns: []*Ydb.Column{ 3835 { 3836 Name: "c", 3837 Type: &Ydb.Type{ 3838 Type: &Ydb.Type_TypeId{ 3839 TypeId: Ydb.Type_UINT64, 3840 }, 3841 }, 3842 }, 3843 { 3844 Name: "d", 3845 Type: &Ydb.Type{ 3846 Type: &Ydb.Type_TypeId{ 3847 TypeId: Ydb.Type_UTF8, 3848 }, 3849 }, 3850 }, 3851 { 3852 Name: "e", 3853 Type: &Ydb.Type{ 3854 Type: &Ydb.Type_TypeId{ 3855 TypeId: Ydb.Type_BOOL, 3856 }, 3857 }, 3858 }, 3859 }, 3860 Rows: []*Ydb.Value{ 3861 { 3862 Items: []*Ydb.Value{{ 3863 Value: &Ydb.Value_Uint64Value{ 3864 Uint64Value: 1, 3865 }, 3866 }, { 3867 Value: &Ydb.Value_TextValue{ 3868 TextValue: "1", 3869 }, 3870 }, { 3871 Value: &Ydb.Value_BoolValue{ 3872 BoolValue: true, 3873 }, 3874 }}, 3875 }, 3876 { 3877 Items: []*Ydb.Value{{ 3878 Value: &Ydb.Value_Uint64Value{ 3879 Uint64Value: 2, 3880 }, 3881 }, { 3882 Value: &Ydb.Value_TextValue{ 3883 TextValue: "2", 3884 }, 3885 }, { 3886 Value: &Ydb.Value_BoolValue{ 3887 BoolValue: false, 3888 }, 3889 }}, 3890 }, 3891 }, 3892 }, 3893 }, nil) 3894 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3895 Status: Ydb.StatusIds_SUCCESS, 3896 ResultSetIndex: 1, 3897 ResultSet: &Ydb.ResultSet{ 3898 Rows: []*Ydb.Value{ 3899 { 3900 Items: []*Ydb.Value{{ 3901 Value: &Ydb.Value_Uint64Value{ 3902 Uint64Value: 3, 3903 }, 3904 }, { 3905 Value: &Ydb.Value_TextValue{ 3906 TextValue: "3", 3907 }, 3908 }, { 3909 Value: &Ydb.Value_BoolValue{ 3910 BoolValue: true, 3911 }, 3912 }}, 3913 }, 3914 { 3915 Items: []*Ydb.Value{{ 3916 Value: &Ydb.Value_Uint64Value{ 3917 Uint64Value: 4, 3918 }, 3919 }, { 3920 Value: &Ydb.Value_TextValue{ 3921 TextValue: "4", 3922 }, 3923 }, { 3924 Value: &Ydb.Value_BoolValue{ 3925 BoolValue: false, 3926 }, 3927 }}, 3928 }, 3929 { 3930 Items: []*Ydb.Value{{ 3931 Value: &Ydb.Value_Uint64Value{ 3932 Uint64Value: 5, 3933 }, 3934 }, { 3935 Value: &Ydb.Value_TextValue{ 3936 TextValue: "5", 3937 }, 3938 }, { 3939 Value: &Ydb.Value_BoolValue{ 3940 BoolValue: false, 3941 }, 3942 }}, 3943 }, 3944 }, 3945 }, 3946 }, nil) 3947 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 3948 Status: Ydb.StatusIds_SUCCESS, 3949 ResultSetIndex: 2, 3950 ResultSet: &Ydb.ResultSet{ 3951 Columns: []*Ydb.Column{ 3952 { 3953 Name: "c", 3954 Type: &Ydb.Type{ 3955 Type: &Ydb.Type_TypeId{ 3956 TypeId: Ydb.Type_UINT64, 3957 }, 3958 }, 3959 }, 3960 { 3961 Name: "d", 3962 Type: &Ydb.Type{ 3963 Type: &Ydb.Type_TypeId{ 3964 TypeId: Ydb.Type_UTF8, 3965 }, 3966 }, 3967 }, 3968 { 3969 Name: "e", 3970 Type: &Ydb.Type{ 3971 Type: &Ydb.Type_TypeId{ 3972 TypeId: Ydb.Type_BOOL, 3973 }, 3974 }, 3975 }, 3976 }, 3977 Rows: []*Ydb.Value{ 3978 { 3979 Items: []*Ydb.Value{{ 3980 Value: &Ydb.Value_Uint64Value{ 3981 Uint64Value: 1, 3982 }, 3983 }, { 3984 Value: &Ydb.Value_TextValue{ 3985 TextValue: "1", 3986 }, 3987 }, { 3988 Value: &Ydb.Value_BoolValue{ 3989 BoolValue: true, 3990 }, 3991 }}, 3992 }, 3993 { 3994 Items: []*Ydb.Value{{ 3995 Value: &Ydb.Value_Uint64Value{ 3996 Uint64Value: 2, 3997 }, 3998 }, { 3999 Value: &Ydb.Value_TextValue{ 4000 TextValue: "2", 4001 }, 4002 }, { 4003 Value: &Ydb.Value_BoolValue{ 4004 BoolValue: false, 4005 }, 4006 }}, 4007 }, 4008 }, 4009 }, 4010 }, nil) 4011 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 4012 Status: Ydb.StatusIds_SUCCESS, 4013 ResultSetIndex: 2, 4014 ResultSet: &Ydb.ResultSet{ 4015 Rows: []*Ydb.Value{ 4016 { 4017 Items: []*Ydb.Value{{ 4018 Value: &Ydb.Value_Uint64Value{ 4019 Uint64Value: 3, 4020 }, 4021 }, { 4022 Value: &Ydb.Value_TextValue{ 4023 TextValue: "3", 4024 }, 4025 }, { 4026 Value: &Ydb.Value_BoolValue{ 4027 BoolValue: true, 4028 }, 4029 }}, 4030 }, 4031 { 4032 Items: []*Ydb.Value{{ 4033 Value: &Ydb.Value_Uint64Value{ 4034 Uint64Value: 4, 4035 }, 4036 }, { 4037 Value: &Ydb.Value_TextValue{ 4038 TextValue: "4", 4039 }, 4040 }, { 4041 Value: &Ydb.Value_BoolValue{ 4042 BoolValue: false, 4043 }, 4044 }}, 4045 }, 4046 { 4047 Items: []*Ydb.Value{{ 4048 Value: &Ydb.Value_Uint64Value{ 4049 Uint64Value: 5, 4050 }, 4051 }, { 4052 Value: &Ydb.Value_TextValue{ 4053 TextValue: "5", 4054 }, 4055 }, { 4056 Value: &Ydb.Value_BoolValue{ 4057 BoolValue: false, 4058 }, 4059 }}, 4060 }, 4061 }, 4062 }, 4063 ExecStats: &Ydb_TableStats.QueryStats{ 4064 ProcessCpuTimeUs: 300, 4065 QueryPlan: "123", 4066 QueryAst: "456", 4067 TotalDurationUs: 100, 4068 TotalCpuTimeUs: 200, 4069 }, 4070 }, nil) 4071 stream.EXPECT().Recv().Return(nil, io.EOF) 4072 var s stats.QueryStats 4073 result, err := newResult(ctx, stream, withStatsCallback(func(queryStats stats.QueryStats) { 4074 s = queryStats 4075 })) 4076 require.NoError(t, err) 4077 require.NotNil(t, result) 4078 defer result.Close(ctx) 4079 for { 4080 resultSet, err := result.NextResultSet(ctx) 4081 if err != nil && xerrors.Is(err, io.EOF) { 4082 break 4083 } 4084 for { 4085 _, err := resultSet.NextRow(ctx) 4086 if err != nil && xerrors.Is(err, io.EOF) { 4087 break 4088 } 4089 } 4090 } 4091 require.NotNil(t, s) 4092 require.Equal(t, "123", s.QueryPlan()) 4093 require.Equal(t, "456", s.QueryAST()) 4094 require.Equal(t, time.Microsecond*100, s.TotalDuration()) 4095 require.Equal(t, time.Microsecond*200, s.TotalCPUTime()) 4096 require.Equal(t, time.Microsecond*300, s.ProcessCPUTime()) 4097 }) 4098 t.Run("EveryPart", func(t *testing.T) { 4099 ctx, cancel := context.WithCancel(xtest.Context(t)) 4100 defer cancel() 4101 ctrl := gomock.NewController(t) 4102 stream := NewMockQueryService_ExecuteQueryClient(ctrl) 4103 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 4104 Status: Ydb.StatusIds_SUCCESS, 4105 ResultSetIndex: 0, 4106 ResultSet: &Ydb.ResultSet{ 4107 Columns: []*Ydb.Column{ 4108 { 4109 Name: "a", 4110 Type: &Ydb.Type{ 4111 Type: &Ydb.Type_TypeId{ 4112 TypeId: Ydb.Type_UINT64, 4113 }, 4114 }, 4115 }, 4116 { 4117 Name: "b", 4118 Type: &Ydb.Type{ 4119 Type: &Ydb.Type_TypeId{ 4120 TypeId: Ydb.Type_UTF8, 4121 }, 4122 }, 4123 }, 4124 }, 4125 Rows: []*Ydb.Value{ 4126 { 4127 Items: []*Ydb.Value{{ 4128 Value: &Ydb.Value_Uint64Value{ 4129 Uint64Value: 1, 4130 }, 4131 }, { 4132 Value: &Ydb.Value_TextValue{ 4133 TextValue: "1", 4134 }, 4135 }}, 4136 }, 4137 { 4138 Items: []*Ydb.Value{{ 4139 Value: &Ydb.Value_Uint64Value{ 4140 Uint64Value: 2, 4141 }, 4142 }, { 4143 Value: &Ydb.Value_TextValue{ 4144 TextValue: "2", 4145 }, 4146 }}, 4147 }, 4148 { 4149 Items: []*Ydb.Value{{ 4150 Value: &Ydb.Value_Uint64Value{ 4151 Uint64Value: 3, 4152 }, 4153 }, { 4154 Value: &Ydb.Value_TextValue{ 4155 TextValue: "3", 4156 }, 4157 }}, 4158 }, 4159 }, 4160 }, 4161 ExecStats: &Ydb_TableStats.QueryStats{ 4162 ProcessCpuTimeUs: 1, 4163 QueryPlan: "sdsd", 4164 QueryAst: "sdffds", 4165 TotalDurationUs: 2, 4166 TotalCpuTimeUs: 3, 4167 }, 4168 }, nil) 4169 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 4170 Status: Ydb.StatusIds_SUCCESS, 4171 ResultSetIndex: 0, 4172 ResultSet: &Ydb.ResultSet{ 4173 Rows: []*Ydb.Value{ 4174 { 4175 Items: []*Ydb.Value{{ 4176 Value: &Ydb.Value_Uint64Value{ 4177 Uint64Value: 4, 4178 }, 4179 }, { 4180 Value: &Ydb.Value_TextValue{ 4181 TextValue: "4", 4182 }, 4183 }}, 4184 }, 4185 { 4186 Items: []*Ydb.Value{{ 4187 Value: &Ydb.Value_Uint64Value{ 4188 Uint64Value: 5, 4189 }, 4190 }, { 4191 Value: &Ydb.Value_TextValue{ 4192 TextValue: "5", 4193 }, 4194 }}, 4195 }, 4196 }, 4197 }, 4198 ExecStats: &Ydb_TableStats.QueryStats{ 4199 ProcessCpuTimeUs: 332400, 4200 QueryPlan: "12wesfse3", 4201 QueryAst: "sedfefs", 4202 TotalDurationUs: 10324320, 4203 TotalCpuTimeUs: 234, 4204 }, 4205 }, nil) 4206 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 4207 Status: Ydb.StatusIds_SUCCESS, 4208 ResultSetIndex: 1, 4209 ResultSet: &Ydb.ResultSet{ 4210 Columns: []*Ydb.Column{ 4211 { 4212 Name: "c", 4213 Type: &Ydb.Type{ 4214 Type: &Ydb.Type_TypeId{ 4215 TypeId: Ydb.Type_UINT64, 4216 }, 4217 }, 4218 }, 4219 { 4220 Name: "d", 4221 Type: &Ydb.Type{ 4222 Type: &Ydb.Type_TypeId{ 4223 TypeId: Ydb.Type_UTF8, 4224 }, 4225 }, 4226 }, 4227 { 4228 Name: "e", 4229 Type: &Ydb.Type{ 4230 Type: &Ydb.Type_TypeId{ 4231 TypeId: Ydb.Type_BOOL, 4232 }, 4233 }, 4234 }, 4235 }, 4236 Rows: []*Ydb.Value{ 4237 { 4238 Items: []*Ydb.Value{{ 4239 Value: &Ydb.Value_Uint64Value{ 4240 Uint64Value: 1, 4241 }, 4242 }, { 4243 Value: &Ydb.Value_TextValue{ 4244 TextValue: "1", 4245 }, 4246 }, { 4247 Value: &Ydb.Value_BoolValue{ 4248 BoolValue: true, 4249 }, 4250 }}, 4251 }, 4252 { 4253 Items: []*Ydb.Value{{ 4254 Value: &Ydb.Value_Uint64Value{ 4255 Uint64Value: 2, 4256 }, 4257 }, { 4258 Value: &Ydb.Value_TextValue{ 4259 TextValue: "2", 4260 }, 4261 }, { 4262 Value: &Ydb.Value_BoolValue{ 4263 BoolValue: false, 4264 }, 4265 }}, 4266 }, 4267 }, 4268 }, 4269 ExecStats: &Ydb_TableStats.QueryStats{ 4270 ProcessCpuTimeUs: 323400, 4271 QueryPlan: "sdfgrdg", 4272 QueryAst: "sdgsrg", 4273 TotalDurationUs: 43554, 4274 TotalCpuTimeUs: 235643, 4275 }, 4276 }, nil) 4277 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 4278 Status: Ydb.StatusIds_SUCCESS, 4279 ResultSetIndex: 1, 4280 ResultSet: &Ydb.ResultSet{ 4281 Rows: []*Ydb.Value{ 4282 { 4283 Items: []*Ydb.Value{{ 4284 Value: &Ydb.Value_Uint64Value{ 4285 Uint64Value: 3, 4286 }, 4287 }, { 4288 Value: &Ydb.Value_TextValue{ 4289 TextValue: "3", 4290 }, 4291 }, { 4292 Value: &Ydb.Value_BoolValue{ 4293 BoolValue: true, 4294 }, 4295 }}, 4296 }, 4297 { 4298 Items: []*Ydb.Value{{ 4299 Value: &Ydb.Value_Uint64Value{ 4300 Uint64Value: 4, 4301 }, 4302 }, { 4303 Value: &Ydb.Value_TextValue{ 4304 TextValue: "4", 4305 }, 4306 }, { 4307 Value: &Ydb.Value_BoolValue{ 4308 BoolValue: false, 4309 }, 4310 }}, 4311 }, 4312 { 4313 Items: []*Ydb.Value{{ 4314 Value: &Ydb.Value_Uint64Value{ 4315 Uint64Value: 5, 4316 }, 4317 }, { 4318 Value: &Ydb.Value_TextValue{ 4319 TextValue: "5", 4320 }, 4321 }, { 4322 Value: &Ydb.Value_BoolValue{ 4323 BoolValue: false, 4324 }, 4325 }}, 4326 }, 4327 }, 4328 }, 4329 ExecStats: &Ydb_TableStats.QueryStats{ 4330 ProcessCpuTimeUs: 3034564570, 4331 QueryPlan: "sdgsrgsg", 4332 QueryAst: "dghytjf", 4333 TotalDurationUs: 45676, 4334 TotalCpuTimeUs: 4562342, 4335 }, 4336 }, nil) 4337 stream.EXPECT().Recv().Return(&Ydb_Query.ExecuteQueryResponsePart{ 4338 Status: Ydb.StatusIds_SUCCESS, 4339 ResultSetIndex: 2, 4340 ResultSet: &Ydb.ResultSet{ 4341 Columns: []*Ydb.Column{ 4342 { 4343 Name: "c", 4344 Type: &Ydb.Type{ 4345 Type: &Ydb.Type_TypeId{ 4346 TypeId: Ydb.Type_UINT64, 4347 }, 4348 }, 4349 }, 4350 { 4351 Name: "d", 4352 Type: &Ydb.Type{ 4353 Type: &Ydb.Type_TypeId{ 4354 TypeId: Ydb.Type_UTF8, 4355 }, 4356 }, 4357 }, 4358 { 4359 Name: "e", 4360 Type: &Ydb.Type{ 4361 Type: &Ydb.Type_TypeId{ 4362 TypeId: Ydb.Type_BOOL, 4363 }, 4364 }, 4365 }, 4366 }, 4367 Rows: []*Ydb.Value{ 4368 { 4369 Items: []*Ydb.Value{{ 4370 Value: &Ydb.Value_Uint64Value{ 4371 Uint64Value: 1, 4372 }, 4373 }, { 4374 Value: &Ydb.Value_TextValue{ 4375 TextValue: "1", 4376 }, 4377 }, { 4378 Value: &Ydb.Value_BoolValue{ 4379 BoolValue: true, 4380 }, 4381 }}, 4382 }, 4383 { 4384 Items: []*Ydb.Value{{ 4385 Value: &Ydb.Value_Uint64Value{ 4386 Uint64Value: 2, 4387 }, 4388 }, { 4389 Value: &Ydb.Value_TextValue{ 4390 TextValue: "2", 4391 }, 4392 }, { 4393 Value: &Ydb.Value_BoolValue{ 4394 BoolValue: false, 4395 }, 4396 }}, 4397 }, 4398 }, 4399 }, 4400 ExecStats: &Ydb_TableStats.QueryStats{ 4401 ProcessCpuTimeUs: 300, 4402 QueryPlan: "123", 4403 QueryAst: "456", 4404 TotalDurationUs: 100, 4405 TotalCpuTimeUs: 200, 4406 }, 4407 }, nil) 4408 stream.EXPECT().Recv().Return(nil, io.EOF) 4409 var s stats.QueryStats 4410 result, err := newResult(ctx, stream, withStatsCallback(func(queryStats stats.QueryStats) { 4411 s = queryStats 4412 })) 4413 require.NoError(t, err) 4414 require.NotNil(t, result) 4415 defer result.Close(ctx) 4416 for { 4417 resultSet, err := result.NextResultSet(ctx) 4418 if err != nil && xerrors.Is(err, io.EOF) { 4419 break 4420 } 4421 for { 4422 _, err := resultSet.NextRow(ctx) 4423 if err != nil && xerrors.Is(err, io.EOF) { 4424 break 4425 } 4426 } 4427 } 4428 require.NotNil(t, s) 4429 require.Equal(t, "123", s.QueryPlan()) 4430 require.Equal(t, "456", s.QueryAST()) 4431 require.Equal(t, time.Microsecond*100, s.TotalDuration()) 4432 require.Equal(t, time.Microsecond*200, s.TotalCPUTime()) 4433 require.Equal(t, time.Microsecond*300, s.ProcessCPUTime()) 4434 }) 4435 }) 4436 }