solentware-base 5.2__tar.gz → 5.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {solentware-base-5.2/solentware_base.egg-info → solentware_base-5.2.2}/PKG-INFO +2 -2
- {solentware-base-5.2 → solentware_base-5.2.2}/pyproject.toml +2 -2
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_database.py +1 -1
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_databasedu.py +3 -3
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_db.py +14 -15
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_db_tkinter.py +16 -15
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_dbdu.py +4 -4
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_dbdu_tkinter.py +4 -4
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_dpt.py +20 -12
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_lmdb.py +10 -12
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_lmdbdu.py +4 -4
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_nosql.py +18 -30
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_nosqldu.py +3 -3
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_sqlite.py +37 -25
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/find.py +4 -2
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/record.py +5 -3
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/where.py +97 -80
- {solentware-base-5.2 → solentware_base-5.2.2/solentware_base.egg-info}/PKG-INFO +2 -2
- {solentware-base-5.2 → solentware_base-5.2.2}/LICENCE +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/MANIFEST.in +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/README +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/setup.cfg +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/__init__.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/apsw_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/apswdu_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/berkeleydb_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/berkeleydbdu_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/bsddb3_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/bsddb3du_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/__init__.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_bytebit.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/_sqlitedu.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/bytebit.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/constants.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/cursor.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/filespec.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/findvalues.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/merge.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/recordset.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/recordsetbasecursor.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/recordsetcursor.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/segmentsize.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/tree.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/core/wherevalues.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/db_tcl.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/db_tkinter_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/db_tkinterdu_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/dpt_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/dptdu_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/dptfastload_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/gnu_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/gnu_module.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/gnudu_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/lmdb_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/lmdbdu_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/modulequery.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/ndbm_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/ndbm_module.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/ndbmdu_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/sqlite3_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/sqlite3du_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/__init__.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/base_3_to_4.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/base_3_to_4_db.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/base_3_to_4_sqlite.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/berkeleydb_du_splice_fix.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/compare_dpt_tape_files.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/create_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/sqlite_table_name_upgrade.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/traverse_dpt_tape_files.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/tools/ui_base_3_to_4.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/unqlite_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/unqlitedu_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/vedis_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base/vedisdu_database.py +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base.egg-info/SOURCES.txt +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base.egg-info/dependency_links.txt +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/solentware_base.egg-info/top_level.txt +0 -0
- {solentware-base-5.2 → solentware_base-5.2.2}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: solentware-base
|
|
3
|
-
Version: 5.2
|
|
3
|
+
Version: 5.2.2
|
|
4
4
|
Summary: Bitmapped record number databases.
|
|
5
5
|
Author-email: Roger Marsh <roger.marsh@solentware.co.uk>
|
|
6
6
|
License: Licence for solentware_base package
|
|
@@ -23,10 +23,10 @@ Project-URL: Homepage, http://www.solentware.co.uk
|
|
|
23
23
|
Project-URL: Repository, https://github.com/RogerMarsh/solentware-base.git
|
|
24
24
|
Project-URL: Bug Tracker, https://github.com/RogerMarsh/solentware-base/issues
|
|
25
25
|
Classifier: License :: OSI Approved :: BSD License
|
|
26
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
27
26
|
Classifier: Programming Language :: Python :: 3.9
|
|
28
27
|
Classifier: Programming Language :: Python :: 3.10
|
|
29
28
|
Classifier: Programming Language :: Python :: 3.11
|
|
29
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
30
30
|
Classifier: Operating System :: OS Independent
|
|
31
31
|
Classifier: Topic :: Database
|
|
32
32
|
Classifier: Intended Audience :: Developers
|
|
@@ -10,17 +10,17 @@ line-length = 79
|
|
|
10
10
|
|
|
11
11
|
[project]
|
|
12
12
|
name = "solentware-base"
|
|
13
|
-
version = "5.2"
|
|
13
|
+
version = "5.2.2"
|
|
14
14
|
authors = [
|
|
15
15
|
{ name="Roger Marsh", email="roger.marsh@solentware.co.uk" },
|
|
16
16
|
]
|
|
17
17
|
description = "Bitmapped record number databases."
|
|
18
18
|
classifiers = [
|
|
19
19
|
"License :: OSI Approved :: BSD License",
|
|
20
|
-
"Programming Language :: Python :: 3.8",
|
|
21
20
|
"Programming Language :: Python :: 3.9",
|
|
22
21
|
"Programming Language :: Python :: 3.10",
|
|
23
22
|
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
24
|
"Operating System :: OS Independent",
|
|
25
25
|
"Topic :: Database",
|
|
26
26
|
"Intended Audience :: Developers",
|
|
@@ -81,7 +81,7 @@ class Database:
|
|
|
81
81
|
"""
|
|
82
82
|
deletekey = instance.key.pack()
|
|
83
83
|
instance.set_packed_value_and_indexes()
|
|
84
|
-
high_record = self.
|
|
84
|
+
high_record = self.get_high_record_number(dbset)
|
|
85
85
|
self.delete(dbset, deletekey, instance.srvalue)
|
|
86
86
|
instance.srkey = self.encode_record_number(deletekey)
|
|
87
87
|
srindex = instance.srindex
|
|
@@ -151,9 +151,9 @@ class Database(_database.Database):
|
|
|
151
151
|
if values[-1] != record_number:
|
|
152
152
|
values.append(record_number)
|
|
153
153
|
if len(values) > SegmentSize.db_upper_conversion_limit:
|
|
154
|
-
vsk = value_segments[
|
|
155
|
-
|
|
156
|
-
|
|
154
|
+
vsk = value_segments[key] = (
|
|
155
|
+
SegmentSize.empty_bitarray.copy()
|
|
156
|
+
)
|
|
157
157
|
for j in values:
|
|
158
158
|
vsk[j] = True
|
|
159
159
|
vsk[record_number] = True
|
|
@@ -695,10 +695,8 @@ class Database(_database.Database):
|
|
|
695
695
|
)
|
|
696
696
|
return None
|
|
697
697
|
|
|
698
|
-
# high_record will become high_record_number to fit changed
|
|
699
|
-
# get_high_record.
|
|
700
698
|
def note_freed_record_number_segment(
|
|
701
|
-
self, dbset, segment, record_number_in_segment,
|
|
699
|
+
self, dbset, segment, record_number_in_segment, high_record_number
|
|
702
700
|
):
|
|
703
701
|
"""Add existence bitmap segment to list with spare record numbers.
|
|
704
702
|
|
|
@@ -708,9 +706,9 @@ class Database(_database.Database):
|
|
|
708
706
|
"""
|
|
709
707
|
del record_number_in_segment
|
|
710
708
|
try:
|
|
711
|
-
high_segment = divmod(
|
|
712
|
-
|
|
713
|
-
]
|
|
709
|
+
high_segment = divmod(
|
|
710
|
+
high_record_number, SegmentSize.db_segment_size
|
|
711
|
+
)[0]
|
|
714
712
|
except TypeError:
|
|
715
713
|
# Implies attempt to delete record from empty database.
|
|
716
714
|
# The delete method will have raised an exception if appropriate.
|
|
@@ -791,13 +789,14 @@ class Database(_database.Database):
|
|
|
791
789
|
)
|
|
792
790
|
return segment, record_number
|
|
793
791
|
|
|
794
|
-
|
|
795
|
-
# Only used in one place, and it is extra work to get the data in_nosql.
|
|
796
|
-
def get_high_record(self, file):
|
|
792
|
+
def get_high_record_number(self, file):
|
|
797
793
|
"""Return the high existing record number in table for file."""
|
|
798
794
|
cursor = self.table[file].cursor(txn=self.dbtxn)
|
|
799
795
|
try:
|
|
800
|
-
|
|
796
|
+
last = cursor.last()
|
|
797
|
+
if last is None:
|
|
798
|
+
return None
|
|
799
|
+
return last[0]
|
|
801
800
|
finally:
|
|
802
801
|
cursor.close()
|
|
803
802
|
|
|
@@ -1414,7 +1413,7 @@ class Database(_database.Database):
|
|
|
1414
1413
|
recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
|
|
1415
1414
|
if keylike is None:
|
|
1416
1415
|
return recordlist
|
|
1417
|
-
|
|
1416
|
+
matcher = re.compile(keylike)
|
|
1418
1417
|
cursor = self.table[SUBFILE_DELIMITER.join((file, field))].cursor(
|
|
1419
1418
|
txn=self.dbtxn
|
|
1420
1419
|
)
|
|
@@ -1422,7 +1421,7 @@ class Database(_database.Database):
|
|
|
1422
1421
|
record = cursor.first()
|
|
1423
1422
|
while record:
|
|
1424
1423
|
key, value = record
|
|
1425
|
-
if
|
|
1424
|
+
if matcher.search(key):
|
|
1426
1425
|
self.populate_recordset_segment(recordlist, value)
|
|
1427
1426
|
record = cursor.next()
|
|
1428
1427
|
finally:
|
|
@@ -1478,9 +1477,9 @@ class Database(_database.Database):
|
|
|
1478
1477
|
|
|
1479
1478
|
Keys are in range set by combinations of ge, gt, le, and lt.
|
|
1480
1479
|
"""
|
|
1481
|
-
if ge and gt:
|
|
1480
|
+
if isinstance(ge, bytes) and isinstance(gt, bytes):
|
|
1482
1481
|
raise DatabaseError("Both 'ge' and 'gt' given in key range")
|
|
1483
|
-
if le and lt:
|
|
1482
|
+
if isinstance(le, bytes) and isinstance(lt, bytes):
|
|
1484
1483
|
raise DatabaseError("Both 'le' and 'lt' given in key range")
|
|
1485
1484
|
recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
|
|
1486
1485
|
cursor = self.table[SUBFILE_DELIMITER.join((file, field))].cursor(
|
|
@@ -1490,7 +1489,7 @@ class Database(_database.Database):
|
|
|
1490
1489
|
if ge is None and gt is None:
|
|
1491
1490
|
record = cursor.first()
|
|
1492
1491
|
else:
|
|
1493
|
-
record = cursor.set_range(ge or gt)
|
|
1492
|
+
record = cursor.set_range(ge or gt or b"")
|
|
1494
1493
|
if gt:
|
|
1495
1494
|
while record:
|
|
1496
1495
|
if record[0] > gt:
|
|
@@ -895,10 +895,8 @@ class Database(_database.Database):
|
|
|
895
895
|
)
|
|
896
896
|
return None
|
|
897
897
|
|
|
898
|
-
# high_record will become high_record_number to fit changed
|
|
899
|
-
# get_high_record.
|
|
900
898
|
def note_freed_record_number_segment(
|
|
901
|
-
self, dbset, segment, record_number_in_segment,
|
|
899
|
+
self, dbset, segment, record_number_in_segment, high_record_number
|
|
902
900
|
):
|
|
903
901
|
"""Add existence bitmap segment to list with spare record numbers.
|
|
904
902
|
|
|
@@ -908,9 +906,9 @@ class Database(_database.Database):
|
|
|
908
906
|
"""
|
|
909
907
|
del record_number_in_segment
|
|
910
908
|
try:
|
|
911
|
-
high_segment = divmod(
|
|
912
|
-
|
|
913
|
-
]
|
|
909
|
+
high_segment = divmod(
|
|
910
|
+
high_record_number, SegmentSize.db_segment_size
|
|
911
|
+
)[0]
|
|
914
912
|
except TypeError:
|
|
915
913
|
# Implies attempt to delete record from empty database.
|
|
916
914
|
# The delete method will have raised an exception if appropriate.
|
|
@@ -1012,16 +1010,17 @@ class Database(_database.Database):
|
|
|
1012
1010
|
tcl_tk_call(tuple(command))
|
|
1013
1011
|
return segment, record_number
|
|
1014
1012
|
|
|
1015
|
-
|
|
1016
|
-
# Only used in one place, and it is extra work to get the data in_nosql.
|
|
1017
|
-
def get_high_record(self, file):
|
|
1013
|
+
def get_high_record_number(self, file):
|
|
1018
1014
|
"""Return the high existing record number in table for file."""
|
|
1019
1015
|
command = [self.table[file], "cursor"]
|
|
1020
1016
|
if self.dbtxn:
|
|
1021
1017
|
command.extend(["-txn", self.dbtxn])
|
|
1022
1018
|
cursor = tcl_tk_call(tuple(command))
|
|
1023
1019
|
try:
|
|
1024
|
-
|
|
1020
|
+
last = tcl_tk_call((cursor, "get", "-last")) or None
|
|
1021
|
+
if last is None:
|
|
1022
|
+
return None
|
|
1023
|
+
return last[0]
|
|
1025
1024
|
finally:
|
|
1026
1025
|
tcl_tk_call((cursor, "close"))
|
|
1027
1026
|
|
|
@@ -1793,7 +1792,7 @@ class Database(_database.Database):
|
|
|
1793
1792
|
recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
|
|
1794
1793
|
if keylike is None:
|
|
1795
1794
|
return recordlist
|
|
1796
|
-
|
|
1795
|
+
matcher = re.compile(keylike)
|
|
1797
1796
|
command = [
|
|
1798
1797
|
self.table[SUBFILE_DELIMITER.join((file, field))],
|
|
1799
1798
|
"cursor",
|
|
@@ -1805,7 +1804,7 @@ class Database(_database.Database):
|
|
|
1805
1804
|
record = tcl_tk_call((cursor, "get", "-first"))
|
|
1806
1805
|
while record:
|
|
1807
1806
|
key, value = record[0]
|
|
1808
|
-
if
|
|
1807
|
+
if matcher.search(key):
|
|
1809
1808
|
self.populate_recordset_segment(recordlist, value)
|
|
1810
1809
|
record = tcl_tk_call((cursor, "get", "-next"))
|
|
1811
1810
|
finally:
|
|
@@ -1872,9 +1871,9 @@ class Database(_database.Database):
|
|
|
1872
1871
|
|
|
1873
1872
|
Keys are in range set by combinations of ge, gt, le, and lt.
|
|
1874
1873
|
"""
|
|
1875
|
-
if ge and gt:
|
|
1874
|
+
if isinstance(ge, str) and isinstance(gt, str):
|
|
1876
1875
|
raise DatabaseError("Both 'ge' and 'gt' given in key range")
|
|
1877
|
-
if le and lt:
|
|
1876
|
+
if isinstance(le, str) and isinstance(lt, str):
|
|
1878
1877
|
raise DatabaseError("Both 'le' and 'lt' given in key range")
|
|
1879
1878
|
recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
|
|
1880
1879
|
command = [
|
|
@@ -1888,7 +1887,9 @@ class Database(_database.Database):
|
|
|
1888
1887
|
if ge is None and gt is None:
|
|
1889
1888
|
record = tcl_tk_call((cursor, "get", "-first"))
|
|
1890
1889
|
else:
|
|
1891
|
-
record = tcl_tk_call(
|
|
1890
|
+
record = tcl_tk_call(
|
|
1891
|
+
(cursor, "get", "-set_range", ge or gt or "")
|
|
1892
|
+
)
|
|
1892
1893
|
if gt:
|
|
1893
1894
|
while record:
|
|
1894
1895
|
record0 = record[0]
|
|
@@ -553,10 +553,10 @@ class Database(_databasedu.Database):
|
|
|
553
553
|
new_segment = make_segment_from_item(item)
|
|
554
554
|
new_segment |= existing_segment
|
|
555
555
|
new_segment.normalize()
|
|
556
|
-
item[
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
556
|
+
item[-2] = (
|
|
557
|
+
self.database.encode_number_for_sequential_file_dump(
|
|
558
|
+
new_segment.count_records(), 2
|
|
559
|
+
)
|
|
560
560
|
)
|
|
561
561
|
if int.from_bytes(high[-2], byteorder="big") == 1:
|
|
562
562
|
item[-1] = segment_table.append(
|
|
@@ -700,10 +700,10 @@ class Database(_databasedu.Database):
|
|
|
700
700
|
new_segment = make_segment_from_item(item)
|
|
701
701
|
new_segment |= existing_segment
|
|
702
702
|
new_segment.normalize()
|
|
703
|
-
item[
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
703
|
+
item[-2] = (
|
|
704
|
+
self.database.encode_number_for_sequential_file_dump(
|
|
705
|
+
new_segment.count_records(), 2
|
|
706
|
+
)
|
|
707
707
|
)
|
|
708
708
|
if int.from_bytes(high[-2], byteorder="big") == 1:
|
|
709
709
|
item[-1] = tcl_tk_call(
|
|
@@ -849,14 +849,14 @@ class Database(_database.Database):
|
|
|
849
849
|
dptapi.APIFieldValue(""),
|
|
850
850
|
)
|
|
851
851
|
)
|
|
852
|
-
matcher = re.compile(
|
|
852
|
+
matcher = re.compile(keylike)
|
|
853
853
|
dvcursor = dptfile.table_connection.OpenDirectValueCursor(
|
|
854
854
|
dptapi.APIFindValuesSpecification(dptfile.secondary[field])
|
|
855
855
|
)
|
|
856
856
|
dvcursor.GotoFirst()
|
|
857
857
|
while dvcursor.Accessible():
|
|
858
858
|
value = dvcursor.GetCurrentValue()
|
|
859
|
-
if matcher.
|
|
859
|
+
if matcher.search(value.ExtractString()):
|
|
860
860
|
vfs = _DPTFoundSet(
|
|
861
861
|
dptfile,
|
|
862
862
|
dptfile.table_connection.FindRecords(
|
|
@@ -961,9 +961,9 @@ class Database(_database.Database):
|
|
|
961
961
|
|
|
962
962
|
cache_size is not relevant to DPT.
|
|
963
963
|
"""
|
|
964
|
-
if ge and gt:
|
|
964
|
+
if isinstance(ge, str) and isinstance(gt, str):
|
|
965
965
|
raise DatabaseError("Both 'ge' and 'gt' given in key range")
|
|
966
|
-
if le and lt:
|
|
966
|
+
if isinstance(le, str) and isinstance(lt, str):
|
|
967
967
|
raise DatabaseError("Both 'le' and 'lt' given in key range")
|
|
968
968
|
if ge is None and gt is None and le is None and lt is None:
|
|
969
969
|
return self.recordlist_all(file, field, cache_size=cache_size)
|
|
@@ -975,8 +975,8 @@ class Database(_database.Database):
|
|
|
975
975
|
dptfile.table_connection.FindRecords(
|
|
976
976
|
dptapi.APIFindSpecification(
|
|
977
977
|
dptfile.secondary[field],
|
|
978
|
-
dptapi.FD_GE if ge else dptapi.FD_GT,
|
|
979
|
-
dptapi.APIFieldValue(ge or gt),
|
|
978
|
+
dptapi.FD_GE if ge is not None else dptapi.FD_GT,
|
|
979
|
+
dptapi.APIFieldValue(ge or gt or ""),
|
|
980
980
|
)
|
|
981
981
|
),
|
|
982
982
|
)
|
|
@@ -986,24 +986,32 @@ class Database(_database.Database):
|
|
|
986
986
|
dptfile.table_connection.FindRecords(
|
|
987
987
|
dptapi.APIFindSpecification(
|
|
988
988
|
dptfile.secondary[field],
|
|
989
|
-
dptapi.FD_LE if le else dptapi.FD_LT,
|
|
990
|
-
dptapi.APIFieldValue(le or lt),
|
|
989
|
+
dptapi.FD_LE if le is not None else dptapi.FD_LT,
|
|
990
|
+
dptapi.APIFieldValue(le or lt or ""),
|
|
991
991
|
)
|
|
992
992
|
),
|
|
993
993
|
)
|
|
994
994
|
else:
|
|
995
995
|
if ge:
|
|
996
|
-
range_ =
|
|
996
|
+
range_ = (
|
|
997
|
+
dptapi.FD_RANGE_GE_LE
|
|
998
|
+
if le is not None
|
|
999
|
+
else dptapi.FD_RANGE_GE_LT
|
|
1000
|
+
)
|
|
997
1001
|
else:
|
|
998
|
-
range_ =
|
|
1002
|
+
range_ = (
|
|
1003
|
+
dptapi.FD_RANGE_GT_LE
|
|
1004
|
+
if le is not None
|
|
1005
|
+
else dptapi.FD_RANGE_GT_LT
|
|
1006
|
+
)
|
|
999
1007
|
foundset = _DPTFoundSet(
|
|
1000
1008
|
dptfile,
|
|
1001
1009
|
dptfile.table_connection.FindRecords(
|
|
1002
1010
|
dptapi.APIFindSpecification(
|
|
1003
1011
|
dptfile.secondary[field],
|
|
1004
1012
|
range_,
|
|
1005
|
-
dptapi.APIFieldValue(ge or gt),
|
|
1006
|
-
dptapi.APIFieldValue(le or lt),
|
|
1013
|
+
dptapi.APIFieldValue(ge or gt or ""),
|
|
1014
|
+
dptapi.APIFieldValue(le or lt or ""),
|
|
1007
1015
|
)
|
|
1008
1016
|
),
|
|
1009
1017
|
)
|
|
@@ -743,10 +743,8 @@ class Database(_database.Database):
|
|
|
743
743
|
)
|
|
744
744
|
return None
|
|
745
745
|
|
|
746
|
-
# high_record will become high_record_number to fit changed
|
|
747
|
-
# get_high_record.
|
|
748
746
|
def note_freed_record_number_segment(
|
|
749
|
-
self, dbset, segment, record_number_in_segment,
|
|
747
|
+
self, dbset, segment, record_number_in_segment, high_record_number
|
|
750
748
|
):
|
|
751
749
|
"""Add existence bitmap segment to list with spare record numbers.
|
|
752
750
|
|
|
@@ -756,7 +754,9 @@ class Database(_database.Database):
|
|
|
756
754
|
"""
|
|
757
755
|
del record_number_in_segment
|
|
758
756
|
try:
|
|
759
|
-
high_segment = divmod(
|
|
757
|
+
high_segment = divmod(
|
|
758
|
+
high_record_number, SegmentSize.db_segment_size
|
|
759
|
+
)[0]
|
|
760
760
|
except TypeError:
|
|
761
761
|
# Implies attempt to delete record from empty database.
|
|
762
762
|
# The delete method will have raised an exception if appropriate.
|
|
@@ -844,9 +844,7 @@ class Database(_database.Database):
|
|
|
844
844
|
)
|
|
845
845
|
return segment, record_number
|
|
846
846
|
|
|
847
|
-
|
|
848
|
-
# Only used in one place, and it is extra work to get the data in_nosql.
|
|
849
|
-
def get_high_record(self, file):
|
|
847
|
+
def get_high_record_number(self, file):
|
|
850
848
|
"""Return the high existing record number in table for file."""
|
|
851
849
|
with self.dbtxn.transaction.cursor(
|
|
852
850
|
self.table[file].datastore
|
|
@@ -1482,14 +1480,14 @@ class Database(_database.Database):
|
|
|
1482
1480
|
recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
|
|
1483
1481
|
if keylike is None:
|
|
1484
1482
|
return recordlist
|
|
1485
|
-
|
|
1483
|
+
matcher = re.compile(keylike)
|
|
1486
1484
|
with self.dbtxn.transaction.cursor(
|
|
1487
1485
|
self.table[SUBFILE_DELIMITER.join((file, field))].datastore
|
|
1488
1486
|
) as cursor:
|
|
1489
1487
|
record = cursor.first()
|
|
1490
1488
|
while record:
|
|
1491
1489
|
key, value = cursor.item()
|
|
1492
|
-
if
|
|
1490
|
+
if matcher.search(key):
|
|
1493
1491
|
self.populate_recordset_segment(recordlist, value)
|
|
1494
1492
|
record = cursor.next()
|
|
1495
1493
|
return recordlist
|
|
@@ -1540,9 +1538,9 @@ class Database(_database.Database):
|
|
|
1540
1538
|
|
|
1541
1539
|
Keys are in range set by combinations of ge, gt, le, and lt.
|
|
1542
1540
|
"""
|
|
1543
|
-
if ge and gt:
|
|
1541
|
+
if isinstance(ge, bytes) and isinstance(gt, bytes):
|
|
1544
1542
|
raise DatabaseError("Both 'ge' and 'gt' given in key range")
|
|
1545
|
-
if le and lt:
|
|
1543
|
+
if isinstance(le, bytes) and isinstance(lt, bytes):
|
|
1546
1544
|
raise DatabaseError("Both 'le' and 'lt' given in key range")
|
|
1547
1545
|
recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
|
|
1548
1546
|
with self.dbtxn.transaction.cursor(
|
|
@@ -1551,7 +1549,7 @@ class Database(_database.Database):
|
|
|
1551
1549
|
if ge is None and gt is None:
|
|
1552
1550
|
record = cursor.first()
|
|
1553
1551
|
else:
|
|
1554
|
-
record = cursor.set_range(ge or gt)
|
|
1552
|
+
record = cursor.set_range(ge or gt or b"")
|
|
1555
1553
|
if gt:
|
|
1556
1554
|
while record:
|
|
1557
1555
|
record = cursor.item()
|
|
@@ -611,10 +611,10 @@ class Database(_databasedu.Database):
|
|
|
611
611
|
new_segment = make_segment_from_item(item)
|
|
612
612
|
new_segment |= existing_segment
|
|
613
613
|
new_segment.normalize()
|
|
614
|
-
item[
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
614
|
+
item[-2] = (
|
|
615
|
+
self.database.encode_number_for_sequential_file_dump(
|
|
616
|
+
new_segment.count_records(), 2
|
|
617
|
+
)
|
|
618
618
|
)
|
|
619
619
|
if int.from_bytes(item[-2], byteorder="big") == 1:
|
|
620
620
|
item[-1] = write_segment_value(
|
|
@@ -108,9 +108,9 @@ class Database(_database.Database):
|
|
|
108
108
|
continue
|
|
109
109
|
for fieldattr in NOSQL_FIELDATTS:
|
|
110
110
|
if fieldattr not in filedesc[FIELDS][fieldname]:
|
|
111
|
-
filedesc[FIELDS][fieldname][
|
|
112
|
-
fieldattr
|
|
113
|
-
|
|
111
|
+
filedesc[FIELDS][fieldname][fieldattr] = (
|
|
112
|
+
SECONDARY_FIELDATTS[fieldattr]
|
|
113
|
+
)
|
|
114
114
|
self.specification = specification
|
|
115
115
|
self.segment_size_bytes = segment_size_bytes
|
|
116
116
|
self.dbenv = None
|
|
@@ -648,15 +648,15 @@ class Database(_database.Database):
|
|
|
648
648
|
|
|
649
649
|
def next_record_number(self, dbset):
|
|
650
650
|
"""Return high record number plus 1."""
|
|
651
|
-
|
|
652
|
-
if
|
|
651
|
+
high_record_number = self.get_high_record_number(dbset)
|
|
652
|
+
if high_record_number is None:
|
|
653
653
|
return 0
|
|
654
|
-
return
|
|
654
|
+
return high_record_number + 1
|
|
655
655
|
|
|
656
656
|
# high_record will become high_record_number to fit changed
|
|
657
|
-
#
|
|
657
|
+
# get_high_record_number method.
|
|
658
658
|
def note_freed_record_number_segment(
|
|
659
|
-
self, dbset, segment, record_number_in_segment,
|
|
659
|
+
self, dbset, segment, record_number_in_segment, high_record_number
|
|
660
660
|
):
|
|
661
661
|
"""Add existence bitmap segment to list with spare record numbers.
|
|
662
662
|
|
|
@@ -666,9 +666,9 @@ class Database(_database.Database):
|
|
|
666
666
|
"""
|
|
667
667
|
del record_number_in_segment
|
|
668
668
|
try:
|
|
669
|
-
high_segment = divmod(
|
|
670
|
-
|
|
671
|
-
]
|
|
669
|
+
high_segment = divmod(
|
|
670
|
+
high_record_number, SegmentSize.db_segment_size
|
|
671
|
+
)[0]
|
|
672
672
|
except TypeError:
|
|
673
673
|
# Implies attempt to delete record from empty database.
|
|
674
674
|
# The delete method will have raised an exception if appropriate.
|
|
@@ -738,24 +738,12 @@ class Database(_database.Database):
|
|
|
738
738
|
ebmcf.high_record_number = max(ebmcf.high_record_number, putkey)
|
|
739
739
|
return segment, record_number
|
|
740
740
|
|
|
741
|
-
|
|
742
|
-
# Only used in one place, and it is extra work to get the data in_nosql.
|
|
743
|
-
# Also actually getting the record does not prove it is the high record; in
|
|
744
|
-
# _sqlite and _db asking for high record returns (key, data) where key will
|
|
745
|
-
# be the high record number.
|
|
746
|
-
def get_high_record(self, file):
|
|
741
|
+
def get_high_record_number(self, file):
|
|
747
742
|
"""Return the high existing record number in table for file."""
|
|
748
743
|
high_record_number = self.ebm_control[file].high_record_number
|
|
749
744
|
if high_record_number == -1:
|
|
750
745
|
return None
|
|
751
|
-
return
|
|
752
|
-
high_record_number,
|
|
753
|
-
self.dbenv[
|
|
754
|
-
SUBFILE_DELIMITER.join(
|
|
755
|
-
(self.table_data[file], str(high_record_number))
|
|
756
|
-
)
|
|
757
|
-
],
|
|
758
|
-
)
|
|
746
|
+
return high_record_number
|
|
759
747
|
|
|
760
748
|
def add_record_to_field_value(
|
|
761
749
|
self, file, field, key, segment, record_number
|
|
@@ -1229,7 +1217,7 @@ class Database(_database.Database):
|
|
|
1229
1217
|
recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
|
|
1230
1218
|
if keylike is None:
|
|
1231
1219
|
return recordlist
|
|
1232
|
-
matcher = re.compile(
|
|
1220
|
+
matcher = re.compile(keylike)
|
|
1233
1221
|
db = self.dbenv
|
|
1234
1222
|
fieldtree = self.trees[SUBFILE_DELIMITER.join((file, field))]
|
|
1235
1223
|
cursor = tree.Cursor(fieldtree)
|
|
@@ -1238,7 +1226,7 @@ class Database(_database.Database):
|
|
|
1238
1226
|
k = cursor.next()
|
|
1239
1227
|
if k is None:
|
|
1240
1228
|
break
|
|
1241
|
-
if not matcher.
|
|
1229
|
+
if not matcher.search(k):
|
|
1242
1230
|
continue
|
|
1243
1231
|
self.populate_recordset(
|
|
1244
1232
|
recordlist,
|
|
@@ -1322,9 +1310,9 @@ class Database(_database.Database):
|
|
|
1322
1310
|
("'", field, "' field in '", file, "' file is not ordered")
|
|
1323
1311
|
)
|
|
1324
1312
|
)
|
|
1325
|
-
if ge and gt:
|
|
1313
|
+
if isinstance(ge, str) and isinstance(gt, str):
|
|
1326
1314
|
raise DatabaseError("Both 'ge' and 'gt' given in key range")
|
|
1327
|
-
if le and lt:
|
|
1315
|
+
if isinstance(le, str) and isinstance(lt, str):
|
|
1328
1316
|
raise DatabaseError("Both 'le' and 'lt' given in key range")
|
|
1329
1317
|
recordlist = RecordList(dbhome=self, dbset=file, cache_size=cache_size)
|
|
1330
1318
|
db = self.dbenv
|
|
@@ -1334,7 +1322,7 @@ class Database(_database.Database):
|
|
|
1334
1322
|
if ge is None and gt is None:
|
|
1335
1323
|
k = cursor.first()
|
|
1336
1324
|
else:
|
|
1337
|
-
k = cursor.nearest(ge or gt)
|
|
1325
|
+
k = cursor.nearest(ge or gt or "")
|
|
1338
1326
|
if gt:
|
|
1339
1327
|
while k is not None:
|
|
1340
1328
|
if k > gt:
|
|
@@ -121,9 +121,9 @@ class Database(_databasedu.Database):
|
|
|
121
121
|
ebmc = self.ebm_control[file]
|
|
122
122
|
tes = ebmc.table_ebm_segments
|
|
123
123
|
insertion_point = bisect_right(tes, segment)
|
|
124
|
-
self.dbenv[
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
self.dbenv[SUBFILE_DELIMITER.join((ebmc.ebm_table, str(segment)))] = (
|
|
125
|
+
repr(self.existence_bit_maps[file][segment].tobytes())
|
|
126
|
+
)
|
|
127
127
|
if not (tes and tes[insertion_point - 1] == segment):
|
|
128
128
|
tes.insert(insertion_point, segment)
|
|
129
129
|
self.dbenv[ebmc.ebm_table] = repr(tes)
|