diff --git a/changelog.md b/changelog.md index 29bb3edf..703ec54d 100644 --- a/changelog.md +++ b/changelog.md @@ -5,6 +5,10 @@ Internal -------- * Create new data class to handle SQL/command results to make further code improvements easier +Bug Fixes +-------- +* Update watch query output to display the correct execution time on all iterations (#763). + 1.44.1 (2026/01/10) ============== @@ -19,7 +23,6 @@ Bug Fixes Features -------- - * Add enum value completions for WHERE/HAVING clauses. (#790) * Add `show_favorite_query` config option to control query printing when running favorite queries. (#1118) diff --git a/mycli/main.py b/mycli/main.py index a462428f..1c63b419 100755 --- a/mycli/main.py +++ b/mycli/main.py @@ -819,11 +819,18 @@ def show_suggestion_tip() -> bool: def output_res(res: Generator[SQLResult], start: float) -> None: nonlocal mutating result_count = 0 - for title, cur, headers, status in res: + for title, cur, headers, status, command in res: + logger.debug("title: %r", title) logger.debug("headers: %r", headers) logger.debug("rows: %r", cur) logger.debug("status: %r", status) threshold = 1000 + # If this is a watch query, offset the start time on the 2nd+ iteration + # to account for the sleep duration + if command is not None and command["name"] == "watch": + watch_seconds = float(command["seconds"]) + if result_count > 0: + start += watch_seconds if is_select(status) and cur and cur.rowcount > threshold: self.echo( f"The result set has more than {threshold} rows.", @@ -873,7 +880,7 @@ def output_res(res: Generator[SQLResult], start: float) -> None: # get and display warnings if enabled if self.show_warnings and isinstance(cur, Cursor) and cur.warning_count > 0: warnings = sqlexecute.run("SHOW WARNINGS") - for title, cur, headers, status in warnings: + for title, cur, headers, status, _command in warnings: formatted = self.format_output( title, cur, @@ -1332,9 +1339,8 @@ def get_prompt(self, string: str) -> str: def run_query(self, query: str, new_line: bool = True) -> None: """Runs *query*.""" assert self.sqlexecute is not None - results = self.sqlexecute.run(query) - for result in results: - title, cur, headers, status = result + res = self.sqlexecute.run(query) + for title, cur, headers, _status, _command in res: self.main_formatter.query = query self.redirect_formatter.query = query output = self.format_output( @@ -1351,7 +1357,7 @@ def run_query(self, query: str, new_line: bool = True) -> None: # get and display warnings if enabled if self.show_warnings and isinstance(cur, Cursor) and cur.warning_count > 0: warnings = self.sqlexecute.run("SHOW WARNINGS") - for title, cur, headers, _ in warnings: + for title, cur, headers, _status, _command in warnings: output = self.format_output( title, cur, diff --git a/mycli/packages/special/iocommands.py b/mycli/packages/special/iocommands.py index c17e5c71..31e66455 100644 --- a/mycli/packages/special/iocommands.py +++ b/mycli/packages/special/iocommands.py @@ -580,11 +580,15 @@ def watch_query(arg: str, **kwargs) -> Generator[SQLResult, None, None]: set_pager_enabled(False) for sql, title in sql_list: cur.execute(sql) + command = { + "name": "watch", + "seconds": seconds, + } if cur.description: headers = [x[0] for x in cur.description] - yield SQLResult(title=title, results=cur, headers=headers) + yield SQLResult(title=title, results=cur, headers=headers, command=command) else: - yield SQLResult(title=title) + yield SQLResult(title=title, command=command) sleep(seconds) except KeyboardInterrupt: # This prints the Ctrl-C character in its own line, which prevents diff --git a/mycli/packages/sqlresult.py b/mycli/packages/sqlresult.py index 5da243bb..46711ad2 100644 --- a/mycli/packages/sqlresult.py +++ b/mycli/packages/sqlresult.py @@ -9,9 +9,10 @@ class SQLResult: results: Cursor | list[tuple] | None = None headers: list[str] | str | None = None status: str | None = None + command: dict[str, object] | None = None def __iter__(self): - return iter((self.title, self.results, self.headers, self.status)) + return iter((self.title, self.results, self.headers, self.status, self.command)) def __str__(self): - return f"{self.title}, {self.results}, {self.headers}, {self.status}" + return f"{self.title}, {self.results}, {self.headers}, {self.status}, {self.command}" diff --git a/mycli/sqlexecute.py b/mycli/sqlexecute.py index e29bf1f4..c33dbc13 100644 --- a/mycli/sqlexecute.py +++ b/mycli/sqlexecute.py @@ -490,7 +490,7 @@ def reset_connection_id(self) -> None: _logger.debug("Get current connection id") try: res = self.run("select connection_id()") - for _title, cur, _headers, _status in res: + for _title, cur, _headers, _status, _command in res: self.connection_id = cur.fetchone()[0] except Exception as e: # See #1054 diff --git a/test/utils.py b/test/utils.py index 3a9b42aa..4c60fb51 100644 --- a/test/utils.py +++ b/test/utils.py @@ -49,7 +49,7 @@ def run(executor, sql, rows_as_list=True): """Return string output for the sql to be run.""" result = [] - for title, rows, headers, status in executor.run(sql): + for title, rows, headers, status, _command in executor.run(sql): rows = list(rows) if (rows_as_list and rows) else rows result.append({"title": title, "rows": rows, "headers": headers, "status": status})