// ExecuteEntityIds excutes a non-streaming query based on given KeyspaceId map. func (vtg *VTGate) ExecuteEntityIds(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, entityColumnName string, entityKeyspaceIDs []*pbg.ExecuteEntityIdsRequest_EntityId, tabletType pb.TabletType, session *proto.Session, notInTransaction bool, reply *proto.QueryResult) error { startTime := time.Now() statsKey := []string{"ExecuteEntityIds", keyspace, strings.ToLower(tabletType.String())} defer vtg.timings.Record(statsKey, startTime) x := vtg.inFlight.Add(1) defer vtg.inFlight.Add(-1) if 0 < vtg.maxInFlight && vtg.maxInFlight < x { return errTooManyInFlight } qr, err := vtg.resolver.ExecuteEntityIds(ctx, sql, bindVariables, keyspace, entityColumnName, entityKeyspaceIDs, tabletType, session, notInTransaction) if err == nil { reply.Result = qr vtg.rowsReturned.Add(statsKey, int64(len(qr.Rows))) } else { query := map[string]interface{}{ "Sql": sql, "BindVariables": bindVariables, "Keyspace": keyspace, "EntityColumnName": entityColumnName, "EntityKeyspaceIDs": entityKeyspaceIDs, "TabletType": strings.ToLower(tabletType.String()), "Session": session, "NotInTransaction": notInTransaction, } reply.Error = handleExecuteError(err, statsKey, query, vtg.logExecuteEntityIds).Error() reply.Err = rpcErrFromVtGateError(err) } reply.Session = session return nil }
// ExecuteKeyRanges executes a non-streaming query based on the specified keyranges. func (vtg *VTGate) ExecuteKeyRanges(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyRanges []*pb.KeyRange, tabletType pb.TabletType, session *proto.Session, notInTransaction bool, reply *proto.QueryResult) error { startTime := time.Now() statsKey := []string{"ExecuteKeyRanges", keyspace, strings.ToLower(tabletType.String())} defer vtg.timings.Record(statsKey, startTime) x := vtg.inFlight.Add(1) defer vtg.inFlight.Add(-1) if 0 < vtg.maxInFlight && vtg.maxInFlight < x { return errTooManyInFlight } sql = sqlannotation.AddFilteredReplicationUnfriendlyIfDML(sql) qr, err := vtg.resolver.ExecuteKeyRanges(ctx, sql, bindVariables, keyspace, keyRanges, tabletType, session, notInTransaction) if err == nil { reply.Result = qr vtg.rowsReturned.Add(statsKey, int64(len(qr.Rows))) } else { query := map[string]interface{}{ "Sql": sql, "BindVariables": bindVariables, "Keyspace": keyspace, "KeyRanges": keyRanges, "TabletType": strings.ToLower(tabletType.String()), "Session": session, "NotInTransaction": notInTransaction, } reply.Error = handleExecuteError(err, statsKey, query, vtg.logExecuteKeyRanges).Error() reply.Err = vterrors.RPCErrFromVtError(err) } reply.Session = session return nil }
// Execute executes a non-streaming query by routing based on the values in the query. func (vtg *VTGate) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool, reply *proto.QueryResult) error { startTime := time.Now() statsKey := []string{"Execute", "Any", strings.ToLower(tabletType.String())} defer vtg.timings.Record(statsKey, startTime) x := vtg.inFlight.Add(1) defer vtg.inFlight.Add(-1) if 0 < vtg.maxInFlight && vtg.maxInFlight < x { return errTooManyInFlight } qr, err := vtg.router.Execute(ctx, sql, bindVariables, tabletType, session, notInTransaction) if err == nil { reply.Result = qr vtg.rowsReturned.Add(statsKey, int64(len(qr.Rows))) } else { query := map[string]interface{}{ "Sql": sql, "BindVariables": bindVariables, "TabletType": strings.ToLower(tabletType.String()), "Session": session, "NotInTransaction": notInTransaction, } handleExecuteError(err, statsKey, query, vtg.logExecute) reply.Err = vterrors.RPCErrFromVtError(err) } reply.Session = session return nil }
func (c *errorClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType pb.TabletType, session *proto.Session, notInTransaction bool, reply *proto.QueryResult) error { if rpcErr := requestToPartialError(sql); rpcErr != nil { reply.Err = rpcErr reply.Error = rpcErr.Message return nil } if err := requestToError(sql); err != nil { return err } return c.fallbackClient.Execute(ctx, sql, bindVariables, tabletType, session, notInTransaction, reply) }
// requestToPartialError fills reply for a partial error if requested. // It returns true if a partial error was requested, false otherwise. // This partial error should only be returned by Execute* calls. func requestToPartialError(request string, session *vtgatepb.Session, reply *proto.QueryResult) bool { if !strings.HasPrefix(request, PartialErrorPrefix) { return false } request = strings.TrimPrefix(request, PartialErrorPrefix) parts := strings.Split(request, "/") rpcErr := vterrors.RPCErrFromVtError(trimmedRequestToError(parts[0])) reply.Err = rpcErr reply.Session = session if len(parts) > 1 && parts[1] == "close transaction" { reply.Session.InTransaction = false } return true }
// AddVtGateErrorToQueryResult will mutate a QueryResult struct to fill in the Err // field with details from the VTGate error. func AddVtGateErrorToQueryResult(err error, reply *proto.QueryResult) { if err == nil { return } reply.Err = rpcErrFromVtGateError(err) }