From 1a7b4e428ee7083c412a394e7c5dd79eb1e1fcfd Mon Sep 17 00:00:00 2001 From: "F.D.Castel" Date: Thu, 7 May 2026 23:47:03 -0300 Subject: [PATCH] Fix ValueError in TraceParser when parameter value contains ' = ' TraceParser._parse_parameters_block called line.split(' = ') without maxsplit. A parameter value that itself contains the substring ' = ' (legitimate -- a varchar column can carry arbitrary text including key=value-shaped strings) splits into 3+ parts and the unpacking '_, param_def = ...' raises: ValueError: too many values to unpack (expected 2, got N) The enclosing trace block is then dropped silently, affecting every event that carries parameters or function-return values. Fix: pass maxsplit=1. The second ' = ' (and any after) stays inside the value, where it belongs. Add regression test test_68_param_value_containing_equals exercising a varchar parameter whose value contains two ' = ' substrings. --- src/firebird/lib/trace.py | 2 +- tests/test_trace.py | 45 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/firebird/lib/trace.py b/src/firebird/lib/trace.py index cdef233..f9185a9 100644 --- a/src/firebird/lib/trace.py +++ b/src/firebird/lib/trace.py @@ -1383,7 +1383,7 @@ def _parse_parameters_block(self) -> list[tuple[str, Any]]: parameters = [] while self.__current_block and self.__current_block[0].startswith('param'): line = self.__current_block.popleft() - _, param_def = line.split(' = ') + _, param_def = line.split(' = ', maxsplit=1) parameters.append(self._parse_value_spec(param_def)) return parameters def _parse_parameters(self, *, for_procedure: bool=False) -> None: diff --git a/tests/test_trace.py b/tests/test_trace.py index 5fffc5e..11bcd14 100644 --- a/tests/test_trace.py +++ b/tests/test_trace.py @@ -513,3 +513,48 @@ def test_67_unknown_performance_parameter(): EventCommit(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 30, 435000), status=, attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE'], run_time=5, reads=10, writes=2, fetches=None, marks=None) """ _check_events(trace_lines, output) + +def test_68_param_value_containing_equals(): + """Tests parsing of a parameter whose value contains the ' = ' substring. + + Without ``maxsplit=1`` on ``line.split(' = ')`` in + ``_parse_parameters_block``, a parameter value that itself contains + ``' = '`` causes ``ValueError: too many values to unpack (expected 2, + got 3)`` and the enclosing trace block is dropped silently. Such + values are entirely legal -- a varchar column can carry arbitrary + text, including key=value-shaped strings. + """ + trace_lines = """2014-05-23T11:00:28.5840 (3720:0000000000EFD9E8) ATTACH_DATABASE + /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) + /opt/firebird/bin/isql:8723 + +2014-05-23T11:00:28.6160 (3720:0000000000EFD9E8) START_TRANSACTION + /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) + /opt/firebird/bin/isql:8723 + (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) + +2014-05-23T11:00:30.4350 (3720:0000000000EFD9E8) EXECUTE_STATEMENT_FINISH + /home/employee.fdb (ATT_8, SYSDBA:NONE, ISO88591, TCPv4:192.168.1.5) + /opt/firebird/bin/isql:8723 + (TRA_1568, READ_COMMITTED | REC_VERSION | WAIT | READ_WRITE) + +Statement 1: +------------------------------------------------------------------------------- +UPDATE NOTES SET BODY = ? WHERE ID = ? +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +param0 = varchar(80), "alpha = 1; beta = 2" +param1 = integer, "42" + +0 records fetched + 15 ms, 147 read(s), 1 write(s), 6 fetch(es) + +""" + # Parameter value 'alpha = 1; beta = 2' contains ' = ' twice. + # The block must parse cleanly and the value must be preserved verbatim. + output = """EventAttach(event_id=1, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 584000), status=, attachment_id=8, database='/home/employee.fdb', charset='ISO88591', protocol='TCPv4', address='192.168.1.5', user='SYSDBA', role='NONE', remote_process='/opt/firebird/bin/isql', remote_pid=8723) +EventTransactionStart(event_id=2, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 28, 616000), status=, attachment_id=8, transaction_id=1568, options=['READ_COMMITTED', 'REC_VERSION', 'WAIT', 'READ_WRITE']) +ParamSet(par_id=1, params=[('varchar(80)', 'alpha = 1; beta = 2'), ('integer', 42)]) +SQLInfo(sql_id=1, sql='UPDATE NOTES SET BODY = ? WHERE ID = ?', plan='') +EventStatementFinish(event_id=3, timestamp=datetime.datetime(2014, 5, 23, 11, 0, 30, 435000), status=, attachment_id=8, transaction_id=1568, statement_id=1, sql_id=1, param_id=1, records=0, run_time=15, reads=147, writes=1, fetches=6, marks=None, access=None) +""" + _check_events(trace_lines, output)