This is an automated email from the ASF dual-hosted git repository.
apkhmv pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new 35d373c931f IGNITE-27452 Add --timed option to CLI (#7314)
35d373c931f is described below
commit 35d373c931fc7ec4b6ffe461896f70997a6eadc3
Author: Aleksandr Pakhomov <[email protected]>
AuthorDate: Fri Dec 26 14:37:45 2025 +0300
IGNITE-27452 Add --timed option to CLI (#7314)
---
.../cli/commands/sql/ItSqlTimedOptionTest.java | 134 +++++++++++++++++++++
.../ignite/internal/cli/commands/Options.java | 7 ++
.../internal/cli/commands/sql/SqlCommand.java | 54 ++++++++-
.../internal/cli/commands/sql/SqlExecCommand.java | 7 +-
.../cli/commands/sql/SqlExecReplCommand.java | 7 +-
.../internal/cli/commands/sql/SqlReplCommand.java | 53 +++++++-
.../cli/decorators/SqlQueryResultDecorator.java | 8 +-
.../apache/ignite/internal/cli/sql/SqlManager.java | 2 +
.../ignite/internal/cli/sql/SqlQueryResult.java | 37 +++++-
.../internal/cli/commands/sql/SqlCommandTest.java | 12 ++
10 files changed, 309 insertions(+), 12 deletions(-)
diff --git
a/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/sql/ItSqlTimedOptionTest.java
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/sql/ItSqlTimedOptionTest.java
new file mode 100644
index 00000000000..6b0dd7a0175
--- /dev/null
+++
b/modules/cli/src/integrationTest/java/org/apache/ignite/internal/cli/commands/sql/ItSqlTimedOptionTest.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.cli.commands.sql;
+
+import static org.junit.jupiter.api.Assertions.assertAll;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests for the --timed option of the sql command.
+ */
+public class ItSqlTimedOptionTest extends CliSqlCommandTestBase {
+
+ /**
+ * Tests that --timed option displays query execution time after SELECT
result.
+ */
+ @Test
+ void timedSelectQuery() {
+ execute("sql", "select * from person", "--jdbc-url", JDBC_URL,
"--timed");
+
+ assertAll(
+ this::assertExitCodeIsZero,
+ // Should contain the table with data
+ () -> assertOutputContains("ID"),
+ () -> assertOutputContains("NAME"),
+ // Should contain timing information at the end
+ () -> assertOutputMatches("(?s).*Query executed in \\d+ms
\\(client-side\\)\\.\\s*"),
+ this::assertErrOutputIsEmpty
+ );
+ }
+
+ /**
+ * Tests that --timed option displays query execution time after INSERT
result.
+ */
+ @Test
+ void timedInsertQuery() {
+ execute("sql", "insert into person(id, name, salary) values (100,
'Test', 50.0)", "--jdbc-url", JDBC_URL, "--timed");
+
+ assertAll(
+ this::assertExitCodeIsZero,
+ // Should contain the update count message
+ () -> assertOutputContains("Updated 1 rows."),
+ // Should contain timing information at the end
+ () -> assertOutputMatches("(?s).*Query executed in \\d+ms
\\(client-side\\)\\.\\s*"),
+ this::assertErrOutputIsEmpty
+ );
+ }
+
+ /**
+ * Tests that --timed option displays query execution time after multiple
statements.
+ */
+ @Test
+ void timedMultipleStatements() {
+ execute("sql", "insert into person(id, name, salary) values (101, 'A',
10.0); select count(*) from person",
+ "--jdbc-url", JDBC_URL, "--timed");
+
+ assertAll(
+ this::assertExitCodeIsZero,
+ // Should contain insert result
+ () -> assertOutputContains("Updated 1 rows."),
+ // Should contain select result (column name)
+ () -> assertOutputContains("COUNT(*)"),
+ // Should contain timing information at the very end (only
once, after all results)
+ () -> assertOutputMatches("(?s).*Query executed in \\d+ms
\\(client-side\\)\\.\\s*"),
+ this::assertErrOutputIsEmpty
+ );
+ }
+
+ /**
+ * Tests that without --timed option, no timing information is displayed.
+ */
+ @Test
+ void noTimedOption() {
+ execute("sql", "select * from person", "--jdbc-url", JDBC_URL);
+
+ assertAll(
+ this::assertExitCodeIsZero,
+ () -> assertOutputContains("ID"),
+ () -> assertOutputDoesNotContain("Query executed in"),
+ this::assertErrOutputIsEmpty
+ );
+ }
+
+ /**
+ * Tests that --timed works together with --plain option.
+ */
+ @Test
+ void timedWithPlainOption() {
+ execute("sql", "select id from person where id = 0", "--jdbc-url",
JDBC_URL, "--timed", "--plain");
+
+ assertAll(
+ this::assertExitCodeIsZero,
+ // Plain output should not have fancy borders
+ () -> assertOutputDoesNotContain("╔"),
+ () -> assertOutputDoesNotContain("║"),
+ // Should still contain timing information
+ () -> assertOutputMatches("(?s).*Query executed in \\d+ms
\\(client-side\\)\\.\\s*"),
+ this::assertErrOutputIsEmpty
+ );
+ }
+
+ /**
+ * Tests that --timed shows time for DDL queries (CREATE TABLE).
+ */
+ @Test
+ void timedDdlQuery() {
+ execute("sql", "create table timed_test(id int primary key)",
"--jdbc-url", JDBC_URL, "--timed");
+
+ assertAll(
+ this::assertExitCodeIsZero,
+ () -> assertOutputContains("Updated 0 rows."),
+ () -> assertOutputMatches("(?s).*Query executed in \\d+ms
\\(client-side\\)\\.\\s*"),
+ this::assertErrOutputIsEmpty
+ );
+
+ // Clean up the created table
+ execute("sql", "drop table timed_test", "--jdbc-url", JDBC_URL);
+ }
+}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/Options.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/Options.java
index 3445a9f864d..29db05f2a4f 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/Options.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/Options.java
@@ -54,6 +54,7 @@ public enum Options {
UNIT_NODES(Constants.UNIT_NODES_OPTION, Constants.UNIT_NODES_OPTION,
Constants.UNIT_NODES_OPTION_DESC),
PLAIN(Constants.PLAIN_OPTION, Constants.PLAIN_OPTION,
Constants.PLAIN_OPTION_DESC),
+ TIMED(Constants.TIMED_OPTION, Constants.TIMED_OPTION,
Constants.TIMED_OPTION_DESC),
VERBOSE(Constants.VERBOSE_OPTION, Constants.VERBOSE_OPTION_SHORT,
Constants.VERBOSE_OPTION_DESC),
HELP(Constants.HELP_OPTION, Constants.HELP_OPTION_SHORT,
Constants.HELP_OPTION_DESC),
VERSION(Constants.VERSION_OPTION, Constants.VERSION_OPTION,
Constants.VERSION_OPTION_DESC),
@@ -204,6 +205,12 @@ public enum Options {
public static final String PLAIN_OPTION_DESC = "Display output with
plain formatting. "
+ "Might be useful if you want to pipe the output to another
command";
+ /** Timed option long name. */
+ public static final String TIMED_OPTION = "--timed";
+
+ /** Timed option description. */
+ public static final String TIMED_OPTION_DESC = "Display query
execution time (measured on the client) after the output";
+
/** JDBC URL option long name. */
public static final String JDBC_URL_OPTION = "--jdbc-url";
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlCommand.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlCommand.java
index 9ab52fdd34b..918130c18a2 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlCommand.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlCommand.java
@@ -17,13 +17,26 @@
package org.apache.ignite.internal.cli.commands.sql;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.JDBC_URL_KEY;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.JDBC_URL_OPTION;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.JDBC_URL_OPTION_DESC;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.PLAIN_OPTION;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.PLAIN_OPTION_DESC;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.SCRIPT_FILE_OPTION;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.SCRIPT_FILE_OPTION_DESC;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.TIMED_OPTION;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.TIMED_OPTION_DESC;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.Callable;
import org.apache.ignite.internal.cli.commands.BaseCommand;
import org.apache.ignite.internal.cli.commands.sql.planner.SqlPlannerCommand;
-import org.apache.ignite.internal.util.ArrayUtils;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.IFactory;
+import picocli.CommandLine.Option;
import picocli.CommandLine.Unmatched;
/**
@@ -40,6 +53,21 @@ import picocli.CommandLine.Unmatched;
description = "SQL query engine operations."
)
public class SqlCommand extends BaseCommand implements Callable<Integer> {
+ // These options are documented here for --help display but are actually
processed by SqlExecCommand.
+ // All args are passed through to SqlExecCommand via @Unmatched.
+
+ @Option(names = JDBC_URL_OPTION, descriptionKey = JDBC_URL_KEY,
description = JDBC_URL_OPTION_DESC)
+ private String jdbc;
+
+ @Option(names = PLAIN_OPTION, description = PLAIN_OPTION_DESC)
+ private boolean plain;
+
+ @Option(names = TIMED_OPTION, description = TIMED_OPTION_DESC)
+ private boolean timed;
+
+ @Option(names = SCRIPT_FILE_OPTION, description = SCRIPT_FILE_OPTION_DESC)
+ private String file;
+
@Unmatched
private String[] args;
@@ -58,6 +86,28 @@ public class SqlCommand extends BaseCommand implements
Callable<Integer> {
.setDefaultValueProvider(spec.defaultValueProvider())
.setExecutionExceptionHandler(spec.commandLine().getExecutionExceptionHandler());
- return commandLine.execute(args == null ?
ArrayUtils.STRING_EMPTY_ARRAY : args);
+ return commandLine.execute(buildArgs());
+ }
+
+ private String[] buildArgs() {
+ List<String> result = new ArrayList<>();
+ // Add unmatched args first - they may contain positional parameters
that need to be
+ // parsed before options for proper ArgGroup mutual exclusion
detection in SqlExecCommand.
+ if (args != null) {
+ Collections.addAll(result, args);
+ }
+ if (jdbc != null) {
+ result.add(JDBC_URL_OPTION + "=" + jdbc);
+ }
+ if (plain) {
+ result.add(PLAIN_OPTION);
+ }
+ if (timed) {
+ result.add(TIMED_OPTION);
+ }
+ if (file != null) {
+ result.add(SCRIPT_FILE_OPTION + "=" + file);
+ }
+ return result.toArray(new String[0]);
}
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlExecCommand.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlExecCommand.java
index 9f0144497bf..c8ca189a8dc 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlExecCommand.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlExecCommand.java
@@ -24,6 +24,8 @@ import static
org.apache.ignite.internal.cli.commands.Options.Constants.PLAIN_OP
import static
org.apache.ignite.internal.cli.commands.Options.Constants.PLAIN_OPTION_DESC;
import static
org.apache.ignite.internal.cli.commands.Options.Constants.SCRIPT_FILE_OPTION;
import static
org.apache.ignite.internal.cli.commands.Options.Constants.SCRIPT_FILE_OPTION_DESC;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.TIMED_OPTION;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.TIMED_OPTION_DESC;
import java.io.File;
import java.io.IOException;
@@ -56,6 +58,9 @@ public class SqlExecCommand extends BaseCommand implements
Callable<Integer> {
@Option(names = PLAIN_OPTION, description = PLAIN_OPTION_DESC)
private boolean plain;
+ @Option(names = TIMED_OPTION, description = TIMED_OPTION_DESC)
+ private boolean timed;
+
@ArgGroup(multiplicity = "1")
private ExecOptions execOptions;
@@ -83,7 +88,7 @@ public class SqlExecCommand extends BaseCommand implements
Callable<Integer> {
return runPipeline(CallExecutionPipeline.builder(new
SqlQueryCall(sqlManager))
.inputProvider(() -> new StringCallInput(executeCommand))
.exceptionHandler(SqlExceptionHandler.INSTANCE)
- .decorator(new SqlQueryResultDecorator(plain))
+ .decorator(new SqlQueryResultDecorator(plain, timed))
);
} catch (SQLException e) {
ExceptionWriter exceptionWriter =
ExceptionWriter.fromPrintWriter(spec.commandLine().getErr());
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlExecReplCommand.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlExecReplCommand.java
index ca7214eecc4..34588cb5dac 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlExecReplCommand.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlExecReplCommand.java
@@ -24,6 +24,8 @@ import static
org.apache.ignite.internal.cli.commands.Options.Constants.PLAIN_OP
import static
org.apache.ignite.internal.cli.commands.Options.Constants.PLAIN_OPTION_DESC;
import static
org.apache.ignite.internal.cli.commands.Options.Constants.SCRIPT_FILE_OPTION;
import static
org.apache.ignite.internal.cli.commands.Options.Constants.SCRIPT_FILE_OPTION_DESC;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.TIMED_OPTION;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.TIMED_OPTION_DESC;
import static
org.apache.ignite.internal.cli.commands.treesitter.parser.Parser.isTreeSitterParserAvailable;
import static org.apache.ignite.internal.cli.core.style.AnsiStringSupport.ansi;
import static org.apache.ignite.internal.cli.core.style.AnsiStringSupport.fg;
@@ -88,6 +90,9 @@ public class SqlExecReplCommand extends BaseCommand
implements Runnable {
@Option(names = PLAIN_OPTION, description = PLAIN_OPTION_DESC)
private boolean plain;
+ @Option(names = TIMED_OPTION, description = TIMED_OPTION_DESC)
+ private boolean timed;
+
@ArgGroup
private ExecOptions execOptions;
@@ -218,7 +223,7 @@ public class SqlExecReplCommand extends BaseCommand
implements Runnable {
.inputProvider(() -> new StringCallInput(line))
.output(spec.commandLine().getOut())
.errOutput(spec.commandLine().getErr())
- .decorator(new SqlQueryResultDecorator(plain))
+ .decorator(new SqlQueryResultDecorator(plain, timed))
.verbose(verbose)
.exceptionHandler(SqlExceptionHandler.INSTANCE)
.build();
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplCommand.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplCommand.java
index 539a475894a..4dedb459109 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplCommand.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/commands/sql/SqlReplCommand.java
@@ -17,13 +17,26 @@
package org.apache.ignite.internal.cli.commands.sql;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.JDBC_URL_KEY;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.JDBC_URL_OPTION;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.JDBC_URL_OPTION_DESC;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.PLAIN_OPTION;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.PLAIN_OPTION_DESC;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.SCRIPT_FILE_OPTION;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.SCRIPT_FILE_OPTION_DESC;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.TIMED_OPTION;
+import static
org.apache.ignite.internal.cli.commands.Options.Constants.TIMED_OPTION_DESC;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.Callable;
import org.apache.ignite.internal.cli.commands.BaseCommand;
import
org.apache.ignite.internal.cli.commands.sql.planner.SqlPlannerReplCommand;
-import org.apache.ignite.internal.util.ArrayUtils;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.IFactory;
+import picocli.CommandLine.Option;
import picocli.CommandLine.Unmatched;
/**
@@ -40,6 +53,21 @@ import picocli.CommandLine.Unmatched;
description = "SQL query engine operations."
)
public class SqlReplCommand extends BaseCommand implements Callable<Integer> {
+ // These options are documented here for --help display but are actually
processed by SqlExecReplCommand.
+ // All args are passed through to SqlExecReplCommand via @Unmatched.
+
+ @Option(names = JDBC_URL_OPTION, descriptionKey = JDBC_URL_KEY,
description = JDBC_URL_OPTION_DESC)
+ private String jdbc;
+
+ @Option(names = PLAIN_OPTION, description = PLAIN_OPTION_DESC)
+ private boolean plain;
+
+ @Option(names = TIMED_OPTION, description = TIMED_OPTION_DESC)
+ private boolean timed;
+
+ @Option(names = SCRIPT_FILE_OPTION, description = SCRIPT_FILE_OPTION_DESC)
+ private String file;
+
@Unmatched
private String[] args;
@@ -58,6 +86,27 @@ public class SqlReplCommand extends BaseCommand implements
Callable<Integer> {
.setDefaultValueProvider(spec.defaultValueProvider())
.setExecutionExceptionHandler(spec.commandLine().getExecutionExceptionHandler());
- return commandLine.execute(args == null ?
ArrayUtils.STRING_EMPTY_ARRAY : args);
+ return commandLine.execute(buildArgs());
+ }
+
+ private String[] buildArgs() {
+ List<String> result = new ArrayList<>();
+ // Add unmatched args first to preserve positional parameter order.
+ if (args != null) {
+ Collections.addAll(result, args);
+ }
+ if (jdbc != null) {
+ result.add(JDBC_URL_OPTION + "=" + jdbc);
+ }
+ if (plain) {
+ result.add(PLAIN_OPTION);
+ }
+ if (timed) {
+ result.add(TIMED_OPTION);
+ }
+ if (file != null) {
+ result.add(SCRIPT_FILE_OPTION + "=" + file);
+ }
+ return result.toArray(new String[0]);
}
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/decorators/SqlQueryResultDecorator.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/decorators/SqlQueryResultDecorator.java
index 77c4aacd001..2c99e6a2ea8 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/decorators/SqlQueryResultDecorator.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/decorators/SqlQueryResultDecorator.java
@@ -26,13 +26,19 @@ import org.apache.ignite.internal.cli.sql.SqlQueryResult;
*/
public class SqlQueryResultDecorator implements Decorator<SqlQueryResult,
TerminalOutput> {
private final boolean plain;
+ private final boolean timed;
public SqlQueryResultDecorator(boolean plain) {
+ this(plain, false);
+ }
+
+ public SqlQueryResultDecorator(boolean plain, boolean timed) {
this.plain = plain;
+ this.timed = timed;
}
@Override
public TerminalOutput decorate(SqlQueryResult data) {
- return data.getResult(plain);
+ return data.getResult(plain, timed);
}
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/sql/SqlManager.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/sql/SqlManager.java
index 372957dcae5..0a9989066b9 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/sql/SqlManager.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/sql/SqlManager.java
@@ -50,6 +50,7 @@ public class SqlManager implements AutoCloseable {
SqlQueryResultBuilder sqlQueryResultBuilder = new
SqlQueryResultBuilder();
+ long startTime = System.currentTimeMillis();
try (Statement statement = connection.createStatement()) {
statement.execute(sql);
@@ -63,6 +64,7 @@ public class SqlManager implements AutoCloseable {
}
} while (statement.getMoreResults() || statement.getUpdateCount()
!= -1);
+ sqlQueryResultBuilder.setDurationMs(System.currentTimeMillis() -
startTime);
return sqlQueryResultBuilder.build();
}
}
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/sql/SqlQueryResult.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/sql/SqlQueryResult.java
index 4f24efff54f..1aaa10a8106 100644
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/sql/SqlQueryResult.java
+++
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/sql/SqlQueryResult.java
@@ -28,9 +28,30 @@ import org.apache.ignite.internal.cli.sql.table.Table;
*/
public class SqlQueryResult {
private final List<SqlQueryResultItem> sqlQueryResultItems;
+ private final long durationMs;
- private SqlQueryResult(List<SqlQueryResultItem> sqlQueryResultItems) {
+ private SqlQueryResult(List<SqlQueryResultItem> sqlQueryResultItems, long
durationMs) {
this.sqlQueryResultItems = sqlQueryResultItems;
+ this.durationMs = durationMs;
+ }
+
+ /**
+ * SQL query result provider.
+ *
+ * @param plain Whether to use plain formatting.
+ * @param timed Whether to include execution time in output.
+ * @return terminal output all items in query result.
+ */
+ public TerminalOutput getResult(boolean plain, boolean timed) {
+ return () -> {
+ String result = sqlQueryResultItems.stream()
+ .map(x -> x.decorate(plain).toTerminalString())
+ .collect(Collectors.joining(""));
+ if (timed) {
+ result += "Query executed in " + durationMs + "ms
(client-side).\n";
+ }
+ return result;
+ };
}
/**
@@ -39,9 +60,7 @@ public class SqlQueryResult {
* @return terminal output all items in query result.
*/
public TerminalOutput getResult(boolean plain) {
- return () -> sqlQueryResultItems.stream()
- .map(x -> x.decorate(plain).toTerminalString())
- .collect(Collectors.joining(""));
+ return getResult(plain, false);
}
/**
@@ -49,6 +68,7 @@ public class SqlQueryResult {
*/
static class SqlQueryResultBuilder {
private final List<SqlQueryResultItem> sqlQueryResultItems = new
ArrayList<>();
+ private long durationMs;
/**
* Add table to query result.
@@ -64,8 +84,15 @@ public class SqlQueryResult {
sqlQueryResultItems.add(new SqlQueryResultMessage(message + "\n"));
}
+ /**
+ * Set the query execution duration in milliseconds.
+ */
+ void setDurationMs(long durationMs) {
+ this.durationMs = durationMs;
+ }
+
public SqlQueryResult build() {
- return new SqlQueryResult(sqlQueryResultItems);
+ return new SqlQueryResult(sqlQueryResultItems, durationMs);
}
}
}
diff --git
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/sql/SqlCommandTest.java
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/sql/SqlCommandTest.java
index 22602dc1de3..851d1ed1c74 100644
---
a/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/sql/SqlCommandTest.java
+++
b/modules/cli/src/test/java/org/apache/ignite/internal/cli/commands/sql/SqlCommandTest.java
@@ -56,4 +56,16 @@ public class SqlCommandTest extends CliCommandTestBase {
() -> assertErrOutputContains("<command>, --file=<file> are
mutually exclusive (specify only one)")
);
}
+
+ @Test
+ @DisplayName("Should show --timed option in help")
+ void timedOptionInHelp() {
+ execute("--help");
+
+ assertAll(
+ this::assertExitCodeIsZero,
+ () -> assertOutputContains("--timed"),
+ () -> assertOutputContains("Display query execution time")
+ );
+ }
}