quasardb 3.13.6__cp39-cp39-win_amd64.whl → 3.13.7__cp39-cp39-win_amd64.whl
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.
Potentially problematic release.
This version of quasardb might be problematic. Click here for more details.
- quasardb/CMakeFiles/generate.stamp.depend +1 -1
- quasardb/CMakeLists.txt +43 -22
- quasardb/INSTALL.vcxproj +11 -11
- quasardb/INSTALL.vcxproj.filters +2 -2
- quasardb/__init__.py +1 -1
- quasardb/add_boost_test.cmake +43 -0
- quasardb/batch_column.hpp +1 -1
- quasardb/batch_inserter.hpp +1 -1
- quasardb/blob.hpp +1 -1
- quasardb/cluster.hpp +42 -17
- quasardb/cmake_install.cmake +4 -4
- quasardb/concepts.hpp +30 -16
- quasardb/continuous.hpp +1 -1
- quasardb/convert/array.hpp +61 -7
- quasardb/convert/point.hpp +16 -11
- quasardb/convert/range.hpp +19 -25
- quasardb/convert/unicode.hpp +457 -149
- quasardb/convert/value.hpp +87 -18
- quasardb/convert.hpp +1 -1
- quasardb/date/ALL_BUILD.vcxproj +21 -21
- quasardb/date/ALL_BUILD.vcxproj.filters +1 -1
- quasardb/date/CMakeFiles/generate.stamp.depend +1 -1
- quasardb/date/INSTALL.vcxproj +11 -11
- quasardb/date/INSTALL.vcxproj.filters +2 -2
- quasardb/date/cmake_install.cmake +6 -6
- quasardb/date/date.sln +31 -31
- quasardb/date/dateTargets.cmake +2 -2
- quasardb/detail/qdb_resource.hpp +6 -6
- quasardb/detail/ts_column.hpp +1 -1
- quasardb/direct_blob.hpp +1 -1
- quasardb/direct_handle.hpp +1 -1
- quasardb/direct_integer.hpp +1 -1
- quasardb/{version.cpp → double.hpp} +46 -28
- quasardb/entry.hpp +1 -1
- quasardb/error.hpp +14 -10
- quasardb/handle.hpp +1 -1
- quasardb/integer.hpp +1 -1
- quasardb/logger.hpp +1 -1
- quasardb/masked_array.hpp +1 -1
- quasardb/module.cpp +73 -0
- quasardb/module.hpp +24 -0
- quasardb/node.hpp +16 -11
- quasardb/numpy/__init__.py +76 -7
- quasardb/numpy.hpp +1 -1
- quasardb/options.hpp +31 -9
- quasardb/pandas/__init__.py +1 -1
- quasardb/perf.hpp +6 -6
- quasardb/pinned_writer.hpp +1 -5
- quasardb/pybind11/ALL_BUILD.vcxproj +25 -25
- quasardb/pybind11/ALL_BUILD.vcxproj.filters +1 -1
- quasardb/pybind11/CMakeFiles/generate.stamp.depend +4 -4
- quasardb/pybind11/INSTALL.vcxproj +11 -11
- quasardb/pybind11/INSTALL.vcxproj.filters +2 -2
- quasardb/pybind11/cmake_install.cmake +1 -1
- quasardb/pybind11/pybind11.sln +31 -31
- quasardb/pytypes.hpp +2 -2
- quasardb/qdb_api.dll +0 -0
- quasardb/quasardb.cp39-win_amd64.pyd +0 -0
- quasardb/query.cpp +3 -3
- quasardb/query.hpp +1 -1
- quasardb/range-v3/ALL_BUILD.vcxproj +25 -25
- quasardb/range-v3/ALL_BUILD.vcxproj.filters +1 -1
- quasardb/range-v3/CMakeFiles/generate.stamp.depend +6 -6
- quasardb/range-v3/INSTALL.vcxproj +11 -11
- quasardb/range-v3/INSTALL.vcxproj.filters +2 -2
- quasardb/range-v3/Range-v3.sln +39 -39
- quasardb/range-v3/cmake_install.cmake +6 -6
- quasardb/range-v3/range-v3-config.cmake +3 -3
- quasardb/range-v3/range.v3.headers.vcxproj +338 -338
- quasardb/range-v3/range.v3.headers.vcxproj.filters +315 -315
- quasardb/reader/ts_row.hpp +1 -1
- quasardb/reader/ts_value.hpp +1 -1
- quasardb/string.hpp +160 -0
- quasardb/table.hpp +1 -1
- quasardb/table_reader.hpp +1 -1
- quasardb/tag.hpp +1 -1
- quasardb/timestamp.hpp +97 -0
- quasardb/utils.hpp +1 -1
- {quasardb-3.13.6.dist-info → quasardb-3.13.7.dist-info}/LICENSE.md +1 -1
- {quasardb-3.13.6.dist-info → quasardb-3.13.7.dist-info}/METADATA +1 -1
- quasardb-3.13.7.dist-info/RECORD +114 -0
- {quasardb-3.13.6.dist-info → quasardb-3.13.7.dist-info}/WHEEL +1 -1
- quasardb/qdb_client.cpp +0 -67
- quasardb/version.hpp +0 -43
- quasardb-3.13.6.dist-info/RECORD +0 -111
- {quasardb-3.13.6.dist-info → quasardb-3.13.7.dist-info}/top_level.txt +0 -0
quasardb/detail/qdb_resource.hpp
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
*
|
|
3
3
|
* Official Python API
|
|
4
4
|
*
|
|
5
|
-
* Copyright (c) 2009-
|
|
5
|
+
* Copyright (c) 2009-2023, quasardb SAS. All rights reserved.
|
|
6
6
|
* All rights reserved.
|
|
7
7
|
*
|
|
8
8
|
* Redistribution and use in source and binary forms, with or without
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
*/
|
|
31
31
|
#pragma once
|
|
32
32
|
|
|
33
|
-
#include
|
|
33
|
+
#include <qdb/client.h> // for qdb_handle_t
|
|
34
34
|
|
|
35
35
|
namespace qdb
|
|
36
36
|
{
|
|
@@ -49,14 +49,14 @@ public:
|
|
|
49
49
|
/**
|
|
50
50
|
* Default constructor, initializes nullpointer.
|
|
51
51
|
*/
|
|
52
|
-
qdb_resource(
|
|
52
|
+
qdb_resource(qdb_handle_t h)
|
|
53
53
|
: qdb_resource(h, nullptr)
|
|
54
54
|
{}
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Constructor and immediately initialize with pointer.
|
|
58
58
|
*/
|
|
59
|
-
qdb_resource(
|
|
59
|
+
qdb_resource(qdb_handle_t h, ValueType * p)
|
|
60
60
|
: h_(h)
|
|
61
61
|
, p_(p)
|
|
62
62
|
{}
|
|
@@ -68,7 +68,7 @@ public:
|
|
|
68
68
|
{
|
|
69
69
|
if (p_ != nullptr)
|
|
70
70
|
{
|
|
71
|
-
qdb_release(
|
|
71
|
+
qdb_release(h_, p_);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
p_ = nullptr;
|
|
@@ -110,7 +110,7 @@ public:
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
private:
|
|
113
|
-
|
|
113
|
+
qdb_handle_t h_;
|
|
114
114
|
ValueType * p_;
|
|
115
115
|
};
|
|
116
116
|
|
quasardb/detail/ts_column.hpp
CHANGED
quasardb/direct_blob.hpp
CHANGED
quasardb/direct_handle.hpp
CHANGED
quasardb/direct_integer.hpp
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
*
|
|
3
3
|
* Official Python API
|
|
4
4
|
*
|
|
5
|
-
* Copyright (c) 2009-
|
|
5
|
+
* Copyright (c) 2009-2023, quasardb SAS. All rights reserved.
|
|
6
6
|
* All rights reserved.
|
|
7
7
|
*
|
|
8
8
|
* Redistribution and use in source and binary forms, with or without
|
|
@@ -28,42 +28,60 @@
|
|
|
28
28
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
29
29
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
30
30
|
*/
|
|
31
|
-
#
|
|
32
|
-
#include <regex>
|
|
33
|
-
#include <sstream>
|
|
34
|
-
#include <stdexcept>
|
|
31
|
+
#pragma once
|
|
35
32
|
|
|
36
|
-
|
|
33
|
+
#include "entry.hpp"
|
|
34
|
+
#include <qdb/double.h>
|
|
35
|
+
|
|
36
|
+
namespace qdb
|
|
37
|
+
{
|
|
38
|
+
|
|
39
|
+
class double_entry : public expirable_entry
|
|
37
40
|
{
|
|
38
|
-
|
|
39
|
-
std::
|
|
40
|
-
|
|
41
|
+
public:
|
|
42
|
+
double_entry(handle_ptr h, std::string a) noexcept
|
|
43
|
+
: expirable_entry{h, a}
|
|
44
|
+
{}
|
|
45
|
+
|
|
46
|
+
public:
|
|
47
|
+
double get()
|
|
41
48
|
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
double result;
|
|
50
|
+
qdb::qdb_throw_if_error(*_handle, qdb_double_get(*_handle, _alias.c_str(), &result));
|
|
51
|
+
return result;
|
|
45
52
|
}
|
|
46
|
-
const auto major = std::stoi(m[1].str());
|
|
47
|
-
const auto minor = std::stoi(m[2].str());
|
|
48
|
-
return std::make_pair(major, minor);
|
|
49
|
-
}
|
|
50
53
|
|
|
51
|
-
|
|
52
|
-
{
|
|
54
|
+
void put(double val)
|
|
55
|
+
{
|
|
56
|
+
qdb::qdb_throw_if_error(*_handle, qdb_double_put(*_handle, _alias.c_str(), val, qdb_time_t{0}));
|
|
57
|
+
}
|
|
53
58
|
|
|
54
|
-
|
|
59
|
+
void update(double val)
|
|
60
|
+
{
|
|
61
|
+
qdb::qdb_throw_if_error(
|
|
62
|
+
*_handle, qdb_double_update(*_handle, _alias.c_str(), val, qdb_time_t{0}));
|
|
63
|
+
}
|
|
55
64
|
|
|
56
|
-
|
|
57
|
-
{
|
|
58
|
-
const auto ver_c = get_version_pair(candidate);
|
|
59
|
-
const auto ver_ref = get_version_pair(qdb_c_api_version);
|
|
60
|
-
if (ver_c != ver_ref)
|
|
65
|
+
double add(double val)
|
|
61
66
|
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
throw std::runtime_error(sstr.str());
|
|
67
|
+
double result;
|
|
68
|
+
qdb::qdb_throw_if_error(*_handle, qdb_double_add(*_handle, _alias.c_str(), val, &result));
|
|
69
|
+
return result;
|
|
66
70
|
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
template <typename Module>
|
|
74
|
+
static inline void register_double(Module & m)
|
|
75
|
+
{
|
|
76
|
+
namespace py = pybind11;
|
|
77
|
+
|
|
78
|
+
py::class_<qdb::double_entry, qdb::expirable_entry>(m, "Double") //
|
|
79
|
+
.def(py::init<qdb::handle_ptr, std::string>()) //
|
|
80
|
+
.def("get", &qdb::double_entry::get) //
|
|
81
|
+
.def("put", &qdb::double_entry::put, py::arg("double")) //
|
|
82
|
+
.def("update", &qdb::double_entry::update, py::arg("double")) //
|
|
83
|
+
.def("add", &qdb::double_entry::add, py::arg("addend")) //
|
|
84
|
+
; //
|
|
67
85
|
}
|
|
68
86
|
|
|
69
87
|
} // namespace qdb
|
quasardb/entry.hpp
CHANGED
quasardb/error.hpp
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
*
|
|
3
3
|
* Official Python API
|
|
4
4
|
*
|
|
5
|
-
* Copyright (c) 2009-
|
|
5
|
+
* Copyright (c) 2009-2023, quasardb SAS. All rights reserved.
|
|
6
6
|
* All rights reserved.
|
|
7
7
|
*
|
|
8
8
|
* Redistribution and use in source and binary forms, with or without
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
#include <qdb/client.h>
|
|
36
36
|
#include <qdb/error.h>
|
|
37
37
|
#include <qdb/query.h>
|
|
38
|
+
#include "detail/qdb_resource.hpp"
|
|
38
39
|
#include <pybind11/pybind11.h>
|
|
39
40
|
#include <iostream>
|
|
40
41
|
#include <utility>
|
|
@@ -209,7 +210,7 @@ inline void qdb_throw_if_error(
|
|
|
209
210
|
|
|
210
211
|
if ((qdb_e_ok != err) && (qdb_e_ok_created != err)) [[unlikely]]
|
|
211
212
|
{
|
|
212
|
-
qdb_string_t msg_;
|
|
213
|
+
detail::qdb_resource<qdb_string_t> msg_{h, nullptr};
|
|
213
214
|
qdb_error_t err_;
|
|
214
215
|
qdb_get_last_error(h, &err_, &msg_);
|
|
215
216
|
|
|
@@ -220,38 +221,41 @@ inline void qdb_throw_if_error(
|
|
|
220
221
|
throw qdb::exception{err, qdb_error(err)};
|
|
221
222
|
}
|
|
222
223
|
assert(err_ == err);
|
|
224
|
+
assert(msg_ != nullptr);
|
|
223
225
|
|
|
224
226
|
pre_throw();
|
|
225
227
|
|
|
228
|
+
std::string msg_data_{msg_.get()->data};
|
|
229
|
+
|
|
226
230
|
switch (err)
|
|
227
231
|
{
|
|
228
232
|
|
|
229
233
|
case qdb_e_invalid_query:
|
|
230
|
-
throw qdb::invalid_query_exception{
|
|
234
|
+
throw qdb::invalid_query_exception{msg_data_};
|
|
231
235
|
|
|
232
236
|
case qdb_e_alias_already_exists:
|
|
233
|
-
throw qdb::alias_already_exists_exception{
|
|
237
|
+
throw qdb::alias_already_exists_exception{msg_data_};
|
|
234
238
|
|
|
235
239
|
case qdb_e_alias_not_found:
|
|
236
|
-
throw qdb::alias_not_found_exception{
|
|
240
|
+
throw qdb::alias_not_found_exception{msg_data_};
|
|
237
241
|
|
|
238
242
|
case qdb_e_network_inbuf_too_small:
|
|
239
243
|
throw qdb::input_buffer_too_small_exception{};
|
|
240
244
|
|
|
241
245
|
case qdb_e_incompatible_type:
|
|
242
|
-
throw qdb::incompatible_type_exception{
|
|
246
|
+
throw qdb::incompatible_type_exception{msg_data_};
|
|
243
247
|
|
|
244
248
|
case qdb_e_not_implemented:
|
|
245
|
-
throw qdb::not_implemented_exception{
|
|
249
|
+
throw qdb::not_implemented_exception{msg_data_};
|
|
246
250
|
|
|
247
251
|
case qdb_e_internal_local:
|
|
248
|
-
throw qdb::internal_local_exception{
|
|
252
|
+
throw qdb::internal_local_exception{msg_data_};
|
|
249
253
|
|
|
250
254
|
case qdb_e_invalid_argument:
|
|
251
|
-
throw qdb::invalid_argument_exception{
|
|
255
|
+
throw qdb::invalid_argument_exception{msg_data_};
|
|
252
256
|
|
|
253
257
|
default:
|
|
254
|
-
throw qdb::exception{err_,
|
|
258
|
+
throw qdb::exception{err_, msg_data_};
|
|
255
259
|
};
|
|
256
260
|
}
|
|
257
261
|
}
|
quasardb/handle.hpp
CHANGED
quasardb/integer.hpp
CHANGED
quasardb/logger.hpp
CHANGED
quasardb/masked_array.hpp
CHANGED
quasardb/module.cpp
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#include "module.hpp"
|
|
2
|
+
#include "cluster.hpp"
|
|
3
|
+
#include "node.hpp"
|
|
4
|
+
#include <functional>
|
|
5
|
+
#include <list>
|
|
6
|
+
|
|
7
|
+
namespace qdb
|
|
8
|
+
{
|
|
9
|
+
/**
|
|
10
|
+
* This approach is inspired from pybind11, where we keep a global static variable
|
|
11
|
+
* of initializers for components/modules that which to register with our global
|
|
12
|
+
* quasardb module.
|
|
13
|
+
*
|
|
14
|
+
* It has the downside of module initialization order essentially being random, which
|
|
15
|
+
* is fine for our use case. It allows decoupling of code in many places.
|
|
16
|
+
*/
|
|
17
|
+
std::list<std::function<void(py::module_ &)>> & initializers()
|
|
18
|
+
{
|
|
19
|
+
static std::list<std::function<void(py::module_ &)>> inits;
|
|
20
|
+
return inits;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
submodule_initializer::submodule_initializer(initialize_fn init)
|
|
24
|
+
{
|
|
25
|
+
initializers().emplace_back(init);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
submodule_initializer::submodule_initializer(const char * submodule_name, initialize_fn init)
|
|
29
|
+
{
|
|
30
|
+
initializers().emplace_back([=](py::module_ & parent) { init(parent); });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
}; // namespace qdb
|
|
34
|
+
|
|
35
|
+
PYBIND11_MODULE(quasardb, m)
|
|
36
|
+
{
|
|
37
|
+
m.doc() = "QuasarDB Official Python API";
|
|
38
|
+
m.def("version", &qdb_version, "Return version number");
|
|
39
|
+
m.def("build", &qdb_build, "Return build number");
|
|
40
|
+
m.attr("never_expires") = std::chrono::system_clock::time_point{};
|
|
41
|
+
|
|
42
|
+
qdb::register_errors(m);
|
|
43
|
+
qdb::register_cluster(m);
|
|
44
|
+
qdb::register_node(m);
|
|
45
|
+
qdb::register_options(m);
|
|
46
|
+
qdb::register_perf(m);
|
|
47
|
+
qdb::register_entry(m);
|
|
48
|
+
qdb::register_double(m);
|
|
49
|
+
qdb::register_integer(m);
|
|
50
|
+
qdb::register_blob(m);
|
|
51
|
+
qdb::register_string(m);
|
|
52
|
+
qdb::register_timestamp(m);
|
|
53
|
+
qdb::register_direct_blob(m);
|
|
54
|
+
qdb::register_direct_integer(m);
|
|
55
|
+
qdb::register_tag(m);
|
|
56
|
+
qdb::register_query(m);
|
|
57
|
+
qdb::register_continuous(m);
|
|
58
|
+
qdb::register_table(m);
|
|
59
|
+
qdb::register_batch_column(m);
|
|
60
|
+
qdb::register_batch_inserter(m);
|
|
61
|
+
qdb::register_pinned_writer(m);
|
|
62
|
+
qdb::register_table_reader(m);
|
|
63
|
+
qdb::register_masked_array(m);
|
|
64
|
+
|
|
65
|
+
qdb::detail::register_ts_column(m);
|
|
66
|
+
qdb::reader::register_ts_value(m);
|
|
67
|
+
qdb::reader::register_ts_row(m);
|
|
68
|
+
|
|
69
|
+
for (const auto & initializer : qdb::initializers())
|
|
70
|
+
{
|
|
71
|
+
initializer(m);
|
|
72
|
+
}
|
|
73
|
+
}
|
quasardb/module.hpp
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <pybind11/pybind11.h>
|
|
4
|
+
|
|
5
|
+
namespace qdb
|
|
6
|
+
{
|
|
7
|
+
|
|
8
|
+
namespace py = pybind11;
|
|
9
|
+
|
|
10
|
+
class submodule_initializer
|
|
11
|
+
{
|
|
12
|
+
using initialize_fn = void (*)(py::module_ &);
|
|
13
|
+
|
|
14
|
+
public:
|
|
15
|
+
explicit submodule_initializer(initialize_fn init);
|
|
16
|
+
submodule_initializer(const char * submodule_name, initialize_fn init);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
}; // namespace qdb
|
|
20
|
+
|
|
21
|
+
#define QDB_REGISTER_MODULE(name, variable) \
|
|
22
|
+
void qdb_submodule_##name(py::module_ &); \
|
|
23
|
+
submodule_initializer name(#name, qdb_submodule_##name); \
|
|
24
|
+
void qdb_submodule_##name(py::module_ &(variable))
|
quasardb/node.hpp
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
*
|
|
3
3
|
* Official Python API
|
|
4
4
|
*
|
|
5
|
-
* Copyright (c) 2009-
|
|
5
|
+
* Copyright (c) 2009-2023, quasardb SAS. All rights reserved.
|
|
6
6
|
* All rights reserved.
|
|
7
7
|
*
|
|
8
8
|
* Redistribution and use in source and binary forms, with or without
|
|
@@ -47,14 +47,17 @@ public:
|
|
|
47
47
|
* Construct a direct node connection directly, possibly with security credentials.
|
|
48
48
|
*/
|
|
49
49
|
node(const std::string & node_uri,
|
|
50
|
-
const std::string & user_name
|
|
51
|
-
const std::string & user_private_key
|
|
52
|
-
const std::string & cluster_public_key
|
|
50
|
+
const std::string & user_name = {},
|
|
51
|
+
const std::string & user_private_key = {},
|
|
52
|
+
const std::string & cluster_public_key = {},
|
|
53
|
+
const std::string & user_security_file = {},
|
|
54
|
+
const std::string & cluster_public_key_file = {})
|
|
53
55
|
: _uri{node_uri}
|
|
54
56
|
, _handle{make_handle_ptr()}
|
|
55
57
|
, _direct_handle{make_direct_handle_ptr()}
|
|
56
58
|
{
|
|
57
|
-
qdb::options{_handle}.apply_credentials(user_name, user_private_key, cluster_public_key
|
|
59
|
+
qdb::options{_handle}.apply_credentials(user_name, user_private_key, cluster_public_key,
|
|
60
|
+
user_security_file, cluster_public_key_file);
|
|
58
61
|
_direct_handle->connect(_handle, node_uri);
|
|
59
62
|
}
|
|
60
63
|
|
|
@@ -104,12 +107,14 @@ static inline void register_node(Module & m)
|
|
|
104
107
|
namespace py = pybind11;
|
|
105
108
|
|
|
106
109
|
py::class_<qdb::node>(m, "Node")
|
|
107
|
-
.def(py::init<std::string const &, std::string const &, std::string const &,
|
|
108
|
-
|
|
109
|
-
py::arg("uri"),
|
|
110
|
-
py::arg("user_name") = std::string{},
|
|
111
|
-
py::arg("user_private_key") = std::string{},
|
|
112
|
-
py::arg("cluster_public_key") = std::string{}
|
|
110
|
+
.def(py::init<std::string const &, std::string const &, std::string const &, std::string const &,
|
|
111
|
+
std::string const &, std::string const &>(),
|
|
112
|
+
py::arg("uri"), //
|
|
113
|
+
py::arg("user_name") = std::string{}, //
|
|
114
|
+
py::arg("user_private_key") = std::string{}, //
|
|
115
|
+
py::arg("cluster_public_key") = std::string{}, //
|
|
116
|
+
py::arg("user_security_file") = std::string{}, //
|
|
117
|
+
py::arg("cluster_public_key_file") = std::string{}) //
|
|
113
118
|
.def("prefix_get", &qdb::node::prefix_get)
|
|
114
119
|
.def("blob", &qdb::node::blob)
|
|
115
120
|
.def("integer", &qdb::node::integer);
|
quasardb/numpy/__init__.py
CHANGED
|
@@ -81,6 +81,19 @@ class IncompatibleDtypeErrors(TypeError):
|
|
|
81
81
|
def msg(self):
|
|
82
82
|
return "\n".join(x.msg() for x in self.xs)
|
|
83
83
|
|
|
84
|
+
class InvalidDataCardinalityError(ValueError):
|
|
85
|
+
"""
|
|
86
|
+
Raised when the provided data arrays doesn't match the table's columns.
|
|
87
|
+
"""
|
|
88
|
+
def __init__(self, data, cinfos):
|
|
89
|
+
self.data = data
|
|
90
|
+
self.cinfos = cinfos
|
|
91
|
+
super().__init__(self.msg())
|
|
92
|
+
|
|
93
|
+
def msg(self):
|
|
94
|
+
return "Provided data array length '{}' exceeds amount of table columns '{}', unable to map data to columns".format(len(self.data), len(self.cinfos))
|
|
95
|
+
|
|
96
|
+
|
|
84
97
|
# Based on QuasarDB column types, which dtype do we accept?
|
|
85
98
|
# First entry will always be the 'preferred' dtype, other ones
|
|
86
99
|
# those that we can natively convert in native code.
|
|
@@ -259,6 +272,42 @@ def _coerce_deduplicate(deduplicate, deduplication_mode, columns):
|
|
|
259
272
|
|
|
260
273
|
return deduplicate
|
|
261
274
|
|
|
275
|
+
def _clean_nulls(xs, dtype):
|
|
276
|
+
"""
|
|
277
|
+
Numpy's masked arrays have a downside that in case they're not able to convert a (masked!) value to
|
|
278
|
+
the desired dtype, they raise an error. So, for example, if I have a masked array of objects that
|
|
279
|
+
look like this
|
|
280
|
+
|
|
281
|
+
xs: [1.234 <pd.NA> 5.678]
|
|
282
|
+
mask: [1 0 1]
|
|
283
|
+
|
|
284
|
+
even though pd.NA is not "visible", because it cannot be converted to a float(), the operation will
|
|
285
|
+
fail!
|
|
286
|
+
|
|
287
|
+
This function fixes this by replacing the null values with an acceptable value that can always be
|
|
288
|
+
converted to the desired dtype.
|
|
289
|
+
"""
|
|
290
|
+
|
|
291
|
+
assert ma.isMA(xs)
|
|
292
|
+
|
|
293
|
+
if xs.dtype is not np.dtype('object'):
|
|
294
|
+
return xs
|
|
295
|
+
|
|
296
|
+
fill_value = None
|
|
297
|
+
if dtype == np.float64 or dtype == np.float32 or dtype == np.float16:
|
|
298
|
+
fill_value = float('nan')
|
|
299
|
+
elif dtype == np.int64 or dtype == np.int32 or dtype == np.int16:
|
|
300
|
+
fill_value = -1
|
|
301
|
+
elif dtype == np.dtype('datetime64[ns]'):
|
|
302
|
+
fill_value = np.datetime64('nat')
|
|
303
|
+
|
|
304
|
+
mask = xs.mask
|
|
305
|
+
xs_ = xs.filled(fill_value)
|
|
306
|
+
|
|
307
|
+
return ma.array(xs_, mask=mask)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
|
|
262
311
|
def _coerce_data(data, dtype):
|
|
263
312
|
"""
|
|
264
313
|
Coerces each numpy array of `data` to the dtype present in `dtype`.
|
|
@@ -271,25 +320,34 @@ def _coerce_data(data, dtype):
|
|
|
271
320
|
data_ = data[i]
|
|
272
321
|
|
|
273
322
|
if dtype_ is not None and dtypes_equal(data_.dtype, dtype_) == False:
|
|
323
|
+
data_ = _clean_nulls(data_, dtype_)
|
|
324
|
+
|
|
325
|
+
assert ma.isMA(data_)
|
|
326
|
+
|
|
274
327
|
logger.debug("data for column with offset %d was provided in dtype '%s', but need '%s': converting data...", i, data_.dtype, dtype_)
|
|
275
328
|
|
|
276
|
-
logger.debug("
|
|
277
|
-
logger.debug("
|
|
278
|
-
logger.debug("
|
|
329
|
+
logger.debug("dtype of data[%d] before: %s", i, data_.dtype)
|
|
330
|
+
logger.debug("type of data[%d] after: %s", i, type(data_))
|
|
331
|
+
logger.debug("size of data[%d] after: %s", i, ma.size(data_))
|
|
332
|
+
logger.debug("data of data[%d] after: %s", i, data_)
|
|
279
333
|
|
|
280
334
|
try:
|
|
281
335
|
data[i] = data_.astype(dtype_)
|
|
282
336
|
except TypeError as err:
|
|
283
337
|
# One 'bug' is that, if everything is masked, the underlying data type can be
|
|
284
338
|
# pretty much anything.
|
|
285
|
-
if
|
|
339
|
+
if _is_all_masked(data_):
|
|
340
|
+
logger.debug("array completely empty, re-initializing to empty array of '%s'", dtype_)
|
|
341
|
+
data[i] = ma.masked_all(ma.size(data_),
|
|
342
|
+
dtype=dtype_)
|
|
343
|
+
|
|
344
|
+
# Another 'bug' is that when the input data is objects, we may have null-like values (like pd.NA)
|
|
345
|
+
# that cannot easily be converted to, say, float.
|
|
346
|
+
else:
|
|
286
347
|
logger.error("An error occured while coercing input data type from dtype '%s' to dtype '%s': ", data_.dtype, dtype_)
|
|
287
348
|
logger.exception(err)
|
|
288
349
|
raise err
|
|
289
350
|
|
|
290
|
-
logger.debug("array completely empty, re-initializing to empty array of '%s'", dtype_)
|
|
291
|
-
data[i] = ma.masked_all(ma.size(data_),
|
|
292
|
-
dtype=dtype_)
|
|
293
351
|
assert data[i].dtype.kind == dtype_.kind
|
|
294
352
|
|
|
295
353
|
logger.debug("type of data[%d] after: %s", i, type(data[i]))
|
|
@@ -321,6 +379,13 @@ def _ensure_list(xs, cinfos):
|
|
|
321
379
|
if isinstance(xs, list):
|
|
322
380
|
return xs
|
|
323
381
|
|
|
382
|
+
if isinstance(xs, np.ndarray):
|
|
383
|
+
ret = []
|
|
384
|
+
for x in xs:
|
|
385
|
+
ret.append(x)
|
|
386
|
+
|
|
387
|
+
return ret
|
|
388
|
+
|
|
324
389
|
# As we only accept list-likes or dicts as input data, it *must* be a dict at this
|
|
325
390
|
# point
|
|
326
391
|
assert isinstance(xs, dict)
|
|
@@ -612,6 +677,10 @@ def write_arrays(
|
|
|
612
677
|
dtype = _add_desired_dtypes(dtype, cinfos)
|
|
613
678
|
|
|
614
679
|
data = _ensure_list(data, cinfos)
|
|
680
|
+
|
|
681
|
+
if len(data) != len(cinfos):
|
|
682
|
+
raise InvalidDataCardinalityError(data, cinfos)
|
|
683
|
+
|
|
615
684
|
data = ensure_ma(data, dtype=dtype)
|
|
616
685
|
data = _coerce_data(data, dtype)
|
|
617
686
|
|
quasardb/numpy.hpp
CHANGED
quasardb/options.hpp
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
*
|
|
3
3
|
* Official Python API
|
|
4
4
|
*
|
|
5
|
-
* Copyright (c) 2009-
|
|
5
|
+
* Copyright (c) 2009-2023, quasardb SAS. All rights reserved.
|
|
6
6
|
* All rights reserved.
|
|
7
7
|
*
|
|
8
8
|
* Redistribution and use in source and binary forms, with or without
|
|
@@ -50,21 +50,35 @@ public:
|
|
|
50
50
|
*/
|
|
51
51
|
void apply_credentials(const std::string & user_name,
|
|
52
52
|
const std::string & user_private_key,
|
|
53
|
-
const std::string & cluster_public_key
|
|
53
|
+
const std::string & cluster_public_key,
|
|
54
|
+
const std::string & user_security_file,
|
|
55
|
+
const std::string & cluster_public_key_file)
|
|
54
56
|
{
|
|
55
|
-
// must specify
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if
|
|
57
|
+
// must specify keys or files or nothing
|
|
58
|
+
auto empty_keys = user_name.empty() && user_private_key.empty() && cluster_public_key.empty();
|
|
59
|
+
auto empty_files = user_security_file.empty() && cluster_public_key_file.empty();
|
|
60
|
+
|
|
61
|
+
if(!empty_keys && !empty_files)
|
|
60
62
|
throw qdb::exception{qdb_e_invalid_argument,
|
|
61
|
-
"Either
|
|
63
|
+
"Either key or file security settings must be provided, or none at all"};
|
|
62
64
|
|
|
63
|
-
if (!
|
|
65
|
+
if (!empty_keys)
|
|
64
66
|
{
|
|
67
|
+
if (user_name.empty() || user_private_key.empty() || cluster_public_key.empty())
|
|
68
|
+
throw qdb::exception{qdb_e_invalid_argument,
|
|
69
|
+
"Either all keys security settings must be provided, or none at all"};
|
|
70
|
+
|
|
65
71
|
set_user_credentials(user_name, user_private_key);
|
|
66
72
|
set_cluster_public_key(cluster_public_key);
|
|
67
73
|
}
|
|
74
|
+
else if (!empty_files)
|
|
75
|
+
{
|
|
76
|
+
if (user_security_file.empty() || cluster_public_key_file.empty())
|
|
77
|
+
throw qdb::exception{qdb_e_invalid_argument,
|
|
78
|
+
"Either all files security settings must be provided, or none at all"};
|
|
79
|
+
|
|
80
|
+
set_file_credential(user_security_file, cluster_public_key_file);
|
|
81
|
+
}
|
|
68
82
|
};
|
|
69
83
|
|
|
70
84
|
void set_timeout(std::chrono::milliseconds ms)
|
|
@@ -123,6 +137,14 @@ public:
|
|
|
123
137
|
*_handle, qdb_option_set_user_credentials(*_handle, user.c_str(), private_key.c_str()));
|
|
124
138
|
}
|
|
125
139
|
|
|
140
|
+
void set_file_credential(
|
|
141
|
+
const std::string & user_security_file, const std::string & cluster_public_key_file)
|
|
142
|
+
{
|
|
143
|
+
qdb::qdb_throw_if_error(
|
|
144
|
+
*_handle, qdb_option_load_security_files(
|
|
145
|
+
*_handle, cluster_public_key_file.c_str(), user_security_file.c_str()));
|
|
146
|
+
}
|
|
147
|
+
|
|
126
148
|
void set_client_max_in_buf_size(size_t max_size)
|
|
127
149
|
{
|
|
128
150
|
qdb::qdb_throw_if_error(*_handle, qdb_option_set_client_max_in_buf_size(*_handle, max_size));
|