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.
Files changed (83) hide show
  1. sqlce-0.1.0/.github/workflows/release.yml +78 -0
  2. sqlce-0.1.0/.gitignore +95 -0
  3. sqlce-0.1.0/CMakeLists.txt +9 -0
  4. sqlce-0.1.0/LICENSE +21 -0
  5. sqlce-0.1.0/PKG-INFO +47 -0
  6. sqlce-0.1.0/README.md +24 -0
  7. sqlce-0.1.0/bindings/CMakeLists.txt +27 -0
  8. sqlce-0.1.0/bindings/src/module.cpp +115 -0
  9. sqlce-0.1.0/bindings/src/value_convert.cpp +146 -0
  10. sqlce-0.1.0/bindings/src/value_convert.hpp +15 -0
  11. sqlce-0.1.0/core/CMakeLists.txt +60 -0
  12. sqlce-0.1.0/core/app/main.cpp +156 -0
  13. sqlce-0.1.0/core/include/sdf/application/ColumnSchema.hpp +24 -0
  14. sqlce-0.1.0/core/include/sdf/application/SdfDatabase.hpp +45 -0
  15. sqlce-0.1.0/core/include/sdf/domain/ColumnDef.hpp +49 -0
  16. sqlce-0.1.0/core/include/sdf/domain/ColumnType.hpp +42 -0
  17. sqlce-0.1.0/core/include/sdf/domain/ColumnValue.hpp +50 -0
  18. sqlce-0.1.0/core/include/sdf/domain/DateTimeValue.hpp +36 -0
  19. sqlce-0.1.0/core/include/sdf/domain/Guid.hpp +27 -0
  20. sqlce-0.1.0/core/include/sdf/domain/IPageStorage.hpp +22 -0
  21. sqlce-0.1.0/core/include/sdf/domain/NumericValue.hpp +37 -0
  22. sqlce-0.1.0/core/include/sdf/domain/PageLayout.hpp +19 -0
  23. sqlce-0.1.0/core/include/sdf/domain/Row.hpp +27 -0
  24. sqlce-0.1.0/core/include/sdf/domain/TableDef.hpp +36 -0
  25. sqlce-0.1.0/core/include/sdf/infrastructure/BinaryReader.hpp +22 -0
  26. sqlce-0.1.0/core/include/sdf/infrastructure/FileStorage.hpp +28 -0
  27. sqlce-0.1.0/core/include/sdf/infrastructure/PageView.hpp +38 -0
  28. sqlce-0.1.0/core/include/sdf/parsing/CatalogPageScanner.hpp +18 -0
  29. sqlce-0.1.0/core/include/sdf/parsing/CatalogRow.hpp +41 -0
  30. sqlce-0.1.0/core/include/sdf/parsing/CatalogRowDecoder.hpp +20 -0
  31. sqlce-0.1.0/core/include/sdf/parsing/CatalogSchema.hpp +93 -0
  32. sqlce-0.1.0/core/include/sdf/parsing/ICatalogPageScanner.hpp +26 -0
  33. sqlce-0.1.0/core/include/sdf/parsing/ICatalogRowDecoder.hpp +23 -0
  34. sqlce-0.1.0/core/include/sdf/parsing/ILobChainRegistry.hpp +22 -0
  35. sqlce-0.1.0/core/include/sdf/parsing/IRowDecoder.hpp +22 -0
  36. sqlce-0.1.0/core/include/sdf/parsing/ITableCatalogBuilder.hpp +23 -0
  37. sqlce-0.1.0/core/include/sdf/parsing/LobChainRegistry.hpp +40 -0
  38. sqlce-0.1.0/core/include/sdf/parsing/RowDecoder.hpp +34 -0
  39. sqlce-0.1.0/core/include/sdf/parsing/TableCatalogBuilder.hpp +28 -0
  40. sqlce-0.1.0/core/include/sdf/parsing/TextDecoder.hpp +15 -0
  41. sqlce-0.1.0/core/src/application/SdfDatabase.cpp +122 -0
  42. sqlce-0.1.0/core/src/domain/ColumnDef.cpp +79 -0
  43. sqlce-0.1.0/core/src/domain/ColumnType.cpp +103 -0
  44. sqlce-0.1.0/core/src/domain/ColumnValue.cpp +105 -0
  45. sqlce-0.1.0/core/src/domain/DateTimeValue.cpp +107 -0
  46. sqlce-0.1.0/core/src/domain/Guid.cpp +49 -0
  47. sqlce-0.1.0/core/src/domain/NumericValue.cpp +93 -0
  48. sqlce-0.1.0/core/src/domain/Row.cpp +29 -0
  49. sqlce-0.1.0/core/src/domain/TableDef.cpp +40 -0
  50. sqlce-0.1.0/core/src/infrastructure/BinaryReader.cpp +59 -0
  51. sqlce-0.1.0/core/src/infrastructure/FileStorage.cpp +59 -0
  52. sqlce-0.1.0/core/src/infrastructure/PageView.cpp +96 -0
  53. sqlce-0.1.0/core/src/parsing/CatalogPageScanner.cpp +74 -0
  54. sqlce-0.1.0/core/src/parsing/CatalogRow.cpp +23 -0
  55. sqlce-0.1.0/core/src/parsing/CatalogRowDecoder.cpp +277 -0
  56. sqlce-0.1.0/core/src/parsing/CatalogSchema.cpp +35 -0
  57. sqlce-0.1.0/core/src/parsing/LobChainRegistry.cpp +198 -0
  58. sqlce-0.1.0/core/src/parsing/RowDecoder.cpp +321 -0
  59. sqlce-0.1.0/core/src/parsing/TableCatalogBuilder.cpp +137 -0
  60. sqlce-0.1.0/core/src/parsing/TextDecoder.cpp +88 -0
  61. sqlce-0.1.0/core/tests/CMakeLists.txt +9 -0
  62. sqlce-0.1.0/core/tests/count_test.cpp +15 -0
  63. sqlce-0.1.0/docs/4.0/ru/00-overview.md +50 -0
  64. sqlce-0.1.0/docs/4.0/ru/01-rows.md +119 -0
  65. sqlce-0.1.0/docs/4.0/ru/02-lob.md +69 -0
  66. sqlce-0.1.0/docs/4.0/ru/03-column-types.md +80 -0
  67. sqlce-0.1.0/docs/4.0/ru/04-catalog.md +66 -0
  68. sqlce-0.1.0/docs/4.0/ru/05-limitations.md +50 -0
  69. sqlce-0.1.0/docs/4.0/ru/catalog/00-schema.md +94 -0
  70. sqlce-0.1.0/docs/4.0/ru/catalog/01-row-layout.md +107 -0
  71. sqlce-0.1.0/docs/4.0/ru/catalog/02-classification.md +32 -0
  72. sqlce-0.1.0/docs/4.0/ru/catalog/03-status.md +72 -0
  73. sqlce-0.1.0/docs/CONVENTIONS.md +8 -0
  74. sqlce-0.1.0/docs/build.txt +5 -0
  75. sqlce-0.1.0/main.py +76 -0
  76. sqlce-0.1.0/pyproject.toml +47 -0
  77. sqlce-0.1.0/python/sqlce/__init__.py +4 -0
  78. sqlce-0.1.0/python/sqlce/__init__.pyi +5 -0
  79. sqlce-0.1.0/python/sqlce/_sdf_native.pyi +51 -0
  80. sqlce-0.1.0/requirements.txt +4 -0
  81. sqlce-0.1.0/research/catalog_parse/sdf_pages.py +93 -0
  82. sqlce-0.1.0/research/catalog_parse/syscatalog.py +241 -0
  83. 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)