github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/internal/query/execute_query.go (about)

     1  package query
     2  
     3  import (
     4  	"context"
     5  	"io"
     6  	"time"
     7  
     8  	"github.com/ydb-platform/ydb-go-genproto/Ydb_Query_V1"
     9  	"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Operations"
    10  	"github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query"
    11  	"google.golang.org/grpc"
    12  	"google.golang.org/protobuf/types/known/durationpb"
    13  
    14  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/allocator"
    15  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/params"
    16  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/query/options"
    17  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/xcontext"
    18  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors"
    19  	"github.com/ydb-platform/ydb-go-sdk/v3/query"
    20  	"github.com/ydb-platform/ydb-go-sdk/v3/retry"
    21  	"github.com/ydb-platform/ydb-go-sdk/v3/table/stats"
    22  )
    23  
    24  type executeSettings interface {
    25  	ExecMode() options.ExecMode
    26  	StatsMode() options.StatsMode
    27  	StatsCallback() func(stats stats.QueryStats)
    28  	TxControl() *query.TransactionControl
    29  	Syntax() options.Syntax
    30  	Params() *params.Parameters
    31  	CallOptions() []grpc.CallOption
    32  	RetryOpts() []retry.Option
    33  	ResourcePool() string
    34  }
    35  
    36  type executeScriptConfig interface {
    37  	executeSettings
    38  
    39  	ResultsTTL() time.Duration
    40  	OperationParams() *Ydb_Operations.OperationParams
    41  }
    42  
    43  func executeQueryScriptRequest(a *allocator.Allocator, q string, cfg executeScriptConfig) (
    44  	*Ydb_Query.ExecuteScriptRequest,
    45  	[]grpc.CallOption,
    46  ) {
    47  	request := &Ydb_Query.ExecuteScriptRequest{
    48  		OperationParams: &Ydb_Operations.OperationParams{
    49  			OperationMode:    0,
    50  			OperationTimeout: nil,
    51  			CancelAfter:      nil,
    52  			Labels:           nil,
    53  			ReportCostInfo:   0,
    54  		},
    55  		ExecMode:      Ydb_Query.ExecMode(cfg.ExecMode()),
    56  		ScriptContent: queryQueryContent(a, Ydb_Query.Syntax(cfg.Syntax()), q),
    57  		Parameters:    cfg.Params().ToYDB(a),
    58  		StatsMode:     Ydb_Query.StatsMode(cfg.StatsMode()),
    59  		ResultsTtl:    durationpb.New(cfg.ResultsTTL()),
    60  		PoolId:        cfg.ResourcePool(),
    61  	}
    62  
    63  	return request, cfg.CallOptions()
    64  }
    65  
    66  func executeQueryRequest(a *allocator.Allocator, sessionID, q string, cfg executeSettings) (
    67  	*Ydb_Query.ExecuteQueryRequest,
    68  	[]grpc.CallOption,
    69  ) {
    70  	request := a.QueryExecuteQueryRequest()
    71  
    72  	request.SessionId = sessionID
    73  	request.ExecMode = Ydb_Query.ExecMode(cfg.ExecMode())
    74  	request.TxControl = cfg.TxControl().ToYDB(a)
    75  	request.Query = queryFromText(a, q, Ydb_Query.Syntax(cfg.Syntax()))
    76  	request.Parameters = cfg.Params().ToYDB(a)
    77  	request.StatsMode = Ydb_Query.StatsMode(cfg.StatsMode())
    78  	request.ConcurrentResultSets = false
    79  	request.PoolId = cfg.ResourcePool()
    80  
    81  	return request, cfg.CallOptions()
    82  }
    83  
    84  func queryQueryContent(a *allocator.Allocator, syntax Ydb_Query.Syntax, q string) *Ydb_Query.QueryContent {
    85  	content := a.QueryQueryContent()
    86  	content.Syntax = syntax
    87  	content.Text = q
    88  
    89  	return content
    90  }
    91  
    92  func queryFromText(
    93  	a *allocator.Allocator, q string, syntax Ydb_Query.Syntax,
    94  ) *Ydb_Query.ExecuteQueryRequest_QueryContent {
    95  	content := a.QueryExecuteQueryRequestQueryContent()
    96  	content.QueryContent = queryQueryContent(a, syntax, q)
    97  
    98  	return content
    99  }
   100  
   101  func execute(
   102  	ctx context.Context, sessionID string, c Ydb_Query_V1.QueryServiceClient,
   103  	q string, settings executeSettings, opts ...resultOption,
   104  ) (
   105  	_ *streamResult, finalErr error,
   106  ) {
   107  	a := allocator.New()
   108  	defer a.Free()
   109  
   110  	request, callOptions := executeQueryRequest(a, sessionID, q, settings)
   111  
   112  	executeCtx := xcontext.ValueOnly(ctx)
   113  
   114  	stream, err := c.ExecuteQuery(executeCtx, request, callOptions...)
   115  	if err != nil {
   116  		return nil, xerrors.WithStackTrace(err)
   117  	}
   118  
   119  	r, err := newResult(ctx, stream, append(opts, withStatsCallback(settings.StatsCallback()))...)
   120  	if err != nil {
   121  		return nil, xerrors.WithStackTrace(err)
   122  	}
   123  
   124  	return r, nil
   125  }
   126  
   127  func readAll(ctx context.Context, r *streamResult) error {
   128  	defer func() {
   129  		_ = r.Close(ctx)
   130  	}()
   131  
   132  	for {
   133  		_, err := r.nextResultSet(ctx)
   134  		if err != nil {
   135  			if xerrors.Is(err, io.EOF) {
   136  				return nil
   137  			}
   138  
   139  			return xerrors.WithStackTrace(err)
   140  		}
   141  	}
   142  }
   143  
   144  func readResultSet(ctx context.Context, r *streamResult) (_ *resultSetWithClose, finalErr error) {
   145  	rs, err := r.nextResultSet(ctx)
   146  	if err != nil {
   147  		return nil, xerrors.WithStackTrace(err)
   148  	}
   149  
   150  	_, err = r.nextResultSet(ctx)
   151  	if err == nil {
   152  		return nil, xerrors.WithStackTrace(errMoreThanOneResultSet)
   153  	}
   154  	if !xerrors.Is(err, io.EOF) {
   155  		return nil, xerrors.WithStackTrace(err)
   156  	}
   157  
   158  	return &resultSetWithClose{
   159  		resultSet: rs,
   160  		close:     r.Close,
   161  	}, nil
   162  }
   163  
   164  func readMaterializedResultSet(ctx context.Context, r *streamResult) (_ *materializedResultSet, finalErr error) {
   165  	defer func() {
   166  		_ = r.Close(ctx)
   167  	}()
   168  
   169  	rs, err := r.nextResultSet(ctx)
   170  	if err != nil {
   171  		return nil, xerrors.WithStackTrace(err)
   172  	}
   173  
   174  	var rows []query.Row
   175  	for {
   176  		row, err := rs.nextRow(ctx)
   177  		if err != nil {
   178  			if xerrors.Is(err, io.EOF) {
   179  				break
   180  			}
   181  
   182  			return nil, xerrors.WithStackTrace(err)
   183  		}
   184  
   185  		rows = append(rows, row)
   186  	}
   187  
   188  	_, err = r.nextResultSet(ctx)
   189  	if err == nil {
   190  		return nil, xerrors.WithStackTrace(errMoreThanOneResultSet)
   191  	}
   192  	if !xerrors.Is(err, io.EOF) {
   193  		return nil, xerrors.WithStackTrace(err)
   194  	}
   195  
   196  	return MaterializedResultSet(rs.Index(), rs.Columns(), rs.ColumnTypes(), rows), nil
   197  }
   198  
   199  func readRow(ctx context.Context, r *streamResult) (_ *Row, finalErr error) {
   200  	defer func() {
   201  		_ = r.Close(ctx)
   202  	}()
   203  
   204  	rs, err := r.nextResultSet(ctx)
   205  	if err != nil {
   206  		return nil, xerrors.WithStackTrace(err)
   207  	}
   208  
   209  	row, err := rs.nextRow(ctx)
   210  	if err != nil {
   211  		return nil, xerrors.WithStackTrace(err)
   212  	}
   213  
   214  	_, err = rs.nextRow(ctx)
   215  	if err == nil {
   216  		return nil, xerrors.WithStackTrace(errMoreThanOneRow)
   217  	}
   218  	if !xerrors.Is(err, io.EOF) {
   219  		return nil, xerrors.WithStackTrace(err)
   220  	}
   221  
   222  	_, err = r.NextResultSet(ctx)
   223  	if err == nil {
   224  		return nil, xerrors.WithStackTrace(errMoreThanOneResultSet)
   225  	}
   226  	if !xerrors.Is(err, io.EOF) {
   227  		return nil, xerrors.WithStackTrace(err)
   228  	}
   229  
   230  	return row, nil
   231  }