// StreamExecute2 starts a streaming query to VTTablet. This differs from StreamExecute in that // it expects errors to be returned as part of the StreamExecute results. func (conn *TabletBson) StreamExecute2(ctx context.Context, query string, bindVars map[string]interface{}, transactionID int64) (<-chan *mproto.QueryResult, tabletconn.ErrFunc, error) { conn.mu.RLock() defer conn.mu.RUnlock() if conn.rpcClient == nil { return nil, nil, tabletconn.ConnClosed } req := &tproto.StreamExecuteRequest{ Target: conn.target, EffectiveCallerID: getEffectiveCallerID(ctx), ImmediateCallerID: getImmediateCallerID(ctx), Query: &tproto.Query{ Sql: query, BindVariables: bindVars, TransactionId: transactionID, SessionId: conn.sessionID, }, } // Use QueryResult instead of StreamExecuteResult for now, due to backwards compatability reasons. // It'll be easuer to migrate all end-points to using StreamExecuteResult instead of // maintaining a mixture of QueryResult and StreamExecuteResult channel returns. sr := make(chan *mproto.QueryResult, 10) c := conn.rpcClient.StreamGo("SqlQuery.StreamExecute2", req, sr) firstResult, ok := <-sr if !ok { return nil, nil, tabletError(c.Error) } // SqlQuery.StreamExecute might return an application error inside the QueryResult vtErr := vterrors.FromRPCError(firstResult.Err) if vtErr != nil { return nil, nil, tabletError(vtErr) } srout := make(chan *mproto.QueryResult, 1) go func() { defer close(srout) srout <- firstResult for r := range sr { vtErr = vterrors.FromRPCError(r.Err) // If we get a QueryResult with an RPCError, that was an extra QueryResult sent by // the server specifically to indicate an error, and we shouldn't surface it to clients. if vtErr == nil { srout <- r } } }() // errFunc will return either an RPC-layer error or an application error, if one exists. // It will only return the most recent application error (i.e, from the QueryResult that // most recently contained an error). It will prioritize an RPC-layer error over an apperror, // if both exist. errFunc := func() error { rpcErr := tabletError(c.Error) if rpcErr != nil { return rpcErr } return tabletError(vtErr) } return srout, errFunc, nil }
// StreamExecute starts a streaming query to VTTablet. func (conn *TabletBson) StreamExecute(ctx context.Context, query string, bindVars map[string]interface{}, transactionID int64) (<-chan *mproto.QueryResult, tabletconn.ErrFunc, error) { conn.mu.RLock() defer conn.mu.RUnlock() if conn.rpcClient == nil { return nil, nil, tabletconn.ConnClosed } req := &tproto.Query{ Sql: query, BindVariables: bindVars, TransactionId: transactionID, SessionId: conn.sessionID, } sr := make(chan *mproto.QueryResult, 10) c := conn.rpcClient.StreamGo("SqlQuery.StreamExecute", req, sr) firstResult, ok := <-sr if !ok { return nil, nil, tabletError(c.Error) } // SqlQuery.StreamExecute might return an application error inside the QueryResult vtErr := vterrors.FromRPCError(firstResult.Err) if vtErr != nil { return nil, nil, tabletError(vtErr) } srout := make(chan *mproto.QueryResult, 1) go func() { defer close(srout) srout <- firstResult for r := range sr { vtErr = vterrors.FromRPCError(r.Err) // If we get a QueryResult with an RPCError, that was an extra QueryResult sent by // the server specifically to indicate an error, and we shouldn't surface it to clients. if vtErr == nil { srout <- r } } }() // errFunc will return either an RPC-layer error or an application error, if one exists. // It will only return the most recent application error (i.e, from the QueryResult that // most recently contained an error). It will prioritize an RPC-layer error over an apperror, // if both exist. errFunc := func() error { rpcErr := tabletError(c.Error) if rpcErr != nil { return rpcErr } return tabletError(vtErr) } return srout, errFunc, nil }
func (conn *vtgateConn) ExecuteBatchShard(ctx context.Context, queries []tproto.BoundQuery, keyspace string, shards []string, tabletType topo.TabletType, notInTransaction bool, session interface{}) ([]mproto.QueryResult, interface{}, error) { var s *proto.Session if session != nil { s = session.(*proto.Session) } request := proto.BatchQueryShard{ Queries: queries, Keyspace: keyspace, Shards: shards, TabletType: tabletType, Session: s, NotInTransaction: notInTransaction, } var result proto.QueryResultList if err := conn.rpcConn.Call(ctx, "VTGate.ExecuteBatchShard", request, &result); err != nil { return nil, session, err } if result.Error != "" { return nil, result.Session, errors.New(result.Error) } if err := vterrors.FromRPCError(result.Err); err != nil { return nil, result.Session, err } return result.List, result.Session, nil }
// DialTablet creates and initializes TabletBson. func DialTablet(ctx context.Context, endPoint *pbt.EndPoint, keyspace, shard string, timeout time.Duration) (tabletconn.TabletConn, error) { addr := netutil.JoinHostPort(endPoint.Host, endPoint.PortMap["vt"]) conn := &TabletBson{endPoint: endPoint} var err error if *tabletBsonUsername != "" { conn.rpcClient, err = bsonrpc.DialAuthHTTP("tcp", addr, *tabletBsonUsername, *tabletBsonPassword, timeout) } else { conn.rpcClient, err = bsonrpc.DialHTTP("tcp", addr, timeout) } if err != nil { return nil, tabletError(err) } if keyspace != "" || shard != "" { var sessionInfo tproto.SessionInfo if err = conn.rpcClient.Call(ctx, "SqlQuery.GetSessionId", tproto.SessionParams{Keyspace: keyspace, Shard: shard}, &sessionInfo); err != nil { conn.rpcClient.Close() return nil, tabletError(err) } // SqlQuery.GetSessionId might return an application error inside the SessionInfo if err = vterrors.FromRPCError(sessionInfo.Err); err != nil { conn.rpcClient.Close() return nil, tabletError(err) } conn.sessionID = sessionInfo.SessionId } return conn, nil }
// Rollback2 should not be used for anything except tests for now; // it will eventually replace the existing Rollback. // Rollback2 rolls back the ongoing transaction. func (conn *TabletBson) Rollback2(ctx context.Context, transactionID int64) error { conn.mu.RLock() defer conn.mu.RUnlock() if conn.rpcClient == nil { return tabletconn.ConnClosed } rollbackRequest := &tproto.RollbackRequest{ Target: conn.target, EffectiveCallerID: getEffectiveCallerID(ctx), ImmediateCallerID: getImmediateCallerID(ctx), SessionId: conn.sessionID, TransactionId: transactionID, } rollbackResponse := new(tproto.RollbackResponse) action := func() error { err := conn.rpcClient.Call(ctx, "SqlQuery.Rollback2", rollbackRequest, rollbackResponse) if err != nil { return err } // SqlQuery.Rollback might return an application error inside the ErrorOnly return vterrors.FromRPCError(rollbackResponse.Err) } err := conn.withTimeout(ctx, action) return tabletError(err) }
// Begin2 should not be used for anything except tests for now; // it will eventually replace the existing Begin. // Begin2 starts a transaction. func (conn *TabletBson) Begin2(ctx context.Context) (transactionID int64, err error) { conn.mu.RLock() defer conn.mu.RUnlock() if conn.rpcClient == nil { return 0, tabletconn.ConnClosed } beginRequest := &tproto.BeginRequest{ Target: conn.target, EffectiveCallerID: getEffectiveCallerID(ctx), ImmediateCallerID: getImmediateCallerID(ctx), SessionId: conn.sessionID, } beginResponse := new(tproto.BeginResponse) action := func() error { err := conn.rpcClient.Call(ctx, "SqlQuery.Begin2", beginRequest, beginResponse) if err != nil { return err } // SqlQuery.Begin might return an application error inside the TransactionInfo return vterrors.FromRPCError(beginResponse.Err) } err = conn.withTimeout(ctx, action) return beginResponse.TransactionId, tabletError(err) }
// ExecuteBatch2 should not be used now other than in tests. // It is the CallerID enabled version of ExecuteBatch // ExecuteBatch2 sends a batch query to VTTablet func (conn *TabletBson) ExecuteBatch2(ctx context.Context, queries []tproto.BoundQuery, asTransaction bool, transactionID int64) (*tproto.QueryResultList, error) { conn.mu.RLock() defer conn.mu.RUnlock() if conn.rpcClient == nil { return nil, tabletconn.ConnClosed } req := tproto.ExecuteBatchRequest{ Target: conn.target, EffectiveCallerID: getEffectiveCallerID(ctx), ImmediateCallerID: getImmediateCallerID(ctx), QueryBatch: tproto.QueryList{ Queries: queries, AsTransaction: asTransaction, TransactionId: transactionID, SessionId: conn.sessionID, }, //TODO::Add CallerID information after it is passed down by context } qrs := new(tproto.QueryResultList) action := func() error { err := conn.rpcClient.Call(ctx, "SqlQuery.ExecuteBatch2", req, qrs) if err != nil { return err } // SqlQuery.ExecuteBatch might return an application error inside the QueryResultList return vterrors.FromRPCError(qrs.Err) } if err := conn.withTimeout(ctx, action); err != nil { return nil, tabletError(err) } return qrs, nil }
// Execute2 should not be used now other than in tests. // It is the CallerID enabled version of Execute // Execute2 sends to query to VTTablet func (conn *TabletBson) Execute2(ctx context.Context, query string, bindVars map[string]interface{}, transactionID int64) (*mproto.QueryResult, error) { conn.mu.RLock() defer conn.mu.RUnlock() if conn.rpcClient == nil { return nil, tabletconn.ConnClosed } req := &tproto.ExecuteRequest{ Target: conn.target, EffectiveCallerID: getEffectiveCallerID(ctx), ImmediateCallerID: getImmediateCallerID(ctx), QueryRequest: tproto.Query{ Sql: query, BindVariables: bindVars, TransactionId: transactionID, SessionId: conn.sessionID, }, // TODO::Fill in EffectiveCallerID and ImmediateCallerID } qr := new(mproto.QueryResult) action := func() error { err := conn.rpcClient.Call(ctx, "SqlQuery.Execute2", req, qr) if err != nil { return err } // SqlQuery.Execute2 might return an application error inside the QueryRequest return vterrors.FromRPCError(qr.Err) } if err := conn.withTimeout(ctx, action); err != nil { return nil, tabletError(err) } return qr, nil }
func (conn *vtgateConn) ExecuteEntityIds(ctx context.Context, query string, keyspace string, entityColumnName string, entityKeyspaceIDs []*vtgatepb.ExecuteEntityIdsRequest_EntityId, bindVars map[string]interface{}, tabletType topodatapb.TabletType, notInTransaction bool, session interface{}) (*sqltypes.Result, interface{}, error) { s := sessionToRPC(session) request := gorpcvtgatecommon.EntityIdsQuery{ CallerID: getEffectiveCallerID(ctx), Sql: query, BindVariables: bindVars, Keyspace: keyspace, EntityColumnName: entityColumnName, EntityKeyspaceIDs: gorpcvtgatecommon.ProtoToEntityIds(entityKeyspaceIDs), TabletType: tabletType, Session: s, NotInTransaction: notInTransaction, } var result gorpcvtgatecommon.QueryResult if err := conn.rpcConn.Call(ctx, "VTGate.ExecuteEntityIds", request, &result); err != nil { return nil, session, err } if err := vterrors.FromRPCError(result.Err); err != nil { return nil, sessionFromRPC(result.Session), err } if result.Result != nil { result.Result.Repair(result.Result.Fields) } return result.Result, sessionFromRPC(result.Session), nil }
// Execute sends the query to VTTablet. func (conn *TabletBson) Execute(ctx context.Context, query string, bindVars map[string]interface{}, transactionID int64) (*mproto.QueryResult, error) { conn.mu.RLock() defer conn.mu.RUnlock() if conn.rpcClient == nil { return nil, tabletconn.ConnClosed } req := &tproto.Query{ Sql: query, BindVariables: bindVars, TransactionId: transactionID, SessionId: conn.sessionID, } qr := new(mproto.QueryResult) action := func() error { err := conn.rpcClient.Call(ctx, "SqlQuery.Execute", req, qr) if err != nil { return err } // SqlQuery.Execute might return an application error inside the QueryResult return vterrors.FromRPCError(qr.Err) } if err := conn.withTimeout(ctx, action); err != nil { return nil, tabletError(err) } return qr, nil }
func sendStreamResults(c *rpcplus.Call, sr chan *gorpcvtgatecommon.QueryResult) (<-chan *sqltypes.Result, vtgateconn.ErrFunc, error) { srout := make(chan *sqltypes.Result, 1) var vtErr error go func() { defer close(srout) var fields []*querypb.Field for r := range sr { vtErr = vterrors.FromRPCError(r.Err) // If we get a QueryResult with an RPCError, that was an extra QueryResult sent by // the server specifically to indicate an error, and we shouldn't surface it to clients. if vtErr == nil { if fields == nil { // first packet, we remember the fields fields = r.Result.Fields } else { // next packet, fix the result r.Result.Repair(fields) } srout <- r.Result } } }() // errFunc will return either an RPC-layer error or an application error, if one exists. // It will only return the most recent application error (i.e, from the QueryResult that // most recently contained an error). It will prioritize an RPC-layer error over an apperror, // if both exist. errFunc := func() error { if c.Error != nil { return c.Error } return vtErr } return srout, errFunc, nil }
// ExecuteBatch sends a batch query to VTTablet. func (conn *TabletBson) ExecuteBatch(ctx context.Context, queries []tproto.BoundQuery, transactionID int64) (*tproto.QueryResultList, error) { conn.mu.RLock() defer conn.mu.RUnlock() if conn.rpcClient == nil { return nil, tabletconn.ConnClosed } req := tproto.QueryList{ Queries: queries, TransactionId: transactionID, SessionId: conn.sessionID, } qrs := new(tproto.QueryResultList) action := func() error { err := conn.rpcClient.Call(ctx, "SqlQuery.ExecuteBatch", req, qrs) if err != nil { return err } // SqlQuery.ExecuteBatch might return an application error inside the QueryResultList return vterrors.FromRPCError(qrs.Err) } if err := conn.withTimeout(ctx, action); err != nil { return nil, tabletError(err) } return qrs, nil }
// SplitQuery is the stub for SqlQuery.SplitQuery RPC func (conn *TabletBson) SplitQuery(ctx context.Context, query tproto.BoundQuery, splitCount int) (queries []tproto.QuerySplit, err error) { conn.mu.RLock() defer conn.mu.RUnlock() if conn.rpcClient == nil { err = tabletconn.ConnClosed return } req := &tproto.SplitQueryRequest{ Query: query, SplitCount: splitCount, SessionID: conn.sessionID, } reply := new(tproto.SplitQueryResult) action := func() error { err := conn.rpcClient.Call(ctx, "SqlQuery.SplitQuery", req, reply) if err != nil { return err } // SqlQuery.SplitQuery might return an application error inside the SplitQueryRequest return vterrors.FromRPCError(reply.Err) } if err := conn.withTimeout(ctx, action); err != nil { return nil, tabletError(err) } return reply.Queries, nil }
func (conn *vtgateConn) ExecuteBatchKeyspaceIds(ctx context.Context, queries []*vtgatepb.BoundKeyspaceIdQuery, tabletType topodatapb.TabletType, asTransaction bool, session interface{}) ([]sqltypes.Result, interface{}, error) { s := sessionToRPC(session) qs, err := gorpcvtgatecommon.ProtoToBoundKeyspaceIdQueries(queries) if err != nil { return nil, session, err } request := gorpcvtgatecommon.KeyspaceIdBatchQuery{ CallerID: getEffectiveCallerID(ctx), Queries: qs, TabletType: tabletType, AsTransaction: asTransaction, Session: s, } var result gorpcvtgatecommon.QueryResultList if err := conn.rpcConn.Call(ctx, "VTGate.ExecuteBatchKeyspaceIds", request, &result); err != nil { return nil, session, err } if err := vterrors.FromRPCError(result.Err); err != nil { return nil, sessionFromRPC(result.Session), err } for _, r := range result.List { r.Repair(r.Fields) } return result.List, sessionFromRPC(result.Session), nil }
// DialTablet creates and initializes TabletBson. func DialTablet(ctx context.Context, endPoint topo.EndPoint, keyspace, shard string, timeout time.Duration) (tabletconn.TabletConn, error) { var addr string var config *tls.Config if *tabletBsonEncrypted { addr = netutil.JoinHostPort(endPoint.Host, endPoint.NamedPortMap["vts"]) config = &tls.Config{} config.InsecureSkipVerify = true } else { addr = netutil.JoinHostPort(endPoint.Host, endPoint.NamedPortMap["vt"]) } conn := &TabletBson{endPoint: endPoint} var err error if *tabletBsonUsername != "" { conn.rpcClient, err = bsonrpc.DialAuthHTTP("tcp", addr, *tabletBsonUsername, *tabletBsonPassword, timeout, config) } else { conn.rpcClient, err = bsonrpc.DialHTTP("tcp", addr, timeout, config) } if err != nil { return nil, tabletError(err) } var sessionInfo tproto.SessionInfo if err = conn.rpcClient.Call(ctx, "SqlQuery.GetSessionId", tproto.SessionParams{Keyspace: keyspace, Shard: shard}, &sessionInfo); err != nil { conn.rpcClient.Close() return nil, tabletError(err) } // SqlQuery.GetSessionId might return an application error inside the SessionInfo if err = vterrors.FromRPCError(sessionInfo.Err); err != nil { conn.rpcClient.Close() return nil, tabletError(err) } conn.sessionID = sessionInfo.SessionId return conn, nil }
func (conn *vtgateConn) ExecuteEntityIds(ctx context.Context, query string, keyspace string, entityColumnName string, entityKeyspaceIDs []*pbg.ExecuteEntityIdsRequest_EntityId, bindVars map[string]interface{}, tabletType pb.TabletType, notInTransaction bool, session interface{}) (*mproto.QueryResult, interface{}, error) { var s *proto.Session if session != nil { s = session.(*proto.Session) } request := proto.EntityIdsQuery{ CallerID: getEffectiveCallerID(ctx), Sql: query, BindVariables: bindVars, Keyspace: keyspace, EntityColumnName: entityColumnName, EntityKeyspaceIDs: proto.ProtoToEntityIds(entityKeyspaceIDs), TabletType: topo.ProtoToTabletType(tabletType), Session: s, NotInTransaction: notInTransaction, } var result proto.QueryResult if err := conn.rpcConn.Call(ctx, "VTGate.ExecuteEntityIds", request, &result); err != nil { return nil, session, err } if err := vterrors.FromRPCError(result.Err); err != nil { return nil, result.Session, err } return result.Result, result.Session, nil }
func (conn *vtgateConn) ExecuteKeyspaceIds(ctx context.Context, query string, keyspace string, keyspaceIds []key.KeyspaceId, bindVars map[string]interface{}, tabletType topo.TabletType, notInTransaction bool, session interface{}) (*mproto.QueryResult, interface{}, error) { var s *proto.Session if session != nil { s = session.(*proto.Session) } request := proto.KeyspaceIdQuery{ Sql: query, BindVariables: bindVars, Keyspace: keyspace, KeyspaceIds: keyspaceIds, TabletType: tabletType, Session: s, NotInTransaction: notInTransaction, } var result proto.QueryResult if err := conn.rpcConn.Call(ctx, "VTGate.ExecuteKeyspaceIds", request, &result); err != nil { return nil, session, err } if result.Error != "" { return nil, result.Session, errors.New(result.Error) } if err := vterrors.FromRPCError(result.Err); err != nil { return nil, result.Session, err } return result.Result, result.Session, nil }
func (conn *vtgateConn) ExecuteShards(ctx context.Context, query string, keyspace string, shards []string, bindVars map[string]interface{}, tabletType pb.TabletType, notInTransaction bool, session interface{}) (*mproto.QueryResult, interface{}, error) { var s *proto.Session if session != nil { s = session.(*proto.Session) } request := proto.QueryShard{ CallerID: getEffectiveCallerID(ctx), Sql: query, BindVariables: bindVars, Keyspace: keyspace, Shards: shards, TabletType: topo.ProtoToTabletType(tabletType), Session: s, NotInTransaction: notInTransaction, } var result proto.QueryResult if err := conn.rpcConn.Call(ctx, "VTGate.ExecuteShard", request, &result); err != nil { return nil, session, err } if result.Error != "" { return nil, result.Session, errors.New(result.Error) } if err := vterrors.FromRPCError(result.Err); err != nil { return nil, result.Session, err } return result.Result, result.Session, nil }
func sendStreamResults(c *rpcplus.Call, sr chan *proto.QueryResult) (<-chan *mproto.QueryResult, vtgateconn.ErrFunc, error) { srout := make(chan *mproto.QueryResult, 1) var vtErr error go func() { defer close(srout) for r := range sr { vtErr = vterrors.FromRPCError(r.Err) // If we get a QueryResult with an RPCError, that was an extra QueryResult sent by // the server specifically to indicate an error, and we shouldn't surface it to clients. if vtErr == nil { srout <- r.Result } } }() // errFunc will return either an RPC-layer error or an application error, if one exists. // It will only return the most recent application error (i.e, from the QueryResult that // most recently contained an error). It will prioritize an RPC-layer error over an apperror, // if both exist. errFunc := func() error { if c.Error != nil { return c.Error } return vtErr } return srout, errFunc, nil }
func (conn *vtgateConn) Rollback2(ctx context.Context, session interface{}) error { s := session.(*proto.Session) request := &proto.RollbackRequest{ Session: s, } reply := new(proto.RollbackResponse) if err := conn.rpcConn.Call(ctx, "VTGate.Rollback2", request, reply); err != nil { return err } return vterrors.FromRPCError(reply.Err) }
func (conn *vtgateConn) Rollback2(ctx context.Context, session interface{}) error { s := sessionToRPC(session) request := &gorpcvtgatecommon.RollbackRequest{ CallerID: getEffectiveCallerID(ctx), Session: s, } reply := new(gorpcvtgatecommon.RollbackResponse) if err := conn.rpcConn.Call(ctx, "VTGate.Rollback2", request, reply); err != nil { return err } return vterrors.FromRPCError(reply.Err) }
func (conn *vtgateConn) Commit2(ctx context.Context, session interface{}) error { s := session.(*proto.Session) request := &proto.CommitRequest{ CallerID: getEffectiveCallerID(ctx), Session: s, } reply := new(proto.CommitResponse) if err := conn.rpcConn.Call(ctx, "VTGate.Commit2", request, reply); err != nil { return err } return vterrors.FromRPCError(reply.Err) }
func (conn *vtgateConn) SplitQuery(ctx context.Context, keyspace string, query tproto.BoundQuery, splitCount int) ([]proto.SplitQueryPart, error) { request := &proto.SplitQueryRequest{ Keyspace: keyspace, Query: query, SplitCount: splitCount, } result := &proto.SplitQueryResult{} if err := conn.rpcConn.Call(ctx, "VTGate.SplitQuery", request, result); err != nil { return nil, err } if err := vterrors.FromRPCError(result.Err); err != nil { return nil, err } return result.Splits, nil }
func (conn *vtgateConn) Begin2(ctx context.Context) (interface{}, error) { request := new(proto.BeginRequest) reply := new(proto.BeginResponse) if err := conn.rpcConn.Call(ctx, "VTGate.Begin2", request, reply); err != nil { return nil, err } if err := vterrors.FromRPCError(reply.Err); err != nil { return nil, err } // Return a non-nil pointer session := &proto.Session{} if reply.Session != nil { session = reply.Session } return session, nil }
func (conn *vtgateConn) ExecuteBatchKeyspaceIds(ctx context.Context, queries []proto.BoundKeyspaceIdQuery, tabletType pb.TabletType, asTransaction bool, session interface{}) ([]sqltypes.Result, interface{}, error) { s := sessionToRPC(session) request := proto.KeyspaceIdBatchQuery{ CallerID: getEffectiveCallerID(ctx), Queries: queries, TabletType: tabletType, AsTransaction: asTransaction, Session: s, } var result proto.QueryResultList if err := conn.rpcConn.Call(ctx, "VTGate.ExecuteBatchKeyspaceIds", request, &result); err != nil { return nil, session, err } if err := vterrors.FromRPCError(result.Err); err != nil { return nil, sessionFromRPC(result.Session), err } return result.List, sessionFromRPC(result.Session), nil }
func (conn *vtgateConn) Begin2(ctx context.Context) (interface{}, error) { request := &gorpcvtgatecommon.BeginRequest{ CallerID: getEffectiveCallerID(ctx), } reply := new(gorpcvtgatecommon.BeginResponse) if err := conn.rpcConn.Call(ctx, "VTGate.Begin2", request, reply); err != nil { return nil, err } if err := vterrors.FromRPCError(reply.Err); err != nil { return nil, err } // Return a non-nil pointer session := &vtgatepb.Session{} if reply.Session != nil { session = reply.Session } return session, nil }
func (conn *vtgateConn) Execute(ctx context.Context, query string, bindVars map[string]interface{}, tabletType pb.TabletType, notInTransaction bool, session interface{}) (*sqltypes.Result, interface{}, error) { s := sessionToRPC(session) request := proto.Query{ CallerID: getEffectiveCallerID(ctx), Sql: query, BindVariables: bindVars, TabletType: tabletType, Session: s, NotInTransaction: notInTransaction, } var result proto.QueryResult if err := conn.rpcConn.Call(ctx, "VTGate.Execute", request, &result); err != nil { return nil, session, err } if err := vterrors.FromRPCError(result.Err); err != nil { return nil, sessionFromRPC(result.Session), err } return result.Result, sessionFromRPC(result.Session), nil }
func (conn *vtgateConn) SplitQuery(ctx context.Context, keyspace string, query string, bindVars map[string]interface{}, splitColumn string, splitCount int) ([]proto.SplitQueryPart, error) { request := &proto.SplitQueryRequest{ CallerID: getEffectiveCallerID(ctx), Keyspace: keyspace, Query: tproto.BoundQuery{ Sql: query, BindVariables: bindVars, }, SplitColumn: splitColumn, SplitCount: splitCount, } result := &proto.SplitQueryResult{} if err := conn.rpcConn.Call(ctx, "VTGate.SplitQuery", request, result); err != nil { return nil, err } if err := vterrors.FromRPCError(result.Err); err != nil { return nil, err } return result.Splits, nil }
func (conn *vtgateConn) ExecuteBatchShards(ctx context.Context, queries []proto.BoundShardQuery, tabletType pb.TabletType, asTransaction bool, session interface{}) ([]mproto.QueryResult, interface{}, error) { var s *proto.Session if session != nil { s = session.(*proto.Session) } request := proto.BatchQueryShard{ CallerID: getEffectiveCallerID(ctx), Queries: queries, TabletType: topo.ProtoToTabletType(tabletType), AsTransaction: asTransaction, Session: s, } var result proto.QueryResultList if err := conn.rpcConn.Call(ctx, "VTGate.ExecuteBatchShard", request, &result); err != nil { return nil, session, err } if err := vterrors.FromRPCError(result.Err); err != nil { return nil, result.Session, err } return result.List, result.Session, nil }
// Begin starts a transaction. func (conn *TabletBson) Begin(ctx context.Context) (transactionID int64, err error) { conn.mu.RLock() defer conn.mu.RUnlock() if conn.rpcClient == nil { return 0, tabletconn.ConnClosed } req := &tproto.Session{ SessionId: conn.sessionID, } var txInfo tproto.TransactionInfo action := func() error { err := conn.rpcClient.Call(ctx, "SqlQuery.Begin", req, &txInfo) if err != nil { return err } // SqlQuery.Begin might return an application error inside the TransactionInfo return vterrors.FromRPCError(txInfo.Err) } err = conn.withTimeout(ctx, action) return txInfo.TransactionId, tabletError(err) }