Skip to content

Commit 7aa33bb

Browse files
committed
Initial support for Firebird 5.0
1 parent cbbdc10 commit 7aa33bb

File tree

10 files changed

+210
-51
lines changed

10 files changed

+210
-51
lines changed

src/firebird/driver/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,4 @@
5959
Server, Statement)
6060

6161
#: Current driver version, SEMVER string.
62-
__VERSION__ = '1.8.0'
62+
__VERSION__ = '1.9.0'

src/firebird/driver/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ def __init__(self, name: str, *, optional: bool=False, description: str=None):
150150
self.decfloat_traps: ListOption = \
151151
ListOption('decfloat_traps', DecfloatTraps,
152152
"Which DECFLOAT exceptional conditions cause a trap")
153+
#: Number of parallel workers
154+
self.parallel_workers = \
155+
IntOption('parallel_workers', "Number of parallel workers")
153156
# Create options
154157
#: Database create option. Page size to be used.
155158
self.page_size: IntOption = \

src/firebird/driver/core.py

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,8 @@ def __init__(self, *, user: str=None, password: str=None, role: str=None,
411411
config: str=None, auth_plugin_list: str=None, session_time_zone: str=None,
412412
set_db_replica: ReplicaMode=None, set_bind: str=None,
413413
decfloat_round: DecfloatRound=None,
414-
decfloat_traps: List[DecfloatTraps]=None
414+
decfloat_traps: List[DecfloatTraps]=None,
415+
parallel_workers: int=None
415416
):
416417
# Available options:
417418
# AuthClient, WireCryptPlugin, Providers, ConnectionTimeout, WireCrypt,
@@ -482,6 +483,8 @@ def __init__(self, *, user: str=None, password: str=None, role: str=None,
482483
self.db_sql_dialect: Optional[int] = db_sql_dialect
483484
#: Character set for the database [db create only]
484485
self.db_charset: Optional[str] = db_charset
486+
#: Number of parallel workers
487+
self.parallel_workers: int = parallel_workers
485488
def clear(self) -> None:
486489
"""Clear all information.
487490
"""
@@ -586,6 +589,8 @@ def parse_buffer(self, buffer: bytes) -> None:
586589
elif tag == DPBItem.DECFLOAT_TRAPS:
587590
self.decfloat_traps = [DecfloatTraps(v.strip())
588591
for v in dpb.get_string().split(',')]
592+
elif tag == DPBItem.PARALLEL_WORKERS:
593+
self.parallel_workers = dpb.get_int()
589594
def get_buffer(self, *, for_create: bool = False) -> bytes:
590595
"""Create DPB from stored information.
591596
"""
@@ -637,6 +642,8 @@ def get_buffer(self, *, for_create: bool = False) -> bytes:
637642
if self.decfloat_traps is not None:
638643
dpb.insert_string(DPBItem.DECFLOAT_TRAPS, ','.join(e.value for e in
639644
self.decfloat_traps))
645+
if self.parallel_workers is not None:
646+
dpb.insert_int(DPBItem.PARALLEL_WORKERS, self.parallel_workers)
640647
if for_create:
641648
if self.page_size is not None:
642649
dpb.insert_int(DPBItem.PAGE_SIZE, self.page_size)
@@ -2118,7 +2125,8 @@ def connect(database: str, *, user: str=None, password: str=None, role: str=None
21182125
config=db_config.config.value, auth_plugin_list=auth_plugin_list,
21192126
session_time_zone=session_time_zone, set_bind=db_config.set_bind.value,
21202127
decfloat_round=db_config.decfloat_round.value,
2121-
decfloat_traps=db_config.decfloat_traps.value)
2128+
decfloat_traps=db_config.decfloat_traps.value,
2129+
parallel_workers=db_config.parallel_workers.value)
21222130
return __make_connection(False, dsn, db_config.utf8filename.value, dpb.get_buffer(),
21232131
db_config.sql_dialect.value, charset, crypt_callback)
21242132

@@ -4222,7 +4230,7 @@ def backup(self, *, database: FILESPEC, backup: Union[FILESPEC, Sequence[FILESPE
42224230
callback: CB_OUTPUT_LINE=None, stats: str=None,
42234231
verbose: bool=False, verbint: int=None, skip_data: str=None,
42244232
include_data: str=None, keyhoder: str=None, keyname: str=None,
4225-
crypt: str=None) -> None:
4233+
crypt: str=None, parallel_workers: int=None) -> None:
42264234
"""Request logical (GBAK) database backup. **(ASYNC service)**
42274235
42284236
Arguments:
@@ -4240,6 +4248,7 @@ def backup(self, *, database: FILESPEC, backup: Union[FILESPEC, Sequence[FILESPE
42404248
keyholder: Keyholder name [Firebird 4]
42414249
keyname: Key name [Firebird 4]
42424250
crypt: Encryption specification [Firebird 4]
4251+
parallel_workers: Number of parallel workers [Firebird 5]
42434252
"""
42444253
if isinstance(backup, (str, Path)):
42454254
backup = [backup]
@@ -4267,6 +4276,8 @@ def backup(self, *, database: FILESPEC, backup: Union[FILESPEC, Sequence[FILESPE
42674276
spb.insert_string(SrvBackupOption.KEYNAME, keyname)
42684277
if crypt is not None:
42694278
spb.insert_string(SrvBackupOption.CRYPT, crypt)
4279+
if parallel_workers is not None:
4280+
spb.insert_int(SrvBackupOption.PARALLEL_WORKERS, parallel_workers)
42704281
spb.insert_int(SPBItem.OPTIONS, flags)
42714282
if verbose:
42724283
spb.insert_tag(SPBItem.VERBOSE)
@@ -4287,7 +4298,7 @@ def restore(self, *, backup: Union[FILESPEC, Sequence[FILESPEC]],
42874298
page_size: int=None, buffers: int=None,
42884299
access_mode: DbAccessMode=DbAccessMode.READ_WRITE, include_data: str=None,
42894300
keyhoder: str=None, keyname: str=None, crypt: str=None,
4290-
replica_mode: ReplicaMode=None) -> None:
4301+
replica_mode: ReplicaMode=None, parallel_workers: int=None) -> None:
42914302
"""Request database restore from logical (GBAK) backup. **(ASYNC service)**
42924303
42934304
Arguments:
@@ -4309,6 +4320,7 @@ def restore(self, *, backup: Union[FILESPEC, Sequence[FILESPEC]],
43094320
keyname: Key name [Firebird 4]
43104321
crypt: Encryption specification [Firebird 4]
43114322
replica_mode: Replica mode for restored database [Firebird 4]
4323+
parallel_workers: Number of parallel workers [Firebird 5]
43124324
"""
43134325
if isinstance(backup, (str, Path)):
43144326
backup = [backup]
@@ -4346,6 +4358,8 @@ def restore(self, *, backup: Union[FILESPEC, Sequence[FILESPEC]],
43464358
spb.insert_string(SrvRestoreOption.CRYPT, crypt)
43474359
if replica_mode is not None:
43484360
spb.insert_int(SrvRestoreOption.REPLICA_MODE, replica_mode.value)
4361+
if parallel_workers is not None:
4362+
spb.insert_int(SrvRestoreOption.PARALLEL_WORKERS, parallel_workers)
43494363
spb.insert_int(SPBItem.OPTIONS, flags)
43504364
if verbose:
43514365
spb.insert_tag(SPBItem.VERBOSE)
@@ -4725,24 +4739,27 @@ def bring_online(self, *, database: FILESPEC, mode: OnlineMode=OnlineMode.NORMAL
47254739
spb.insert_bytes(SrvPropertiesOption.ONLINE_MODE, bytes([mode]))
47264740
self._srv()._svc.start(spb.get_buffer())
47274741
self._srv().wait()
4728-
def sweep(self, *, database: FILESPEC, role: str=None) -> None:
4742+
def sweep(self, *, database: FILESPEC, role: str=None, parallel_workers: int=None) -> None:
47294743
"""Perform database sweep operation.
47304744
47314745
Arguments:
47324746
database: Database specification or alias.
47334747
role: SQL ROLE name passed to gfix.
4748+
parallel_workers: Number of parallel workers [Firebird 5]
47344749
"""
47354750
self._srv()._reset_output()
47364751
with a.get_api().util.get_xpb_builder(XpbKind.SPB_START) as spb:
47374752
spb.insert_tag(ServerAction.REPAIR)
47384753
spb.insert_string(SPBItem.DBNAME, str(database), encoding=self._srv().encoding)
47394754
if role is not None:
47404755
spb.insert_string(SPBItem.SQL_ROLE_NAME, role, encoding=self._srv().encoding)
4756+
if parallel_workers is not None:
4757+
spb.insert_int(SrvRepairOption.PARALLEL_WORKERS, parallel_workers)
47414758
spb.insert_int(SPBItem.OPTIONS, SrvRepairFlag.SWEEP_DB)
47424759
self._srv()._svc.start(spb.get_buffer())
47434760
self._srv().wait()
47444761
def repair(self, *, database: FILESPEC, flags: SrvRepairFlag=SrvRepairFlag.REPAIR,
4745-
role: str=None) -> bytes:
4762+
role: str=None) -> None:
47464763
"""Perform database repair operation. **(SYNC service)**
47474764
47484765
Arguments:
@@ -4903,7 +4920,7 @@ def rollback_limbo_transaction(self, *, database: FILESPEC, transaction_id: int)
49034920
self._srv()._svc.start(spb.get_buffer())
49044921
self._srv()._read_all_binary_output()
49054922

4906-
class ServerDbServices(ServerDbServices3):
4923+
class ServerDbServices4(ServerDbServices3):
49074924
"""Database-related actions and services [Firebird 4+].
49084925
"""
49094926
def nfix_database(self, *, database: FILESPEC, role: str=None,
@@ -4942,6 +4959,26 @@ def set_replica_mode(self, *, database: FILESPEC, mode: ReplicaMode, role: str=N
49424959
self._srv()._svc.start(spb.get_buffer())
49434960
self._srv().wait()
49444961

4962+
class ServerDbServices(ServerDbServices4):
4963+
"""Database-related actions and services [Firebird 5+].
4964+
"""
4965+
def upgrade(self, *, database: FILESPEC) -> bytes:
4966+
"""Perform database repair operation. **(SYNC service)**
4967+
4968+
Arguments:
4969+
database: Database specification or alias.
4970+
flags: Repair flags.
4971+
role: SQL ROLE name passed to gfix.
4972+
"""
4973+
self._srv()._reset_output()
4974+
with a.get_api().util.get_xpb_builder(XpbKind.SPB_START) as spb:
4975+
spb.insert_tag(ServerAction.REPAIR)
4976+
spb.insert_string(SPBItem.DBNAME, str(database), encoding=self._srv().encoding)
4977+
spb.insert_int(SPBItem.OPTIONS, SrvRepairFlag.UPGRADE_DB)
4978+
self._srv()._svc.start(spb.get_buffer())
4979+
self._srv().wait()
4980+
4981+
49454982
class ServerUserServices(ServerServiceProvider):
49464983
"""User-related actions and services.
49474984
"""
@@ -5457,8 +5494,12 @@ def database(self) -> Union[ServerDbServices3, ServerDbServices]:
54575494
"""Access to various database-related actions and services.
54585495
"""
54595496
if self.__dbsvc is None:
5460-
cls = ServerDbServices if self._engine_version() >= 4.0 \
5461-
else ServerDbServices3
5497+
if self._engine_version() >= 5.0:
5498+
cls = ServerDbServices
5499+
elif self._engine_version() == 4.0:
5500+
cls = ServerDbServices4
5501+
else:
5502+
cls = ServerDbServices3
54625503
self.__dbsvc = cls(self)
54635504
return self.__dbsvc
54645505
@property

src/firebird/driver/fbapi.py

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -981,8 +981,14 @@ class IInt128_struct(Structure):
981981
IResultSet_deprecatedClose = CFUNCTYPE(None, IResultSet, IStatus)
982982
# procedure setDelayedOutputFormat(this: IResultSet; status: IStatus; format: IMessageMetadata)
983983
IResultSet_setDelayedOutputFormat = CFUNCTYPE(None, IResultSet, IStatus, IMessageMetadata)
984+
# IResultSet(4) : IResultSet(3)
984985
# procedure close(this: IResultSet; status: IStatus)
985986
IResultSet_close = CFUNCTYPE(None, IResultSet, IStatus)
987+
# >>> Firebird 5
988+
# IResultSet(5) : IResultSet(4)
989+
# procedure(this: IResultSet; status: IStatus; itemsLength: Cardinal; items: BytePtr; bufferLength: Cardinal; buffer: BytePtr); cdecl;
990+
IResultSet_getInfo = CFUNCTYPE(None, IResultSet, IStatus, Cardinal, BytePtr, Cardinal, BytePtr)
991+
986992
#
987993
# IStatement(3) : ReferenceCounted
988994
# --------------------------------
@@ -1549,7 +1555,9 @@ class IInt128_struct(Structure):
15491555
('getMetadata', IResultSet_getMetadata),
15501556
('deprecatedClose', IResultSet_deprecatedClose),
15511557
('setDelayedOutputFormat', IResultSet_setDelayedOutputFormat),
1552-
('close', IResultSet_close)] # v4: 3.0.7 => 3.0.8, 4.0.0 => 4.0.1
1558+
('close', IResultSet_close), # v4: 3.0.7 => 3.0.8, 4.0.0 => 4.0.1
1559+
('getInfo', IResultSet_getInfo), # v5: 5.0.0
1560+
]
15531561
# >>> Firebird 4
15541562
# IStatement(5) : ReferenceCounted
15551563
IStatement_VTable._fields_ = [ # v3 - initial
@@ -1955,22 +1963,59 @@ class FirebirdAPI:
19551963
`ISC_LONG`
19561964
19571965
isc_array_lookup_bounds():
1958-
Old API function isc_array_lookup_bounds()
1966+
Old API function.
19591967
19601968
isc_array_put_slice():
1961-
Old API function isc_array_put_slice()
1969+
Old API function.
19621970
19631971
isc_array_get_slice():
1964-
Old API function isc_array_get_slice()
1972+
Old API function.
19651973
19661974
isc_que_events():
1967-
Old API function isc_que_events()
1975+
Old API function.
19681976
19691977
isc_event_counts():
1970-
Old API function isc_event_counts()
1978+
Old API function.
19711979
19721980
isc_cancel_events():
1973-
Old API function isc_cancel_events()
1981+
Old API function.
1982+
1983+
isc_compile_request()
1984+
Old API function.
1985+
1986+
isc_start_request()
1987+
Old API function.
1988+
1989+
isc_release_request()
1990+
Old API function.
1991+
1992+
isc_receive()
1993+
Old API function.
1994+
1995+
isc_start_and_send()
1996+
Old API function.
1997+
1998+
isc_send()
1999+
Old API function.
2000+
2001+
isc_open_blob2()
2002+
Old API function.
2003+
2004+
isc_blob_info()
2005+
Old API function.
2006+
2007+
isc_create_blob2()
2008+
Old API function.
2009+
2010+
isc_get_segment()
2011+
Old API function.
2012+
2013+
isc_put_segment()
2014+
Old API function.
2015+
2016+
isc_close_blob():
2017+
Old API function.
2018+
19742019
"""
19752020
def __init__(self, filename: Path = None):
19762021
decimal.getcontext().prec = 34

src/firebird/driver/interfaces.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -715,8 +715,8 @@ def set_delayed_output_format(self, fmt: iMessageMetadata) -> None:
715715
self.vtable.setDelayedOutputFormat(self, self.status, fmt)
716716
self._check()
717717

718-
# IResultSet(3) : ReferenceCounted
719-
class iResultSet(iResultSet_v3):
718+
# IResultSet(4) : ReferenceCounted
719+
class iResultSet_v4(iResultSet_v3):
720720
"Class that wraps IResultSet interface for use from Python"
721721
VERSION = 4
722722
def close(self) -> None:
@@ -725,6 +725,15 @@ def close(self) -> None:
725725
self._check()
726726
self._refcnt -= 1
727727

728+
# IResultSet(5) : ReferenceCounted
729+
class iResultSet(iResultSet_v3):
730+
"Class that wraps IResultSet interface for use from Python"
731+
VERSION = 5
732+
def get_info(self, items: bytes, buffer: bytes) -> None:
733+
"Returns information about result set."
734+
self.vtable.getInfo(self, self.status, len(items), items, len(buffer), buffer)
735+
self._check()
736+
728737
# IStatement(3) : ReferenceCounted
729738
class iStatement_v3(iReferenceCounted):
730739
"Class that wraps IStatement v3 interface for use from Python"

0 commit comments

Comments
 (0)