// ExecuteEntityIds executes a non-streaming query based on given KeyspaceId map. // It retries query if new keyspace/shards are re-resolved after a retryable error. func (res *Resolver) ExecuteEntityIds( context context.Context, query *proto.EntityIdsQuery, ) (*mproto.QueryResult, error) { newKeyspace, shardIDMap, err := mapEntityIdsToShards( res.scatterConn.toposerv, res.scatterConn.cell, query.Keyspace, query.EntityKeyspaceIDs, query.TabletType) if err != nil { return nil, err } query.Keyspace = newKeyspace shards, sqls, bindVars := buildEntityIds(shardIDMap, query.Sql, query.EntityColumnName, query.BindVariables) for { qr, err := res.scatterConn.ExecuteEntityIds( context, shards, sqls, bindVars, query.Keyspace, query.TabletType, NewSafeSession(query.Session)) if connError, ok := err.(*ShardConnError); ok && connError.Code == tabletconn.ERR_RETRY { resharding := false newKeyspace, newShardIDMap, err := mapEntityIdsToShards( res.scatterConn.toposerv, res.scatterConn.cell, query.Keyspace, query.EntityKeyspaceIDs, query.TabletType) if err != nil { return nil, err } // check keyspace change for vertical resharding if newKeyspace != query.Keyspace { query.Keyspace = newKeyspace resharding = true } // check shards change for horizontal resharding newShards, newSqls, newBindVars := buildEntityIds(newShardIDMap, query.Sql, query.EntityColumnName, query.BindVariables) if !StrsEquals(newShards, shards) { shards = newShards sqls = newSqls bindVars = newBindVars resharding = true } // retry if resharding happened if resharding { continue } } if err != nil { return nil, err } return qr, err } }