// SplitQuery splits a BoundQuery into smaller queries that return a subset of rows from the original query. func (sq *SqlQuery) SplitQuery(context context.Context, req *proto.SplitQueryRequest, reply *proto.SplitQueryResult) error { logStats := newSqlQueryStats("SplitQuery", context) var err error // TODO(sougou/anandhenry): Add session validation. defer handleError(&err, logStats) splitter := NewQuerySplitter(&(req.Query), req.SplitCount, sq.qe.schemaInfo) err = splitter.validateQuery() if err != nil { return NewTabletError(FAIL, "query validation error: %s", err) } // Partial initialization or QueryExecutor is enough to call execSQL requestContext := RequestContext{ ctx: context, logStats: logStats, qe: sq.qe, } conn := getOrPanic(sq.qe.connPool) // TODO: For fetching pkMinMax, include where clauses on the // primary key, if any, in the original query which might give a narrower // range of PKs to work with. minMaxSql := fmt.Sprintf("SELECT MIN(%v), MAX(%v) FROM %v", splitter.pkCol, splitter.pkCol, splitter.tableName) pkMinMax := requestContext.execSQL(conn, minMaxSql, true) reply.Queries = splitter.split(pkMinMax) return nil }
// SplitQuery is part of the queryservice.QueryService interface func (f *FakeQueryService) SplitQuery(ctx context.Context, req *proto.SplitQueryRequest, reply *proto.SplitQueryResult) error { if f.hasError { return testTabletError } if f.panics { panic(fmt.Errorf("test-triggered panic")) } if !reflect.DeepEqual(req.Query, splitQueryBoundQuery) { f.t.Errorf("invalid SplitQuery.SplitQueryRequest.Query: got %v expected %v", req.Query, splitQueryBoundQuery) } if req.SplitCount != splitQuerySplitCount { f.t.Errorf("invalid SplitQuery.SplitQueryRequest.SplitCount: got %v expected %v", req.SplitCount, splitQuerySplitCount) } reply.Queries = splitQueryQuerySplitList return nil }
// SplitQuery is part of the queryservice.QueryService interface func (f *FakeQueryService) SplitQuery(ctx context.Context, target *pb.Target, req *proto.SplitQueryRequest, reply *proto.SplitQueryResult) error { if f.panics { panic(fmt.Errorf("test-triggered panic")) } if f.checkExtraFields { f.checkTargetCallerID(ctx, "SplitQuery", target) } if !reflect.DeepEqual(req.Query, splitQueryBoundQuery) { f.t.Errorf("invalid SplitQuery.SplitQueryRequest.Query: got %v expected %v", req.Query, splitQueryBoundQuery) } if req.SplitColumn != splitQuerySplitColumn { f.t.Errorf("invalid SplitQuery.SplitQueryRequest.SplitColumn: got %v expected %v", req.SplitColumn, splitQuerySplitColumn) } if req.SplitCount != splitQuerySplitCount { f.t.Errorf("invalid SplitQuery.SplitQueryRequest.SplitCount: got %v expected %v", req.SplitCount, splitQuerySplitCount) } reply.Queries = splitQueryQuerySplitList return nil }
// AddTabletErrorToSplitQueryResult will mutate a SplitQueryResult struct to fill in the Err // field with details from the TabletError. func AddTabletErrorToSplitQueryResult(err error, reply *proto.SplitQueryResult) { if err == nil { return } reply.Err = rpcErrFromTabletError(err) }