Two oddities were encountered during investigation of some application (with probably extremely wrong approach to statements control).
Consider following Python script (let its name be: chk_multiple_prepare_in_same_attachment.py):
import os
import argparse as ap
from firebird.driver import driver_config, connect
parser = ap.ArgumentParser()
parser.add_argument("fb_clnt", help="Path to FB client library")
parser.add_argument("query_cnt", nargs='?', type=int, default=30, help="Number of queries to generate")
parser.add_argument("protocol", nargs='?', default='inet', type = str.lower, choices = ('xnet', 'inet', 'inet4', 'local'), help="Protocol to be used for connection.")
args = parser.parse_args()
assert os.path.isfile(args.fb_clnt), "FB client library not found: '%s'" % args.fb_clnt
assert args.query_cnt > 0
driver_config.fb_client_library.value = args.fb_clnt
#########################
### S E T T I N G S ###
#########################
DB_NAME = 'employee'
CHECK_QUERY = "select count(*) from rdb$pages where rdb$page_number = ?"
#########################
dsn = ('' if args.protocol == 'local' else args.protocol + '://') + str(DB_NAME)
with connect(dsn, user='SYSDBA', password='masterkey') as con:
print(con.info.version)
con.begin()
cur = con.cursor()
cur.execute("select rdb$config_name, rdb$config_value from rdb$config where rdb$config_name = 'MaxStatementCacheSize'")
k,v = cur.fetchone()
print(k, '=', v)
ps_lst = []
for i in range(args.query_cnt):
print(f'{i+1:6} / {args.query_cnt}')
ps_lst.append( cur.prepare( CHECK_QUERY ) )
cur.execute( ps_lst[-1], (i,) )
print('Doing rollback...')
con.rollback()
print('Done. Now closing connection...')
print('Connection closed. Bye-bye')
/*
It is assumed that:
Python firebird-driver has been installed;
databases.conf has employee alias that points to existing employee.fdb;
security.db contains regular SYSDBA/masterkey
*/
### ISSUE-1 ###
Let us change alias employee`` by adding non-zero MaxStatementCacheSize``` paameter:
employee = $(dir_sampleDb)/employee.fdb
{
MaxStatementCacheSize = 2M
}
(it seems that one may to set here ANY reasonable value; i've tried 1K, 8K, 16K, 512K, 1M, 2M, 50M and 256M)
Now run script:
%PYTHON3X_HOME%\chk_multiple_prepare_in_same_attachment.py C:\FB\50SS\fbclient.dll 1010
-- where:
C:\FB\50SS\fbclient.dll -- full path to running FB 5.x client library;
1010 -- number of parametrized statements to be prepared within same transaction.
Console output will be:
5.0.5.1888
MaxStatementCacheSize = 268435456
1 / 1010
2 / 1010
3 / 1010
...
999 / 1010
1000 / 1010
1001 / 1010
But further:
1002 / 1010
Traceback (most recent call last):
File "C:\FBTESTING\qa\misc\chk_multiple_prepare_in_same_attachment-p.py", line 35, in <module>
ps_lst.append( cur.prepare( CHECK_QUERY ) )
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Python3x\Lib\site-packages\firebird\driver\core.py", line 4034, in prepare
return self._connection._prepare(operation, self._transaction)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Python3x\Lib\site-packages\firebird\driver\core.py", line 1853, in _prepare
stmt = self._att.prepare(tra._tra, sql, self.__sql_dialect)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Python3x\Lib\site-packages\firebird\driver\interfaces.py", line 1167, in prepare
self._check()
File "C:\Python3x\Lib\site-packages\firebird\driver\interfaces.py", line 141, in _check
raise self.__report(DatabaseError, self.status.get_errors())
firebird.driver.types.DatabaseError: Too many concurrent executions of the same request
-- and application finishes with abend at this point (and no any message in the firebird.log).
NB (again): this outcome will be the same for any MaxStatementCacheSize.
### ISSUE-2 ###
Now let change alias settings like this:
employee = $(dir_sampleDb)/employee.fdb
{
MaxStatementCacheSize = 0
}
And run script with some BIG value of parameter N2:
``%PYTHON3X_HOME%\chk_multiple_prepare_in_same_attachment.py C:\FB\50SS\fbclient.dll 50000```
(yes, we want to prepare 50'000 statements within same connection)
This script will complete without errors.
But since the moment after all 50K FREE_STATEMENTS + DETACH_DATABASE completed and up to return control to OS one need to wait about 7 minutes.
This is console when i run this script and redirect its output to console splitter with requirement to show timestamps (mtee /t):
13:31:31.676 49998
13:31:31.679 49999
13:31:31.681 Doing rollback...
13:31:31.694 Done. Now closing connection... ---------- [ 1 ]
13:38:32.032 Connection closed. Bye-bye --------------- [ 2 ]
Trace:
2026-09-22T13:31:31.6820 (15692:0000000004FD2340) EXECUTE_STATEMENT_FINISH
employee (ATT_44, SYSDBA:NONE, NONE, TCPv6:::1/56397)
C:\Python3x\python.exe:14480
(TRA_181, CONCURRENCY | WAIT | READ_WRITE)
Statement 50089:
-------------------------------------------------------------------------------
select count(*) from rdb$pages where rdb$page_number = ?
param0 = integer, "49999"
0 records fetched
0 ms
2026-09-22T13:31:31.6820 (15692:0000000004FD2340) CLOSE_CURSOR
employee (ATT_44, SYSDBA:NONE, NONE, TCPv6:::1/56397)
C:\Python3x\python.exe:14480
Statement 50089:
-------------------------------------------------------------------------------
select count(*) from rdb$pages where rdb$page_number = ?
2026-09-22T13:31:31.6820 (15692:0000000004FD2340) ROLLBACK_TRANSACTION
employee (ATT_44, SYSDBA:NONE, NONE, TCPv6:::1/56397)
C:\Python3x\python.exe:14480
(TRA_181, CONCURRENCY | WAIT | READ_WRITE)
0 ms, 1 fetch(es), 1 mark(s)
2026-09-22T13:31:31.6940 (15692:0000000004FD2340) FREE_STATEMENT
employee (ATT_44, SYSDBA:NONE, NONE, TCPv6:::1/56397)
C:\Python3x\python.exe:14480
Statement 50089:
-------------------------------------------------------------------------------
select count(*) from rdb$pages where rdb$page_number = ?
2026-09-22T13:31:31.6950 (15692:0000000004FD2340) FREE_STATEMENT
employee (ATT_44, SYSDBA:NONE, NONE, TCPv6:::1/56397)
C:\Python3x\python.exe:14480
Statement 50088:
-------------------------------------------------------------------------------
select count(*) from rdb$pages where rdb$page_number = ?
2026-09-22T13:31:31.6950 (15692:0000000004FD2340) FREE_STATEMENT
employee (ATT_44, SYSDBA:NONE, NONE, TCPv6:::1/56397)
C:\Python3x\python.exe:14480
............................................
SIMILAR ~49999 'FREE_STATEMENT' BLOCKS BELOW
............................................
2026-09-22T13:32:04.9200 (15692:0000000004FD2340) FREE_STATEMENT
employee (ATT_44, SYSDBA:NONE, NONE, TCPv6:::1/56397)
C:\Python3x\python.exe:14480
Statement 90:
-------------------------------------------------------------------------------
select count(*) from rdb$pages where rdb$page_number = ?
2026-09-22T13:32:04.9210 (15692:0000000004FD2340) DETACH_DATABASE
employee (ATT_44, SYSDBA:NONE, NONE, TCPv6:::1/56397)
C:\Python3x\python.exe:14480
What engine(?) did for ~7 minutes after connection has been closed ?
Two oddities were encountered during investigation of some application (with probably extremely wrong approach to statements control).
Consider following Python script (let its name be:
chk_multiple_prepare_in_same_attachment.py):/*
It is assumed that:
Python firebird-driver has been installed;
databases.conf has
employeealias that points to existing employee.fdb;security.db contains regular
SYSDBA/masterkey*/
### ISSUE-1 ###
Let us change alias
employee`` by adding non-zeroMaxStatementCacheSize``` paameter:(it seems that one may to set here ANY reasonable value; i've tried 1K, 8K, 16K, 512K, 1M, 2M, 50M and 256M)
Now run script:
%PYTHON3X_HOME%\chk_multiple_prepare_in_same_attachment.py C:\FB\50SS\fbclient.dll 1010-- where:
C:\FB\50SS\fbclient.dll-- full path to running FB 5.x client library;1010-- number of parametrized statements to be prepared within same transaction.Console output will be:
But further:
-- and application finishes with abend at this point (and no any message in the firebird.log).
NB (again): this outcome will be the same for any MaxStatementCacheSize.
### ISSUE-2 ###
Now let change alias settings like this:
And run script with some BIG value of parameter N2:
``%PYTHON3X_HOME%\chk_multiple_prepare_in_same_attachment.py C:\FB\50SS\fbclient.dll 50000```
(yes, we want to prepare 50'000 statements within same connection)
This script will complete without errors.
But since the moment after all 50K
FREE_STATEMENTS+DETACH_DATABASEcompleted and up to return control to OS one need to wait about 7 minutes.This is console when i run this script and redirect its output to console splitter with requirement to show timestamps (
mtee /t):Trace:
What engine(?) did for ~7 minutes after connection has been closed ?