github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/table/table.go (about) 1 package table 2 3 import ( 4 "context" 5 "time" 6 7 "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Formats" 8 "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Table" 9 10 "github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator" 11 "github.com/ydb-platform/ydb-go-sdk/v3/internal/closer" 12 "github.com/ydb-platform/ydb-go-sdk/v3/internal/params" 13 "github.com/ydb-platform/ydb-go-sdk/v3/internal/tx" 14 "github.com/ydb-platform/ydb-go-sdk/v3/internal/types" 15 "github.com/ydb-platform/ydb-go-sdk/v3/internal/value" 16 "github.com/ydb-platform/ydb-go-sdk/v3/retry" 17 "github.com/ydb-platform/ydb-go-sdk/v3/retry/budget" 18 "github.com/ydb-platform/ydb-go-sdk/v3/table/options" 19 "github.com/ydb-platform/ydb-go-sdk/v3/table/result" 20 "github.com/ydb-platform/ydb-go-sdk/v3/trace" 21 ) 22 23 // Operation is the interface that holds an operation for retry. 24 // if Operation returns not nil - operation will retry 25 // if Operation returns nil - retry loop will break 26 type Operation func(ctx context.Context, s Session) error 27 28 // TxOperation is the interface that holds an operation for retry. 29 // if TxOperation returns not nil - operation will retry 30 // if TxOperation returns nil - retry loop will break 31 type TxOperation func(ctx context.Context, tx TransactionActor) error 32 33 type ClosableSession interface { 34 closer.Closer 35 36 Session 37 } 38 39 type Client interface { 40 // CreateSession returns session or error for manually control of session lifecycle 41 // 42 // CreateSession implements internal busy loop until one of the following conditions is met: 43 // - context was canceled or deadlined 44 // - session was created 45 // 46 // Deprecated: not for public usage. Because explicit session often leaked on server-side due to bad client-side usage. 47 // Will be removed after Oct 2024. 48 // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated 49 CreateSession(ctx context.Context, opts ...Option) (s ClosableSession, err error) 50 51 // Do provide the best effort for execute operation. 52 // 53 // Do implements internal busy loop until one of the following conditions is met: 54 // - deadline was canceled or deadlined 55 // - retry operation returned nil as error 56 // 57 // Warning: if context without deadline or cancellation func than Do can run indefinitely. 58 Do(ctx context.Context, op Operation, opts ...Option) error 59 60 // DoTx provide the best effort for execute transaction. 61 // 62 // DoTx implements internal busy loop until one of the following conditions is met: 63 // - deadline was canceled or deadlined 64 // - retry operation returned nil as error 65 // 66 // DoTx makes auto begin (with TxSettings, by default - SerializableReadWrite), commit and 67 // rollback (on error) of transaction. 68 // 69 // If op TxOperation returns nil - transaction will be committed 70 // If op TxOperation return non nil - transaction will be rollback 71 // Warning: if context without deadline or cancellation func than DoTx can run indefinitely 72 DoTx(ctx context.Context, op TxOperation, opts ...Option) error 73 74 // BulkUpsert upserts a batch of rows non-transactionally. 75 // 76 // Returns success only when all rows were successfully upserted. In case of an error some rows might 77 // be upserted and some might not. 78 BulkUpsert(ctx context.Context, table string, data BulkUpsertData, opts ...Option) error 79 } 80 81 type SessionStatus = string 82 83 const ( 84 SessionStatusUnknown = SessionStatus("unknown") 85 SessionReady = SessionStatus("ready") 86 SessionBusy = SessionStatus("busy") 87 SessionClosing = SessionStatus("closing") 88 SessionClosed = SessionStatus("closed") 89 ) 90 91 type SessionInfo interface { 92 ID() string 93 NodeID() uint32 94 Status() SessionStatus 95 LastUsage() time.Time 96 } 97 98 type Session interface { 99 SessionInfo 100 101 CreateTable( 102 ctx context.Context, 103 path string, 104 opts ...options.CreateTableOption, 105 ) (err error) 106 107 DescribeTable( 108 ctx context.Context, 109 path string, 110 opts ...options.DescribeTableOption, 111 ) (desc options.Description, err error) 112 113 DropTable( 114 ctx context.Context, 115 path string, 116 opts ...options.DropTableOption, 117 ) (err error) 118 119 AlterTable( 120 ctx context.Context, 121 path string, 122 opts ...options.AlterTableOption, 123 ) (err error) 124 125 // Deprecated: use CopyTables method instead 126 // Will be removed after Oct 2024. 127 // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated 128 CopyTable( 129 ctx context.Context, 130 dst, src string, 131 opts ...options.CopyTableOption, 132 ) (err error) 133 134 CopyTables( 135 ctx context.Context, 136 opts ...options.CopyTablesOption, 137 ) (err error) 138 139 RenameTables( 140 ctx context.Context, 141 opts ...options.RenameTablesOption, 142 ) (err error) 143 144 Explain( 145 ctx context.Context, 146 query string, 147 ) (exp DataQueryExplanation, err error) 148 149 // Prepare prepares query for executing in the future 150 Prepare( 151 ctx context.Context, 152 query string, 153 ) (stmt Statement, err error) 154 155 // Execute executes query. 156 // 157 // By default, Execute have a flag options.WithKeepInCache(true) if params is not empty. For redefine behavior - 158 // append option options.WithKeepInCache(false) 159 Execute( 160 ctx context.Context, 161 tx *TransactionControl, 162 query string, 163 params *params.Parameters, 164 opts ...options.ExecuteDataQueryOption, 165 ) (txr Transaction, r result.Result, err error) 166 167 ExecuteSchemeQuery( 168 ctx context.Context, 169 query string, 170 opts ...options.ExecuteSchemeQueryOption, 171 ) (err error) 172 173 DescribeTableOptions( 174 ctx context.Context, 175 ) (desc options.TableOptionsDescription, err error) 176 177 StreamReadTable( 178 ctx context.Context, 179 path string, 180 opts ...options.ReadTableOption, 181 ) (r result.StreamResult, err error) 182 183 StreamExecuteScanQuery( 184 ctx context.Context, 185 query string, 186 params *params.Parameters, 187 opts ...options.ExecuteScanQueryOption, 188 ) (_ result.StreamResult, err error) 189 190 // Deprecated: use Client instance instead. 191 BulkUpsert( 192 ctx context.Context, 193 table string, 194 rows value.Value, 195 opts ...options.BulkUpsertOption, 196 ) (err error) 197 198 ReadRows( 199 ctx context.Context, 200 path string, 201 keys value.Value, 202 opts ...options.ReadRowsOption, 203 ) (_ result.Result, err error) 204 205 BeginTransaction( 206 ctx context.Context, 207 tx *TransactionSettings, 208 ) (x Transaction, err error) 209 210 KeepAlive( 211 ctx context.Context, 212 ) error 213 } 214 215 type TransactionSettings struct { 216 settings Ydb_Table.TransactionSettings 217 } 218 219 func (t *TransactionSettings) Settings() *Ydb_Table.TransactionSettings { 220 if t == nil { 221 return nil 222 } 223 224 return &t.settings 225 } 226 227 // Explanation is a result of Explain calls. 228 type Explanation struct { 229 Plan string 230 } 231 232 // ScriptingYQLExplanation is a result of Explain calls. 233 type ScriptingYQLExplanation struct { 234 Explanation 235 236 ParameterTypes map[string]types.Type 237 } 238 239 // DataQueryExplanation is a result of ExplainDataQuery call. 240 type DataQueryExplanation struct { 241 Explanation 242 243 AST string 244 } 245 246 // DataQuery only for tracers 247 type DataQuery interface { 248 String() string 249 ID() string 250 YQL() string 251 } 252 253 type TransactionIdentifier = tx.Identifier 254 255 type TransactionActor interface { 256 TransactionIdentifier 257 258 Execute( 259 ctx context.Context, 260 query string, 261 params *params.Parameters, 262 opts ...options.ExecuteDataQueryOption, 263 ) (result.Result, error) 264 ExecuteStatement( 265 ctx context.Context, 266 stmt Statement, 267 params *params.Parameters, 268 opts ...options.ExecuteDataQueryOption, 269 ) (result.Result, error) 270 } 271 272 type Transaction interface { 273 TransactionActor 274 275 CommitTx( 276 ctx context.Context, 277 opts ...options.CommitTransactionOption, 278 ) (r result.Result, err error) 279 Rollback( 280 ctx context.Context, 281 ) (err error) 282 } 283 284 type Statement interface { 285 Execute( 286 ctx context.Context, 287 tx *TransactionControl, 288 params *params.Parameters, 289 opts ...options.ExecuteDataQueryOption, 290 ) (txr Transaction, r result.Result, err error) 291 NumInput() int 292 Text() string 293 } 294 295 var ( 296 serializableReadWrite = &Ydb_Table.TransactionSettings_SerializableReadWrite{ 297 SerializableReadWrite: &Ydb_Table.SerializableModeSettings{}, 298 } 299 staleReadOnly = &Ydb_Table.TransactionSettings_StaleReadOnly{ 300 StaleReadOnly: &Ydb_Table.StaleModeSettings{}, 301 } 302 snapshotReadOnly = &Ydb_Table.TransactionSettings_SnapshotReadOnly{ 303 SnapshotReadOnly: &Ydb_Table.SnapshotModeSettings{}, 304 } 305 ) 306 307 // Transaction control options 308 type ( 309 txDesc Ydb_Table.TransactionSettings 310 TxOption func(*txDesc) 311 ) 312 313 // TxSettings returns transaction settings 314 func TxSettings(opts ...TxOption) *TransactionSettings { 315 s := new(TransactionSettings) 316 for _, opt := range opts { 317 if opt != nil { 318 opt((*txDesc)(&s.settings)) 319 } 320 } 321 322 return s 323 } 324 325 // BeginTx returns begin transaction control option 326 func BeginTx(opts ...TxOption) TxControlOption { 327 return func(d *txControlDesc) { 328 s := TxSettings(opts...) 329 d.TxSelector = &Ydb_Table.TransactionControl_BeginTx{ 330 BeginTx: &s.settings, 331 } 332 } 333 } 334 335 func WithTx(t TransactionIdentifier) TxControlOption { 336 return func(d *txControlDesc) { 337 d.TxSelector = &Ydb_Table.TransactionControl_TxId{ 338 TxId: t.ID(), 339 } 340 } 341 } 342 343 func WithTxID(txID string) TxControlOption { 344 return func(d *txControlDesc) { 345 d.TxSelector = &Ydb_Table.TransactionControl_TxId{ 346 TxId: txID, 347 } 348 } 349 } 350 351 // CommitTx returns commit transaction control option 352 func CommitTx() TxControlOption { 353 return func(d *txControlDesc) { 354 d.CommitTx = true 355 } 356 } 357 358 func WithSerializableReadWrite() TxOption { 359 return func(d *txDesc) { 360 d.TxMode = serializableReadWrite 361 } 362 } 363 364 func WithSnapshotReadOnly() TxOption { 365 return func(d *txDesc) { 366 d.TxMode = snapshotReadOnly 367 } 368 } 369 370 func WithStaleReadOnly() TxOption { 371 return func(d *txDesc) { 372 d.TxMode = staleReadOnly 373 } 374 } 375 376 func WithOnlineReadOnly(opts ...TxOnlineReadOnlyOption) TxOption { 377 return func(d *txDesc) { 378 var ro txOnlineReadOnly 379 for _, opt := range opts { 380 if opt != nil { 381 opt(&ro) 382 } 383 } 384 d.TxMode = &Ydb_Table.TransactionSettings_OnlineReadOnly{ 385 OnlineReadOnly: (*Ydb_Table.OnlineModeSettings)(&ro), 386 } 387 } 388 } 389 390 type ( 391 txOnlineReadOnly Ydb_Table.OnlineModeSettings 392 TxOnlineReadOnlyOption func(*txOnlineReadOnly) 393 ) 394 395 func WithInconsistentReads() TxOnlineReadOnlyOption { 396 return func(d *txOnlineReadOnly) { 397 d.AllowInconsistentReads = true 398 } 399 } 400 401 type ( 402 txControlDesc Ydb_Table.TransactionControl 403 TxControlOption func(*txControlDesc) 404 ) 405 406 type TransactionControl struct { 407 desc Ydb_Table.TransactionControl 408 } 409 410 func (t *TransactionControl) Desc() *Ydb_Table.TransactionControl { 411 if t == nil { 412 return nil 413 } 414 415 return &t.desc 416 } 417 418 // TxControl makes transaction control from given options 419 func TxControl(opts ...TxControlOption) *TransactionControl { 420 c := new(TransactionControl) 421 for _, opt := range opts { 422 if opt != nil { 423 opt((*txControlDesc)(&c.desc)) 424 } 425 } 426 427 return c 428 } 429 430 // DefaultTxControl returns default transaction control with serializable read-write isolation mode and auto-commit 431 func DefaultTxControl() *TransactionControl { 432 return TxControl( 433 BeginTx(WithSerializableReadWrite()), 434 CommitTx(), 435 ) 436 } 437 438 // SerializableReadWriteTxControl returns transaction control with serializable read-write isolation mode 439 func SerializableReadWriteTxControl(opts ...TxControlOption) *TransactionControl { 440 return TxControl( 441 append([]TxControlOption{ 442 BeginTx(WithSerializableReadWrite()), 443 }, opts...)..., 444 ) 445 } 446 447 // OnlineReadOnlyTxControl returns online read-only transaction control 448 func OnlineReadOnlyTxControl(opts ...TxOnlineReadOnlyOption) *TransactionControl { 449 return TxControl( 450 BeginTx(WithOnlineReadOnly(opts...)), 451 CommitTx(), // open transactions not supported for OnlineReadOnly 452 ) 453 } 454 455 // StaleReadOnlyTxControl returns stale read-only transaction control 456 func StaleReadOnlyTxControl() *TransactionControl { 457 return TxControl( 458 BeginTx(WithStaleReadOnly()), 459 CommitTx(), // open transactions not supported for StaleReadOnly 460 ) 461 } 462 463 // SnapshotReadOnlyTxControl returns snapshot read-only transaction control 464 func SnapshotReadOnlyTxControl() *TransactionControl { 465 return TxControl( 466 BeginTx(WithSnapshotReadOnly()), 467 CommitTx(), // open transactions not supported for StaleReadOnly 468 ) 469 } 470 471 // QueryParameters 472 type ( 473 ParameterOption = params.NamedValue 474 QueryParameters = params.Parameters 475 ) 476 477 func NewQueryParameters(opts ...ParameterOption) *QueryParameters { 478 qp := QueryParameters(make([]*params.Parameter, len(opts))) 479 for i, opt := range opts { 480 if opt != nil { 481 qp[i] = params.Named(opt.Name(), opt.Value()) 482 } 483 } 484 485 return &qp 486 } 487 488 func ValueParam(name string, v value.Value) ParameterOption { 489 switch len(name) { 490 case 0: 491 panic("empty name") 492 default: 493 if name[0] != '$' { 494 name = "$" + name 495 } 496 } 497 498 return params.Named(name, v) 499 } 500 501 type Options struct { 502 Label string 503 Idempotent bool 504 TxSettings *TransactionSettings 505 TxCommitOptions []options.CommitTransactionOption 506 RetryOptions []retry.Option 507 Trace *trace.Table 508 } 509 510 type Option interface { 511 ApplyTableOption(opts *Options) 512 } 513 514 var _ Option = labelOption("") 515 516 type labelOption string 517 518 func (label labelOption) ApplyTableOption(opts *Options) { 519 opts.Label = string(label) 520 opts.RetryOptions = append(opts.RetryOptions, retry.WithLabel(string(label))) 521 } 522 523 func WithLabel(label string) labelOption { 524 return labelOption(label) 525 } 526 527 var _ Option = retryOptionsOption{} 528 529 type retryOptionsOption []retry.Option 530 531 func (retryOptions retryOptionsOption) ApplyTableOption(opts *Options) { 532 opts.RetryOptions = append(opts.RetryOptions, retryOptions...) 533 } 534 535 // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental 536 func WithRetryBudget(b budget.Budget) retryOptionsOption { 537 return []retry.Option{retry.WithBudget(b)} 538 } 539 540 // Deprecated: redundant option 541 // Will be removed after Oct 2024. 542 // Read about versioning policy: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#deprecated 543 func WithRetryOptions(retryOptions []retry.Option) retryOptionsOption { 544 return retryOptions 545 } 546 547 func WithIdempotent() retryOptionsOption { 548 return []retry.Option{retry.WithIdempotent(true)} 549 } 550 551 var _ Option = txSettingsOption{} 552 553 type txSettingsOption struct { 554 txSettings *TransactionSettings 555 } 556 557 func (opt txSettingsOption) ApplyTableOption(opts *Options) { 558 opts.TxSettings = opt.txSettings 559 } 560 561 func WithTxSettings(txSettings *TransactionSettings) txSettingsOption { 562 return txSettingsOption{txSettings: txSettings} 563 } 564 565 var _ Option = txCommitOptionsOption(nil) 566 567 type txCommitOptionsOption []options.CommitTransactionOption 568 569 func (txCommitOpts txCommitOptionsOption) ApplyTableOption(opts *Options) { 570 opts.TxCommitOptions = append(opts.TxCommitOptions, txCommitOpts...) 571 } 572 573 func WithTxCommitOptions(opts ...options.CommitTransactionOption) txCommitOptionsOption { 574 return opts 575 } 576 577 var _ Option = traceOption{} 578 579 type traceOption struct { 580 t *trace.Table 581 } 582 583 func (opt traceOption) ApplyTableOption(opts *Options) { 584 opts.Trace = opts.Trace.Compose(opt.t) 585 } 586 587 func WithTrace(t trace.Table) traceOption { //nolint:gocritic 588 return traceOption{t: &t} 589 } 590 591 type BulkUpsertData interface { 592 ToYDB(a *allocator.Allocator, tableName string) (*Ydb_Table.BulkUpsertRequest, error) 593 } 594 595 type bulkUpsertRows struct { 596 rows value.Value 597 } 598 599 func (data bulkUpsertRows) ToYDB(a *allocator.Allocator, tableName string) (*Ydb_Table.BulkUpsertRequest, error) { 600 return &Ydb_Table.BulkUpsertRequest{ 601 Table: tableName, 602 Rows: value.ToYDB(data.rows, a), 603 }, nil 604 } 605 606 func BulkUpsertDataRows(rows value.Value) bulkUpsertRows { 607 return bulkUpsertRows{ 608 rows: rows, 609 } 610 } 611 612 type bulkUpsertCsv struct { 613 data []byte 614 opts []csvFormatOption 615 } 616 617 type csvFormatOption interface { 618 applyCsvFormatOption(dataFormat *Ydb_Table.BulkUpsertRequest_CsvSettings) (err error) 619 } 620 621 func (data bulkUpsertCsv) ToYDB(a *allocator.Allocator, tableName string) (*Ydb_Table.BulkUpsertRequest, error) { 622 var ( 623 request = &Ydb_Table.BulkUpsertRequest{ 624 Table: tableName, 625 Data: data.data, 626 } 627 dataFormat = &Ydb_Table.BulkUpsertRequest_CsvSettings{ 628 CsvSettings: &Ydb_Formats.CsvSettings{}, 629 } 630 ) 631 632 for _, opt := range data.opts { 633 if opt != nil { 634 if err := opt.applyCsvFormatOption(dataFormat); err != nil { 635 return nil, err 636 } 637 } 638 } 639 640 request.DataFormat = dataFormat 641 642 return request, nil 643 } 644 645 func BulkUpsertDataCsv(data []byte, opts ...csvFormatOption) bulkUpsertCsv { 646 return bulkUpsertCsv{ 647 data: data, 648 opts: opts, 649 } 650 } 651 652 type csvHeaderOption struct{} 653 654 func (opt *csvHeaderOption) applyCsvFormatOption(dataFormat *Ydb_Table.BulkUpsertRequest_CsvSettings) error { 655 dataFormat.CsvSettings.Header = true 656 657 return nil 658 } 659 660 // First not skipped line is a CSV header (list of column names). 661 func WithCsvHeader() csvFormatOption { 662 return &csvHeaderOption{} 663 } 664 665 type csvNullValueOption []byte 666 667 func (nullValue csvNullValueOption) applyCsvFormatOption(dataFormat *Ydb_Table.BulkUpsertRequest_CsvSettings) error { 668 dataFormat.CsvSettings.NullValue = nullValue 669 670 return nil 671 } 672 673 // String value that would be interpreted as NULL. 674 func WithCsvNullValue(value []byte) csvFormatOption { 675 return csvNullValueOption(value) 676 } 677 678 type csvDelimiterOption []byte 679 680 func (delimeter csvDelimiterOption) applyCsvFormatOption(dataFormat *Ydb_Table.BulkUpsertRequest_CsvSettings) error { 681 dataFormat.CsvSettings.Delimiter = delimeter 682 683 return nil 684 } 685 686 // Fields delimiter in CSV file. It's "," if not set. 687 func WithCsvDelimiter(value []byte) csvFormatOption { 688 return csvDelimiterOption(value) 689 } 690 691 type csvSkipRowsOption uint32 692 693 func (skipRows csvSkipRowsOption) applyCsvFormatOption(dataFormat *Ydb_Table.BulkUpsertRequest_CsvSettings) error { 694 dataFormat.CsvSettings.SkipRows = uint32(skipRows) 695 696 return nil 697 } 698 699 // Number of rows to skip before CSV data. It should be present only in the first upsert of CSV file. 700 func WithCsvSkipRows(skipRows uint32) csvFormatOption { 701 return csvSkipRowsOption(skipRows) 702 } 703 704 type bulkUpsertArrow struct { 705 data []byte 706 opts []arrowFormatOption 707 } 708 709 type arrowFormatOption interface { 710 applyArrowFormatOption(req *Ydb_Table.BulkUpsertRequest_ArrowBatchSettings) (err error) 711 } 712 713 func (data bulkUpsertArrow) ToYDB(a *allocator.Allocator, tableName string) (*Ydb_Table.BulkUpsertRequest, error) { 714 var ( 715 request = &Ydb_Table.BulkUpsertRequest{ 716 Table: tableName, 717 Data: data.data, 718 } 719 dataFormat = &Ydb_Table.BulkUpsertRequest_ArrowBatchSettings{ 720 ArrowBatchSettings: &Ydb_Formats.ArrowBatchSettings{}, 721 } 722 ) 723 724 for _, opt := range data.opts { 725 if opt != nil { 726 if err := opt.applyArrowFormatOption(dataFormat); err != nil { 727 return nil, err 728 } 729 } 730 } 731 732 request.DataFormat = dataFormat 733 734 return request, nil 735 } 736 737 func BulkUpsertDataArrow(data []byte, opts ...arrowFormatOption) bulkUpsertArrow { 738 return bulkUpsertArrow{ 739 data: data, 740 opts: opts, 741 } 742 } 743 744 type arrowSchemaOption []byte 745 746 func (schema arrowSchemaOption) applyArrowFormatOption( 747 dataFormat *Ydb_Table.BulkUpsertRequest_ArrowBatchSettings, 748 ) error { 749 dataFormat.ArrowBatchSettings.Schema = schema 750 751 return nil 752 } 753 754 func WithArrowSchema(schema []byte) arrowFormatOption { 755 return arrowSchemaOption(schema) 756 }