1 
2 #include <pybind11/numpy.h>
3 #include <pybind11/pybind11.h>
4 #include <pybind11/pytypes.h>
5 #include <pybind11/stl.h>
6 
7 #include <exception>
8 
9 #define TILEDB_DEPRECATED
10 #define TILEDB_DEPRECATED_EXPORT
11 
12 #include "util.h"
13 #include <tiledb/tiledb> // C++
14 
15 #if TILEDB_VERSION_MAJOR == 2 && TILEDB_VERSION_MINOR >= 2
16 
17 #if !defined(NDEBUG)
18 #include "debug.cc"
19 #endif
20 
21 namespace tiledbpy {
22 
23 using namespace std;
24 using namespace tiledb;
25 namespace py = pybind11;
26 using namespace pybind11::literals;
27 
28 class PyFragmentInfo {
29 
30 private:
31   Context ctx_;
32   shared_ptr<FragmentInfo> fi_;
33 
34 public:
35   tiledb_ctx_t *c_ctx_;
36 
37 public:
38   PyFragmentInfo() = delete;
39 
PyFragmentInfo(const string & uri,py::object ctx)40   PyFragmentInfo(const string &uri, py::object ctx) {
41     if (ctx.is(py::none())) {
42       auto tiledblib = py::module::import("tiledb");
43       auto default_ctx = tiledblib.attr("default_ctx");
44       ctx = default_ctx();
45     }
46 
47     tiledb_ctx_t *c_ctx_ = (py::capsule)ctx.attr("__capsule__")();
48 
49     if (c_ctx_ == nullptr)
50       TPY_ERROR_LOC("Invalid context pointer!");
51 
52     ctx_ = Context(c_ctx_, false);
53 
54     fi_ = shared_ptr<tiledb::FragmentInfo>(new FragmentInfo(ctx_, uri));
55   }
56 
57   template <typename T>
for_all_fid(T (FragmentInfo::* fn)(uint32_t)const) const58   py::object for_all_fid(T (FragmentInfo::*fn)(uint32_t) const) const {
59     py::list l;
60     uint32_t nfrag = fragment_num();
61 
62     for (uint32_t i = 0; i < nfrag; ++i)
63       l.append((fi_.get()->*fn)(i));
64     return py::tuple(l);
65   }
66 
load() const67   void load() const {
68     try {
69       fi_->load();
70     } catch (TileDBError &e) {
71       TPY_ERROR_LOC(e.what());
72     }
73   }
74 
load(tiledb_encryption_type_t encryption_type,const string & encryption_key) const75   void load(tiledb_encryption_type_t encryption_type,
76             const string &encryption_key) const {
77     try {
78       fi_->load(encryption_type, encryption_key);
79     } catch (TileDBError &e) {
80       TPY_ERROR_LOC(e.what());
81     }
82   }
83 
fragment_uri(py::object fid) const84   py::object fragment_uri(py::object fid) const {
85     return fid.is(py::none())
86                ? for_all_fid(&FragmentInfo::fragment_uri)
87                : py::str(fi_->fragment_uri(py::cast<uint32_t>(fid)));
88   }
89 
get_non_empty_domain(py::object schema) const90   py::tuple get_non_empty_domain(py::object schema) const {
91     py::list all_frags;
92     uint32_t nfrag = fragment_num();
93 
94     for (uint32_t fid = 0; fid < nfrag; ++fid)
95       all_frags.append(get_non_empty_domain(schema, fid));
96 
97     return all_frags;
98   }
99 
get_non_empty_domain(py::object schema,uint32_t fid) const100   py::tuple get_non_empty_domain(py::object schema, uint32_t fid) const {
101     py::list all_dims;
102     int ndim = (schema.attr("domain").attr("ndim")).cast<int>();
103 
104     for (int did = 0; did < ndim; ++did)
105       all_dims.append(get_non_empty_domain(schema, fid, did));
106 
107     return all_dims;
108   }
109 
110   template <typename T>
get_non_empty_domain(py::object schema,uint32_t fid,T did) const111   py::tuple get_non_empty_domain(py::object schema, uint32_t fid, T did) const {
112     py::bool_ isvar = get_dim_isvar(schema.attr("domain"), did);
113 
114     if (isvar) {
115       pair<string, string> lims = fi_->non_empty_domain_var(fid, did);
116       return py::make_tuple(lims.first, lims.second);
117     }
118 
119     py::dtype type = get_dim_type(schema.attr("domain"), did);
120     py::dtype array_type =
121         type.kind() == 'M' ? pybind11::dtype::of<uint64_t>() : type;
122 
123     py::array limits = py::array(array_type, 2);
124     py::buffer_info buffer = limits.request();
125     fi_->get_non_empty_domain(fid, did, buffer.ptr);
126 
127     if (type.kind() == 'M') {
128       auto np = py::module::import("numpy");
129       auto datetime64 = np.attr("datetime64");
130       auto datetime_data = np.attr("datetime_data");
131 
132       uint64_t *dates = static_cast<uint64_t *>(buffer.ptr);
133       limits = py::make_tuple(datetime64(dates[0], datetime_data(type)),
134                               datetime64(dates[1], datetime_data(type)));
135     }
136 
137     return limits;
138   }
139 
get_dim_isvar(py::object dom,uint32_t did) const140   py::bool_ get_dim_isvar(py::object dom, uint32_t did) const {
141     // passing templated type "did" to Python function dom.attr("dim")
142     // does not work
143     return (dom.attr("dim")(did).attr("isvar")).cast<py::bool_>();
144   }
145 
get_dim_isvar(py::object dom,string did) const146   py::bool_ get_dim_isvar(py::object dom, string did) const {
147     // passing templated type "did" to Python function dom.attr("dim")
148     // does not work
149     return (dom.attr("dim")(did).attr("isvar")).cast<py::bool_>();
150   }
151 
get_dim_type(py::object dom,uint32_t did) const152   py::dtype get_dim_type(py::object dom, uint32_t did) const {
153     // passing templated type "did" to Python function dom.attr("dim")
154     // does not work
155     return (dom.attr("dim")(did).attr("dtype")).cast<py::dtype>();
156   }
157 
get_dim_type(py::object dom,string did) const158   py::dtype get_dim_type(py::object dom, string did) const {
159     // passing templated type "did" to Python function dom.attr("dim")
160     // does not work
161     return (dom.attr("dim")(did).attr("dtype")).cast<py::dtype>();
162   }
163 
timestamp_range(py::object fid) const164   py::object timestamp_range(py::object fid) const {
165     if (fid.is(py::none()))
166       return for_all_fid(&FragmentInfo::timestamp_range);
167 
168     auto p = fi_->timestamp_range(py::cast<uint32_t>(fid));
169     return py::make_tuple(p.first, p.second);
170   }
171 
fragment_num() const172   uint32_t fragment_num() const { return fi_->fragment_num(); }
173 
dense(py::object fid) const174   py::object dense(py::object fid) const {
175     return fid.is(py::none()) ? for_all_fid(&FragmentInfo::dense)
176                               : py::bool_(fi_->dense(py::cast<uint32_t>(fid)));
177   }
178 
sparse(py::object fid) const179   py::object sparse(py::object fid) const {
180     return fid.is(py::none()) ? for_all_fid(&FragmentInfo::sparse)
181                               : py::bool_(fi_->sparse(py::cast<uint32_t>(fid)));
182   }
183 
cell_num(py::object fid) const184   py::object cell_num(py::object fid) const {
185     return fid.is(py::none())
186                ? for_all_fid(&FragmentInfo::cell_num)
187                : py::int_(fi_->cell_num(py::cast<uint32_t>(fid)));
188   }
189 
version(py::object fid) const190   py::object version(py::object fid) const {
191     return fid.is(py::none()) ? for_all_fid(&FragmentInfo::version)
192                               : py::int_(fi_->version(py::cast<uint32_t>(fid)));
193   }
194 
has_consolidated_metadata(py::object fid) const195   py::object has_consolidated_metadata(py::object fid) const {
196     return fid.is(py::none())
197                ? for_all_fid(&FragmentInfo::has_consolidated_metadata)
198                : py::bool_(
199                      fi_->has_consolidated_metadata(py::cast<uint32_t>(fid)));
200   }
201 
unconsolidated_metadata_num() const202   uint32_t unconsolidated_metadata_num() const {
203     return fi_->unconsolidated_metadata_num();
204   }
205 
to_vacuum_num() const206   uint32_t to_vacuum_num() const { return fi_->to_vacuum_num(); }
207 
to_vacuum_uri(py::object fid) const208   py::object to_vacuum_uri(py::object fid) const {
209     return fid.is(py::none())
210                ? for_all_fid(&FragmentInfo::to_vacuum_uri)
211                : py::str(fi_->to_vacuum_uri(py::cast<uint32_t>(fid)));
212   }
213 
dump() const214   void dump() const { return fi_->dump(stdout); }
215 };
216 
PYBIND11_MODULE(_fragment,m)217 PYBIND11_MODULE(_fragment, m) {
218   py::class_<PyFragmentInfo>(m, "info")
219       .def(py::init<const string &, py::object>(), py::arg("uri"),
220            py::arg("ctx") = py::none())
221 
222       .def("load",
223            static_cast<void (PyFragmentInfo::*)() const>(&PyFragmentInfo::load))
224       .def("load", static_cast<void (PyFragmentInfo::*)(
225                        tiledb_encryption_type_t, const string &) const>(
226                        &PyFragmentInfo::load))
227 
228       .def("get_non_empty_domain",
229            static_cast<py::tuple (PyFragmentInfo::*)(py::object) const>(
230                &PyFragmentInfo::get_non_empty_domain))
231       .def("get_non_empty_domain",
232            static_cast<py::tuple (PyFragmentInfo::*)(py::object, uint32_t)
233                            const>(&PyFragmentInfo::get_non_empty_domain))
234       .def("get_non_empty_domain", static_cast<py::tuple (PyFragmentInfo::*)(
235                                        py::object, uint32_t, uint32_t) const>(
236                                        &PyFragmentInfo::get_non_empty_domain))
237       .def("get_non_empty_domain",
238            static_cast<py::tuple (PyFragmentInfo::*)(py::object, uint32_t,
239                                                      const string &) const>(
240                &PyFragmentInfo::get_non_empty_domain))
241 
242       .def("fragment_uri", &PyFragmentInfo::fragment_uri,
243            py::arg("fid") = py::none())
244       .def("timestamp_range", &PyFragmentInfo::timestamp_range,
245            py::arg("fid") = py::none())
246       .def("fragment_num", &PyFragmentInfo::fragment_num)
247       .def("dense", &PyFragmentInfo::dense, py::arg("fid") = py::none())
248       .def("sparse", &PyFragmentInfo::sparse, py::arg("fid") = py::none())
249       .def("cell_num", &PyFragmentInfo::cell_num, py::arg("fid") = py::none())
250       .def("version", &PyFragmentInfo::version, py::arg("fid") = py::none())
251       .def("has_consolidated_metadata",
252            &PyFragmentInfo::has_consolidated_metadata,
253            py::arg("fid") = py::none())
254       .def("unconsolidated_metadata_num",
255            &PyFragmentInfo::unconsolidated_metadata_num)
256       .def("to_vacuum_num", &PyFragmentInfo::to_vacuum_num)
257       .def("to_vacuum_uri", &PyFragmentInfo::to_vacuum_uri,
258            py::arg("fid") = py::none())
259       .def("dump", &PyFragmentInfo::dump);
260 }
261 
262 }; // namespace tiledbpy
263 
264 #endif