diff --git a/query/src/main/java/tech/ydb/query/impl/TableClientImpl.java b/query/src/main/java/tech/ydb/query/impl/TableClientImpl.java index be90f07c..b9f6fb26 100644 --- a/query/src/main/java/tech/ydb/query/impl/TableClientImpl.java +++ b/query/src/main/java/tech/ydb/query/impl/TableClientImpl.java @@ -22,6 +22,7 @@ import tech.ydb.query.QueryStream; import tech.ydb.query.result.QueryInfo; import tech.ydb.query.result.QueryResultPart; +import tech.ydb.query.result.QueryStats; import tech.ydb.query.settings.ExecuteQuerySettings; import tech.ydb.query.settings.QueryStatsMode; import tech.ydb.table.Session; @@ -30,17 +31,10 @@ import tech.ydb.table.impl.BaseSession; import tech.ydb.table.query.DataQueryResult; import tech.ydb.table.query.Params; -import tech.ydb.table.query.stats.CompilationStats; -import tech.ydb.table.query.stats.OperationStats; -import tech.ydb.table.query.stats.QueryPhaseStats; -import tech.ydb.table.query.stats.QueryStats; -import tech.ydb.table.query.stats.TableAccessStats; import tech.ydb.table.rpc.TableRpc; import tech.ydb.table.rpc.grpc.GrpcTableRpc; import tech.ydb.table.settings.ExecuteDataQuerySettings; -import static java.util.stream.Collectors.toList; - /** * * @author Aleksandr Gorshenin @@ -100,53 +94,6 @@ private YdbQuery.TransactionControl mapTxControl(YdbTable.TransactionControl tc) return TxControl.txModeCtrl(TxMode.NONE, tc.getCommitTx()); } - private static QueryStats queryStats(tech.ydb.query.result.QueryStats stats) { - if (stats == null) { - return null; - } - return new QueryStats( - stats.getPhases().stream().map(qp -> queryPhaseStats(qp)).collect(toList()), - compilationStats(stats.getCompilationStats()), - stats.getProcessCpuTimeUs(), - stats.getQueryPlan(), - stats.getQueryAst(), - stats.getTotalDurationUs(), - stats.getTotalCpuTimeUs() - ); - } - - private static QueryPhaseStats queryPhaseStats(tech.ydb.query.result.QueryStats.QueryPhase queryPhase) { - return new QueryPhaseStats( - queryPhase.getDurationUs(), - queryPhase.getTableAccesses().stream().map(ta -> tableAccessStats(ta)).collect(toList()), - queryPhase.getCpuTimeUs(), - queryPhase.getAffectedShards(), - queryPhase.isLiteralPhase() - ); - } - - private static TableAccessStats tableAccessStats(tech.ydb.query.result.QueryStats.TableAccess tableAccess) { - return new TableAccessStats( - tableAccess.getTableName(), - operationStats(tableAccess.getReads()), - operationStats(tableAccess.getUpdates()), - operationStats(tableAccess.getDeletes()), - tableAccess.getPartitionsCount() - ); - } - - private static OperationStats operationStats(tech.ydb.query.result.QueryStats.Operation operation) { - return new OperationStats(operation.getRows(), operation.getBytes()); - } - - private static CompilationStats compilationStats(tech.ydb.query.result.QueryStats.Compilation compilation) { - return new CompilationStats( - compilation.isFromCache(), - compilation.getDurationUs(), - compilation.getCpuTimeUs() - ); - } - private class TableSession extends BaseSession { private final SessionImpl querySession; @@ -204,10 +151,11 @@ public void onNextRawPart(long index, ValueProtos.ResultSet rs) { if (!res.isSuccess()) { return res.map(v -> null); } - QueryStats info = queryStats(res.getValue().getStats()); + QueryStats stats = res.getValue().getStats(); String txId = txRef.get(); Status status = res.getStatus().withIssues(issues.toArray(new Issue[0])); - return Result.success(new DataQueryResult(txId, results, info), status); + DataQueryResult value = new DataQueryResult(txId, results, stats != null ? stats.toProtobuf() : null); + return Result.success(value, status); }); } diff --git a/query/src/main/java/tech/ydb/query/result/QueryStats.java b/query/src/main/java/tech/ydb/query/result/QueryStats.java index 7c38b331..98265e3a 100644 --- a/query/src/main/java/tech/ydb/query/result/QueryStats.java +++ b/query/src/main/java/tech/ydb/query/result/QueryStats.java @@ -1,6 +1,7 @@ package tech.ydb.query.result; import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; import tech.ydb.proto.YdbQueryStats; @@ -30,11 +31,23 @@ public QueryStats(YdbQueryStats.QueryStats stats) { this.totalCpuTimeUs = stats.getTotalCpuTimeUs(); } + public YdbQueryStats.QueryStats toProtobuf() { + return YdbQueryStats.QueryStats.newBuilder() + .setQueryAst(queryAst) + .setQueryPlan(queryPlan) + .setTotalCpuTimeUs(totalCpuTimeUs) + .setTotalDurationUs(totalDurationUs) + .setProcessCpuTimeUs(processCpuTimeUs) + .setCompilation(compilationStats.toProtobuf()) + .addAllQueryPhases(queryPhases.stream().map(QueryPhase::toProtobuf).collect(Collectors.toList())) + .build(); + } + public List getPhases() { return this.queryPhases; } - /** + /* * @deprecated Use {{@link #getCompilationStats()}} instead */ @Deprecated @@ -66,6 +79,34 @@ public long getProcessCpuTimeUs() { return this.processCpuTimeUs; } + @Override + public int hashCode() { + int hash = Objects.hash(queryPlan, queryAst, compilationStats, queryPhases); + hash = 31 * hash + (int) (processCpuTimeUs ^ (processCpuTimeUs >>> 32)); + hash = 31 * hash + (int) (totalDurationUs ^ (totalDurationUs >>> 32)); + hash = 31 * hash + (int) (totalCpuTimeUs ^ (totalCpuTimeUs >>> 32)); + return hash; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + + QueryStats o = (QueryStats) other; + return Objects.equals(queryPlan, o.queryPlan) + && Objects.equals(queryAst, o.queryAst) + && Objects.equals(compilationStats, o.compilationStats) + && Objects.equals(queryPhases, o.queryPhases) + && processCpuTimeUs == o.processCpuTimeUs + && totalDurationUs == o.totalDurationUs + && totalCpuTimeUs == o.totalCpuTimeUs; + } + @Override public String toString() { StringBuilder sb = new StringBuilder("QueryStats{"); @@ -104,10 +145,39 @@ public boolean isFromCache() { return this.isFromCache; } + public YdbQueryStats.CompilationStats toProtobuf() { + return YdbQueryStats.CompilationStats.newBuilder() + .setCpuTimeUs(cpuTimeUs) + .setDurationUs(durationUs) + .setFromCache(isFromCache) + .build(); + } + @Override public String toString() { return "Compilation{durationUs=" + durationUs + ", cpuTimeUs=" + cpuTimeUs + ", cache=" + isFromCache + "}"; } + + @Override + public int hashCode() { + int hash = Boolean.hashCode(isFromCache); + hash = 31 * hash + (int) (durationUs ^ (durationUs >>> 32)); + hash = 31 * hash + (int) (cpuTimeUs ^ (cpuTimeUs >>> 32)); + return hash; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + + Compilation o = (Compilation) other; + return isFromCache == o.isFromCache && durationUs == o.durationUs && cpuTimeUs == o.cpuTimeUs; + } } public static class QueryPhase { @@ -157,6 +227,40 @@ public String toString() { sb.append("]}"); return sb.toString(); } + + public YdbQueryStats.QueryPhaseStats toProtobuf() { + return YdbQueryStats.QueryPhaseStats.newBuilder() + .setAffectedShards(affectedShards) + .setCpuTimeUs(cpuTimeUs) + .setDurationUs(durationUs) + .setLiteralPhase(isLiteralPhase) + .addAllTableAccess(tableAccesses.stream().map(TableAccess::toProtobuf).collect(Collectors.toList())) + .build(); + } + + @Override + public int hashCode() { + int hash = Boolean.hashCode(isLiteralPhase); + hash = 31 * hash + (int) (durationUs ^ (durationUs >>> 32)); + hash = 31 * hash + (int) (cpuTimeUs ^ (cpuTimeUs >>> 32)); + hash = 31 * hash + (int) (affectedShards ^ (affectedShards >>> 32)); + hash = 31 * hash + tableAccesses.hashCode(); + return hash; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + + QueryPhase o = (QueryPhase) other; + return durationUs == o.durationUs && cpuTimeUs == o.cpuTimeUs && affectedShards == o.affectedShards + && isLiteralPhase == o.isLiteralPhase && Objects.equals(tableAccesses, o.tableAccesses); + } } public static class TableAccess { @@ -203,6 +307,40 @@ public String toString() { + ", deletes={rows=" + deletes.rows + ", byte=" + deletes.bytes + "}" + "}"; } + + public YdbQueryStats.TableAccessStats toProtobuf() { + return YdbQueryStats.TableAccessStats.newBuilder() + .setName(name) + .setPartitionsCount(partitionsCount) + .setReads(reads.toProtobuf()) + .setDeletes(deletes.toProtobuf()) + .setUpdates(updates.toProtobuf()) + .build(); + } + + @Override + public int hashCode() { + int hash = Objects.hash(name, reads, updates, deletes); + hash = 31 * hash + (int) (partitionsCount ^ (partitionsCount >>> 32)); + return hash; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + + TableAccess o = (TableAccess) other; + return Objects.equals(name, o.name) + && Objects.equals(reads, o.reads) + && Objects.equals(updates, o.updates) + && Objects.equals(deletes, o.deletes) + && partitionsCount == o.partitionsCount; + } } public static class Operation { @@ -226,5 +364,29 @@ public long getBytes() { public String toString() { return "OperationStats{rows=" + rows + ", bytes=" + bytes + "}"; } + + public YdbQueryStats.OperationStats toProtobuf() { + return YdbQueryStats.OperationStats.newBuilder().setRows(rows).setBytes(bytes).build(); + } + + @Override + public int hashCode() { + int hash = 31 + (int) (rows ^ (rows >>> 32)); + hash = 31 * hash + (int) (bytes ^ (bytes >>> 32)); + return hash; + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + + Operation o = (Operation) other; + return rows == o.rows && bytes == o.bytes; + } } } diff --git a/query/src/test/java/tech/ydb/query/result/QueryStatsTest.java b/query/src/test/java/tech/ydb/query/result/QueryStatsTest.java new file mode 100644 index 00000000..5a582382 --- /dev/null +++ b/query/src/test/java/tech/ydb/query/result/QueryStatsTest.java @@ -0,0 +1,235 @@ +package tech.ydb.query.result; + +import java.util.Arrays; + +import org.junit.Assert; +import org.junit.Test; + +import tech.ydb.proto.YdbQueryStats; + +/** + * + * @author Aleksandr Gorshenin + */ +public class QueryStatsTest { + + private static YdbQueryStats.CompilationStats comp(boolean fromCache, long cpu, long duration) { + return YdbQueryStats.CompilationStats.newBuilder() + .setFromCache(fromCache) + .setCpuTimeUs(cpu) + .setDurationUs(duration) + .build(); + } + + private static YdbQueryStats.OperationStats op(long rows, long bytes) { + return YdbQueryStats.OperationStats.newBuilder() + .setRows(rows) + .setBytes(bytes) + .build(); + } + + private static YdbQueryStats.TableAccessStats table(String name, long parts, YdbQueryStats.OperationStats reads, + YdbQueryStats.OperationStats updates, YdbQueryStats.OperationStats deletes) { + return YdbQueryStats.TableAccessStats.newBuilder() + .setName(name) + .setPartitionsCount(parts) + .setReads(reads) + .setUpdates(updates) + .setDeletes(deletes) + .build(); + } + + private static YdbQueryStats.QueryPhaseStats phase(boolean literal, long shards, long cpu, long duration, + YdbQueryStats.TableAccessStats... tables) { + return YdbQueryStats.QueryPhaseStats.newBuilder() + .setLiteralPhase(literal) + .setAffectedShards(shards) + .setCpuTimeUs(cpu) + .setDurationUs(duration) + .addAllTableAccess(Arrays.asList(tables)) + .build(); + } + + private static YdbQueryStats.QueryStats stats(String ast, String plan, long totalCpu, long duration, + long processCpu, YdbQueryStats.CompilationStats cs, YdbQueryStats.QueryPhaseStats... qps) { + return YdbQueryStats.QueryStats.newBuilder().setQueryAst(ast).setQueryPlan(plan).setTotalCpuTimeUs(totalCpu) + .setTotalDurationUs(duration).setProcessCpuTimeUs(processCpu).setCompilation(cs) + .addAllQueryPhases(Arrays.asList(qps)) + .build(); + } + + @Test + public void queryStatsGettersTest() { + YdbQueryStats.QueryPhaseStats ph = phase(true, 1, 2, 3, table("t1", 10, op(1, 2), op(3, 4), op(5, 6))); + QueryStats qs = new QueryStats(stats("a", "b", 1, 2, 3, comp(true, 10, 20), ph)); + + Assert.assertEquals("a", qs.getQueryAst()); + Assert.assertEquals("b", qs.getQueryPlan()); + Assert.assertEquals(1l, qs.getTotalCpuTimeUs()); + Assert.assertEquals(2l, qs.getTotalDurationUs()); + Assert.assertEquals(3l, qs.getProcessCpuTimeUs()); + + Assert.assertTrue(qs.getCompilationStats().isFromCache()); + Assert.assertEquals(10l, qs.getCompilationStats().getCpuTimeUs()); + Assert.assertEquals(20l, qs.getCompilationStats().getDurationUs()); + + Assert.assertEquals(1, qs.getPhases().size()); + Assert.assertTrue(qs.getPhases().get(0).isLiteralPhase()); + Assert.assertEquals(1l, qs.getPhases().get(0).getAffectedShards()); + Assert.assertEquals(2l, qs.getPhases().get(0).getCpuTimeUs()); + Assert.assertEquals(3l, qs.getPhases().get(0).getDurationUs()); + + Assert.assertEquals(1, qs.getPhases().get(0).getTableAccesses().size()); + Assert.assertEquals("t1", qs.getPhases().get(0).getTableAccesses().get(0).getTableName()); + Assert.assertEquals(10l, qs.getPhases().get(0).getTableAccesses().get(0).getPartitionsCount()); + Assert.assertEquals(1l, qs.getPhases().get(0).getTableAccesses().get(0).getReads().getRows()); + Assert.assertEquals(2l, qs.getPhases().get(0).getTableAccesses().get(0).getReads().getBytes()); + Assert.assertEquals(3l, qs.getPhases().get(0).getTableAccesses().get(0).getUpdates().getRows()); + Assert.assertEquals(4l, qs.getPhases().get(0).getTableAccesses().get(0).getUpdates().getBytes()); + Assert.assertEquals(5l, qs.getPhases().get(0).getTableAccesses().get(0).getDeletes().getRows()); + Assert.assertEquals(6l, qs.getPhases().get(0).getTableAccesses().get(0).getDeletes().getBytes()); + } + + @Test + @Deprecated + public void queryStatsDeprectedGettersTest() { + YdbQueryStats.QueryPhaseStats ph = phase(true, 1, 2, 3, table("t1", 10, op(1, 2), op(3, 4), op(5, 6))); + QueryStats qs = new QueryStats(stats("a", "b", 1, 2, 3, comp(true, 10, 20), ph)); + Assert.assertEquals(qs.getCompilationStats(), qs.getComplilationStats()); + } + + @Test + public void queryStatsEqualsTest() { + YdbQueryStats.TableAccessStats t1 = table("t1", 5, op(1, 1), op(0, 0), op(0, 0)); + YdbQueryStats.CompilationStats c1 = comp(true, 10, 20); + YdbQueryStats.CompilationStats c2 = comp(false, 10, 20); + YdbQueryStats.QueryPhaseStats ph1 = phase(true, 1, 2, 3, t1); + YdbQueryStats.QueryPhaseStats ph2 = phase(false, 1, 2, 3, t1); + + QueryStats s1 = new QueryStats(stats("a", "b", 1, 2, 3, c1, ph1)); + + Assert.assertEquals(s1.hashCode(), new QueryStats(stats("a", "b", 1, 2, 3, c1, ph1)).hashCode()); + Assert.assertNotEquals(s1.hashCode(), new QueryStats(stats("a", "b", 1, 3, 3, c1, ph1)).hashCode()); + Assert.assertNotEquals(s1.hashCode(), new QueryStats(stats("b", "b", 1, 2, 3, c1, ph1)).hashCode()); + Assert.assertNotEquals(s1.hashCode(), new QueryStats(stats("a", "c", 1, 2, 3, c1, ph1)).hashCode()); + Assert.assertNotEquals(s1.hashCode(), new QueryStats(stats("a", "b", 2, 2, 3, c1, ph1)).hashCode()); + Assert.assertNotEquals(s1.hashCode(), new QueryStats(stats("a", "b", 1, 3, 3, c1, ph1)).hashCode()); + Assert.assertNotEquals(s1.hashCode(), new QueryStats(stats("a", "b", 1, 2, 4, c1, ph1)).hashCode()); + Assert.assertNotEquals(s1.hashCode(), new QueryStats(stats("a", "b", 1, 2, 3, c2, ph1)).hashCode()); + Assert.assertNotEquals(s1.hashCode(), new QueryStats(stats("a", "b", 1, 2, 3, c1, ph2)).hashCode()); + Assert.assertNotEquals(s1.hashCode(), new QueryStats(stats("a", "b", 1, 2, 3, c1, ph1, ph2))); + + Assert.assertEquals(s1, s1); + Assert.assertEquals(s1, new QueryStats(stats("a", "b", 1, 2, 3, c1, ph1))); + + Assert.assertNotEquals(s1, null); + Assert.assertNotEquals(s1, t1); + + Assert.assertNotEquals(s1, new QueryStats(stats("b", "b", 1, 2, 3, c1, ph1))); + Assert.assertNotEquals(s1, new QueryStats(stats("a", "c", 1, 2, 3, c1, ph1))); + Assert.assertNotEquals(s1, new QueryStats(stats("a", "b", 2, 2, 3, c1, ph1))); + Assert.assertNotEquals(s1, new QueryStats(stats("a", "b", 1, 3, 3, c1, ph1))); + Assert.assertNotEquals(s1, new QueryStats(stats("a", "b", 1, 2, 4, c1, ph1))); + Assert.assertNotEquals(s1, new QueryStats(stats("a", "b", 1, 2, 3, c2, ph1))); + Assert.assertNotEquals(s1, new QueryStats(stats("a", "b", 1, 2, 3, c1, ph2))); + Assert.assertNotEquals(s1, new QueryStats(stats("a", "b", 1, 2, 3, c1, ph1, ph2))); + } + + @Test + public void compilationEqualsTest() { + QueryStats.Compilation c1 = new QueryStats.Compilation(comp(true, 10, 20)); + + Assert.assertEquals(c1.hashCode(), new QueryStats.Compilation(comp(true, 10, 20)).hashCode()); + Assert.assertNotEquals(c1.hashCode(), new QueryStats.Compilation(comp(false, 10, 20)).hashCode()); + Assert.assertNotEquals(c1.hashCode(), new QueryStats.Compilation(comp(true, 11, 20)).hashCode()); + Assert.assertNotEquals(c1.hashCode(), new QueryStats.Compilation(comp(true, 10, 22)).hashCode()); + + Assert.assertEquals(c1, c1); + Assert.assertEquals(c1, new QueryStats.Compilation(comp(true, 10, 20))); + + Assert.assertNotEquals(c1, null); + Assert.assertNotEquals(c1, comp(true, 10, 20)); + + Assert.assertNotEquals(c1, new QueryStats.Compilation(comp(false, 10, 20))); + Assert.assertNotEquals(c1, new QueryStats.Compilation(comp(true, 11, 20))); + Assert.assertNotEquals(c1, new QueryStats.Compilation(comp(true, 10, 21))); + } + + @Test + public void operationEqualsTest() { + QueryStats.Operation o1 = new QueryStats.Operation(op(10, 20)); + + Assert.assertEquals(o1.hashCode(), new QueryStats.Operation(op(10, 20)).hashCode()); + Assert.assertNotEquals(o1.hashCode(), new QueryStats.Operation(op(11, 20)).hashCode()); + Assert.assertNotEquals(o1.hashCode(), new QueryStats.Operation(op(10, 22)).hashCode()); + + Assert.assertEquals(o1, o1); + Assert.assertEquals(o1, new QueryStats.Operation(op(10, 20))); + + Assert.assertNotEquals(o1, null); + Assert.assertNotEquals(o1, op(10, 20)); + + Assert.assertNotEquals(o1, new QueryStats.Operation(op(11, 20))); + Assert.assertNotEquals(o1, new QueryStats.Operation(op(10, 21))); + + Assert.assertEquals("OperationStats{rows=10, bytes=20}", o1.toString()); + } + + @Test + public void tableAccessEqualsTest() { + YdbQueryStats.OperationStats o1 = op(1, 1); + YdbQueryStats.OperationStats o2 = op(1, 2); + YdbQueryStats.OperationStats o3 = op(1, 3); + YdbQueryStats.OperationStats o4 = op(1, 4); + + QueryStats.TableAccess t1 = new QueryStats.TableAccess(table("t1", 5, o1, o2, o3)); + + Assert.assertEquals(t1.hashCode(), new QueryStats.TableAccess(table("t1", 5, o1, o2, o3)).hashCode()); + Assert.assertNotEquals(t1.hashCode(), new QueryStats.TableAccess(table("t2", 5, o1, o2, o3)).hashCode()); + Assert.assertNotEquals(t1.hashCode(), new QueryStats.TableAccess(table("t1", 6, o1, o2, o3)).hashCode()); + Assert.assertNotEquals(t1.hashCode(), new QueryStats.TableAccess(table("t1", 5, o4, o2, o3)).hashCode()); + Assert.assertNotEquals(t1.hashCode(), new QueryStats.TableAccess(table("t1", 5, o1, o4, o3)).hashCode()); + Assert.assertNotEquals(t1.hashCode(), new QueryStats.TableAccess(table("t1", 5, o1, o2, o4)).hashCode()); + + Assert.assertEquals(t1, t1); + Assert.assertEquals(t1, new QueryStats.TableAccess(table("t1", 5, o1, o2, o3))); + + Assert.assertNotEquals(t1, null); + Assert.assertNotEquals(t1, table("t1", 5, o1, o2, o3)); + + Assert.assertNotEquals(t1, new QueryStats.TableAccess(table("t2", 5, o1, o2, o3))); + Assert.assertNotEquals(t1, new QueryStats.TableAccess(table("t1", 6, o1, o2, o3))); + Assert.assertNotEquals(t1, new QueryStats.TableAccess(table("t1", 5, o4, o2, o3))); + Assert.assertNotEquals(t1, new QueryStats.TableAccess(table("t1", 5, o1, o4, o3))); + Assert.assertNotEquals(t1, new QueryStats.TableAccess(table("t1", 5, o1, o2, o4))); + } + + @Test + public void queryPhaseEqualsTest() { + YdbQueryStats.TableAccessStats t1 = table("t1", 5, op(1, 1), op(1, 2), op(1, 3)); + YdbQueryStats.TableAccessStats t2 = table("t2", 5, op(1, 1), op(1, 2), op(1, 3)); + + QueryStats.QueryPhase p1 = new QueryStats.QueryPhase(phase(true, 1, 2, 3, t1)); + + Assert.assertEquals(p1.hashCode(), new QueryStats.QueryPhase(phase(true, 1, 2, 3, t1)).hashCode()); + Assert.assertNotEquals(p1.hashCode(), new QueryStats.QueryPhase(phase(false, 1, 2, 3, t1)).hashCode()); + Assert.assertNotEquals(p1.hashCode(), new QueryStats.QueryPhase(phase(true, 2, 2, 3, t1)).hashCode()); + Assert.assertNotEquals(p1.hashCode(), new QueryStats.QueryPhase(phase(true, 1, 3, 3, t1)).hashCode()); + Assert.assertNotEquals(p1.hashCode(), new QueryStats.QueryPhase(phase(true, 1, 2, 4, t1)).hashCode()); + Assert.assertNotEquals(p1.hashCode(), new QueryStats.QueryPhase(phase(true, 1, 2, 3, t2)).hashCode()); + Assert.assertNotEquals(p1.hashCode(), new QueryStats.QueryPhase(phase(true, 1, 2, 3, t1, t2)).hashCode()); + + Assert.assertEquals(p1, p1); + Assert.assertEquals(p1, new QueryStats.QueryPhase(phase(true, 1, 2, 3, t1))); + + Assert.assertNotEquals(p1, null); + Assert.assertNotEquals(p1, phase(true, 1, 2, 3, t1)); + + Assert.assertNotEquals(p1, new QueryStats.QueryPhase(phase(false, 1, 2, 3, t1))); + Assert.assertNotEquals(p1, new QueryStats.QueryPhase(phase(true, 2, 2, 3, t1))); + Assert.assertNotEquals(p1, new QueryStats.QueryPhase(phase(true, 1, 3, 3, t1))); + Assert.assertNotEquals(p1, new QueryStats.QueryPhase(phase(true, 1, 2, 4, t1))); + Assert.assertNotEquals(p1, new QueryStats.QueryPhase(phase(true, 1, 2, 3, t2))); + Assert.assertNotEquals(p1, new QueryStats.QueryPhase(phase(true, 1, 2, 3, t1, t2))); + } +} diff --git a/table/src/main/java/tech/ydb/table/query/DataQueryResult.java b/table/src/main/java/tech/ydb/table/query/DataQueryResult.java index 406685da..1d8ef707 100644 --- a/table/src/main/java/tech/ydb/table/query/DataQueryResult.java +++ b/table/src/main/java/tech/ydb/table/query/DataQueryResult.java @@ -1,8 +1,10 @@ package tech.ydb.table.query; import java.util.List; +import java.util.stream.Collectors; import tech.ydb.proto.ValueProtos; +import tech.ydb.proto.YdbQueryStats; import tech.ydb.proto.table.YdbTable; import tech.ydb.table.query.stats.QueryStats; import tech.ydb.table.result.ResultSetReader; @@ -15,18 +17,60 @@ public class DataQueryResult { private final String txId; private final List resultSets; - private final QueryStats queryStats; + private final YdbQueryStats.QueryStats queryStats; public DataQueryResult(YdbTable.ExecuteQueryResult result) { this.txId = result.getTxMeta().getId(); this.resultSets = result.getResultSetsList(); - queryStats = result.hasQueryStats() ? new QueryStats(result.getQueryStats()) : null; + this.queryStats = result.hasQueryStats() ? result.getQueryStats() : null; } + public DataQueryResult(String txId, List results, YdbQueryStats.QueryStats stats) { + this.txId = txId; + this.resultSets = results; + this.queryStats = stats; + } + + @Deprecated public DataQueryResult(String txId, List results, QueryStats stats) { this.txId = txId; this.resultSets = results; - queryStats = stats; + this.queryStats = YdbQueryStats.QueryStats.newBuilder() + .setQueryAst(stats.getQueryAst()) + .setQueryPlan(stats.getQueryPlan()) + .setTotalCpuTimeUs(stats.getTotalCpuTimeUs()) + .setTotalDurationUs(stats.getTotalDurationUs()) + .setProcessCpuTimeUs(stats.getProcessCpuTimeUs()) + .setCompilation(YdbQueryStats.CompilationStats.newBuilder() + .setCpuTimeUs(stats.getCompilation().getCpuTimeUs()) + .setDurationUs(stats.getCompilation().getDurationUs()) + .setFromCache(stats.getCompilation().getFromCache()) + .build()) + .addAllQueryPhases(stats.getQueryPhasesList().stream().map( + phase -> YdbQueryStats.QueryPhaseStats.newBuilder() + .setAffectedShards(phase.getAffectedShards()) + .setCpuTimeUs(phase.getCpuTimeUs()) + .setDurationUs(phase.getDurationUs()) + .setLiteralPhase(phase.getLiteralPhase()) + .addAllTableAccess(phase.getTableAccessList().stream().map( + table -> YdbQueryStats.TableAccessStats.newBuilder() + .setName(table.getName()) + .setPartitionsCount(table.getPartitionsCount()) + .setReads(YdbQueryStats.OperationStats.newBuilder() + .setRows(table.getReads().getRows()) + .setBytes(table.getReads().getBytes()) + .build()) + .setDeletes(YdbQueryStats.OperationStats.newBuilder() + .setRows(table.getDeletes().getRows()) + .setBytes(table.getDeletes().getBytes()) + .build()) + .setUpdates(YdbQueryStats.OperationStats.newBuilder() + .setRows(table.getUpdates().getRows()) + .setBytes(table.getUpdates().getBytes()) + .build()) + .build()).collect(Collectors.toList())) + .build()).collect(Collectors.toList())) + .build(); } public String getTxId() { @@ -58,6 +102,10 @@ public boolean isEmpty() { } public QueryStats getQueryStats() { + return new QueryStats(queryStats); + } + + public YdbQueryStats.QueryStats getRawQueryStats() { return queryStats; }