sqlce 0.1.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.
- sqlce-0.1.0/.github/workflows/release.yml +78 -0
- sqlce-0.1.0/.gitignore +95 -0
- sqlce-0.1.0/CMakeLists.txt +9 -0
- sqlce-0.1.0/LICENSE +21 -0
- sqlce-0.1.0/PKG-INFO +47 -0
- sqlce-0.1.0/README.md +24 -0
- sqlce-0.1.0/bindings/CMakeLists.txt +27 -0
- sqlce-0.1.0/bindings/src/module.cpp +115 -0
- sqlce-0.1.0/bindings/src/value_convert.cpp +146 -0
- sqlce-0.1.0/bindings/src/value_convert.hpp +15 -0
- sqlce-0.1.0/core/CMakeLists.txt +60 -0
- sqlce-0.1.0/core/app/main.cpp +156 -0
- sqlce-0.1.0/core/include/sdf/application/ColumnSchema.hpp +24 -0
- sqlce-0.1.0/core/include/sdf/application/SdfDatabase.hpp +45 -0
- sqlce-0.1.0/core/include/sdf/domain/ColumnDef.hpp +49 -0
- sqlce-0.1.0/core/include/sdf/domain/ColumnType.hpp +42 -0
- sqlce-0.1.0/core/include/sdf/domain/ColumnValue.hpp +50 -0
- sqlce-0.1.0/core/include/sdf/domain/DateTimeValue.hpp +36 -0
- sqlce-0.1.0/core/include/sdf/domain/Guid.hpp +27 -0
- sqlce-0.1.0/core/include/sdf/domain/IPageStorage.hpp +22 -0
- sqlce-0.1.0/core/include/sdf/domain/NumericValue.hpp +37 -0
- sqlce-0.1.0/core/include/sdf/domain/PageLayout.hpp +19 -0
- sqlce-0.1.0/core/include/sdf/domain/Row.hpp +27 -0
- sqlce-0.1.0/core/include/sdf/domain/TableDef.hpp +36 -0
- sqlce-0.1.0/core/include/sdf/infrastructure/BinaryReader.hpp +22 -0
- sqlce-0.1.0/core/include/sdf/infrastructure/FileStorage.hpp +28 -0
- sqlce-0.1.0/core/include/sdf/infrastructure/PageView.hpp +38 -0
- sqlce-0.1.0/core/include/sdf/parsing/CatalogPageScanner.hpp +18 -0
- sqlce-0.1.0/core/include/sdf/parsing/CatalogRow.hpp +41 -0
- sqlce-0.1.0/core/include/sdf/parsing/CatalogRowDecoder.hpp +20 -0
- sqlce-0.1.0/core/include/sdf/parsing/CatalogSchema.hpp +93 -0
- sqlce-0.1.0/core/include/sdf/parsing/ICatalogPageScanner.hpp +26 -0
- sqlce-0.1.0/core/include/sdf/parsing/ICatalogRowDecoder.hpp +23 -0
- sqlce-0.1.0/core/include/sdf/parsing/ILobChainRegistry.hpp +22 -0
- sqlce-0.1.0/core/include/sdf/parsing/IRowDecoder.hpp +22 -0
- sqlce-0.1.0/core/include/sdf/parsing/ITableCatalogBuilder.hpp +23 -0
- sqlce-0.1.0/core/include/sdf/parsing/LobChainRegistry.hpp +40 -0
- sqlce-0.1.0/core/include/sdf/parsing/RowDecoder.hpp +34 -0
- sqlce-0.1.0/core/include/sdf/parsing/TableCatalogBuilder.hpp +28 -0
- sqlce-0.1.0/core/include/sdf/parsing/TextDecoder.hpp +15 -0
- sqlce-0.1.0/core/src/application/SdfDatabase.cpp +122 -0
- sqlce-0.1.0/core/src/domain/ColumnDef.cpp +79 -0
- sqlce-0.1.0/core/src/domain/ColumnType.cpp +103 -0
- sqlce-0.1.0/core/src/domain/ColumnValue.cpp +105 -0
- sqlce-0.1.0/core/src/domain/DateTimeValue.cpp +107 -0
- sqlce-0.1.0/core/src/domain/Guid.cpp +49 -0
- sqlce-0.1.0/core/src/domain/NumericValue.cpp +93 -0
- sqlce-0.1.0/core/src/domain/Row.cpp +29 -0
- sqlce-0.1.0/core/src/domain/TableDef.cpp +40 -0
- sqlce-0.1.0/core/src/infrastructure/BinaryReader.cpp +59 -0
- sqlce-0.1.0/core/src/infrastructure/FileStorage.cpp +59 -0
- sqlce-0.1.0/core/src/infrastructure/PageView.cpp +96 -0
- sqlce-0.1.0/core/src/parsing/CatalogPageScanner.cpp +74 -0
- sqlce-0.1.0/core/src/parsing/CatalogRow.cpp +23 -0
- sqlce-0.1.0/core/src/parsing/CatalogRowDecoder.cpp +277 -0
- sqlce-0.1.0/core/src/parsing/CatalogSchema.cpp +35 -0
- sqlce-0.1.0/core/src/parsing/LobChainRegistry.cpp +198 -0
- sqlce-0.1.0/core/src/parsing/RowDecoder.cpp +321 -0
- sqlce-0.1.0/core/src/parsing/TableCatalogBuilder.cpp +137 -0
- sqlce-0.1.0/core/src/parsing/TextDecoder.cpp +88 -0
- sqlce-0.1.0/core/tests/CMakeLists.txt +9 -0
- sqlce-0.1.0/core/tests/count_test.cpp +15 -0
- sqlce-0.1.0/docs/4.0/ru/00-overview.md +50 -0
- sqlce-0.1.0/docs/4.0/ru/01-rows.md +119 -0
- sqlce-0.1.0/docs/4.0/ru/02-lob.md +69 -0
- sqlce-0.1.0/docs/4.0/ru/03-column-types.md +80 -0
- sqlce-0.1.0/docs/4.0/ru/04-catalog.md +66 -0
- sqlce-0.1.0/docs/4.0/ru/05-limitations.md +50 -0
- sqlce-0.1.0/docs/4.0/ru/catalog/00-schema.md +94 -0
- sqlce-0.1.0/docs/4.0/ru/catalog/01-row-layout.md +107 -0
- sqlce-0.1.0/docs/4.0/ru/catalog/02-classification.md +32 -0
- sqlce-0.1.0/docs/4.0/ru/catalog/03-status.md +72 -0
- sqlce-0.1.0/docs/CONVENTIONS.md +8 -0
- sqlce-0.1.0/docs/build.txt +5 -0
- sqlce-0.1.0/main.py +76 -0
- sqlce-0.1.0/pyproject.toml +47 -0
- sqlce-0.1.0/python/sqlce/__init__.py +4 -0
- sqlce-0.1.0/python/sqlce/__init__.pyi +5 -0
- sqlce-0.1.0/python/sqlce/_sdf_native.pyi +51 -0
- sqlce-0.1.0/requirements.txt +4 -0
- sqlce-0.1.0/research/catalog_parse/sdf_pages.py +93 -0
- sqlce-0.1.0/research/catalog_parse/syscatalog.py +241 -0
- sqlce-0.1.0/research/sdf_reader.py +515 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
name: Build and publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build-linux:
|
|
10
|
+
name: Build wheel (Linux)
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- name: Build wheels
|
|
16
|
+
uses: pypa/cibuildwheel@v2.21.3
|
|
17
|
+
env:
|
|
18
|
+
CIBW_ARCHS_LINUX: x86_64
|
|
19
|
+
CIBW_BUILD_VERBOSITY: 1
|
|
20
|
+
|
|
21
|
+
- name: Build sdist
|
|
22
|
+
run: |
|
|
23
|
+
python -m pip install --upgrade pip build
|
|
24
|
+
python -m build --sdist
|
|
25
|
+
|
|
26
|
+
- name: Collect wheels and sdist into one flat folder
|
|
27
|
+
run: |
|
|
28
|
+
mkdir -p collected
|
|
29
|
+
cp wheelhouse/*.whl collected/
|
|
30
|
+
cp dist/*.tar.gz collected/
|
|
31
|
+
|
|
32
|
+
- uses: actions/upload-artifact@v4
|
|
33
|
+
with:
|
|
34
|
+
name: dist-linux
|
|
35
|
+
path: collected/*
|
|
36
|
+
|
|
37
|
+
build-windows:
|
|
38
|
+
name: Build wheel (Windows)
|
|
39
|
+
runs-on: windows-latest
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
|
|
43
|
+
- uses: actions/setup-python@v5
|
|
44
|
+
with:
|
|
45
|
+
python-version: "3.11"
|
|
46
|
+
|
|
47
|
+
- name: Install build tools
|
|
48
|
+
run: |
|
|
49
|
+
python -m pip install --upgrade pip
|
|
50
|
+
pip install build
|
|
51
|
+
|
|
52
|
+
- name: Build wheel
|
|
53
|
+
run: |
|
|
54
|
+
python -m build --wheel -C cmake.args="-DSDF_BUILD_PYTHON_BINDINGS=ON"
|
|
55
|
+
|
|
56
|
+
- uses: actions/upload-artifact@v4
|
|
57
|
+
with:
|
|
58
|
+
name: dist-windows
|
|
59
|
+
path: dist/*
|
|
60
|
+
|
|
61
|
+
publish:
|
|
62
|
+
name: Publish to PyPI
|
|
63
|
+
needs: [build-linux, build-windows]
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
environment: pypi
|
|
66
|
+
permissions:
|
|
67
|
+
id-token: write
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/download-artifact@v4
|
|
70
|
+
with:
|
|
71
|
+
pattern: dist-*
|
|
72
|
+
path: dist
|
|
73
|
+
merge-multiple: true
|
|
74
|
+
|
|
75
|
+
- name: Publish to PyPI
|
|
76
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
77
|
+
with:
|
|
78
|
+
packages-dir: dist
|
sqlce-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
*.d
|
|
2
|
+
|
|
3
|
+
*.slo
|
|
4
|
+
*.lo
|
|
5
|
+
*.o
|
|
6
|
+
*.obj
|
|
7
|
+
|
|
8
|
+
*.gch
|
|
9
|
+
*.pch
|
|
10
|
+
|
|
11
|
+
*.ilk
|
|
12
|
+
*.pdb
|
|
13
|
+
|
|
14
|
+
*.so
|
|
15
|
+
*.so.*
|
|
16
|
+
*.dylib
|
|
17
|
+
*.dll
|
|
18
|
+
|
|
19
|
+
*.mod
|
|
20
|
+
*.smod
|
|
21
|
+
|
|
22
|
+
*.lai
|
|
23
|
+
*.la
|
|
24
|
+
*.a
|
|
25
|
+
*.lib
|
|
26
|
+
|
|
27
|
+
*.exe
|
|
28
|
+
*.out
|
|
29
|
+
*.app
|
|
30
|
+
|
|
31
|
+
build/
|
|
32
|
+
Build/
|
|
33
|
+
build-*/
|
|
34
|
+
cmake-build-debug/
|
|
35
|
+
cmake-build-release/
|
|
36
|
+
CMakeFiles/
|
|
37
|
+
CMakeCache.txt
|
|
38
|
+
cmake_install.cmake
|
|
39
|
+
Makefile
|
|
40
|
+
install_manifest.txt
|
|
41
|
+
compile_commands.json
|
|
42
|
+
vcpkg_installed/
|
|
43
|
+
Testing/
|
|
44
|
+
.cache/
|
|
45
|
+
|
|
46
|
+
.idea/
|
|
47
|
+
.vscode/
|
|
48
|
+
|
|
49
|
+
.venv/
|
|
50
|
+
venv/
|
|
51
|
+
env/
|
|
52
|
+
ENV/
|
|
53
|
+
|
|
54
|
+
__pycache__/
|
|
55
|
+
*.pyo
|
|
56
|
+
*.pyd
|
|
57
|
+
*.egg
|
|
58
|
+
*.egg-info/
|
|
59
|
+
dist/
|
|
60
|
+
|
|
61
|
+
*.dwo
|
|
62
|
+
|
|
63
|
+
.pytest_cache/
|
|
64
|
+
coverage.xml
|
|
65
|
+
.coverage
|
|
66
|
+
htmlcov/
|
|
67
|
+
|
|
68
|
+
*.tmp
|
|
69
|
+
*.log
|
|
70
|
+
*.bak
|
|
71
|
+
*.swp
|
|
72
|
+
|
|
73
|
+
raw/
|
|
74
|
+
images/
|
|
75
|
+
sessions/
|
|
76
|
+
downloads/
|
|
77
|
+
|
|
78
|
+
*.tar.gz
|
|
79
|
+
*.zip
|
|
80
|
+
*.whl
|
|
81
|
+
|
|
82
|
+
*.bat
|
|
83
|
+
*.jpg
|
|
84
|
+
*.png
|
|
85
|
+
*.json
|
|
86
|
+
|
|
87
|
+
!/assets/*.jpg
|
|
88
|
+
!/assets/*.png
|
|
89
|
+
|
|
90
|
+
.DS_Store
|
|
91
|
+
Thumbs.db
|
|
92
|
+
cookies.txt
|
|
93
|
+
|
|
94
|
+
.env
|
|
95
|
+
.env.local
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.20)
|
|
2
|
+
project(sqlce_workspace LANGUAGES CXX)
|
|
3
|
+
|
|
4
|
+
option(SDF_BUILD_PYTHON_BINDINGS "Build the _sdf_native pybind11 extension module" OFF)
|
|
5
|
+
add_subdirectory(core)
|
|
6
|
+
|
|
7
|
+
if(SDF_BUILD_PYTHON_BINDINGS)
|
|
8
|
+
add_subdirectory(bindings)
|
|
9
|
+
endif()
|
sqlce-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 boykopovar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
sqlce-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: sqlce
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Cross-platform lib for reading SQL Server CE (.sdf)
|
|
5
|
+
Author-Email: boykopovar <boykopovar@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: C++
|
|
17
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
18
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
19
|
+
Project-URL: Homepage, https://github.com/boykopovar/sqlce
|
|
20
|
+
Project-URL: Issues, https://github.com/boykopovar/sqlce/issues
|
|
21
|
+
Requires-Python: >=3.8
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# sqlce
|
|
25
|
+
|
|
26
|
+
Реверс-инжиниринг бинарного формата `.sdf` (SQL Server Compact Edition 4.0).
|
|
27
|
+
|
|
28
|
+
Анализ внутреннего устройства формата по декомпилированным компонентам SQL CE. Цель - предоставить кроссплатформенную и независимую от рантайма реализацию чтения `.sdf` и документацию формата.
|
|
29
|
+
|
|
30
|
+
## Структура
|
|
31
|
+
|
|
32
|
+
- `core/` - реализация парсера на C++
|
|
33
|
+
- `bindings/` - Биндинги для C++ библиотеки к другим языкам
|
|
34
|
+
- `python/sqlce/` - Python API
|
|
35
|
+
- `research/` - Экспериментальные скрипты
|
|
36
|
+
|
|
37
|
+
## Установка
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install sqlce
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
[Документирование формата](docs/4.0/ru/00-overview.md)
|
|
44
|
+
|
|
45
|
+
Текущая [реализация](main.py) поддерживает чтение списка таблиц, структуры таблиц, содержимого записей. Использует c++.
|
|
46
|
+
|
|
47
|
+
[Соглашения по написанию кода](docs/CONVENTIONS.md)
|
sqlce-0.1.0/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# sqlce
|
|
2
|
+
|
|
3
|
+
Реверс-инжиниринг бинарного формата `.sdf` (SQL Server Compact Edition 4.0).
|
|
4
|
+
|
|
5
|
+
Анализ внутреннего устройства формата по декомпилированным компонентам SQL CE. Цель - предоставить кроссплатформенную и независимую от рантайма реализацию чтения `.sdf` и документацию формата.
|
|
6
|
+
|
|
7
|
+
## Структура
|
|
8
|
+
|
|
9
|
+
- `core/` - реализация парсера на C++
|
|
10
|
+
- `bindings/` - Биндинги для C++ библиотеки к другим языкам
|
|
11
|
+
- `python/sqlce/` - Python API
|
|
12
|
+
- `research/` - Экспериментальные скрипты
|
|
13
|
+
|
|
14
|
+
## Установка
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install sqlce
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
[Документирование формата](docs/4.0/ru/00-overview.md)
|
|
21
|
+
|
|
22
|
+
Текущая [реализация](main.py) поддерживает чтение списка таблиц, структуры таблиц, содержимого записей. Использует c++.
|
|
23
|
+
|
|
24
|
+
[Соглашения по написанию кода](docs/CONVENTIONS.md)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
if(POLICY CMP0148)
|
|
2
|
+
cmake_policy(SET CMP0148 NEW)
|
|
3
|
+
endif()
|
|
4
|
+
|
|
5
|
+
find_package(pybind11 CONFIG REQUIRED)
|
|
6
|
+
pybind11_add_module(_sdf_native
|
|
7
|
+
src/module.cpp
|
|
8
|
+
src/value_convert.cpp
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
target_compile_features(_sdf_native PRIVATE cxx_std_20)
|
|
12
|
+
set_target_properties(_sdf_native PROPERTIES CXX_STANDARD 20 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF)
|
|
13
|
+
|
|
14
|
+
target_link_libraries(_sdf_native PRIVATE libsdf)
|
|
15
|
+
|
|
16
|
+
if(MINGW)
|
|
17
|
+
target_link_options(_sdf_native PRIVATE -static-libgcc -static-libstdc++ -static -lwinpthread)
|
|
18
|
+
endif()
|
|
19
|
+
|
|
20
|
+
if(MSVC)
|
|
21
|
+
target_compile_options(_sdf_native PRIVATE /W4 /utf-8 /permissive-)
|
|
22
|
+
target_compile_definitions(_sdf_native PRIVATE NOMINMAX _CRT_SECURE_NO_WARNINGS)
|
|
23
|
+
else()
|
|
24
|
+
target_compile_options(_sdf_native PRIVATE -Wall -Wextra)
|
|
25
|
+
endif()
|
|
26
|
+
|
|
27
|
+
install(TARGETS _sdf_native LIBRARY DESTINATION sqlce)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#include <pybind11/pybind11.h>
|
|
2
|
+
#include <pybind11/stl.h>
|
|
3
|
+
|
|
4
|
+
#include <cstdint>
|
|
5
|
+
#include <optional>
|
|
6
|
+
#include <string>
|
|
7
|
+
#include <utility>
|
|
8
|
+
#include <vector>
|
|
9
|
+
|
|
10
|
+
#include "sdf/application/ColumnSchema.hpp"
|
|
11
|
+
#include "sdf/application/SdfDatabase.hpp"
|
|
12
|
+
#include "sdf/domain/Row.hpp"
|
|
13
|
+
|
|
14
|
+
#include "value_convert.hpp"
|
|
15
|
+
|
|
16
|
+
namespace sdf::bindings
|
|
17
|
+
{
|
|
18
|
+
|
|
19
|
+
namespace py = pybind11;
|
|
20
|
+
|
|
21
|
+
namespace
|
|
22
|
+
{
|
|
23
|
+
|
|
24
|
+
constexpr char ModuleDoc[] = "Native reader for SQL Server Compact (.sdf) database files.";
|
|
25
|
+
|
|
26
|
+
constexpr char DatabaseClassName[] = "SdfDatabase";
|
|
27
|
+
constexpr char DatabaseDoc[] = "Reads tables, schemas and rows from a .sdf database file.";
|
|
28
|
+
constexpr char InitDoc[] = "Open a .sdf file at the given path.";
|
|
29
|
+
constexpr char PathArgName[] = "path";
|
|
30
|
+
constexpr char ListTablesName[] = "list_tables";
|
|
31
|
+
constexpr char ListTablesDoc[] = "Return the names of all tables in the database.";
|
|
32
|
+
constexpr char TableSchemaName[] = "table_schema";
|
|
33
|
+
constexpr char TableSchemaDoc[] = "Return the column schema of a table.";
|
|
34
|
+
constexpr char ReadTableName[] = "read_table";
|
|
35
|
+
constexpr char ReadTableDoc[] = "Return every row of a table as a list of column-name -> value mappings.";
|
|
36
|
+
constexpr char TableNameArgName[] = "table_name";
|
|
37
|
+
|
|
38
|
+
constexpr char SchemaClassName[] = "ColumnSchema";
|
|
39
|
+
constexpr char SchemaDoc[] = "Describes a single column of a table.";
|
|
40
|
+
constexpr char OrdinalAttrName[] = "ordinal";
|
|
41
|
+
constexpr char NameAttrName[] = "name";
|
|
42
|
+
constexpr char TypeNameAttrName[] = "type_name";
|
|
43
|
+
constexpr char DeclaredSizeAttrName[] = "declared_size";
|
|
44
|
+
constexpr char PrecisionAttrName[] = "precision";
|
|
45
|
+
constexpr char ScaleAttrName[] = "scale";
|
|
46
|
+
|
|
47
|
+
py::dict RowToDict(const domain::Row& row)
|
|
48
|
+
{
|
|
49
|
+
py::dict result;
|
|
50
|
+
for (const auto& [columnName, value] : row.Values())
|
|
51
|
+
{
|
|
52
|
+
result[py::str(columnName)] = ToPyObject(value);
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
std::vector<py::dict> ReadTableAsDicts(const application::SdfDatabase& database, const std::string& tableName)
|
|
58
|
+
{
|
|
59
|
+
std::vector<py::dict> result;
|
|
60
|
+
const std::vector<domain::Row> rows = database.ReadTable(tableName);
|
|
61
|
+
result.reserve(rows.size());
|
|
62
|
+
for (const domain::Row& row : rows)
|
|
63
|
+
{
|
|
64
|
+
result.push_back(RowToDict(row));
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
std::optional<int> OptionalByteToInt(std::optional<std::uint8_t> value)
|
|
70
|
+
{
|
|
71
|
+
if (!value.has_value())
|
|
72
|
+
{
|
|
73
|
+
return std::nullopt;
|
|
74
|
+
}
|
|
75
|
+
return static_cast<int>(*value);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
PYBIND11_MODULE(_sdf_native, module)
|
|
81
|
+
{
|
|
82
|
+
module.doc() = ModuleDoc;
|
|
83
|
+
|
|
84
|
+
py::class_<application::ColumnSchema>(module, SchemaClassName, SchemaDoc)
|
|
85
|
+
.def_property_readonly(
|
|
86
|
+
OrdinalAttrName,
|
|
87
|
+
[](const application::ColumnSchema& schema) { return schema.ordinal; })
|
|
88
|
+
.def_property_readonly(
|
|
89
|
+
NameAttrName,
|
|
90
|
+
[](const application::ColumnSchema& schema) { return schema.name; })
|
|
91
|
+
.def_property_readonly(
|
|
92
|
+
TypeNameAttrName,
|
|
93
|
+
[](const application::ColumnSchema& schema) { return std::string(schema.typeName); })
|
|
94
|
+
.def_property_readonly(
|
|
95
|
+
DeclaredSizeAttrName,
|
|
96
|
+
[](const application::ColumnSchema& schema) { return schema.declaredSize; })
|
|
97
|
+
.def_property_readonly(
|
|
98
|
+
PrecisionAttrName,
|
|
99
|
+
[](const application::ColumnSchema& schema) { return OptionalByteToInt(schema.precision); })
|
|
100
|
+
.def_property_readonly(
|
|
101
|
+
ScaleAttrName,
|
|
102
|
+
[](const application::ColumnSchema& schema) { return OptionalByteToInt(schema.scale); });
|
|
103
|
+
|
|
104
|
+
py::class_<application::SdfDatabase>(module, DatabaseClassName, DatabaseDoc)
|
|
105
|
+
.def(py::init<const std::string&>(), py::arg(PathArgName), InitDoc)
|
|
106
|
+
.def(ListTablesName, &application::SdfDatabase::ListTables, ListTablesDoc)
|
|
107
|
+
.def(
|
|
108
|
+
TableSchemaName,
|
|
109
|
+
&application::SdfDatabase::TableSchema,
|
|
110
|
+
py::arg(TableNameArgName),
|
|
111
|
+
TableSchemaDoc)
|
|
112
|
+
.def(ReadTableName, &ReadTableAsDicts, py::arg(TableNameArgName), ReadTableDoc);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#include "value_convert.hpp"
|
|
2
|
+
|
|
3
|
+
#include <pybind11/stl.h>
|
|
4
|
+
|
|
5
|
+
#include <array>
|
|
6
|
+
#include <cstdint>
|
|
7
|
+
#include <string>
|
|
8
|
+
#include <variant>
|
|
9
|
+
#include <vector>
|
|
10
|
+
|
|
11
|
+
#include "sdf/domain/DateTimeValue.hpp"
|
|
12
|
+
#include "sdf/domain/Guid.hpp"
|
|
13
|
+
#include "sdf/domain/NumericValue.hpp"
|
|
14
|
+
|
|
15
|
+
namespace sdf::bindings
|
|
16
|
+
{
|
|
17
|
+
|
|
18
|
+
namespace py = pybind11;
|
|
19
|
+
|
|
20
|
+
namespace
|
|
21
|
+
{
|
|
22
|
+
|
|
23
|
+
constexpr char DatetimeModuleName[] = "datetime";
|
|
24
|
+
constexpr char DatetimeClassName[] = "datetime";
|
|
25
|
+
constexpr char DecimalModuleName[] = "decimal";
|
|
26
|
+
constexpr char DecimalClassName[] = "Decimal";
|
|
27
|
+
constexpr char UuidModuleName[] = "uuid";
|
|
28
|
+
constexpr char UuidClassName[] = "UUID";
|
|
29
|
+
constexpr char BytesLeArgName[] = "bytes_le";
|
|
30
|
+
constexpr std::uint32_t MicrosecondsPerMillisecond = 1000;
|
|
31
|
+
constexpr std::uint32_t MillisecondsPerSecond = 1000;
|
|
32
|
+
constexpr std::uint32_t SecondsPerMinute = 60;
|
|
33
|
+
constexpr std::uint32_t MinutesPerHour = 60;
|
|
34
|
+
constexpr std::uint32_t HoursPerDay = 24;
|
|
35
|
+
|
|
36
|
+
py::object ImportAttr(const char* moduleName, const char* attrName)
|
|
37
|
+
{
|
|
38
|
+
return py::module_::import(moduleName).attr(attrName);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
py::tuple DigitsToTuple(const std::string& digits)
|
|
42
|
+
{
|
|
43
|
+
py::tuple result(digits.size());
|
|
44
|
+
for (std::size_t i = 0; i < digits.size(); ++i)
|
|
45
|
+
{
|
|
46
|
+
result[i] = py::int_(digits[i] - '0');
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
py::object DateTimeFromValue(const domain::DateTimeValue& value)
|
|
52
|
+
{
|
|
53
|
+
static const py::object datetimeClass = ImportAttr(DatetimeModuleName, DatetimeClassName);
|
|
54
|
+
|
|
55
|
+
const domain::CalendarDate date = value.Date();
|
|
56
|
+
const std::uint32_t totalSeconds = value.MillisecondsSinceMidnight() / MillisecondsPerSecond;
|
|
57
|
+
const std::uint32_t microsecond =
|
|
58
|
+
(value.MillisecondsSinceMidnight() % MillisecondsPerSecond) * MicrosecondsPerMillisecond;
|
|
59
|
+
const std::uint32_t hour = (totalSeconds / (SecondsPerMinute * MinutesPerHour)) % HoursPerDay;
|
|
60
|
+
const std::uint32_t minute = (totalSeconds / SecondsPerMinute) % MinutesPerHour;
|
|
61
|
+
const std::uint32_t second = totalSeconds % SecondsPerMinute;
|
|
62
|
+
|
|
63
|
+
return datetimeClass(date.year, date.month, date.day, hour, minute, second, microsecond);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
py::object DecimalFromValue(const domain::NumericValue& value)
|
|
67
|
+
{
|
|
68
|
+
static const py::object decimalClass = ImportAttr(DecimalModuleName, DecimalClassName);
|
|
69
|
+
|
|
70
|
+
const int sign = value.IsPositive() ? 0 : 1;
|
|
71
|
+
const py::tuple digits = DigitsToTuple(value.UnscaledDigits());
|
|
72
|
+
const int exponent = -static_cast<int>(value.Scale());
|
|
73
|
+
|
|
74
|
+
return decimalClass(py::make_tuple(sign, digits, exponent));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
py::object UuidFromValue(const domain::Guid& value)
|
|
78
|
+
{
|
|
79
|
+
static const py::object uuidClass = ImportAttr(UuidModuleName, UuidClassName);
|
|
80
|
+
|
|
81
|
+
const std::array<std::uint8_t, 16>& bytes = value.Bytes();
|
|
82
|
+
py::bytes bytesLe(reinterpret_cast<const char*>(bytes.data()), bytes.size());
|
|
83
|
+
return uuidClass(py::arg(BytesLeArgName) = bytesLe);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
struct ValueVisitor
|
|
87
|
+
{
|
|
88
|
+
py::object operator()(const domain::NullValue&) const
|
|
89
|
+
{
|
|
90
|
+
return py::none();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
py::object operator()(std::int64_t value) const
|
|
94
|
+
{
|
|
95
|
+
return py::int_(value);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
py::object operator()(std::uint64_t value) const
|
|
99
|
+
{
|
|
100
|
+
return py::int_(value);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
py::object operator()(double value) const
|
|
104
|
+
{
|
|
105
|
+
return py::float_(value);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
py::object operator()(bool value) const
|
|
109
|
+
{
|
|
110
|
+
return py::bool_(value);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
py::object operator()(const std::string& value) const
|
|
114
|
+
{
|
|
115
|
+
return py::str(value);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
py::object operator()(const std::vector<std::uint8_t>& value) const
|
|
119
|
+
{
|
|
120
|
+
return py::bytes(reinterpret_cast<const char*>(value.data()), value.size());
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
py::object operator()(const domain::DateTimeValue& value) const
|
|
124
|
+
{
|
|
125
|
+
return DateTimeFromValue(value);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
py::object operator()(const domain::NumericValue& value) const
|
|
129
|
+
{
|
|
130
|
+
return DecimalFromValue(value);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
py::object operator()(const domain::Guid& value) const
|
|
134
|
+
{
|
|
135
|
+
return UuidFromValue(value);
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
py::object ToPyObject(const domain::ColumnValue& value)
|
|
142
|
+
{
|
|
143
|
+
return std::visit(ValueVisitor{}, value.Storage());
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#ifndef SDF_BINDINGS_VALUE_CONVERT_HPP
|
|
2
|
+
#define SDF_BINDINGS_VALUE_CONVERT_HPP
|
|
3
|
+
|
|
4
|
+
#include <pybind11/pybind11.h>
|
|
5
|
+
|
|
6
|
+
#include "sdf/domain/ColumnValue.hpp"
|
|
7
|
+
|
|
8
|
+
namespace sdf::bindings
|
|
9
|
+
{
|
|
10
|
+
|
|
11
|
+
pybind11::object ToPyObject(const domain::ColumnValue& value);
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#endif
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.20)
|
|
2
|
+
project(libsdf LANGUAGES CXX)
|
|
3
|
+
|
|
4
|
+
set(CMAKE_CXX_STANDARD 20)
|
|
5
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
6
|
+
set(CMAKE_CXX_EXTENSIONS OFF)
|
|
7
|
+
|
|
8
|
+
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
|
9
|
+
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE)
|
|
10
|
+
endif()
|
|
11
|
+
|
|
12
|
+
add_library(libsdf
|
|
13
|
+
src/domain/ColumnDef.cpp
|
|
14
|
+
src/domain/ColumnType.cpp
|
|
15
|
+
src/domain/ColumnValue.cpp
|
|
16
|
+
src/domain/DateTimeValue.cpp
|
|
17
|
+
src/domain/Guid.cpp
|
|
18
|
+
src/domain/NumericValue.cpp
|
|
19
|
+
src/domain/Row.cpp
|
|
20
|
+
src/domain/TableDef.cpp
|
|
21
|
+
src/infrastructure/BinaryReader.cpp
|
|
22
|
+
src/infrastructure/FileStorage.cpp
|
|
23
|
+
src/infrastructure/PageView.cpp
|
|
24
|
+
src/parsing/CatalogPageScanner.cpp
|
|
25
|
+
src/parsing/CatalogRow.cpp
|
|
26
|
+
src/parsing/CatalogRowDecoder.cpp
|
|
27
|
+
src/parsing/CatalogSchema.cpp
|
|
28
|
+
src/parsing/LobChainRegistry.cpp
|
|
29
|
+
src/parsing/RowDecoder.cpp
|
|
30
|
+
src/parsing/TableCatalogBuilder.cpp
|
|
31
|
+
src/parsing/TextDecoder.cpp
|
|
32
|
+
src/application/SdfDatabase.cpp
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
set_target_properties(libsdf PROPERTIES PREFIX "" OUTPUT_NAME "libsdf" POSITION_INDEPENDENT_CODE ON)
|
|
36
|
+
|
|
37
|
+
target_include_directories(libsdf PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
|
38
|
+
|
|
39
|
+
if(MSVC)
|
|
40
|
+
target_compile_options(libsdf PRIVATE /W4 /utf-8 /permissive-)
|
|
41
|
+
target_compile_definitions(libsdf PRIVATE NOMINMAX _CRT_SECURE_NO_WARNINGS)
|
|
42
|
+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|
43
|
+
target_compile_options(libsdf PRIVATE -Wall -Wextra -Wno-free-nonheap-object)
|
|
44
|
+
else()
|
|
45
|
+
target_compile_options(libsdf PRIVATE -Wall -Wextra)
|
|
46
|
+
endif()
|
|
47
|
+
|
|
48
|
+
add_executable(sdf_dump app/main.cpp)
|
|
49
|
+
target_link_libraries(sdf_dump PRIVATE libsdf)
|
|
50
|
+
|
|
51
|
+
if(MSVC)
|
|
52
|
+
target_compile_options(sdf_dump PRIVATE /W4 /utf-8 /permissive-)
|
|
53
|
+
target_compile_definitions(sdf_dump PRIVATE NOMINMAX _CRT_SECURE_NO_WARNINGS)
|
|
54
|
+
else()
|
|
55
|
+
target_compile_options(sdf_dump PRIVATE -Wall -Wextra)
|
|
56
|
+
endif()
|
|
57
|
+
|
|
58
|
+
enable_testing()
|
|
59
|
+
|
|
60
|
+
add_subdirectory(tests)
|