From e934fa6a6eff4f427c9a5ab663d6e2e77486aaa0 Mon Sep 17 00:00:00 2001 From: Martin Gallwey Date: Mon, 29 Jun 2026 18:12:27 +0100 Subject: [PATCH] Optimize result fetching via block-draining and check inlining Accelerate data retrieval pathways in the Cursor class by optimizing row iteration and reducing interpreter overhead on high-frequency method loops. Detailed changes: - fetchone: Inline the `_check_closed()` state verification directly into the method body. This removes function-call stack overhead for every individual row retrieved. - fetchall: Refactor the loop to slice and drain the current in-memory result batch in bulk using `list.extend()` instead of sequentially invoking `fetchone()` row by row. - fetchall: Directly request the next network payload batch via `fetch_result_set_next` once the in-memory collection is exhausted, updating total `rownumber` tracking as a single block operation. - fetchall: Add a defensive guard clause against unallocated result sets to ensure strict DB-API compatibility. --- pynuodb/cursor.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/pynuodb/cursor.py b/pynuodb/cursor.py index 4e515f5..f944518 100644 --- a/pynuodb/cursor.py +++ b/pynuodb/cursor.py @@ -184,7 +184,11 @@ def executemany(self, operation, seq_of_parameters): def fetchone(self): # type: () -> Optional[result_set.Row] """Return the next row of results from the previous SQL operation.""" - self._check_closed() + # Inline _check_closed to avoid per-row function-call overhead. + if self.closed: + raise Error("cursor is closed") + if self.session.closed: + raise Error("connection is closed") if self._result_set is None: raise Error("Previous execute did not produce any results or no call was issued yet") self.rownumber += 1 @@ -218,14 +222,22 @@ def fetchall(self): # type: () -> List[result_set.Row] """Return all rows generated by the previous SQL operation.""" self._check_closed() + if self._result_set is None: + raise Error("Previous execute did not produce any results or no call was issued yet") - fetched_rows = [] + fetched_rows = [] # type: List[result_set.Row] while True: - row = self.fetchone() - if row is None: + # Drain the current in-memory batch in one shot instead of calling + # fetchone() per row. + idx = self._result_set.results_idx + batch = self._result_set.results + if idx < len(batch): + fetched_rows.extend(batch[idx:]) + self._result_set.results_idx = len(batch) + if self._result_set.complete: break - else: - fetched_rows.append(row) + self.session.fetch_result_set_next(self._result_set) + self.rownumber += len(fetched_rows) return fetched_rows def nextset(self): # pylint: disable=no-self-use