apsw-sqlite3mc 3.53.0.0__tar.gz → 3.53.2.0__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.
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/PKG-INFO +3 -2
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/README.rst +1 -1
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/__init__.pyi +21 -4
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/aio.py +1 -5
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/ext.py +2 -2
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/sqlite_extra.json +1 -5
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/tests/__main__.py +1 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/tests/aiotest.py +204 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/tests/jsonb.py +4 -4
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/tests/mctests.py +5 -1
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw_sqlite3mc.egg-info/PKG-INFO +3 -2
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/checksums +6 -1
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/setup.py +3 -2
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/sqlite3/sqlite3.c +1281 -287
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/apsw.docstrings +7 -0
- apsw_sqlite3mc-3.53.2.0/src/apswversion.h +1 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/constants.c +4 -2
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/cursor.c +138 -57
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/faultinject.h +16 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/tools/vend.py +3 -13
- apsw_sqlite3mc-3.53.0.0/src/apswversion.h +0 -1
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/LICENSE +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/MANIFEST.in +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/__main__.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/bestpractice.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/fts5.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/fts5aux.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/fts5query.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/fts_test_strings +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/mcall.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/py.typed +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/shell.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/speedtest.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/sqlite_extra.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/sqlite_extra_binaries/README.md +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/tests/async_meta.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/tests/carray.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/tests/extratest.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/tests/fork_checker.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/tests/ftstests.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/tests/sessiontests.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/tests/shelltest.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/trace.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw/unicode.py +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw_sqlite3mc.egg-info/SOURCES.txt +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw_sqlite3mc.egg-info/dependency_links.txt +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw_sqlite3mc.egg-info/entry_points.txt +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/apsw_sqlite3mc.egg-info/top_level.txt +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/pyproject.toml +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/setup.apsw +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/setup.cfg +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/_unicodedb.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/apsw.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/argparse.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/async.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/backup.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/blob.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/carray.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/connection.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/exceptions.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/faultinject.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/fileio_win32.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/fts.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/jsonb.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/pyutil.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/session.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/sqlite_debug.h +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/statementcache.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/stringconstants.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/testextension.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/traceback.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/unicode.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/util.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/vfs.c +0 -0
- {apsw_sqlite3mc-3.53.0.0 → apsw_sqlite3mc-3.53.2.0}/src/vtable.c +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: apsw_sqlite3mc
|
|
3
|
-
Version: 3.53.
|
|
3
|
+
Version: 3.53.2.0
|
|
4
4
|
Summary: SQLite3 Multiple Ciphers combined with Another Python SQLite Wrapper
|
|
5
5
|
Home-page: https://github.com/utelle/apsw-sqlite3mc
|
|
6
6
|
Author: Ulrich Telle
|
|
@@ -24,6 +24,7 @@ Classifier: Framework :: Trio
|
|
|
24
24
|
Classifier: Framework :: AsyncIO
|
|
25
25
|
Classifier: Framework :: AnyIO
|
|
26
26
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
27
|
+
Classifier: Typing :: Typed
|
|
27
28
|
Requires-Python: >=3.10
|
|
28
29
|
Description-Content-Type: text/x-rst
|
|
29
30
|
License-File: LICENSE
|
|
@@ -89,7 +90,7 @@ Setting the key on a new database is the only change needed to your code.
|
|
|
89
90
|
|
|
90
91
|
>>> import apsw
|
|
91
92
|
>>> print(apsw.mc_version)
|
|
92
|
-
SQLite3 Multiple Ciphers 2.3.
|
|
93
|
+
SQLite3 Multiple Ciphers 2.3.5
|
|
93
94
|
>>> con = apsw.Connection("database.sqlite3")
|
|
94
95
|
>>> con.pragma("key", "my secret passphrase")
|
|
95
96
|
ok
|
|
@@ -59,7 +59,7 @@ Setting the key on a new database is the only change needed to your code.
|
|
|
59
59
|
|
|
60
60
|
>>> import apsw
|
|
61
61
|
>>> print(apsw.mc_version)
|
|
62
|
-
SQLite3 Multiple Ciphers 2.3.
|
|
62
|
+
SQLite3 Multiple Ciphers 2.3.5
|
|
63
63
|
>>> con = apsw.Connection("database.sqlite3")
|
|
64
64
|
>>> con.pragma("key", "my secret passphrase")
|
|
65
65
|
ok
|
|
@@ -2805,6 +2805,13 @@ class Cursor:
|
|
|
2805
2805
|
- [(3, 4), (4, 5)]
|
|
2806
2806
|
* - select 3,4; select 5
|
|
2807
2807
|
- [(3, 4), 5]
|
|
2808
|
+
* - select null
|
|
2809
|
+
- None
|
|
2810
|
+
* - select 'yes' where 1=2
|
|
2811
|
+
- None
|
|
2812
|
+
|
|
2813
|
+
It is not possible to tell the difference between :code:`None`
|
|
2814
|
+
returned, versus no matching rows.
|
|
2808
2815
|
|
|
2809
2816
|
Row tracers are not called when using this method."""
|
|
2810
2817
|
|
|
@@ -4530,6 +4537,8 @@ SQLITE_CHANGESETAPPLY_INVERT: int = 2
|
|
|
4530
4537
|
"""For `Flags for sqlite3changeset_apply_v2 <https://sqlite.org/session/c_changesetapply_fknoaction.html>'__"""
|
|
4531
4538
|
SQLITE_CHANGESETAPPLY_NOSAVEPOINT: int = 1
|
|
4532
4539
|
"""For `Flags for sqlite3changeset_apply_v2 <https://sqlite.org/session/c_changesetapply_fknoaction.html>'__"""
|
|
4540
|
+
SQLITE_CHANGESETAPPLY_NOUPDATELOOP: int = 16
|
|
4541
|
+
"""For `Flags for sqlite3changeset_apply_v2 <https://sqlite.org/session/c_changesetapply_fknoaction.html>'__"""
|
|
4533
4542
|
SQLITE_CHANGESETSTART_INVERT: int = 2
|
|
4534
4543
|
"""For `Flags for sqlite3changeset_start_v2 <https://sqlite.org/session/c_changesetstart_invert.html>'__"""
|
|
4535
4544
|
SQLITE_CHANGESET_ABORT: int = 2
|
|
@@ -5563,7 +5572,8 @@ mapping_session_changeset_apply_v2_flags: dict[str | int, int | str]
|
|
|
5563
5572
|
Doc at https://sqlite.org/session/c_changesetapply_fknoaction.html
|
|
5564
5573
|
|
|
5565
5574
|
SQLITE_CHANGESETAPPLY_FKNOACTION SQLITE_CHANGESETAPPLY_IGNORENOOP
|
|
5566
|
-
SQLITE_CHANGESETAPPLY_INVERT SQLITE_CHANGESETAPPLY_NOSAVEPOINT
|
|
5575
|
+
SQLITE_CHANGESETAPPLY_INVERT SQLITE_CHANGESETAPPLY_NOSAVEPOINT
|
|
5576
|
+
SQLITE_CHANGESETAPPLY_NOUPDATELOOP"""
|
|
5567
5577
|
|
|
5568
5578
|
mapping_session_changeset_start_v2_flags: dict[str | int, int | str]
|
|
5569
5579
|
"""Flags for sqlite3changeset_start_v2 mapping names to int and int to names.
|
|
@@ -7500,13 +7510,13 @@ class AsyncCursor:
|
|
|
7500
7510
|
* :attr:`Cursor.description_full`
|
|
7501
7511
|
* :attr:`Cursor.description`"""
|
|
7502
7512
|
|
|
7503
|
-
description:
|
|
7513
|
+
description: tuple[tuple[str, str, None, None, None, None, None], ...]
|
|
7504
7514
|
"""Based on the `DB-API cursor property
|
|
7505
7515
|
<https://www.python.org/dev/peps/pep-0249/>`__, this returns the
|
|
7506
7516
|
same as :meth:`get_description` but with 5 Nones appended because
|
|
7507
7517
|
SQLite does not have the information."""
|
|
7508
7518
|
|
|
7509
|
-
description_full:
|
|
7519
|
+
description_full: tuple[tuple[str, str, str, str, str], ...]
|
|
7510
7520
|
"""Only present if SQLITE_ENABLE_COLUMN_METADATA was defined at
|
|
7511
7521
|
compile time.
|
|
7512
7522
|
|
|
@@ -7627,6 +7637,13 @@ class AsyncCursor:
|
|
|
7627
7637
|
- [(3, 4), (4, 5)]
|
|
7628
7638
|
* - select 3,4; select 5
|
|
7629
7639
|
- [(3, 4), 5]
|
|
7640
|
+
* - select null
|
|
7641
|
+
- None
|
|
7642
|
+
* - select 'yes' where 1=2
|
|
7643
|
+
- None
|
|
7644
|
+
|
|
7645
|
+
It is not possible to tell the difference between :code:`None`
|
|
7646
|
+
returned, versus no matching rows.
|
|
7630
7647
|
|
|
7631
7648
|
Row tracers are not called when using this method."""
|
|
7632
7649
|
|
|
@@ -7634,7 +7651,7 @@ class AsyncCursor:
|
|
|
7634
7651
|
"""Returns the :attr:`connection` this cursor is part of"""
|
|
7635
7652
|
...
|
|
7636
7653
|
|
|
7637
|
-
|
|
7654
|
+
def get_description(self) -> tuple[tuple[str, str], ...]:
|
|
7638
7655
|
"""If you are trying to get information about a table or view,
|
|
7639
7656
|
then `pragma table_info <https://sqlite.org/pragma.html#pragma_table_info>`__
|
|
7640
7657
|
is better. If you want to know up front what columns and other
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import asyncio
|
|
5
6
|
import contextlib
|
|
6
7
|
import contextvars
|
|
7
8
|
import logging
|
|
@@ -368,9 +369,6 @@ class AsyncIO:
|
|
|
368
369
|
return await task
|
|
369
370
|
|
|
370
371
|
def __init__(self, *, thread_name: str = "asyncio apsw background worker"):
|
|
371
|
-
global asyncio
|
|
372
|
-
import asyncio
|
|
373
|
-
|
|
374
372
|
self.queue: queue.SimpleQueue[_CallTracker | None] = queue.SimpleQueue()
|
|
375
373
|
self.loop = asyncio.get_running_loop()
|
|
376
374
|
threading.Thread(name=thread_name, target=self.worker_thread_run).start()
|
|
@@ -651,8 +649,6 @@ def Auto() -> Trio | AsyncIO | AnyIO:
|
|
|
651
649
|
|
|
652
650
|
if found is None and "asyncio" in sys.modules:
|
|
653
651
|
try:
|
|
654
|
-
import asyncio
|
|
655
|
-
|
|
656
652
|
asyncio.get_running_loop()
|
|
657
653
|
found = AsyncIO
|
|
658
654
|
except:
|
|
@@ -180,7 +180,7 @@ class TypesConverterCursorFactory:
|
|
|
180
180
|
"""Registers a callable that converts from a SQLite value"""
|
|
181
181
|
self.converters[name] = callable
|
|
182
182
|
|
|
183
|
-
def __call__(self, connection: apsw.Connection) -> TypeConverterCursor:
|
|
183
|
+
def __call__(self, connection: apsw.Connection) -> TypesConverterCursorFactory.TypeConverterCursor:
|
|
184
184
|
"Returns a new convertor :class:`cursor <apsw.Cursor>` for the `connection`"
|
|
185
185
|
return TypesConverterCursorFactory.TypeConverterCursor(connection, self)
|
|
186
186
|
|
|
@@ -2224,7 +2224,7 @@ def get_column_names(row: Any) -> tuple[Sequence[str], VTColumnAccess]:
|
|
|
2224
2224
|
* - Type
|
|
2225
2225
|
- Access
|
|
2226
2226
|
- Column names From
|
|
2227
|
-
* - :
|
|
2227
|
+
* - :func:`dataclasses.is_dataclass`
|
|
2228
2228
|
- :attr:`VTColumnAccess.By_Attr`
|
|
2229
2229
|
- :func:`dataclasses.fields`
|
|
2230
2230
|
* - :func:`isinstance <isinstance>`\(:class:`tuple`) and :func:`hasattr <hasattr>`\(:code:`"_fields"`) - eg :func:`~collections.namedtuple`
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"type": "extension"
|
|
61
61
|
},
|
|
62
62
|
"ieee754": {
|
|
63
|
-
"description": "functions for the exact display
|
|
63
|
+
"description": "functions for the exact display and input of IEEE754 Binary64 floating-point numbers",
|
|
64
64
|
"type": "extension"
|
|
65
65
|
},
|
|
66
66
|
"memstat": {
|
|
@@ -147,10 +147,6 @@
|
|
|
147
147
|
"description": "Database Remote-Copy Tool",
|
|
148
148
|
"type": "executable"
|
|
149
149
|
},
|
|
150
|
-
"sqlite3_scrub": {
|
|
151
|
-
"description": "Makes a backup zeroing out all deleted content",
|
|
152
|
-
"type": "executable"
|
|
153
|
-
},
|
|
154
150
|
"sqlite3_shell": {
|
|
155
151
|
"description": "Command line shell",
|
|
156
152
|
"type": "executable"
|
|
@@ -10,6 +10,7 @@ import functools
|
|
|
10
10
|
import threading
|
|
11
11
|
import unittest
|
|
12
12
|
import tempfile
|
|
13
|
+
import random
|
|
13
14
|
import sys
|
|
14
15
|
import math
|
|
15
16
|
import inspect
|
|
@@ -539,6 +540,209 @@ class Async(unittest.TestCase):
|
|
|
539
540
|
|
|
540
541
|
self.assertEqual(values, list(range(min(NUM_ENTRIES, error))))
|
|
541
542
|
|
|
543
|
+
async def atestCursorStatementAttributes(self, fw):
|
|
544
|
+
|
|
545
|
+
# This is to verify #613 needing to keep iteration, prefetch,
|
|
546
|
+
# and description in sync with each other, not to mention all
|
|
547
|
+
# the other cursor statement related attributes. Multiple
|
|
548
|
+
# tables with varying number of columns and content are
|
|
549
|
+
# selected from in a single SQL string and async iteration
|
|
550
|
+
# compared to sync
|
|
551
|
+
|
|
552
|
+
# used to name the tables, columns, and types with languages
|
|
553
|
+
# from wikipedia.org front page
|
|
554
|
+
names = """one two three four five six seven eight nine ten
|
|
555
|
+
eleven twelve thirteen fourteen fifteen sixteen seventeen
|
|
556
|
+
eighteen nineteen twenty العربية Deutsch English Español فارسی
|
|
557
|
+
Français Italiano مصرى Nederlands日本語Polski Português
|
|
558
|
+
Sinugboanong Binisaya Svenska Українська Tiếng Việt Winaray中
|
|
559
|
+
文Русский articles Afrikaans Shqip Asturianu Azərbaycanca
|
|
560
|
+
Български閩南語 Bân-lâm-gú বাংলা Беларуская Català Čeština
|
|
561
|
+
Cymraeg Dansk Eesti Ελληνικά Esperanto Euskara Galego 한국어
|
|
562
|
+
Հայերեն हिन्दी Hrvatski Bahasa Indonesia עברית ქართული Ladin
|
|
563
|
+
Latina Latviešu Lietuvių Magyar Македонски Malagasy मराठी
|
|
564
|
+
Bahasa Melayu Bahaso Minangkabau မြန်မာဘာသာ Norskbokmålnynorsk
|
|
565
|
+
Нохчийн Oʻzbekcha Ўзбекча Қазақша Qazaqşa قازاقشا Română
|
|
566
|
+
Simple English Slovenčina Slovenščina Српски Srpski
|
|
567
|
+
Srpskohrvatski Српскохрватски Suomi Kiswahili தமிழ் Татарча
|
|
568
|
+
Tatarça తెలుగు ภาษาไทย Тоҷикӣ تۆرکجه Türkçe اردو粵語Bahsa Acèh
|
|
569
|
+
Alemannisch አማርኛ Aragonés Արեւմտահայերէն Bahasa Hulontalo Basa
|
|
570
|
+
Bali Bahasa Banjar Basa Banyumasan Башҡортса Беларуская
|
|
571
|
+
тарашкевіца Bikol Central বিষ্ণুপ্রিয়া মণিপুরী Boarisch
|
|
572
|
+
Bosanski Brezhoneg Чӑвашла Dagbanli الدارجة Diné Bizaad
|
|
573
|
+
Emigliàn–Rumagnòl Fiji Hindi Føroyskt Frysk Fulfulde Gaeilge
|
|
574
|
+
Gàidhlig گیلکی ગુજરાતી Hak-kâ-ngî 客家語Hausa Hornjoserbsce
|
|
575
|
+
Ido Igbo Ilokano Interlingua Interlingue Ирон Íslenska Jawa
|
|
576
|
+
ಕನ್ನಡ Kapampangan ភាសាខ្មែរ Kotava Kreyòl Ayisyen Kurdî كوردی
|
|
577
|
+
کوردیی ناوەندی Кыргызча Кырык мары Lëtzebuergesch Lìgure
|
|
578
|
+
Limburgs Lombard मैथिली മലയാളം მარგალური مازِرونی
|
|
579
|
+
Mìng-dĕ̤ng-ngṳ̄ 閩東語Монгол Napulitano नेपाल भाषा Nordfriisk
|
|
580
|
+
Occitan Олык марий ଓଡି଼ଆ অসমীযা় ਪੰਜਾਬੀ پنجابی شاہ مکھی پښتو
|
|
581
|
+
Piemontèis Plattdüütsch Qaraqalpaqsha Qırımtatarca Runa Simi
|
|
582
|
+
Русиньскый संस्कृतम् ᱥᱟᱱᱛᱟᱲᱤ سرائیکی Саха Тыла Scots ChiShona
|
|
583
|
+
Sicilianu සිංහල سنڌي Ślůnski Soomaaliga Basa Sunda Taclḥit
|
|
584
|
+
Tagalog ၽႃႇသႃႇတႆး ⵜⴰⵎⴰⵣⵉⵖⵜ ⵜⴰⵏⴰⵡⴰⵢⵜ tolışi chiTumbuka Basa Ugi
|
|
585
|
+
Vèneto Volapük Walon文言吴语ייִדיש """.split()
|
|
586
|
+
|
|
587
|
+
con = apsw.Connection("")
|
|
588
|
+
acon = await apsw.Connection.as_async("")
|
|
589
|
+
|
|
590
|
+
has_full = hasattr(apsw.Cursor, "description_full")
|
|
591
|
+
|
|
592
|
+
try:
|
|
593
|
+
apsw.allow_missing_dict_bindings(True)
|
|
594
|
+
|
|
595
|
+
tables = []
|
|
596
|
+
|
|
597
|
+
table_columns = {}
|
|
598
|
+
|
|
599
|
+
for table in random.choices(names, k=6):
|
|
600
|
+
# choices can return duplicates
|
|
601
|
+
if table in tables:
|
|
602
|
+
continue
|
|
603
|
+
tables.append(table)
|
|
604
|
+
sql = ""
|
|
605
|
+
sql += f'create table "{table}"('
|
|
606
|
+
columns = list(set(random.choices(names, k=random.randint(1, 10))))
|
|
607
|
+
table_columns[table] = columns
|
|
608
|
+
|
|
609
|
+
sql += ",".join(
|
|
610
|
+
f'"{name}" "{coltype}"' for (name, coltype) in zip(columns, random.choices(names, k=len(columns)))
|
|
611
|
+
)
|
|
612
|
+
sql += ");"
|
|
613
|
+
|
|
614
|
+
con.execute(sql)
|
|
615
|
+
await acon.execute(sql)
|
|
616
|
+
|
|
617
|
+
insert = f'insert into "{table}" values(' + ",".join("?" * len(columns)) + ")"
|
|
618
|
+
|
|
619
|
+
async with acon:
|
|
620
|
+
with con:
|
|
621
|
+
for row in range(random.randint(0, 100)):
|
|
622
|
+
con.execute(insert, [row] * len(columns))
|
|
623
|
+
await acon.execute(insert, [row] * len(columns))
|
|
624
|
+
|
|
625
|
+
sql = []
|
|
626
|
+
emsql = []
|
|
627
|
+
emvalues = []
|
|
628
|
+
|
|
629
|
+
stuff = "abcdefghijklmnopqrstuvwxyz"
|
|
630
|
+
|
|
631
|
+
for i in range(12):
|
|
632
|
+
sql.append(f'SELECT * FROM "{random.choice(tables)}" LIMIT {random.randint(0, 10)};')
|
|
633
|
+
table = random.choice(tables)
|
|
634
|
+
one = "".join(random.choices(stuff, k=10))
|
|
635
|
+
two = "".join(random.choices(stuff, k=10))
|
|
636
|
+
emsql.append(f'SELECT * FROM "{table}" WHERE coalesce(${one},:{two}, 3) is not null LIMIT :limit ;')
|
|
637
|
+
emvalues.append({"limit": random.randint(0, 10), one: 77, two: 94})
|
|
638
|
+
if i in {1, 3, 7, 11, 17}:
|
|
639
|
+
for q in (
|
|
640
|
+
"/* no vdbe for this */ ;",
|
|
641
|
+
"explain query plan select * from sqlite_schema;",
|
|
642
|
+
"create table if not exists orange(a,c);",
|
|
643
|
+
):
|
|
644
|
+
sql.append(q)
|
|
645
|
+
emsql.append(q)
|
|
646
|
+
|
|
647
|
+
embindings = emvalues[:]
|
|
648
|
+
random.shuffle(embindings)
|
|
649
|
+
|
|
650
|
+
async_attrs = "bindings_names expanded_sql sql".split()
|
|
651
|
+
sync_attrs = "bindings_count has_vdbe is_explain is_readonly description".split() + (
|
|
652
|
+
["description_full"] if has_full else []
|
|
653
|
+
)
|
|
654
|
+
|
|
655
|
+
sync_cur = con.cursor()
|
|
656
|
+
async_cur = acon.cursor()
|
|
657
|
+
self.assertRaises(apsw.ExecutionCompleteError, sync_cur.get_description)
|
|
658
|
+
self.assertRaises(apsw.ExecutionCompleteError, async_cur.get_description)
|
|
659
|
+
for a in async_attrs:
|
|
660
|
+
self.assertRaises(apsw.ExecutionCompleteError, getattr, sync_cur, a)
|
|
661
|
+
with self.assertRaises(apsw.ExecutionCompleteError):
|
|
662
|
+
await getattr(async_cur, a)
|
|
663
|
+
for a in sync_attrs:
|
|
664
|
+
self.assertRaises(apsw.ExecutionCompleteError, getattr, sync_cur, a)
|
|
665
|
+
self.assertRaises(apsw.ExecutionCompleteError, getattr, async_cur, a)
|
|
666
|
+
|
|
667
|
+
for prefetch in (1, 3, 11, 64):
|
|
668
|
+
apsw.async_cursor_prefetch.set(prefetch)
|
|
669
|
+
random.shuffle(sql)
|
|
670
|
+
# regular execute mode
|
|
671
|
+
sync_cur = con.execute("".join(sql))
|
|
672
|
+
async_cur = await acon.execute("".join(sql))
|
|
673
|
+
|
|
674
|
+
async for row in async_cur:
|
|
675
|
+
self.assertEqual(row, next(sync_cur))
|
|
676
|
+
self.assertEqual(sync_cur.get_description(), async_cur.get_description())
|
|
677
|
+
for a in async_attrs:
|
|
678
|
+
self.assertEqual(getattr(sync_cur, a), await getattr(async_cur, a))
|
|
679
|
+
for a in sync_attrs:
|
|
680
|
+
self.assertEqual(getattr(sync_cur, a), getattr(async_cur, a))
|
|
681
|
+
|
|
682
|
+
# check raises complete
|
|
683
|
+
self.assertRaises(StopIteration, next, sync_cur)
|
|
684
|
+
with self.assertRaises(StopAsyncIteration):
|
|
685
|
+
await anext(async_cur)
|
|
686
|
+
|
|
687
|
+
self.assertRaises(apsw.ExecutionCompleteError, sync_cur.get_description)
|
|
688
|
+
self.assertRaises(apsw.ExecutionCompleteError, async_cur.get_description)
|
|
689
|
+
for a in async_attrs:
|
|
690
|
+
self.assertRaises(apsw.ExecutionCompleteError, getattr, sync_cur, a)
|
|
691
|
+
with self.assertRaises(apsw.ExecutionCompleteError):
|
|
692
|
+
await getattr(async_cur, a)
|
|
693
|
+
for a in sync_attrs:
|
|
694
|
+
self.assertRaises(apsw.ExecutionCompleteError, getattr, sync_cur, a)
|
|
695
|
+
self.assertRaises(apsw.ExecutionCompleteError, getattr, async_cur, a)
|
|
696
|
+
|
|
697
|
+
# errors
|
|
698
|
+
error_sql = "select 3; select syntax error"
|
|
699
|
+
sync_cur = con.execute(error_sql)
|
|
700
|
+
async_cur = aiter(await acon.execute(error_sql))
|
|
701
|
+
|
|
702
|
+
next(sync_cur)
|
|
703
|
+
await anext(async_cur)
|
|
704
|
+
|
|
705
|
+
self.assertRaises(apsw.SQLError, next, sync_cur)
|
|
706
|
+
with self.assertRaises(apsw.SQLError):
|
|
707
|
+
await anext(async_cur)
|
|
708
|
+
|
|
709
|
+
self.assertRaises(StopIteration, next, sync_cur)
|
|
710
|
+
with self.assertRaises(StopAsyncIteration):
|
|
711
|
+
await anext(async_cur)
|
|
712
|
+
|
|
713
|
+
# executemany mode
|
|
714
|
+
random.shuffle(emsql)
|
|
715
|
+
|
|
716
|
+
sync_cur = con.executemany("".join(emsql), embindings)
|
|
717
|
+
async_cur = await acon.executemany("".join(emsql), embindings)
|
|
718
|
+
async for row in async_cur:
|
|
719
|
+
self.assertEqual(row, next(sync_cur))
|
|
720
|
+
self.assertEqual(sync_cur.get_description(), async_cur.get_description())
|
|
721
|
+
for a in async_attrs:
|
|
722
|
+
self.assertEqual(getattr(sync_cur, a), await getattr(async_cur, a))
|
|
723
|
+
for a in sync_attrs:
|
|
724
|
+
self.assertEqual(getattr(sync_cur, a), getattr(async_cur, a))
|
|
725
|
+
|
|
726
|
+
# check raises complete
|
|
727
|
+
self.assertRaises(StopIteration, next, sync_cur)
|
|
728
|
+
with self.assertRaises(StopAsyncIteration):
|
|
729
|
+
await anext(async_cur)
|
|
730
|
+
|
|
731
|
+
self.assertRaises(apsw.ExecutionCompleteError, sync_cur.get_description)
|
|
732
|
+
self.assertRaises(apsw.ExecutionCompleteError, async_cur.get_description)
|
|
733
|
+
for a in async_attrs:
|
|
734
|
+
self.assertRaises(apsw.ExecutionCompleteError, getattr, sync_cur, a)
|
|
735
|
+
with self.assertRaises(apsw.ExecutionCompleteError):
|
|
736
|
+
await getattr(async_cur, a)
|
|
737
|
+
for a in sync_attrs:
|
|
738
|
+
self.assertRaises(apsw.ExecutionCompleteError, getattr, sync_cur, a)
|
|
739
|
+
self.assertRaises(apsw.ExecutionCompleteError, getattr, async_cur, a)
|
|
740
|
+
|
|
741
|
+
finally:
|
|
742
|
+
apsw.allow_missing_dict_bindings(False)
|
|
743
|
+
con.close(True)
|
|
744
|
+
acon.close(True)
|
|
745
|
+
|
|
542
746
|
async def atestConfigure(self, fw):
|
|
543
747
|
auto = apsw.aio.Auto()
|
|
544
748
|
auto.close()
|
|
@@ -1109,12 +1109,12 @@ class JSONB(unittest.TestCase):
|
|
|
1109
1109
|
|
|
1110
1110
|
def testRandomJSON(self):
|
|
1111
1111
|
"sqlite randomjson extension if present"
|
|
1112
|
-
|
|
1112
|
+
import apsw.sqlite_extra
|
|
1113
|
+
try:
|
|
1114
|
+
apsw.sqlite_extra.load(self.db, "randomjson")
|
|
1115
|
+
except apsw.sqlite_extra.NotAvailable:
|
|
1113
1116
|
return
|
|
1114
1117
|
|
|
1115
|
-
self.db.enable_load_extension(True)
|
|
1116
|
-
self.db.load_extension("./randomjson")
|
|
1117
|
-
|
|
1118
1118
|
for seed in range(2000, 3000):
|
|
1119
1119
|
# we round trip the json through as many combinations of SQLite, Python and APSW
|
|
1120
1120
|
# encoders / decoders as possible
|
|
@@ -141,6 +141,7 @@ class MultipleCiphers(unittest.TestCase):
|
|
|
141
141
|
for config in (
|
|
142
142
|
{
|
|
143
143
|
"plaintext_header_size": 64,
|
|
144
|
+
"cipher_salt": "B1349F791FE98DDD1648406C5554BD1F",
|
|
144
145
|
"cipher": "sqlcipher",
|
|
145
146
|
"key": "one",
|
|
146
147
|
},
|
|
@@ -286,6 +287,9 @@ def apply_encryption(db, **kwargs):
|
|
|
286
287
|
# then anything with legacy in the name
|
|
287
288
|
if "legacy" in pragma:
|
|
288
289
|
return 3
|
|
290
|
+
# explicit cipher salt
|
|
291
|
+
if pragma == "cipher_salt":
|
|
292
|
+
return 99
|
|
289
293
|
# all except keys
|
|
290
294
|
if pragma not in {"key", "hexkey", "rekey", "hexrekey"}:
|
|
291
295
|
return 3
|
|
@@ -299,7 +303,7 @@ def apply_encryption(db, **kwargs):
|
|
|
299
303
|
for pragma, value in sorted(kwargs.items(), key=pragma_order):
|
|
300
304
|
# if the pragma was understood and in range we get the value
|
|
301
305
|
# back, while key related ones return 'ok'
|
|
302
|
-
expected = "ok" if pragma_order((pragma, value))
|
|
306
|
+
expected = "ok" if pragma_order((pragma, value)) >= 99 else str(value)
|
|
303
307
|
if db.pragma(pragma, value) != expected:
|
|
304
308
|
raise ValueError(f"Failed to configure {pragma=}")
|
|
305
309
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: apsw-sqlite3mc
|
|
3
|
-
Version: 3.53.
|
|
3
|
+
Version: 3.53.2.0
|
|
4
4
|
Summary: SQLite3 Multiple Ciphers combined with Another Python SQLite Wrapper
|
|
5
5
|
Home-page: https://github.com/utelle/apsw-sqlite3mc
|
|
6
6
|
Author: Ulrich Telle
|
|
@@ -24,6 +24,7 @@ Classifier: Framework :: Trio
|
|
|
24
24
|
Classifier: Framework :: AsyncIO
|
|
25
25
|
Classifier: Framework :: AnyIO
|
|
26
26
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
27
|
+
Classifier: Typing :: Typed
|
|
27
28
|
Requires-Python: >=3.10
|
|
28
29
|
Description-Content-Type: text/x-rst
|
|
29
30
|
License-File: LICENSE
|
|
@@ -89,7 +90,7 @@ Setting the key on a new database is the only change needed to your code.
|
|
|
89
90
|
|
|
90
91
|
>>> import apsw
|
|
91
92
|
>>> print(apsw.mc_version)
|
|
92
|
-
SQLite3 Multiple Ciphers 2.3.
|
|
93
|
+
SQLite3 Multiple Ciphers 2.3.5
|
|
93
94
|
>>> con = apsw.Connection("database.sqlite3")
|
|
94
95
|
>>> con.pragma("key", "my secret passphrase")
|
|
95
96
|
ok
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
# way.
|
|
10
10
|
|
|
11
11
|
# These are used too compile sqlite extra
|
|
12
|
-
|
|
12
|
+
https://sqlite.org/vec1/zip/vec1-20260526165101-762865e44d.zip 152789 977b062b7f1a15756fb428676d3425a57e3c84dc254cb104cb7ff31f642ede1c a332720cdebb74739b01c53187c6487b9c143c5cca45d863ef80c36e2683a0ba
|
|
13
|
+
https://sqlite.org/vec1/zip/vec1-20260505104119-eb38e10fef.zip 149803 b37509b229a393a387f3f4f352529dcf10cc3ebdbb2c75fa062763d4fdd0953b ceb3aa3699c378872e88b06b237e94eec9e545ffc1abe7388f521a107ec50699
|
|
13
14
|
https://sqlite.org/vec1/zip/vec1-20260409204746-4b73767df0.zip 119674 952af14601531b527a497df81d038a2693c1a39dba2d76ed798c3e5ba3dd7c22 55e2d7e05da20b7eb4abbe77688bdff4662a6f4f248f6710e7d2b605d3c90107
|
|
14
15
|
https://sqlite.org/vec1/zip/vec1-20260330201854-5b7c141049.zip 107146 099acc5f1eee719cae16d4843e904bba432cda9ce43d1cefb756f6566462d9f5 1c3e4264a416d68209ea37139c7e0ad42fcee4f66c021c8f495cce9882bc71e3
|
|
15
16
|
https://sqlite.org/vec1/zip/vec1-20260306155250-d070184523.zip 75980 6a58eebbe1e4679645c80084fdfc44f2902e19cde95da5af932bb51bfdc7d02d 77785c8f4e0a9672dded6794861a2ca9d5a5a8dda43300b183690cd84149bf35
|
|
@@ -20,6 +21,10 @@ https://sqlite.org/sqlar/zip/sqlar-src-20180107193712-4824e73896.zip 1980460 63b
|
|
|
20
21
|
https://www.zlib.net/zlib132.zip 1616754 e8bf55f3017aa181690990cb58a994e77885da140609fc8f94abe9b65d2cae28 6b35b981f73425dc5f142cbee457f078d42240c022c804982849b962f1d1e2c6
|
|
21
22
|
|
|
22
23
|
# SQLite releases
|
|
24
|
+
https://sqlite.org/2026/sqlite-autoconf-3530200.tar.gz 3279926 588ad51949419a56ebe81fe56193d510c559eb94c9a57748387860b5d3069316 025328da165109f48abccc6e7478508060804412bed2bd81d47e98ba1b72983b
|
|
25
|
+
https://sqlite.org/2026/sqlite-src-3530200.zip 14527073 cafff764c03f6d720968f746e2f47a986bbf12bf4c18904f1eb131c0b0b592d3 490ec7af32a6bfa5f3e05dc279c04286cfe3f328def4a8b7344e3fa20be18a4c
|
|
26
|
+
https://sqlite.org/2026/sqlite-autoconf-3530100.tar.gz 3275272 83e6b2020a034e9a7ad4a72feea59e1ad52f162e09cbd26735a3ffb98359fc4f 36ca143645cf76997d07b66e9244c636b8ccdec64a1d50558259c4e415e6558b
|
|
27
|
+
https://sqlite.org/2026/sqlite-src-3530100.zip 14515734 1b2b5755d9064c4d5d1b0bf5307b48b089963e291c40cc7351318aa1b61c460e 27cfc9264b2188fd17f811a8c03424eb65391c2ef9874cbfc860ea25f4322363
|
|
23
28
|
https://sqlite.org/2026/sqlite-autoconf-3530000.tar.gz 3274709 851e9b38192fe2ceaa65e0baa665e7fa06230c3d9bd1a6a9662d02380d73365a 60c4b08c6729761e488d185e0d52411da10b14c72b53ada6936dc5eea225cefe
|
|
24
29
|
https://sqlite.org/2026/sqlite-src-3530000.zip 14513779 fbc30cdbfcfa42c78fe7bddd3fd37ab8995369a31d39097a5d0633296c0b6e65 4ffbd00ba8db1e1172dbc69a5203a2c185556a32543e58585ba3713abf676fe5
|
|
25
30
|
|
|
@@ -306,7 +306,7 @@ class fetch(Command):
|
|
|
306
306
|
for desc, url, replace in (
|
|
307
307
|
(
|
|
308
308
|
"experimental vec1 extension source",
|
|
309
|
-
"https://sqlite.org/vec1/zip/vec1-
|
|
309
|
+
"https://sqlite.org/vec1/zip/vec1-20260526165101-762865e44d.zip",
|
|
310
310
|
"sqlite3/vec1",
|
|
311
311
|
),
|
|
312
312
|
(
|
|
@@ -406,7 +406,7 @@ class apsw_build(bparent):
|
|
|
406
406
|
|
|
407
407
|
def run(self):
|
|
408
408
|
# this has to be done first ...
|
|
409
|
-
if all(pathlib.Path(f).exists() for f in ("sqlite3/tool/dbtotxt.c", "sqlite3/ext/misc/
|
|
409
|
+
if all(pathlib.Path(f).exists() for f in ("sqlite3/tool/dbtotxt.c", "sqlite3/ext/misc/unionvtab.c")):
|
|
410
410
|
# Call into vend which we can't import so do something similar
|
|
411
411
|
vend = types.ModuleType("vend")
|
|
412
412
|
sys.modules["vend"] = vend
|
|
@@ -1019,6 +1019,7 @@ if __name__ == "__main__":
|
|
|
1019
1019
|
"Framework :: AsyncIO",
|
|
1020
1020
|
"Framework :: AnyIO",
|
|
1021
1021
|
"Programming Language :: Python :: Implementation :: CPython",
|
|
1022
|
+
"Typing :: Typed",
|
|
1022
1023
|
],
|
|
1023
1024
|
keywords=["database", "sqlite", "encryption"],
|
|
1024
1025
|
license="OSI Approved",
|