1 /*************************************************************************************************
2 * Python binding
3 * Copyright (C) 2009-2010 FAL Labs
4 * This file is part of Kyoto Cabinet.
5 * This program is free software: you can redistribute it and/or modify it under the terms of
6 * the GNU General Public License as published by the Free Software Foundation, either version
7 * 3 of the License, or any later version.
8 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 * See the GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License along with this program.
12 * If not, see <http://www.gnu.org/licenses/>.
13 *************************************************************************************************/
14
15
16 #include <kcpolydb.h>
17
18 namespace kc = kyotocabinet;
19
20 extern "C" {
21
22 #undef _POSIX_C_SOURCE
23 #undef _XOPEN_SOURCE
24 #include <Python.h>
25 #include <structmember.h>
26
27
28 /* precedent type declaration */
29 class SoftString;
30 class CursorBurrow;
31 class SoftCursor;
32 class SoftVisitor;
33 class SoftFileProcessor;
34 struct Error_data;
35 struct Visitor_data;
36 struct FileProcessor_data;
37 struct Cursor_data;
38 struct DB_data;
39 class NativeFunction;
40 typedef std::map<std::string, std::string> StringMap;
41 typedef std::vector<std::string> StringVector;
42
43
44 /* function prototypes */
45 PyMODINIT_FUNC PyInit_kyotocabinet(void);
46 static bool setconstuint32(PyObject* pyobj, const char* name, uint32_t value);
47 static void throwruntime(const char* message);
48 static void throwinvarg();
49 static PyObject* newstring(const char* str);
50 static PyObject* newbytes(const char* ptr, size_t size);
51 static int64_t pyatoi(PyObject* pyobj);
52 static double pyatof(PyObject* pyobj);
53 static PyObject* maptopymap(const StringMap* map);
54 static PyObject* vectortopylist(const StringVector* vec);
55 static void threadyield();
56 static bool define_module();
57 static PyObject* kc_conv_bytes(PyObject* pyself, PyObject* pyargs);
58 static PyObject* kc_atoi(PyObject* pyself, PyObject* pyargs);
59 static PyObject* kc_atoix(PyObject* pyself, PyObject* pyargs);
60 static PyObject* kc_atof(PyObject* pyself, PyObject* pyargs);
61 static PyObject* kc_hash_murmur(PyObject* pyself, PyObject* pyargs);
62 static PyObject* kc_hash_fnv(PyObject* pyself, PyObject* pyargs);
63 static PyObject* kc_levdist(PyObject* pyself, PyObject* pyargs);
64 static bool define_err();
65 static bool err_define_child(const char* name, uint32_t code);
66 static PyObject* err_new(PyTypeObject* pytype, PyObject* pyargs, PyObject* pykwds);
67 static void err_dealloc(Error_data* data);
68 static int err_init(Error_data* data, PyObject* pyargs, PyObject* pykwds);
69 static PyObject* err_repr(Error_data* data);
70 static PyObject* err_str(Error_data* data);
71 static PyObject* err_richcmp(Error_data* data, PyObject* right, int op);
72 static PyObject* err_set(Error_data* data, PyObject* pyargs);
73 static PyObject* err_code(Error_data* data);
74 static PyObject* err_name(Error_data* data);
75 static PyObject* err_message(Error_data* data);
76 static bool define_vis();
77 static PyObject* vis_new(PyTypeObject* pytype, PyObject* pyargs, PyObject* pykwds);
78 static void vis_dealloc(Visitor_data* data);
79 static int vis_init(Visitor_data* data, PyObject* pyargs, PyObject* pykwds);
80 static PyObject* vis_visit_full(Visitor_data* data, PyObject* pyargs);
81 static PyObject* vis_visit_empty(Visitor_data* data, PyObject* pyargs);
82 static bool define_fproc();
83 static PyObject* fproc_new(PyTypeObject* pytype, PyObject* pyargs, PyObject* pykwds);
84 static void fproc_dealloc(FileProcessor_data* data);
85 static int fproc_init(FileProcessor_data* data, PyObject* pyargs, PyObject* pykwds);
86 static PyObject* fproc_process(FileProcessor_data* data, PyObject* pyargs);
87 static bool define_cur();
88 static PyObject* cur_new(PyTypeObject* pytype, PyObject* pyargs, PyObject* pykwds);
89 static void cur_dealloc(Cursor_data* data);
90 static int cur_init(Cursor_data* data, PyObject* pyargs, PyObject* pykwds);
91 static PyObject* cur_repr(Cursor_data* data);
92 static PyObject* cur_str(Cursor_data* data);
93 static PyObject* cur_disable(Cursor_data* data);
94 static PyObject* cur_accept(Cursor_data* data, PyObject* pyargs);
95 static PyObject* cur_set_value(Cursor_data* data, PyObject* pyargs);
96 static PyObject* cur_remove(Cursor_data* data);
97 static PyObject* cur_get_key(Cursor_data* data, PyObject* pyargs);
98 static PyObject* cur_get_key_str(Cursor_data* data, PyObject* pyargs);
99 static PyObject* cur_get_value(Cursor_data* data, PyObject* pyargs);
100 static PyObject* cur_get_value_str(Cursor_data* data, PyObject* pyargs);
101 static PyObject* cur_get(Cursor_data* data, PyObject* pyargs);
102 static PyObject* cur_get_str(Cursor_data* data, PyObject* pyargs);
103 static PyObject* cur_seize(Cursor_data* data);
104 static PyObject* cur_seize_str(Cursor_data* data);
105 static PyObject* cur_jump(Cursor_data* data, PyObject* pyargs);
106 static PyObject* cur_jump_back(Cursor_data* data, PyObject* pyargs);
107 static PyObject* cur_step(Cursor_data* data);
108 static PyObject* cur_step_back(Cursor_data* data);
109 static PyObject* cur_db(Cursor_data* data);
110 static PyObject* cur_error(Cursor_data* data);
111 static PyObject* cur_op_iter(Cursor_data* data);
112 static PyObject* cur_op_iternext(Cursor_data* data);
113 static bool define_db();
114 static PyObject* db_new(PyTypeObject* pytype, PyObject* pyargs, PyObject* pykwds);
115 static void db_dealloc(DB_data* data);
116 static bool db_raise(DB_data* data);
117 static int db_init(DB_data* data, PyObject* pyargs, PyObject* pykwds);
118 static PyObject* db_repr(DB_data* data);
119 static PyObject* db_str(DB_data* data);
120 static PyObject* db_error(DB_data* data);
121 static PyObject* db_open(DB_data* data, PyObject* pyargs);
122 static PyObject* db_close(DB_data* data);
123 static PyObject* db_accept(DB_data* data, PyObject* pyargs);
124 static PyObject* db_accept_bulk(DB_data* data, PyObject* pyargs);
125 static PyObject* db_iterate(DB_data* data, PyObject* pyargs);
126 static PyObject* db_set(DB_data* data, PyObject* pyargs);
127 static PyObject* db_add(DB_data* data, PyObject* pyargs);
128 static PyObject* db_replace(DB_data* data, PyObject* pyargs);
129 static PyObject* db_append(DB_data* data, PyObject* pyargs);
130 static PyObject* db_increment(DB_data* data, PyObject* pyargs);
131 static PyObject* db_increment_double(DB_data* data, PyObject* pyargs);
132 static PyObject* db_cas(DB_data* data, PyObject* pyargs);
133 static PyObject* db_remove(DB_data* data, PyObject* pyargs);
134 static PyObject* db_get(DB_data* data, PyObject* pyargs);
135 static PyObject* db_get_str(DB_data* data, PyObject* pyargs);
136 static PyObject* db_check(DB_data* data, PyObject* pyargs);
137 static PyObject* db_seize(DB_data* data, PyObject* pyargs);
138 static PyObject* db_seize_str(DB_data* data, PyObject* pyargs);
139 static PyObject* db_set_bulk(DB_data* data, PyObject* pyargs);
140 static PyObject* db_remove_bulk(DB_data* data, PyObject* pyargs);
141 static PyObject* db_get_bulk(DB_data* data, PyObject* pyargs);
142 static PyObject* db_get_bulk_str(DB_data* data, PyObject* pyargs);
143 static PyObject* db_clear(DB_data* data);
144 static PyObject* db_synchronize(DB_data* data, PyObject* pyargs);
145 static PyObject* db_occupy(DB_data* data, PyObject* pyargs);
146 static PyObject* db_copy(DB_data* data, PyObject* pyargs);
147 static PyObject* db_begin_transaction(DB_data* data, PyObject* pyargs);
148 static PyObject* db_end_transaction(DB_data* data, PyObject* pyargs);
149 static PyObject* db_transaction(DB_data* data, PyObject* pyargs);
150 static PyObject* db_dump_snapshot(DB_data* data, PyObject* pyargs);
151 static PyObject* db_load_snapshot(DB_data* data, PyObject* pyargs);
152 static PyObject* db_count(DB_data* data);
153 static PyObject* db_size(DB_data* data);
154 static PyObject* db_path(DB_data* data);
155 static PyObject* db_status(DB_data* data);
156 static PyObject* db_match_prefix(DB_data* data, PyObject* pyargs);
157 static PyObject* db_match_regex(DB_data* data, PyObject* pyargs);
158 static PyObject* db_match_similar(DB_data* data, PyObject* pyargs);
159 static PyObject* db_merge(DB_data* data, PyObject* pyargs);
160 static PyObject* db_cursor(DB_data* data);
161 static PyObject* db_cursor_process(DB_data* data, PyObject* pyargs);
162 static PyObject* db_shift(DB_data* data);
163 static PyObject* db_shift_str(DB_data* data);
164 static char* db_shift_impl(kc::PolyDB* db, size_t* ksp, const char** vbp, size_t* vsp);
165 static PyObject* db_tune_exception_rule(DB_data* data, PyObject* pyargs);
166 static Py_ssize_t db_op_len(DB_data* data);
167 static PyObject* db_op_getitem(DB_data* data, PyObject* pykey);
168 static int db_op_setitem(DB_data* data, PyObject* pykey, PyObject* pyvalue);
169 static PyObject* db_op_iter(DB_data* data);
170 static PyObject* db_process(PyObject* cls, PyObject* pyargs);
171
172
173 /* global variables */
174 PyObject* mod_kc;
175 PyObject* mod_th;
176 PyObject* mod_time;
177 PyObject* cls_err;
178 PyObject* cls_err_children[(int)kc::PolyDB::Error::MISC+1];
179 PyObject* cls_vis;
180 PyObject* obj_vis_nop;
181 PyObject* obj_vis_remove;
182 PyObject* cls_fproc;
183 PyObject* cls_cur;
184 PyObject* cls_db;
185
186
187 /**
188 * Generic options.
189 */
190 enum GenericOption {
191 GEXCEPTIONAL = 1 << 0,
192 GCONCURRENT = 1 << 1
193 };
194
195
196 /**
197 * Wrapper to treat a Python string as a C++ string.
198 */
199 class SoftString {
200 public:
SoftString(PyObject * pyobj)201 explicit SoftString(PyObject* pyobj) :
202 pyobj_(pyobj), pystr_(NULL), pybytes_(NULL), ptr_(NULL), size_(0) {
203 Py_INCREF(pyobj_);
204 if (PyUnicode_Check(pyobj_)) {
205 pybytes_ = PyUnicode_AsUTF8String(pyobj_);
206 if (pybytes_) {
207 ptr_ = PyBytes_AS_STRING(pybytes_);
208 size_ = PyBytes_GET_SIZE(pybytes_);
209 } else {
210 PyErr_Clear();
211 ptr_ = "";
212 size_ = 0;
213 }
214 } else if (PyBytes_Check(pyobj_)) {
215 ptr_ = PyBytes_AS_STRING(pyobj_);
216 size_ = PyBytes_GET_SIZE(pyobj_);
217 } else if (PyByteArray_Check(pyobj_)) {
218 ptr_ = PyByteArray_AS_STRING(pyobj_);
219 size_ = PyByteArray_GET_SIZE(pyobj_);
220 } else if (pyobj_ == Py_None) {
221 ptr_ = "";
222 size_ = 0;
223 } else {
224 pystr_ = PyObject_Str(pyobj_);
225 if (pystr_) {
226 pybytes_ = PyUnicode_AsUTF8String(pystr_);
227 if (pybytes_) {
228 ptr_ = PyBytes_AS_STRING(pybytes_);
229 size_ = PyBytes_GET_SIZE(pybytes_);
230 } else {
231 PyErr_Clear();
232 ptr_ = "";
233 size_ = 0;
234 }
235 } else {
236 ptr_ = "(unknown)";
237 size_ = std::strlen(ptr_);
238 }
239 }
240 }
~SoftString()241 ~SoftString() {
242 if (pybytes_) Py_DECREF(pybytes_);
243 if (pystr_) Py_DECREF(pystr_);
244 Py_DECREF(pyobj_);
245 }
ptr()246 const char* ptr() {
247 return ptr_;
248 }
size()249 const size_t size() {
250 return size_;
251 }
252 private:
253 PyObject* pyobj_;
254 PyObject* pystr_;
255 PyObject* pybytes_;
256 const char* ptr_;
257 size_t size_;
258 };
259
260
261 /**
262 * Burrow of cursors no longer in use.
263 */
264 class CursorBurrow {
265 private:
266 typedef std::vector<kc::PolyDB::Cursor*> CursorList;
267 public:
CursorBurrow()268 explicit CursorBurrow() : dcurs_() {}
~CursorBurrow()269 ~CursorBurrow() {
270 sweap();
271 }
sweap()272 void sweap() {
273 if (dcurs_.size() > 0) {
274 CursorList::iterator dit = dcurs_.begin();
275 CursorList::iterator ditend = dcurs_.end();
276 while (dit != ditend) {
277 kc::PolyDB::Cursor* cur = *dit;
278 delete cur;
279 dit++;
280 }
281 dcurs_.clear();
282 }
283 }
deposit(kc::PolyDB::Cursor * cur)284 void deposit(kc::PolyDB::Cursor* cur) {
285 dcurs_.push_back(cur);
286 }
287 private:
288 CursorList dcurs_;
289 } g_curbur;
290
291
292 /**
293 * Wrapper of a cursor.
294 */
295 class SoftCursor {
296 public:
SoftCursor(kc::PolyDB * db)297 explicit SoftCursor(kc::PolyDB* db) : cur_(NULL) {
298 cur_ = db->cursor();
299 }
~SoftCursor()300 ~SoftCursor() {
301 if (cur_) g_curbur.deposit(cur_);
302 }
cur()303 kc::PolyDB::Cursor* cur() {
304 return cur_;
305 }
disable()306 void disable() {
307 delete cur_;
308 cur_ = NULL;
309 }
310 private:
311 kc::PolyDB::Cursor* cur_;
312 };
313
314
315 /**
316 * Wrapper of a visitor.
317 */
318 class SoftVisitor : public kc::PolyDB::Visitor {
319 public:
SoftVisitor(PyObject * pyvisitor,bool writable)320 explicit SoftVisitor(PyObject* pyvisitor, bool writable) :
321 pyvisitor_(pyvisitor), writable_(writable), pyrv_(NULL), rv_(NULL),
322 pyextype_(NULL), pyexvalue_(NULL), pyextrace_(NULL) {
323 Py_INCREF(pyvisitor_);
324 }
~SoftVisitor()325 ~SoftVisitor() {
326 cleanup();
327 Py_DECREF(pyvisitor_);
328 }
exception(PyObject ** typep,PyObject ** valuep,PyObject ** tracep)329 bool exception(PyObject** typep, PyObject** valuep, PyObject** tracep) {
330 if (!pyextype_) return false;
331 *typep = pyextype_;
332 *valuep = pyexvalue_;
333 *tracep = pyextrace_;
334 return true;
335 }
336 private:
visit_full(const char * kbuf,size_t ksiz,const char * vbuf,size_t vsiz,size_t * sp)337 const char* visit_full(const char* kbuf, size_t ksiz,
338 const char* vbuf, size_t vsiz, size_t* sp) {
339 cleanup();
340 PyObject* pyrv;
341 if (PyCallable_Check(pyvisitor_)) {
342 pyrv = PyObject_CallFunction(pyvisitor_, (char*)"(y#y#)", kbuf, ksiz, vbuf, vsiz);
343 } else {
344 pyrv = PyObject_CallMethod(pyvisitor_, (char*)"visit_full",
345 (char*)"(y#y#)", kbuf, ksiz, vbuf, vsiz);
346 }
347 if (!pyrv) {
348 if (PyErr_Occurred()) PyErr_Fetch(&pyextype_, &pyexvalue_, &pyextrace_);
349 return NOP;
350 }
351 if (pyrv == Py_None || pyrv == obj_vis_nop) {
352 Py_DECREF(pyrv);
353 return NOP;
354 }
355 if (!writable_) {
356 Py_DECREF(pyrv);
357 throwruntime("confliction with the read-only parameter");
358 if (PyErr_Occurred()) PyErr_Fetch(&pyextype_, &pyexvalue_, &pyextrace_);
359 return NOP;
360 }
361 if (pyrv == obj_vis_remove) {
362 Py_DECREF(pyrv);
363 return REMOVE;
364 }
365 pyrv_ = pyrv;
366 rv_ = new SoftString(pyrv);
367 *sp = rv_->size();
368 return rv_->ptr();
369 }
visit_empty(const char * kbuf,size_t ksiz,size_t * sp)370 const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
371 cleanup();
372 PyObject* pyrv;
373 if (PyCallable_Check(pyvisitor_)) {
374 pyrv = PyObject_CallFunction(pyvisitor_, (char*)"(y#O)", kbuf, ksiz, Py_None);
375 } else {
376 pyrv = PyObject_CallMethod(pyvisitor_, (char*)"visit_empty",
377 (char*)"(y#)", kbuf, ksiz);
378 }
379 if (!pyrv) {
380 if (PyErr_Occurred()) PyErr_Fetch(&pyextype_, &pyexvalue_, &pyextrace_);
381 return NOP;
382 }
383 if (pyrv == Py_None || pyrv == obj_vis_nop) {
384 Py_DECREF(pyrv);
385 return NOP;
386 }
387 if (!writable_) {
388 Py_DECREF(pyrv);
389 throwruntime("confliction with the read-only parameter");
390 if (PyErr_Occurred()) PyErr_Fetch(&pyextype_, &pyexvalue_, &pyextrace_);
391 return NOP;
392 }
393 if (pyrv == obj_vis_remove) {
394 Py_DECREF(pyrv);
395 return REMOVE;
396 }
397 pyrv_ = pyrv;
398 rv_ = new SoftString(pyrv);
399 *sp = rv_->size();
400 return rv_->ptr();
401 }
cleanup()402 void cleanup() {
403 if (pyextrace_) {
404 Py_DECREF(pyextrace_);
405 pyextrace_ = NULL;
406 }
407 if (pyexvalue_) {
408 Py_DECREF(pyexvalue_);
409 pyexvalue_ = NULL;
410 }
411 if (pyextype_) {
412 Py_DECREF(pyextype_);
413 pyextype_ = NULL;
414 }
415 delete rv_;
416 rv_ = NULL;
417 if (pyrv_) {
418 Py_DECREF(pyrv_);
419 pyrv_ = NULL;
420 }
421 }
422 PyObject* pyvisitor_;
423 bool writable_;
424 PyObject* pyrv_;
425 SoftString* rv_;
426 PyObject* pyextype_;
427 PyObject* pyexvalue_;
428 PyObject* pyextrace_;
429 };
430
431
432 /**
433 * Wrapper of a file processor.
434 */
435 class SoftFileProcessor : public kc::PolyDB::FileProcessor {
436 public:
SoftFileProcessor(PyObject * pyproc)437 explicit SoftFileProcessor(PyObject* pyproc) :
438 pyproc_(pyproc), pyextype_(NULL), pyexvalue_(NULL), pyextrace_(NULL) {
439 Py_INCREF(pyproc_);
440 }
~SoftFileProcessor()441 ~SoftFileProcessor() {
442 if (pyextrace_) Py_DECREF(pyextrace_);
443 if (pyexvalue_) Py_DECREF(pyexvalue_);
444 if (pyextype_) Py_DECREF(pyextype_);
445 Py_DECREF(pyproc_);
446 }
exception(PyObject ** typep,PyObject ** valuep,PyObject ** tracep)447 bool exception(PyObject** typep, PyObject** valuep, PyObject** tracep) {
448 if (!pyextype_) return false;
449 *typep = pyextype_;
450 *valuep = pyexvalue_;
451 *tracep = pyextrace_;
452 return true;
453 }
454 private:
process(const std::string & path,int64_t count,int64_t size)455 bool process(const std::string& path, int64_t count, int64_t size) {
456 PyObject* pyrv;
457 if (PyCallable_Check(pyproc_)) {
458 pyrv = PyObject_CallFunction(pyproc_, (char*)"(sLL)",
459 path.c_str(), (long long)count, (long long)size);
460 } else {
461 pyrv = PyObject_CallMethod(pyproc_, (char*)"process", (char*)"(sLL)",
462 path.c_str(), (long long)count, (long long)size);
463 }
464 if (!pyrv) {
465 if (PyErr_Occurred()) PyErr_Fetch(&pyextype_, &pyexvalue_, &pyextrace_);
466 return false;
467 }
468 bool rv = PyObject_IsTrue(pyrv);
469 Py_DECREF(pyrv);
470 return rv;
471 }
472 PyObject* pyproc_;
473 PyObject* pyextype_;
474 PyObject* pyexvalue_;
475 PyObject* pyextrace_;
476 };
477
478
479 /**
480 * Internal data of an error object.
481 */
482 struct Error_data {
483 PyException_HEAD
484 PyObject* pycode;
485 PyObject* pymessage;
486 };
487
488
489 /**
490 * Internal data of a visitor object.
491 */
492 struct Visitor_data {
493 PyObject_HEAD
494 };
495
496
497 /**
498 * Internal data of a file processor object.
499 */
500 struct FileProcessor_data {
501 PyObject_HEAD
502 };
503
504
505 /**
506 * Internal data of a cursor object.
507 */
508 struct Cursor_data {
509 PyObject_HEAD
510 SoftCursor* cur;
511 PyObject* pydb;
512 };
513
514
515 /**
516 * Internal data of a database object.
517 */
518 struct DB_data {
519 PyObject_HEAD
520 kc::PolyDB* db;
521 uint32_t exbits;
522 PyObject* pylock;
523 };
524
525
526 /**
527 * Locking device of the database.
528 */
529 class NativeFunction {
530 public:
NativeFunction(DB_data * data)531 NativeFunction(DB_data* data) : data_(data), thstate_(NULL) {
532 PyObject* pylock = data_->pylock;
533 if (pylock == Py_None) {
534 thstate_ = PyEval_SaveThread();
535 } else {
536 PyObject* pyrv = PyObject_CallMethod(pylock, (char*)"acquire", NULL);
537 if (pyrv) Py_DECREF(pyrv);
538 }
539 }
cleanup()540 void cleanup() {
541 PyObject* pylock = data_->pylock;
542 if (pylock == Py_None) {
543 if (thstate_) PyEval_RestoreThread(thstate_);
544 } else {
545 PyObject* pyrv = PyObject_CallMethod(pylock, (char*)"release", NULL);
546 if (pyrv) Py_DECREF(pyrv);
547 }
548 }
549 private:
550 DB_data* data_;
551 PyThreadState* thstate_;
552 };
553
554
555 /**
556 * Entry point of the library.
557 */
PyInit_kyotocabinet(void)558 PyMODINIT_FUNC PyInit_kyotocabinet(void) {
559 if (!define_module()) return NULL;
560 if (!define_err()) return NULL;
561 if (!define_vis()) return NULL;
562 if (!define_fproc()) return NULL;
563 if (!define_cur()) return NULL;
564 if (!define_db()) return NULL;
565 return mod_kc;
566 }
567
568
569 /**
570 * Set a constant of unsigned integer.
571 */
setconstuint32(PyObject * pyobj,const char * name,uint32_t value)572 static bool setconstuint32(PyObject* pyobj, const char* name, uint32_t value) {
573 PyObject* pyname = PyUnicode_FromString(name);
574 PyObject* pyvalue = PyLong_FromUnsignedLong(value);
575 return PyObject_GenericSetAttr(pyobj, pyname, pyvalue) == 0;
576 }
577
578
579 /**
580 * Throw a runtime error.
581 */
throwruntime(const char * message)582 static void throwruntime(const char* message) {
583 PyErr_SetString(PyExc_RuntimeError, message);
584 }
585
586
587 /**
588 * throw the invalid argument error.
589 */
throwinvarg()590 static void throwinvarg() {
591 PyErr_SetString(PyExc_TypeError, "invalid arguments");
592 }
593
594
595 /**
596 * Create a new string.
597 */
newstring(const char * str)598 static PyObject* newstring(const char* str) {
599 return PyUnicode_DecodeUTF8(str, std::strlen(str), "ignore");
600 }
601
602
603 /**
604 * Create a new byte array.
605 */
newbytes(const char * ptr,size_t size)606 static PyObject* newbytes(const char* ptr, size_t size) {
607 return PyBytes_FromStringAndSize(ptr, size);
608 }
609
610
611 /**
612 * Convert a numeric parameter to an integer.
613 */
pyatoi(PyObject * pyobj)614 static int64_t pyatoi(PyObject* pyobj) {
615 if (PyLong_Check(pyobj)) {
616 return PyLong_AsLong(pyobj);
617 } else if (PyFloat_Check(pyobj)) {
618 double dnum = PyFloat_AsDouble(pyobj);
619 if (kc::chknan(dnum)) {
620 return kc::INT64MIN;
621 } else if (kc::chkinf(dnum)) {
622 return dnum < 0 ? kc::INT64MIN : kc::INT64MAX;
623 }
624 return dnum;
625 } else if (PyUnicode_Check(pyobj) || PyBytes_Check(pyobj)) {
626 SoftString numstr(pyobj);
627 const char* str = numstr.ptr();
628 double dnum = kc::atof(str);
629 if (kc::chknan(dnum)) {
630 return kc::INT64MIN;
631 } else if (kc::chkinf(dnum)) {
632 return dnum < 0 ? kc::INT64MIN : kc::INT64MAX;
633 }
634 return dnum;
635 } else if (pyobj != Py_None) {
636 int64_t inum = 0;
637 PyObject* pylong = PyNumber_Long(pyobj);
638 if (pylong) {
639 inum = PyLong_AsLong(pyobj);
640 Py_DECREF(pylong);
641 }
642 return inum;
643 }
644 return 0;
645 }
646
647
648 /**
649 * Convert a numeric parameter to a real number.
650 */
pyatof(PyObject * pyobj)651 static double pyatof(PyObject* pyobj) {
652 if (PyLong_Check(pyobj)) {
653 return PyLong_AsLong(pyobj);
654 } else if (PyFloat_Check(pyobj)) {
655 return PyFloat_AsDouble(pyobj);
656 } else if (PyUnicode_Check(pyobj) || PyBytes_Check(pyobj)) {
657 SoftString numstr(pyobj);
658 const char* str = numstr.ptr();
659 return kc::atof(str);
660 } else if (pyobj != Py_None) {
661 double dnum = 0;
662 PyObject* pyfloat = PyNumber_Float(pyobj);
663 if (pyfloat) {
664 dnum = PyFloat_AsDouble(pyfloat);
665 Py_DECREF(pyfloat);
666 }
667 return dnum;
668 }
669 return 0;
670 }
671
672
673 /**
674 * Convert an internal map to a Python map.
675 */
maptopymap(const StringMap * map)676 static PyObject* maptopymap(const StringMap* map) {
677 PyObject* pymap = PyDict_New();
678 StringMap::const_iterator it = map->begin();
679 StringMap::const_iterator itend = map->end();
680 while (it != itend) {
681 PyObject* pyvalue = newstring(it->second.c_str());
682 PyDict_SetItemString(pymap, it->first.c_str(), pyvalue);
683 Py_DECREF(pyvalue);
684 it++;
685 }
686 return pymap;
687 }
688
689
690 /**
691 * Convert an internal vector to a Python list.
692 */
vectortopylist(const StringVector * vec)693 static PyObject* vectortopylist(const StringVector* vec) {
694 size_t num = vec->size();
695 PyObject* pylist = PyList_New(num);
696 for (size_t i = 0; i < num; i++) {
697 PyObject* pystr = newstring((*vec)[i].c_str());
698 PyList_SET_ITEM(pylist, i, pystr);
699 }
700 return pylist;
701 }
702
703
704 /**
705 * Pass the current execution state.
706 */
threadyield()707 static void threadyield() {
708 PyObject* pyrv = PyObject_CallMethod(mod_time, (char*)"sleep", (char*)"(I)", 0);
709 if (pyrv) Py_DECREF(pyrv);
710 }
711
712
713 /**
714 * Define objects of the module.
715 */
define_module()716 static bool define_module() {
717 static PyModuleDef module_def = { PyModuleDef_HEAD_INIT };
718 size_t zoff = offsetof(PyModuleDef, m_name);
719 std::memset((char*)&module_def + zoff, 0, sizeof(module_def) - zoff);
720 module_def.m_name = "kyotocabinet";
721 module_def.m_doc = "a straightforward implementation of DBM";
722 module_def.m_size = -1;
723 static PyMethodDef method_table[] = {
724 { "conv_bytes", (PyCFunction)kc_conv_bytes, METH_VARARGS,
725 "Convert any object to a byte array." },
726 { "atoi", (PyCFunction)kc_atoi, METH_VARARGS,
727 "Convert a string to an integer." },
728 { "atoix", (PyCFunction)kc_atoix, METH_VARARGS,
729 "Convert a string with a metric prefix to an integer." },
730 { "atof", (PyCFunction)kc_atof, METH_VARARGS,
731 "Convert a string to a real number." },
732 { "hash_murmur", (PyCFunction)kc_hash_murmur, METH_VARARGS,
733 "Get the hash value of a string by MurMur hashing." },
734 { "hash_fnv", (PyCFunction)kc_hash_fnv, METH_VARARGS,
735 "Get the hash value of a string by FNV hashing." },
736 { "levdist", (PyCFunction)kc_levdist, METH_VARARGS,
737 "Calculate the levenshtein distance of two strings." },
738 { NULL, NULL, 0, NULL }
739 };
740 module_def.m_methods = method_table;
741 mod_kc = PyModule_Create(&module_def);
742 if (PyModule_AddStringConstant(mod_kc, "VERSION", kc::VERSION) != 0) return false;
743 mod_th = PyImport_ImportModule("threading");
744 mod_time = PyImport_ImportModule("time");
745 if (!mod_th) return false;
746 return true;
747 }
748
749
750 /**
751 * Implementation of conv_bytes.
752 */
kc_conv_bytes(PyObject * pyself,PyObject * pyargs)753 static PyObject* kc_conv_bytes(PyObject* pyself, PyObject* pyargs) {
754 int32_t argc = PyTuple_Size(pyargs);
755 if (argc != 1) {
756 throwinvarg();
757 return NULL;
758 }
759 PyObject* pyobj = PyTuple_GetItem(pyargs, 0);
760 SoftString str(pyobj);
761 return PyBytes_FromStringAndSize(str.ptr(), str.size());
762 }
763
764
765 /**
766 * Implementation of atoi.
767 */
kc_atoi(PyObject * pyself,PyObject * pyargs)768 static PyObject* kc_atoi(PyObject* pyself, PyObject* pyargs) {
769 int32_t argc = PyTuple_Size(pyargs);
770 if (argc != 1) {
771 throwinvarg();
772 return NULL;
773 }
774 PyObject* pystr = PyTuple_GetItem(pyargs, 0);
775 SoftString str(pystr);
776 return PyLong_FromLongLong(kc::atoi(str.ptr()));
777 }
778
779
780 /**
781 * Implementation of atoix.
782 */
kc_atoix(PyObject * pyself,PyObject * pyargs)783 static PyObject* kc_atoix(PyObject* pyself, PyObject* pyargs) {
784 int32_t argc = PyTuple_Size(pyargs);
785 if (argc != 1) {
786 throwinvarg();
787 return NULL;
788 }
789 PyObject* pystr = PyTuple_GetItem(pyargs, 0);
790 SoftString str(pystr);
791 return PyLong_FromLongLong(kc::atoix(str.ptr()));
792 }
793
794
795 /**
796 * Implementation of atof.
797 */
kc_atof(PyObject * pyself,PyObject * pyargs)798 static PyObject* kc_atof(PyObject* pyself, PyObject* pyargs) {
799 int32_t argc = PyTuple_Size(pyargs);
800 if (argc != 1) {
801 throwinvarg();
802 return NULL;
803 }
804 PyObject* pystr = PyTuple_GetItem(pyargs, 0);
805 SoftString str(pystr);
806 return PyFloat_FromDouble(kc::atof(str.ptr()));
807 }
808
809
810 /**
811 * Implementation of hash_murmur.
812 */
kc_hash_murmur(PyObject * pyself,PyObject * pyargs)813 static PyObject* kc_hash_murmur(PyObject* pyself, PyObject* pyargs) {
814 int32_t argc = PyTuple_Size(pyargs);
815 if (argc != 1) {
816 throwinvarg();
817 return NULL;
818 }
819 PyObject* pystr = PyTuple_GetItem(pyargs, 0);
820 SoftString str(pystr);
821 return PyLong_FromUnsignedLongLong(kc::hashmurmur(str.ptr(), str.size()));
822 }
823
824
825 /**
826 * Implementation of hash_fnv.
827 */
kc_hash_fnv(PyObject * pyself,PyObject * pyargs)828 static PyObject* kc_hash_fnv(PyObject* pyself, PyObject* pyargs) {
829 int32_t argc = PyTuple_Size(pyargs);
830 if (argc != 1) {
831 throwinvarg();
832 return NULL;
833 }
834 PyObject* pystr = PyTuple_GetItem(pyargs, 0);
835 SoftString str(pystr);
836 return PyLong_FromUnsignedLongLong(kc::hashfnv(str.ptr(), str.size()));
837 }
838
839
840 /**
841 * Implementation of levdist.
842 */
kc_levdist(PyObject * pyself,PyObject * pyargs)843 static PyObject* kc_levdist(PyObject* pyself, PyObject* pyargs) {
844 int32_t argc = PyTuple_Size(pyargs);
845 if (argc < 2) {
846 throwinvarg();
847 return NULL;
848 }
849 PyObject* pya = PyTuple_GetItem(pyargs, 0);
850 PyObject* pyb = PyTuple_GetItem(pyargs, 1);
851 PyObject* pyutf = Py_None;
852 if (argc > 2) pyutf = PyTuple_GetItem(pyargs, 2);
853 SoftString astr(pya);
854 const char* abuf = astr.ptr();
855 size_t asiz = astr.size();
856 SoftString bstr(pyb);
857 const char* bbuf = bstr.ptr();
858 size_t bsiz = bstr.size();
859 bool utf = PyObject_IsTrue(pyutf);
860 size_t dist;
861 if (utf) {
862 uint32_t astack[128];
863 uint32_t* aary = asiz > sizeof(astack) / sizeof(*astack) ? new uint32_t[asiz] : astack;
864 size_t anum;
865 kc::strutftoucs(abuf, asiz, aary, &anum);
866 uint32_t bstack[128];
867 uint32_t* bary = bsiz > sizeof(bstack) / sizeof(*bstack) ? new uint32_t[bsiz] : bstack;
868 size_t bnum;
869 kc::strutftoucs(bbuf, bsiz, bary, &bnum);
870 dist = kc::strucsdist(aary, anum, bary, bnum);
871 if (bary != bstack) delete[] bary;
872 if (aary != astack) delete[] aary;
873 } else {
874 dist = kc::memdist(abuf, asiz, bbuf, bsiz);
875 }
876 return PyLong_FromUnsignedLongLong(dist);
877 }
878
879
880 /**
881 * Define objects of the Error class.
882 */
define_err()883 static bool define_err() {
884 static PyTypeObject type_err = { PyVarObject_HEAD_INIT(NULL, 0) };
885 size_t zoff = offsetof(PyTypeObject, tp_name);
886 std::memset((char*)&type_err + zoff, 0, sizeof(type_err) - zoff);
887 type_err.tp_name = "kyotocabinet.Error";
888 type_err.tp_basicsize = sizeof(Error_data);
889 type_err.tp_itemsize = 0;
890 type_err.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
891 type_err.tp_doc = "Error data.";
892 type_err.tp_new = err_new;
893 type_err.tp_dealloc = (destructor)err_dealloc;
894 type_err.tp_init = (initproc)err_init;
895 type_err.tp_repr = (unaryfunc)err_repr;
896 type_err.tp_str = (unaryfunc)err_str;
897 type_err.tp_richcompare = (richcmpfunc)err_richcmp;
898 static PyMethodDef err_methods[] = {
899 { "set", (PyCFunction)err_set, METH_VARARGS,
900 "Set the error information." },
901 { "code", (PyCFunction)err_code, METH_NOARGS,
902 "Get the error code." },
903 { "name", (PyCFunction)err_name, METH_NOARGS,
904 "Get the readable string of the code." },
905 { "message", (PyCFunction)err_message, METH_NOARGS,
906 "Get the supplement message." },
907 { NULL, NULL, 0, NULL }
908 };
909 type_err.tp_methods = err_methods;
910 type_err.tp_base = (PyTypeObject*)PyExc_RuntimeError;
911 if (PyType_Ready(&type_err) != 0) return false;
912 cls_err = (PyObject*)&type_err;
913 for (size_t i = 0; i < sizeof(cls_err_children) / sizeof(*cls_err_children); i++) {
914 cls_err_children[i] = NULL;
915 }
916 if (!err_define_child("SUCCESS", kc::PolyDB::Error::SUCCESS)) return false;
917 if (!err_define_child("NOIMPL", kc::PolyDB::Error::NOIMPL)) return false;
918 if (!err_define_child("INVALID", kc::PolyDB::Error::INVALID)) return false;
919 if (!err_define_child("NOREPOS", kc::PolyDB::Error::NOREPOS)) return false;
920 if (!err_define_child("NOPERM", kc::PolyDB::Error::NOPERM)) return false;
921 if (!err_define_child("BROKEN", kc::PolyDB::Error::BROKEN)) return false;
922 if (!err_define_child("DUPREC", kc::PolyDB::Error::DUPREC)) return false;
923 if (!err_define_child("NOREC", kc::PolyDB::Error::NOREC)) return false;
924 if (!err_define_child("LOGIC", kc::PolyDB::Error::LOGIC)) return false;
925 if (!err_define_child("SYSTEM", kc::PolyDB::Error::SYSTEM)) return false;
926 if (!err_define_child("MISC", kc::PolyDB::Error::MISC)) return false;
927 Py_INCREF(cls_err);
928 if (PyModule_AddObject(mod_kc, "Error", cls_err) != 0) return false;
929 return true;
930 }
931
932
933 /**
934 * Define the constant and the subclass of an error code.
935 */
err_define_child(const char * name,uint32_t code)936 static bool err_define_child(const char* name, uint32_t code) {
937 if (!setconstuint32(cls_err, name, code)) return false;
938 char xname[kc::NUMBUFSIZ];
939 std::sprintf(xname, "X%s", name);
940 char fname[kc::NUMBUFSIZ*2];
941 std::sprintf(fname, "kyotocabinet.Error.%s", xname);
942 PyObject* pyxname = PyUnicode_FromString(xname);
943 PyObject* pyvalue = PyErr_NewException(fname, cls_err, NULL);
944 cls_err_children[code] = pyvalue;
945 return PyObject_GenericSetAttr(cls_err, pyxname, pyvalue) == 0;
946 }
947
948
949 /**
950 * Implementation of new.
951 */
err_new(PyTypeObject * pytype,PyObject * pyargs,PyObject * pykwds)952 static PyObject* err_new(PyTypeObject* pytype, PyObject* pyargs, PyObject* pykwds) {
953 Error_data* data = (Error_data*)pytype->tp_alloc(pytype, 0);
954 if (!data) return NULL;
955 data->pycode = PyLong_FromUnsignedLong(kc::PolyDB::Error::SUCCESS);
956 data->pymessage = PyUnicode_FromString("error");
957 return (PyObject*)data;
958 }
959
960
961 /**
962 * Implementation of dealloc.
963 */
err_dealloc(Error_data * data)964 static void err_dealloc(Error_data* data) {
965 Py_DECREF(data->pymessage);
966 Py_DECREF(data->pycode);
967 Py_CLEAR(data->dict);
968 Py_CLEAR(data->args);
969 Py_CLEAR(data->traceback);
970 Py_CLEAR(data->cause);
971 Py_CLEAR(data->context);
972 Py_TYPE(data)->tp_free((PyObject*)data);
973 }
974
975
976 /**
977 * Implementation of init.
978 */
err_init(Error_data * data,PyObject * pyargs,PyObject * pykwds)979 static int err_init(Error_data* data, PyObject* pyargs, PyObject* pykwds) {
980 int32_t argc = PyTuple_Size(pyargs);
981 if (argc > 2) {
982 throwinvarg();
983 return -1;
984 }
985 if (argc > 1) {
986 PyObject* pycode = PyTuple_GetItem(pyargs, 0);
987 PyObject* pymessage = PyTuple_GetItem(pyargs, 1);
988 if (PyLong_Check(pycode) && PyUnicode_Check(pymessage)) {
989 Py_DECREF(data->pycode);
990 Py_DECREF(data->pymessage);
991 Py_INCREF(pycode);
992 data->pycode = pycode;
993 Py_INCREF(pymessage);
994 data->pymessage = pymessage;
995 }
996 } else if (argc > 0) {
997 PyObject* pyexpr = PyTuple_GetItem(pyargs, 0);
998 if (PyUnicode_Check(pyexpr)) {
999 pyexpr = PyUnicode_AsUTF8String(pyexpr);
1000 const char* expr = PyBytes_AS_STRING(pyexpr);
1001 uint32_t code = kc::atoi(expr);
1002 const char* rp = std::strchr(expr, ':');
1003 if (rp) expr = rp + 1;
1004 while (*expr == ' ') {
1005 expr++;
1006 }
1007 Py_DECREF(data->pycode);
1008 Py_DECREF(data->pymessage);
1009 data->pycode = PyLong_FromLongLong(code);
1010 data->pymessage = PyUnicode_FromString(expr);
1011 Py_DECREF(pyexpr);
1012 }
1013 }
1014 return 0;
1015 }
1016
1017
1018 /**
1019 * Implementation of repr.
1020 */
err_repr(Error_data * data)1021 static PyObject* err_repr(Error_data* data) {
1022 uint32_t code = (uint32_t)PyLong_AsLong(data->pycode);
1023 const char* name = kc::PolyDB::Error::codename((kc::PolyDB::Error::Code)code);
1024 return PyUnicode_FromFormat("<kyotocabinet.Error: %s: %U>", name, data->pymessage);
1025 }
1026
1027
1028 /**
1029 * Implementation of str.
1030 */
err_str(Error_data * data)1031 static PyObject* err_str(Error_data* data) {
1032 uint32_t code = (uint32_t)PyLong_AsLong(data->pycode);
1033 const char* name = kc::PolyDB::Error::codename((kc::PolyDB::Error::Code)code);
1034 return PyUnicode_FromFormat("%s: %U", name, data->pymessage);
1035 }
1036
1037
1038 /**
1039 * Implementation of richcmp.
1040 */
err_richcmp(Error_data * data,PyObject * pyright,int op)1041 static PyObject* err_richcmp(Error_data* data, PyObject* pyright, int op) {
1042 bool rv;
1043 uint32_t code = (uint32_t)PyLong_AsLong(data->pycode);
1044 uint32_t rcode;
1045 if (PyObject_IsInstance(pyright, cls_err)) {
1046 Error_data* rdata = (Error_data*)pyright;
1047 rcode = (uint32_t)PyLong_AsLong(rdata->pycode);
1048 } else if (PyLong_Check(pyright)) {
1049 rcode = (uint32_t)PyLong_AsLong(pyright);
1050 } else {
1051 rcode = kc::INT32MAX;
1052 }
1053 switch (op) {
1054 case Py_LT: rv = code < rcode; break;
1055 case Py_LE: rv = code <= rcode; break;
1056 case Py_EQ: rv = code == rcode; break;
1057 case Py_NE: rv = code != rcode; break;
1058 case Py_GT: rv = code > rcode; break;
1059 case Py_GE: rv = code >= rcode; break;
1060 default: rv = false; break;
1061 }
1062 if (rv) Py_RETURN_TRUE;
1063 Py_RETURN_FALSE;
1064 }
1065
1066
1067 /**
1068 * Implementation of set.
1069 */
err_set(Error_data * data,PyObject * pyargs)1070 static PyObject* err_set(Error_data* data, PyObject* pyargs) {
1071 int32_t argc = PyTuple_Size(pyargs);
1072 if (argc != 2) {
1073 throwinvarg();
1074 return NULL;
1075 }
1076 PyObject* pycode = PyTuple_GetItem(pyargs, 0);
1077 PyObject* pymessage = PyTuple_GetItem(pyargs, 1);
1078 if (!PyLong_Check(pycode) && !PyUnicode_Check(pymessage)) {
1079 throwinvarg();
1080 return NULL;
1081 }
1082 Py_DECREF(data->pycode);
1083 Py_DECREF(data->pymessage);
1084 Py_INCREF(pycode);
1085 data->pycode = pycode;
1086 Py_INCREF(pymessage);
1087 data->pymessage = pymessage;
1088 Py_RETURN_NONE;
1089 }
1090
1091
1092 /**
1093 * Implementation of code.
1094 */
err_code(Error_data * data)1095 static PyObject* err_code(Error_data* data) {
1096 Py_INCREF(data->pycode);
1097 return data->pycode;
1098 }
1099
1100
1101 /**
1102 * Implementation of name.
1103 */
err_name(Error_data * data)1104 static PyObject* err_name(Error_data* data) {
1105 uint32_t code = PyLong_AsLong(data->pycode);
1106 const char* name = kc::PolyDB::Error::codename((kc::PolyDB::Error::Code)code);
1107 return newstring(name);
1108 }
1109
1110
1111 /**
1112 * Implementation of message.
1113 */
err_message(Error_data * data)1114 static PyObject* err_message(Error_data* data) {
1115 Py_INCREF(data->pymessage);
1116 return data->pymessage;
1117 }
1118
1119
1120 /**
1121 * Define objects of the Visitor class.
1122 */
define_vis()1123 static bool define_vis() {
1124 static PyTypeObject type_vis = { PyVarObject_HEAD_INIT(NULL, 0) };
1125 size_t zoff = offsetof(PyTypeObject, tp_name);
1126 std::memset((char*)&type_vis + zoff, 0, sizeof(type_vis) - zoff);
1127 type_vis.tp_name = "kyotocabinet.Visitor";
1128 type_vis.tp_basicsize = sizeof(Visitor_data);
1129 type_vis.tp_itemsize = 0;
1130 type_vis.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
1131 type_vis.tp_doc = "Interface to access a record.";
1132 type_vis.tp_new = vis_new;
1133 type_vis.tp_dealloc = (destructor)vis_dealloc;
1134 type_vis.tp_init = (initproc)vis_init;
1135 static PyMethodDef vis_methods[] = {
1136 { "visit_full", (PyCFunction)vis_visit_full, METH_VARARGS,
1137 "Visit a record.", },
1138 { "visit_empty", (PyCFunction)vis_visit_empty, METH_VARARGS,
1139 "Visit a empty record space." },
1140 { NULL, NULL, 0, NULL }
1141 };
1142 type_vis.tp_methods = vis_methods;
1143 if (PyType_Ready(&type_vis) != 0) return false;
1144 cls_vis = (PyObject*)&type_vis;
1145 PyObject* pyname = PyUnicode_FromString("NOP");
1146 obj_vis_nop = PyUnicode_FromString("[NOP]");
1147 if (PyObject_GenericSetAttr(cls_vis, pyname, obj_vis_nop) != 0) return false;
1148 pyname = PyUnicode_FromString("REMOVE");
1149 obj_vis_remove = PyUnicode_FromString("[REMOVE]");
1150 if (PyObject_GenericSetAttr(cls_vis, pyname, obj_vis_remove) != 0) return false;
1151 Py_INCREF(cls_vis);
1152 if (PyModule_AddObject(mod_kc, "Visitor", cls_vis) != 0) return false;
1153 return true;
1154 }
1155
1156
1157 /**
1158 * Implementation of new.
1159 */
vis_new(PyTypeObject * pytype,PyObject * pyargs,PyObject * pykwds)1160 static PyObject* vis_new(PyTypeObject* pytype, PyObject* pyargs, PyObject* pykwds) {
1161 Visitor_data* data = (Visitor_data*)pytype->tp_alloc(pytype, 0);
1162 if (!data) return NULL;
1163 return (PyObject*)data;
1164 }
1165
1166
1167 /**
1168 * Implementation of dealloc.
1169 */
vis_dealloc(Visitor_data * data)1170 static void vis_dealloc(Visitor_data* data) {
1171 Py_TYPE(data)->tp_free((PyObject*)data);
1172 }
1173
1174
1175 /**
1176 * Implementation of init.
1177 */
vis_init(Visitor_data * data,PyObject * pyargs,PyObject * pykwds)1178 static int vis_init(Visitor_data* data, PyObject* pyargs, PyObject* pykwds) {
1179 int32_t argc = PyTuple_Size(pyargs);
1180 if (argc != 0) {
1181 throwinvarg();
1182 return -1;
1183 }
1184 return 0;
1185 }
1186
1187
1188 /**
1189 * Implementation of visit_full.
1190 */
vis_visit_full(Visitor_data * data,PyObject * pyargs)1191 static PyObject* vis_visit_full(Visitor_data* data, PyObject* pyargs) {
1192 int32_t argc = PyTuple_Size(pyargs);
1193 if (argc != 2) {
1194 throwinvarg();
1195 return NULL;
1196 }
1197 Py_INCREF(obj_vis_nop);
1198 return obj_vis_nop;
1199 }
1200
1201
1202 /**
1203 * Implementation of visit_empty.
1204 */
vis_visit_empty(Visitor_data * data,PyObject * pyargs)1205 static PyObject* vis_visit_empty(Visitor_data* data, PyObject* pyargs) {
1206 int32_t argc = PyTuple_Size(pyargs);
1207 if (argc != 1) {
1208 throwinvarg();
1209 return NULL;
1210 }
1211 Py_INCREF(obj_vis_nop);
1212 return obj_vis_nop;
1213 }
1214
1215
1216 /**
1217 * Define objects of the FileProcessor class.
1218 */
define_fproc()1219 static bool define_fproc() {
1220 static PyTypeObject type_fproc = { PyVarObject_HEAD_INIT(NULL, 0) };
1221 size_t zoff = offsetof(PyTypeObject, tp_name);
1222 std::memset((char*)&type_fproc + zoff, 0, sizeof(type_fproc) - zoff);
1223 type_fproc.tp_name = "kyotocabinet.FileProcessor";
1224 type_fproc.tp_basicsize = sizeof(FileProcessor_data);
1225 type_fproc.tp_itemsize = 0;
1226 type_fproc.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
1227 type_fproc.tp_doc = "Interface to process the database file.";
1228 type_fproc.tp_new = fproc_new;
1229 type_fproc.tp_dealloc = (destructor)fproc_dealloc;
1230 type_fproc.tp_init = (initproc)fproc_init;
1231 static PyMethodDef fproc_methods[] = {
1232 { "process", (PyCFunction)fproc_process, METH_VARARGS,
1233 "Process the database file.", },
1234 { NULL, NULL, 0, NULL }
1235 };
1236 type_fproc.tp_methods = fproc_methods;
1237 if (PyType_Ready(&type_fproc) != 0) return false;
1238 cls_fproc = (PyObject*)&type_fproc;
1239 Py_INCREF(cls_fproc);
1240 if (PyModule_AddObject(mod_kc, "FileProcessor", cls_fproc) != 0) return false;
1241 return true;
1242 }
1243
1244
1245 /**
1246 * Implementation of new.
1247 */
fproc_new(PyTypeObject * pytype,PyObject * pyargs,PyObject * pykwds)1248 static PyObject* fproc_new(PyTypeObject* pytype, PyObject* pyargs, PyObject* pykwds) {
1249 FileProcessor_data* data = (FileProcessor_data*)pytype->tp_alloc(pytype, 0);
1250 if (!data) return NULL;
1251 return (PyObject*)data;
1252 }
1253
1254
1255 /**
1256 * Implementation of dealloc.
1257 */
fproc_dealloc(FileProcessor_data * data)1258 static void fproc_dealloc(FileProcessor_data* data) {
1259 Py_TYPE(data)->tp_free((PyObject*)data);
1260 }
1261
1262
1263 /**
1264 * Implementation of init.
1265 */
fproc_init(FileProcessor_data * data,PyObject * pyargs,PyObject * pykwds)1266 static int fproc_init(FileProcessor_data* data, PyObject* pyargs, PyObject* pykwds) {
1267 int32_t argc = PyTuple_Size(pyargs);
1268 if (argc != 0) {
1269 throwinvarg();
1270 return -1;
1271 }
1272 return 0;
1273 }
1274
1275
1276 /**
1277 * Implementation of process.
1278 */
fproc_process(FileProcessor_data * data,PyObject * pyargs)1279 static PyObject* fproc_process(FileProcessor_data* data, PyObject* pyargs) {
1280 int32_t argc = PyTuple_Size(pyargs);
1281 if (argc != 3) {
1282 throwinvarg();
1283 return NULL;
1284 }
1285 Py_RETURN_TRUE;
1286 }
1287
1288
1289 /**
1290 * Define objects of the Cursor class.
1291 */
define_cur()1292 static bool define_cur() {
1293 static PyTypeObject type_cur = { PyVarObject_HEAD_INIT(NULL, 0) };
1294 size_t zoff = offsetof(PyTypeObject, tp_name);
1295 std::memset((char*)&type_cur + zoff, 0, sizeof(type_cur) - zoff);
1296 type_cur.tp_name = "kyotocabinet.Cursor";
1297 type_cur.tp_basicsize = sizeof(Cursor_data);
1298 type_cur.tp_itemsize = 0;
1299 type_cur.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
1300 type_cur.tp_doc = "Interface of cursor to indicate a record.";
1301 type_cur.tp_new = cur_new;
1302 type_cur.tp_dealloc = (destructor)cur_dealloc;
1303 type_cur.tp_init = (initproc)cur_init;
1304 type_cur.tp_repr = (unaryfunc)cur_repr;
1305 type_cur.tp_str = (unaryfunc)cur_str;
1306 static PyMethodDef cur_methods[] = {
1307 { "disable", (PyCFunction)cur_disable, METH_NOARGS,
1308 "Disable the cursor." },
1309 { "accept", (PyCFunction)cur_accept, METH_VARARGS,
1310 "Accept a visitor to the current record." },
1311 { "set_value", (PyCFunction)cur_set_value, METH_VARARGS,
1312 "Set the value of the current record." },
1313 { "remove", (PyCFunction)cur_remove, METH_NOARGS,
1314 "Remove the current record." },
1315 { "get_key", (PyCFunction)cur_get_key, METH_VARARGS,
1316 "Get the key of the current record." },
1317 { "get_key_str", (PyCFunction)cur_get_key_str, METH_VARARGS,
1318 "Get the key of the current record." },
1319 { "get_value", (PyCFunction)cur_get_value, METH_VARARGS,
1320 "Get the value of the current record." },
1321 { "get_value_str", (PyCFunction)cur_get_value_str, METH_VARARGS,
1322 "Get the value of the current record." },
1323 { "get", (PyCFunction)cur_get, METH_VARARGS,
1324 "Get a pair of the key and the value of the current record." },
1325 { "get_str", (PyCFunction)cur_get_str, METH_VARARGS,
1326 "Get a pair of the key and the value of the current record." },
1327 { "seize", (PyCFunction)cur_seize, METH_NOARGS,
1328 "Get a pair of the key and the value of the current record and remove it atomically." },
1329 { "seize_str", (PyCFunction)cur_seize_str, METH_NOARGS,
1330 "Get a pair of the key and the value of the current record and remove it atomically." },
1331 { "jump", (PyCFunction)cur_jump, METH_VARARGS,
1332 "Jump the cursor to a record for forward scan." },
1333 { "jump_back", (PyCFunction)cur_jump_back, METH_VARARGS,
1334 "Jump the cursor to a record for backward scan." },
1335 { "step", (PyCFunction)cur_step, METH_NOARGS,
1336 "Step the cursor to the next record." },
1337 { "step_back", (PyCFunction)cur_step_back, METH_NOARGS,
1338 "Step the cursor to the previous record." },
1339 { "db", (PyCFunction)cur_db, METH_NOARGS,
1340 "Get the database object." },
1341 { "error", (PyCFunction)cur_error, METH_NOARGS,
1342 "Get the last happened error." },
1343 { NULL, NULL, 0, NULL }
1344 };
1345 type_cur.tp_methods = cur_methods;
1346 type_cur.tp_iter = (getiterfunc)cur_op_iter;
1347 type_cur.tp_iternext = (iternextfunc)cur_op_iternext;
1348 if (PyType_Ready(&type_cur) != 0) return false;
1349 cls_cur = (PyObject*)&type_cur;
1350 Py_INCREF(cls_cur);
1351 if (PyModule_AddObject(mod_kc, "Cursor", cls_cur) != 0) return false;
1352 return true;
1353 }
1354
1355
1356 /**
1357 * Implementation of new.
1358 */
cur_new(PyTypeObject * pytype,PyObject * pyargs,PyObject * pykwds)1359 static PyObject* cur_new(PyTypeObject* pytype, PyObject* pyargs, PyObject* pykwds) {
1360 Cursor_data* data = (Cursor_data*)pytype->tp_alloc(pytype, 0);
1361 if (!data) return NULL;
1362 Py_INCREF(Py_None);
1363 data->cur = NULL;
1364 data->pydb = Py_None;
1365 return (PyObject*)data;
1366 }
1367
1368
1369 /**
1370 * Implementation of dealloc.
1371 */
cur_dealloc(Cursor_data * data)1372 static void cur_dealloc(Cursor_data* data) {
1373 SoftCursor* cur = data->cur;
1374 PyObject* pydb = data->pydb;
1375 Py_DECREF(pydb);
1376 delete cur;
1377 Py_TYPE(data)->tp_free((PyObject*)data);
1378 }
1379
1380
1381 /**
1382 * Implementation of init.
1383 */
cur_init(Cursor_data * data,PyObject * pyargs,PyObject * pykwds)1384 static int cur_init(Cursor_data* data, PyObject* pyargs, PyObject* pykwds) {
1385 int32_t argc = PyTuple_Size(pyargs);
1386 if (argc != 1) {
1387 throwinvarg();
1388 return -1;
1389 }
1390 PyObject* pydb = PyTuple_GetItem(pyargs, 0);
1391 if (!PyObject_IsInstance(pydb, cls_db)) {
1392 throwinvarg();
1393 return -1;
1394 }
1395 DB_data* dbdata = (DB_data*)pydb;
1396 kc::PolyDB* db = dbdata->db;
1397 NativeFunction nf((DB_data*)pydb);
1398 g_curbur.sweap();
1399 data->cur = new SoftCursor(db);
1400 nf.cleanup();
1401 Py_INCREF(pydb);
1402 data->pydb = pydb;
1403 return 0;
1404 }
1405
1406
1407 /**
1408 * Implementation of repr.
1409 */
cur_repr(Cursor_data * data)1410 static PyObject* cur_repr(Cursor_data* data) {
1411 SoftCursor* cur = data->cur;
1412 PyObject* pydb = data->pydb;
1413 kc::PolyDB::Cursor* icur = cur->cur();
1414 if (!icur) return newstring("<kyotocabinet.Cursor: (disabled)>");
1415 NativeFunction nf((DB_data*)pydb);
1416 kc::PolyDB* db = icur->db();
1417 std::string path = db->path();
1418 if (path.size() < 1) path = "(None)";
1419 std::string str;
1420 kc::strprintf(&str, "<kyotocabinet.Cursor: %s: ", path.c_str());
1421 size_t ksiz;
1422 char* kbuf = icur->get_key(&ksiz);
1423 if (kbuf) {
1424 str.append(kbuf, ksiz);
1425 delete[] kbuf;
1426 } else {
1427 str.append("(None)");
1428 }
1429 str.append(">");
1430 nf.cleanup();
1431 return PyUnicode_FromString(str.c_str());
1432 }
1433
1434
1435 /**
1436 * Implementation of str.
1437 */
cur_str(Cursor_data * data)1438 static PyObject* cur_str(Cursor_data* data) {
1439 SoftCursor* cur = data->cur;
1440 PyObject* pydb = data->pydb;
1441 kc::PolyDB::Cursor* icur = cur->cur();
1442 if (!icur) return newstring("(disabled)");
1443 NativeFunction nf((DB_data*)pydb);
1444 kc::PolyDB* db = icur->db();
1445 std::string path = db->path();
1446 if (path.size() < 1) path = "(None)";
1447 std::string str;
1448 kc::strprintf(&str, "%s: ", path.c_str());
1449 size_t ksiz;
1450 char* kbuf = icur->get_key(&ksiz);
1451 if (kbuf) {
1452 str.append(kbuf, ksiz);
1453 delete[] kbuf;
1454 } else {
1455 str.append("(None)");
1456 }
1457 nf.cleanup();
1458 return PyUnicode_FromString(str.c_str());
1459 }
1460
1461
1462 /**
1463 * Implementation of disable.
1464 */
cur_disable(Cursor_data * data)1465 static PyObject* cur_disable(Cursor_data* data) {
1466 SoftCursor* cur = data->cur;
1467 PyObject* pydb = data->pydb;
1468 kc::PolyDB::Cursor* icur = cur->cur();
1469 if (!icur) Py_RETURN_NONE;
1470 NativeFunction nf((DB_data*)pydb);
1471 cur->disable();
1472 nf.cleanup();
1473 Py_RETURN_NONE;
1474 }
1475
1476
1477 /**
1478 * Implementation of accept.
1479 */
cur_accept(Cursor_data * data,PyObject * pyargs)1480 static PyObject* cur_accept(Cursor_data* data, PyObject* pyargs) {
1481 int32_t argc = PyTuple_Size(pyargs);
1482 if (argc < 1) {
1483 throwinvarg();
1484 return NULL;
1485 }
1486 SoftCursor* cur = data->cur;
1487 PyObject* pydb = data->pydb;
1488 kc::PolyDB::Cursor* icur = cur->cur();
1489 if (!icur) Py_RETURN_FALSE;
1490 if (((DB_data*)pydb)->pylock == Py_None) {
1491 icur->db()->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
1492 if (db_raise((DB_data*)pydb)) return NULL;
1493 Py_RETURN_NONE;
1494 }
1495 PyObject* pyvisitor = PyTuple_GetItem(pyargs, 0);
1496 PyObject* pywritable = Py_None;
1497 if (argc > 1) pywritable = PyTuple_GetItem(pyargs, 1);
1498 PyObject* pystep = Py_None;
1499 if (argc > 2) pystep = PyTuple_GetItem(pyargs, 2);
1500 bool writable = pywritable == Py_None || PyObject_IsTrue(pywritable);
1501 bool step = PyObject_IsTrue(pystep);
1502 bool rv;
1503 if (PyObject_IsInstance(pyvisitor, cls_vis) || PyCallable_Check(pyvisitor)) {
1504 SoftVisitor visitor(pyvisitor, writable);
1505 NativeFunction nf((DB_data*)pydb);
1506 rv = icur->accept(&visitor, writable, step);
1507 nf.cleanup();
1508 PyObject* pyextype, *pyexvalue, *pyextrace;
1509 if (visitor.exception(&pyextype, &pyexvalue, &pyextrace)) {
1510 PyErr_SetObject(pyextype, pyexvalue);
1511 return NULL;
1512 }
1513 } else {
1514 throwinvarg();
1515 return NULL;
1516 }
1517 if (rv) Py_RETURN_TRUE;
1518 if (db_raise((DB_data*)pydb)) return NULL;
1519 Py_RETURN_FALSE;
1520 }
1521
1522
1523 /**
1524 * Implementation of set_value.
1525 */
cur_set_value(Cursor_data * data,PyObject * pyargs)1526 static PyObject* cur_set_value(Cursor_data* data, PyObject* pyargs) {
1527 int32_t argc = PyTuple_Size(pyargs);
1528 if (argc < 1 || argc > 2) {
1529 throwinvarg();
1530 return NULL;
1531 }
1532 PyObject* pyvalue = PyTuple_GetItem(pyargs, 0);
1533 PyObject* pystep = Py_None;
1534 if (argc > 1) pystep = PyTuple_GetItem(pyargs, 1);
1535 SoftCursor* cur = data->cur;
1536 PyObject* pydb = data->pydb;
1537 kc::PolyDB::Cursor* icur = cur->cur();
1538 if (!icur) Py_RETURN_FALSE;
1539 SoftString value(pyvalue);
1540 bool step = PyObject_IsTrue(pystep);
1541 NativeFunction nf((DB_data*)pydb);
1542 bool rv = icur->set_value(value.ptr(), value.size(), step);
1543 nf.cleanup();
1544 if (rv) Py_RETURN_TRUE;
1545 if (db_raise((DB_data*)pydb)) return NULL;
1546 Py_RETURN_FALSE;
1547 }
1548
1549
1550 /**
1551 * Implementation of remove.
1552 */
cur_remove(Cursor_data * data)1553 static PyObject* cur_remove(Cursor_data* data) {
1554 SoftCursor* cur = data->cur;
1555 PyObject* pydb = data->pydb;
1556 kc::PolyDB::Cursor* icur = cur->cur();
1557 if (!icur) Py_RETURN_FALSE;
1558 NativeFunction nf((DB_data*)pydb);
1559 bool rv = icur->remove();
1560 nf.cleanup();
1561 if (rv) Py_RETURN_TRUE;
1562 if (db_raise((DB_data*)pydb)) return NULL;
1563 Py_RETURN_FALSE;
1564 }
1565
1566
1567 /**
1568 * Implementation of get_key.
1569 */
cur_get_key(Cursor_data * data,PyObject * pyargs)1570 static PyObject* cur_get_key(Cursor_data* data, PyObject* pyargs) {
1571 int32_t argc = PyTuple_Size(pyargs);
1572 if (argc > 1) {
1573 throwinvarg();
1574 return NULL;
1575 }
1576 PyObject* pystep = Py_None;
1577 if (argc > 0) pystep = PyTuple_GetItem(pyargs, 0);
1578 SoftCursor* cur = data->cur;
1579 PyObject* pydb = data->pydb;
1580 kc::PolyDB::Cursor* icur = cur->cur();
1581 if (!icur) Py_RETURN_NONE;
1582 bool step = PyObject_IsTrue(pystep);
1583 NativeFunction nf((DB_data*)pydb);
1584 size_t ksiz;
1585 char* kbuf = icur->get_key(&ksiz, step);
1586 nf.cleanup();
1587 PyObject* pyrv;
1588 if (kbuf) {
1589 pyrv = newbytes(kbuf, ksiz);
1590 delete[] kbuf;
1591 } else {
1592 if (db_raise((DB_data*)pydb)) return NULL;
1593 Py_INCREF(Py_None);
1594 pyrv = Py_None;
1595 }
1596 return pyrv;
1597 }
1598
1599
1600 /**
1601 * Implementation of get_key_str.
1602 */
cur_get_key_str(Cursor_data * data,PyObject * pyargs)1603 static PyObject* cur_get_key_str(Cursor_data* data, PyObject* pyargs) {
1604 int32_t argc = PyTuple_Size(pyargs);
1605 if (argc > 1) {
1606 throwinvarg();
1607 return NULL;
1608 }
1609 PyObject* pystep = Py_None;
1610 if (argc > 0) pystep = PyTuple_GetItem(pyargs, 0);
1611 SoftCursor* cur = data->cur;
1612 PyObject* pydb = data->pydb;
1613 kc::PolyDB::Cursor* icur = cur->cur();
1614 if (!icur) Py_RETURN_NONE;
1615 bool step = PyObject_IsTrue(pystep);
1616 NativeFunction nf((DB_data*)pydb);
1617 size_t ksiz;
1618 char* kbuf = icur->get_key(&ksiz, step);
1619 nf.cleanup();
1620 PyObject* pyrv;
1621 if (kbuf) {
1622 pyrv = newstring(kbuf);
1623 delete[] kbuf;
1624 } else {
1625 if (db_raise((DB_data*)pydb)) return NULL;
1626 Py_INCREF(Py_None);
1627 pyrv = Py_None;
1628 }
1629 return pyrv;
1630 }
1631
1632
1633 /**
1634 * Implementation of get_value.
1635 */
cur_get_value(Cursor_data * data,PyObject * pyargs)1636 static PyObject* cur_get_value(Cursor_data* data, PyObject* pyargs) {
1637 int32_t argc = PyTuple_Size(pyargs);
1638 if (argc > 1) {
1639 throwinvarg();
1640 return NULL;
1641 }
1642 PyObject* pystep = Py_None;
1643 if (argc > 0) pystep = PyTuple_GetItem(pyargs, 0);
1644 SoftCursor* cur = data->cur;
1645 PyObject* pydb = data->pydb;
1646 kc::PolyDB::Cursor* icur = cur->cur();
1647 if (!icur) Py_RETURN_NONE;
1648 bool step = PyObject_IsTrue(pystep);
1649 NativeFunction nf((DB_data*)pydb);
1650 size_t vsiz;
1651 char* vbuf = icur->get_value(&vsiz, step);
1652 nf.cleanup();
1653 PyObject* pyrv;
1654 if (vbuf) {
1655 pyrv = newbytes(vbuf, vsiz);
1656 delete[] vbuf;
1657 } else {
1658 if (db_raise((DB_data*)pydb)) return NULL;
1659 Py_INCREF(Py_None);
1660 pyrv = Py_None;
1661 }
1662 return pyrv;
1663 }
1664
1665
1666 /**
1667 * Implementation of get_value_str.
1668 */
cur_get_value_str(Cursor_data * data,PyObject * pyargs)1669 static PyObject* cur_get_value_str(Cursor_data* data, PyObject* pyargs) {
1670 int32_t argc = PyTuple_Size(pyargs);
1671 if (argc > 1) {
1672 throwinvarg();
1673 return NULL;
1674 }
1675 PyObject* pystep = Py_None;
1676 if (argc > 0) pystep = PyTuple_GetItem(pyargs, 0);
1677 SoftCursor* cur = data->cur;
1678 PyObject* pydb = data->pydb;
1679 kc::PolyDB::Cursor* icur = cur->cur();
1680 if (!icur) Py_RETURN_NONE;
1681 bool step = PyObject_IsTrue(pystep);
1682 NativeFunction nf((DB_data*)pydb);
1683 size_t vsiz;
1684 char* vbuf = icur->get_value(&vsiz, step);
1685 nf.cleanup();
1686 PyObject* pyrv;
1687 if (vbuf) {
1688 pyrv = newstring(vbuf);
1689 delete[] vbuf;
1690 } else {
1691 if (db_raise((DB_data*)pydb)) return NULL;
1692 Py_INCREF(Py_None);
1693 pyrv = Py_None;
1694 }
1695 return pyrv;
1696 }
1697
1698
1699 /**
1700 * Implementation of get.
1701 */
cur_get(Cursor_data * data,PyObject * pyargs)1702 static PyObject* cur_get(Cursor_data* data, PyObject* pyargs) {
1703 int32_t argc = PyTuple_Size(pyargs);
1704 if (argc > 1) {
1705 throwinvarg();
1706 return NULL;
1707 }
1708 PyObject* pystep = Py_None;
1709 if (argc > 0) pystep = PyTuple_GetItem(pyargs, 0);
1710 SoftCursor* cur = data->cur;
1711 PyObject* pydb = data->pydb;
1712 kc::PolyDB::Cursor* icur = cur->cur();
1713 if (!icur) Py_RETURN_NONE;
1714 bool step = PyObject_IsTrue(pystep);
1715 NativeFunction nf((DB_data*)pydb);
1716 const char* vbuf;
1717 size_t ksiz, vsiz;
1718 char* kbuf = icur->get(&ksiz, &vbuf, &vsiz, step);
1719 nf.cleanup();
1720 PyObject* pyrv;
1721 if (kbuf) {
1722 pyrv = PyTuple_New(2);
1723 PyObject* pykey = newbytes(kbuf, ksiz);
1724 PyObject* pyvalue = newbytes(vbuf, vsiz);
1725 PyTuple_SetItem(pyrv, 0, pykey);
1726 PyTuple_SetItem(pyrv, 1, pyvalue);
1727 delete[] kbuf;
1728 } else {
1729 if (db_raise((DB_data*)pydb)) return NULL;
1730 Py_INCREF(Py_None);
1731 pyrv = Py_None;
1732 }
1733 return pyrv;
1734 }
1735
1736
1737 /**
1738 * Implementation of get_str.
1739 */
cur_get_str(Cursor_data * data,PyObject * pyargs)1740 static PyObject* cur_get_str(Cursor_data* data, PyObject* pyargs) {
1741 int32_t argc = PyTuple_Size(pyargs);
1742 if (argc > 1) {
1743 throwinvarg();
1744 return NULL;
1745 }
1746 PyObject* pystep = Py_None;
1747 if (argc > 0) pystep = PyTuple_GetItem(pyargs, 0);
1748 SoftCursor* cur = data->cur;
1749 PyObject* pydb = data->pydb;
1750 kc::PolyDB::Cursor* icur = cur->cur();
1751 if (!icur) Py_RETURN_NONE;
1752 bool step = PyObject_IsTrue(pystep);
1753 NativeFunction nf((DB_data*)pydb);
1754 const char* vbuf;
1755 size_t ksiz, vsiz;
1756 char* kbuf = icur->get(&ksiz, &vbuf, &vsiz, step);
1757 nf.cleanup();
1758 PyObject* pyrv;
1759 if (kbuf) {
1760 pyrv = PyTuple_New(2);
1761 PyObject* pykey = newstring(kbuf);
1762 PyObject* pyvalue = newstring(vbuf);
1763 PyTuple_SetItem(pyrv, 0, pykey);
1764 PyTuple_SetItem(pyrv, 1, pyvalue);
1765 delete[] kbuf;
1766 } else {
1767 if (db_raise((DB_data*)pydb)) return NULL;
1768 Py_INCREF(Py_None);
1769 pyrv = Py_None;
1770 }
1771 return pyrv;
1772 }
1773
1774
1775 /**
1776 * Implementation of seize.
1777 */
cur_seize(Cursor_data * data)1778 static PyObject* cur_seize(Cursor_data* data) {
1779 SoftCursor* cur = data->cur;
1780 PyObject* pydb = data->pydb;
1781 kc::PolyDB::Cursor* icur = cur->cur();
1782 if (!icur) Py_RETURN_NONE;
1783 NativeFunction nf((DB_data*)pydb);
1784 const char* vbuf;
1785 size_t ksiz, vsiz;
1786 char* kbuf = icur->seize(&ksiz, &vbuf, &vsiz);
1787 nf.cleanup();
1788 PyObject* pyrv;
1789 if (kbuf) {
1790 pyrv = PyTuple_New(2);
1791 PyObject* pykey = newbytes(kbuf, ksiz);
1792 PyObject* pyvalue = newbytes(vbuf, vsiz);
1793 PyTuple_SetItem(pyrv, 0, pykey);
1794 PyTuple_SetItem(pyrv, 1, pyvalue);
1795 delete[] kbuf;
1796 } else {
1797 if (db_raise((DB_data*)pydb)) return NULL;
1798 Py_INCREF(Py_None);
1799 pyrv = Py_None;
1800 }
1801 return pyrv;
1802 }
1803
1804
1805 /**
1806 * Implementation of seize_str.
1807 */
cur_seize_str(Cursor_data * data)1808 static PyObject* cur_seize_str(Cursor_data* data) {
1809 SoftCursor* cur = data->cur;
1810 PyObject* pydb = data->pydb;
1811 kc::PolyDB::Cursor* icur = cur->cur();
1812 if (!icur) Py_RETURN_NONE;
1813 NativeFunction nf((DB_data*)pydb);
1814 const char* vbuf;
1815 size_t ksiz, vsiz;
1816 char* kbuf = icur->seize(&ksiz, &vbuf, &vsiz);
1817 nf.cleanup();
1818 PyObject* pyrv;
1819 if (kbuf) {
1820 pyrv = PyTuple_New(2);
1821 PyObject* pykey = newstring(kbuf);
1822 PyObject* pyvalue = newstring(vbuf);
1823 PyTuple_SetItem(pyrv, 0, pykey);
1824 PyTuple_SetItem(pyrv, 1, pyvalue);
1825 delete[] kbuf;
1826 } else {
1827 if (db_raise((DB_data*)pydb)) return NULL;
1828 Py_INCREF(Py_None);
1829 pyrv = Py_None;
1830 }
1831 return pyrv;
1832 }
1833
1834
1835 /**
1836 * Implementation of jump.
1837 */
cur_jump(Cursor_data * data,PyObject * pyargs)1838 static PyObject* cur_jump(Cursor_data* data, PyObject* pyargs) {
1839 int32_t argc = PyTuple_Size(pyargs);
1840 if (argc > 1) {
1841 throwinvarg();
1842 return NULL;
1843 }
1844 PyObject* pykey = Py_None;
1845 if (argc > 0) pykey = PyTuple_GetItem(pyargs, 0);
1846 SoftCursor* cur = data->cur;
1847 PyObject* pydb = data->pydb;
1848 kc::PolyDB::Cursor* icur = cur->cur();
1849 if (!icur) Py_RETURN_FALSE;
1850 bool rv;
1851 if (pykey == Py_None) {
1852 NativeFunction nf((DB_data*)pydb);
1853 rv = icur->jump();
1854 nf.cleanup();
1855 } else {
1856 SoftString key(pykey);
1857 NativeFunction nf((DB_data*)pydb);
1858 rv = icur->jump(key.ptr(), key.size());
1859 nf.cleanup();
1860 }
1861 if (rv) Py_RETURN_TRUE;
1862 if (db_raise((DB_data*)pydb)) return NULL;
1863 Py_RETURN_FALSE;
1864 }
1865
1866
1867 /**
1868 * Implementation of jump_back.
1869 */
cur_jump_back(Cursor_data * data,PyObject * pyargs)1870 static PyObject* cur_jump_back(Cursor_data* data, PyObject* pyargs) {
1871 int32_t argc = PyTuple_Size(pyargs);
1872 if (argc > 1) {
1873 throwinvarg();
1874 return NULL;
1875 }
1876 PyObject* pykey = Py_None;
1877 if (argc > 0) pykey = PyTuple_GetItem(pyargs, 0);
1878 SoftCursor* cur = data->cur;
1879 PyObject* pydb = data->pydb;
1880 kc::PolyDB::Cursor* icur = cur->cur();
1881 if (!icur) Py_RETURN_FALSE;
1882 bool rv;
1883 if (pykey == Py_None) {
1884 NativeFunction nf((DB_data*)pydb);
1885 rv = icur->jump_back();
1886 nf.cleanup();
1887 } else {
1888 SoftString key(pykey);
1889 NativeFunction nf((DB_data*)pydb);
1890 rv = icur->jump_back(key.ptr(), key.size());
1891 nf.cleanup();
1892 }
1893 if (rv) Py_RETURN_TRUE;
1894 if (db_raise((DB_data*)pydb)) return NULL;
1895 Py_RETURN_FALSE;
1896 }
1897
1898
1899 /**
1900 * Implementation of step.
1901 */
cur_step(Cursor_data * data)1902 static PyObject* cur_step(Cursor_data* data) {
1903 SoftCursor* cur = data->cur;
1904 PyObject* pydb = data->pydb;
1905 kc::PolyDB::Cursor* icur = cur->cur();
1906 if (!icur) Py_RETURN_FALSE;
1907 NativeFunction nf((DB_data*)pydb);
1908 bool rv = icur->step();
1909 nf.cleanup();
1910 if (rv) Py_RETURN_TRUE;
1911 if (db_raise((DB_data*)pydb)) return NULL;
1912 Py_RETURN_FALSE;
1913 }
1914
1915
1916 /**
1917 * Implementation of step_back.
1918 */
cur_step_back(Cursor_data * data)1919 static PyObject* cur_step_back(Cursor_data* data) {
1920 SoftCursor* cur = data->cur;
1921 PyObject* pydb = data->pydb;
1922 kc::PolyDB::Cursor* icur = cur->cur();
1923 if (!icur) Py_RETURN_FALSE;
1924 NativeFunction nf((DB_data*)pydb);
1925 bool rv = icur->step_back();
1926 nf.cleanup();
1927 if (rv) Py_RETURN_TRUE;
1928 if (db_raise((DB_data*)pydb)) return NULL;
1929 Py_RETURN_FALSE;
1930 }
1931
1932
1933 /**
1934 * Implementation of db.
1935 */
cur_db(Cursor_data * data)1936 static PyObject* cur_db(Cursor_data* data) {
1937 SoftCursor* cur = data->cur;
1938 PyObject* pydb = data->pydb;
1939 kc::PolyDB::Cursor* icur = cur->cur();
1940 if (!icur) Py_RETURN_FALSE;
1941 Py_INCREF(data->pydb);
1942 return pydb;
1943 }
1944
1945
1946 /**
1947 * Implementation of error.
1948 */
cur_error(Cursor_data * data)1949 static PyObject* cur_error(Cursor_data* data) {
1950 SoftCursor* cur = data->cur;
1951 kc::PolyDB::Cursor* icur = cur->cur();
1952 if (!icur) Py_RETURN_NONE;
1953 kc::PolyDB::Error err = icur->error();
1954 PyObject* pyerr = PyObject_CallMethod(mod_kc, (char*)"Error",
1955 (char*)"(IU)", err.code(), err.message());
1956 return pyerr;
1957 }
1958
1959
1960 /**
1961 * Implementation of __iter__.
1962 */
cur_op_iter(Cursor_data * data)1963 static PyObject* cur_op_iter(Cursor_data* data) {
1964 Py_INCREF((PyObject*)data);
1965 return (PyObject*)data;
1966 }
1967
1968
1969 /**
1970 * Implementation of __next__.
1971 */
cur_op_iternext(Cursor_data * data)1972 static PyObject* cur_op_iternext(Cursor_data* data) {
1973 SoftCursor* cur = data->cur;
1974 PyObject* pydb = data->pydb;
1975 kc::PolyDB::Cursor* icur = cur->cur();
1976 if (!icur) return NULL;
1977 NativeFunction nf((DB_data*)pydb);
1978 size_t ksiz;
1979 char* kbuf = icur->get_key(&ksiz, true);
1980 nf.cleanup();
1981 PyObject* pyrv;
1982 if (kbuf) {
1983 pyrv = newbytes(kbuf, ksiz);
1984 delete[] kbuf;
1985 } else {
1986 pyrv = NULL;
1987 }
1988 return pyrv;
1989 }
1990
1991
1992 /**
1993 * Define objects of the DB class.
1994 */
define_db()1995 static bool define_db() {
1996 static PyTypeObject type_db = { PyVarObject_HEAD_INIT(NULL, 0) };
1997 size_t zoff = offsetof(PyTypeObject, tp_name);
1998 std::memset((char*)&type_db + zoff, 0, sizeof(type_db) - zoff);
1999 type_db.tp_name = "kyotocabinet.DB";
2000 type_db.tp_basicsize = sizeof(DB_data);
2001 type_db.tp_itemsize = 0;
2002 type_db.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
2003 type_db.tp_doc = "Interface of database abstraction.";
2004 type_db.tp_new = db_new;
2005 type_db.tp_dealloc = (destructor)db_dealloc;
2006 type_db.tp_init = (initproc)db_init;
2007 type_db.tp_repr = (unaryfunc)db_repr;
2008 type_db.tp_str = (unaryfunc)db_str;
2009 static PyMethodDef db_methods[] = {
2010 { "error", (PyCFunction)db_error, METH_NOARGS,
2011 "Get the last happened error." },
2012 { "open", (PyCFunction)db_open, METH_VARARGS,
2013 "Open a database file." },
2014 { "close", (PyCFunction)db_close, METH_NOARGS,
2015 "Close the database file." },
2016 { "accept", (PyCFunction)db_accept, METH_VARARGS,
2017 "Accept a visitor to a record." },
2018 { "accept_bulk", (PyCFunction)db_accept_bulk, METH_VARARGS,
2019 "Accept a visitor to multiple records at once." },
2020 { "iterate", (PyCFunction)db_iterate, METH_VARARGS,
2021 "Iterate to accept a visitor for each record." },
2022 { "set", (PyCFunction)db_set, METH_VARARGS,
2023 "Set the value of a record." },
2024 { "add", (PyCFunction)db_add, METH_VARARGS,
2025 "Add a record." },
2026 { "replace", (PyCFunction)db_replace, METH_VARARGS,
2027 "Replace the value of a record." },
2028 { "append", (PyCFunction)db_append, METH_VARARGS,
2029 "Append the value of a record." },
2030 { "increment", (PyCFunction)db_increment, METH_VARARGS,
2031 "Add a number to the numeric integer value of a record." },
2032 { "increment_double", (PyCFunction)db_increment_double, METH_VARARGS,
2033 "Add a number to the numeric double value of a record." },
2034 { "cas", (PyCFunction)db_cas, METH_VARARGS,
2035 "Perform compare-and-swap." },
2036 { "remove", (PyCFunction)db_remove, METH_VARARGS,
2037 "Remove a record." },
2038 { "get", (PyCFunction)db_get, METH_VARARGS,
2039 "Retrieve the value of a record." },
2040 { "get_str", (PyCFunction)db_get_str, METH_VARARGS,
2041 "Retrieve the value of a record." },
2042 { "check", (PyCFunction)db_check, METH_VARARGS,
2043 "Check the existence of a record." },
2044 { "seize", (PyCFunction)db_seize, METH_VARARGS,
2045 "Retrieve the value of a record and remove it atomically." },
2046 { "get_seize", (PyCFunction)db_seize_str, METH_VARARGS,
2047 "Retrieve the value of a record and remove it atomically." },
2048 { "set_bulk", (PyCFunction)db_set_bulk, METH_VARARGS,
2049 "Store records at once." },
2050 { "remove_bulk", (PyCFunction)db_remove_bulk, METH_VARARGS,
2051 "Remove records at once." },
2052 { "get_bulk", (PyCFunction)db_get_bulk, METH_VARARGS,
2053 "Retrieve records at once." },
2054 { "get_bulk_str", (PyCFunction)db_get_bulk_str, METH_VARARGS,
2055 "Retrieve records at once." },
2056 { "clear", (PyCFunction)db_clear, METH_NOARGS,
2057 "Remove all records." },
2058 { "synchronize", (PyCFunction)db_synchronize, METH_VARARGS,
2059 "Synchronize updated contents with the file and the device." },
2060 { "occupy", (PyCFunction)db_occupy, METH_VARARGS,
2061 "Occupy database by locking and do something meanwhile." },
2062 { "copy", (PyCFunction)db_copy, METH_VARARGS,
2063 "Create a copy of the database file." },
2064 { "begin_transaction", (PyCFunction)db_begin_transaction, METH_VARARGS,
2065 "Begin transaction." },
2066 { "end_transaction", (PyCFunction)db_end_transaction, METH_VARARGS,
2067 "End transaction." },
2068 { "transaction", (PyCFunction)db_transaction, METH_VARARGS,
2069 "Perform entire transaction by a functor." },
2070 { "dump_snapshot", (PyCFunction)db_dump_snapshot, METH_VARARGS,
2071 "Dump records into a snapshot file." },
2072 { "load_snapshot", (PyCFunction)db_load_snapshot, METH_VARARGS,
2073 "Load records from a snapshot file." },
2074 { "count", (PyCFunction)db_count, METH_NOARGS,
2075 "Get the number of records." },
2076 { "size", (PyCFunction)db_size, METH_NOARGS,
2077 "Get the size of the database file." },
2078 { "path", (PyCFunction)db_path, METH_NOARGS,
2079 "Get the path of the database file." },
2080 { "status", (PyCFunction)db_status, METH_NOARGS,
2081 "Get the miscellaneous status information." },
2082 { "match_prefix", (PyCFunction)db_match_prefix, METH_VARARGS,
2083 "Get keys matching a prefix string." },
2084 { "match_regex", (PyCFunction)db_match_regex, METH_VARARGS,
2085 "Get keys matching a regular expression string." },
2086 { "match_similar", (PyCFunction)db_match_similar, METH_VARARGS,
2087 "Get keys similar to a string in terms of the levenshtein distance." },
2088 { "merge", (PyCFunction)db_merge, METH_VARARGS,
2089 "Merge records from other databases." },
2090 { "cursor", (PyCFunction)db_cursor, METH_NOARGS,
2091 "Create a cursor object." },
2092 { "cursor_process", (PyCFunction)db_cursor_process, METH_VARARGS,
2093 "Process a cursor by the block parameter." },
2094 { "shift", (PyCFunction)db_shift, METH_NOARGS,
2095 "Remove the first record." },
2096 { "shift_str", (PyCFunction)db_shift_str, METH_NOARGS,
2097 "Remove the first record." },
2098 { "tune_exception_rule", (PyCFunction)db_tune_exception_rule, METH_VARARGS,
2099 "Set the rule about throwing exception." },
2100 { "process", (PyCFunction)db_process, METH_VARARGS | METH_CLASS,
2101 "Process a database by a functor" },
2102 { NULL, NULL, 0, NULL }
2103 };
2104 type_db.tp_methods = db_methods;
2105 static PyMappingMethods type_db_map;
2106 std::memset(&type_db_map, 0, sizeof(type_db_map));
2107 type_db_map.mp_length = (lenfunc)db_op_len;
2108 type_db_map.mp_subscript = (binaryfunc)db_op_getitem;
2109 type_db_map.mp_ass_subscript = (objobjargproc)db_op_setitem;
2110 type_db.tp_as_mapping = &type_db_map;
2111 type_db.tp_iter = (getiterfunc)db_op_iter;
2112 if (PyType_Ready(&type_db) != 0) return false;
2113 cls_db = (PyObject*)&type_db;
2114 if (!setconstuint32(cls_db, "GEXCEPTIONAL", GEXCEPTIONAL)) return false;
2115 if (!setconstuint32(cls_db, "GCONCURRENT", GCONCURRENT)) return false;
2116 if (!setconstuint32(cls_db, "OREADER", kc::PolyDB::OREADER)) return false;
2117 if (!setconstuint32(cls_db, "OWRITER", kc::PolyDB::OWRITER)) return false;
2118 if (!setconstuint32(cls_db, "OCREATE", kc::PolyDB::OCREATE)) return false;
2119 if (!setconstuint32(cls_db, "OTRUNCATE", kc::PolyDB::OTRUNCATE)) return false;
2120 if (!setconstuint32(cls_db, "OAUTOTRAN", kc::PolyDB::OAUTOTRAN)) return false;
2121 if (!setconstuint32(cls_db, "OAUTOSYNC", kc::PolyDB::OAUTOSYNC)) return false;
2122 if (!setconstuint32(cls_db, "ONOLOCK", kc::PolyDB::ONOLOCK)) return false;
2123 if (!setconstuint32(cls_db, "OTRYLOCK", kc::PolyDB::OTRYLOCK)) return false;
2124 if (!setconstuint32(cls_db, "ONOREPAIR", kc::PolyDB::ONOREPAIR)) return false;
2125 if (!setconstuint32(cls_db, "MSET", kc::PolyDB::MSET)) return false;
2126 if (!setconstuint32(cls_db, "MADD", kc::PolyDB::MADD)) return false;
2127 if (!setconstuint32(cls_db, "MREPLACE", kc::PolyDB::MREPLACE)) return false;
2128 if (!setconstuint32(cls_db, "MAPPEND", kc::PolyDB::MAPPEND)) return false;
2129 Py_INCREF(cls_db);
2130 if (PyModule_AddObject(mod_kc, "DB", cls_db) != 0) return false;
2131 return true;
2132 }
2133
2134
2135 /**
2136 * Implementation of new.
2137 */
db_new(PyTypeObject * pytype,PyObject * pyargs,PyObject * pykwds)2138 static PyObject* db_new(PyTypeObject* pytype, PyObject* pyargs, PyObject* pykwds) {
2139 DB_data* data = (DB_data*)pytype->tp_alloc(pytype, 0);
2140 if (!data) return NULL;
2141 data->db = NULL;
2142 data->exbits = 0;
2143 data->pylock = NULL;
2144 return (PyObject*)data;
2145 }
2146
2147
2148 /**
2149 * Implementation of dealloc.
2150 */
db_dealloc(DB_data * data)2151 static void db_dealloc(DB_data* data) {
2152 kc::PolyDB* db = data->db;
2153 PyObject* pylock = data->pylock;
2154 Py_DECREF(pylock);
2155 delete db;
2156 Py_TYPE(data)->tp_free((PyObject*)data);
2157 }
2158
2159
2160 /**
2161 * Raise the exception of an error code.
2162 */
db_raise(DB_data * data)2163 static bool db_raise(DB_data* data) {
2164 if (data->exbits == 0) return false;
2165 kc::PolyDB::Error err = data->db->error();
2166 uint32_t code = err.code();
2167 if (data->exbits & (1 << code)) {
2168 PyErr_Format(cls_err_children[code], "%u: %s", code, err.message());
2169 return true;
2170 }
2171 return false;
2172 }
2173
2174
2175 /**
2176 * Implementation of init.
2177 */
db_init(DB_data * data,PyObject * pyargs,PyObject * pykwds)2178 static int db_init(DB_data* data, PyObject* pyargs, PyObject* pykwds) {
2179 int32_t argc = PyTuple_Size(pyargs);
2180 PyObject* pyopts = Py_None;
2181 if (argc > 0) pyopts = PyTuple_GetItem(pyargs, 0);
2182 data->db = new kc::PolyDB();
2183 uint32_t opts = PyLong_Check(pyopts) ? (uint32_t)PyLong_AsLong(pyopts) : 0;
2184 if (opts & GEXCEPTIONAL) {
2185 uint32_t exbits = 0;
2186 exbits |= 1 << kc::PolyDB::Error::NOIMPL;
2187 exbits |= 1 << kc::PolyDB::Error::INVALID;
2188 exbits |= 1 << kc::PolyDB::Error::NOREPOS;
2189 exbits |= 1 << kc::PolyDB::Error::NOPERM;
2190 exbits |= 1 << kc::PolyDB::Error::BROKEN;
2191 exbits |= 1 << kc::PolyDB::Error::SYSTEM;
2192 exbits |= 1 << kc::PolyDB::Error::MISC;
2193 data->exbits = exbits;
2194 } else {
2195 data->exbits = 0;
2196 }
2197 if (opts & GCONCURRENT) {
2198 Py_INCREF(Py_None);
2199 data->pylock = Py_None;
2200 } else {
2201 data->pylock = PyObject_CallMethod(mod_th, (char*)"Lock", NULL);
2202 }
2203 return 0;
2204 }
2205
2206
2207 /**
2208 * Implementation of repr.
2209 */
db_repr(DB_data * data)2210 static PyObject* db_repr(DB_data* data) {
2211 kc::PolyDB* db = data->db;
2212 std::string path = db->path();
2213 if (path.size() < 1) path = "(None)";
2214 std::string str;
2215 NativeFunction nf(data);
2216 kc::strprintf(&str, "<kyotocabinet.DB: %s: %lld: %lld>",
2217 path.c_str(), (long long)db->count(), (long long)db->size());
2218 nf.cleanup();
2219 return PyUnicode_FromString(str.c_str());
2220 }
2221
2222
2223 /**
2224 * Implementation of str.
2225 */
db_str(DB_data * data)2226 static PyObject* db_str(DB_data* data) {
2227 kc::PolyDB* db = data->db;
2228 std::string path = db->path();
2229 if (path.size() < 1) path = "(None)";
2230 std::string str;
2231 NativeFunction nf(data);
2232 kc::strprintf(&str, "%s: %lld: %lld",
2233 path.c_str(), (long long)db->count(), (long long)db->size());
2234 nf.cleanup();
2235 return PyUnicode_FromString(str.c_str());
2236 }
2237
2238
2239 /**
2240 * Implementation of error.
2241 */
db_error(DB_data * data)2242 static PyObject* db_error(DB_data* data) {
2243 kc::PolyDB* db = data->db;
2244 kc::PolyDB::Error err = db->error();
2245 PyObject* pyerr = PyObject_CallMethod(mod_kc, (char*)"Error",
2246 (char*)"(IU)", err.code(), err.message());
2247 return pyerr;
2248 }
2249
2250
2251 /**
2252 * Implementation of open.
2253 */
db_open(DB_data * data,PyObject * pyargs)2254 static PyObject* db_open(DB_data* data, PyObject* pyargs) {
2255 int32_t argc = PyTuple_Size(pyargs);
2256 if (argc > 2) {
2257 throwinvarg();
2258 return NULL;
2259 }
2260 PyObject* pypath = Py_None;
2261 if (argc > 0) pypath = PyTuple_GetItem(pyargs, 0);
2262 PyObject* pymode = Py_None;
2263 if (argc > 1) pymode = PyTuple_GetItem(pyargs, 1);
2264 kc::PolyDB* db = data->db;
2265 SoftString path(pypath);
2266 const char* tpath = path.size() > 0 ? path.ptr() : ":";
2267 uint32_t mode = PyLong_Check(pymode) ? (uint32_t)PyLong_AsLong(pymode) :
2268 kc::PolyDB::OWRITER | kc::PolyDB::OCREATE;
2269 NativeFunction nf(data);
2270 bool rv = db->open(tpath, mode);
2271 nf.cleanup();
2272 if (rv) Py_RETURN_TRUE;
2273 if (db_raise(data)) return NULL;
2274 Py_RETURN_FALSE;
2275 }
2276
2277
2278 /**
2279 * Implementation of close.
2280 */
db_close(DB_data * data)2281 static PyObject* db_close(DB_data* data) {
2282 kc::PolyDB* db = data->db;
2283 NativeFunction nf(data);
2284 g_curbur.sweap();
2285 bool rv = db->close();
2286 nf.cleanup();
2287 if (rv) Py_RETURN_TRUE;
2288 if (db_raise(data)) return NULL;
2289 Py_RETURN_FALSE;
2290 }
2291
2292
2293 /**
2294 * Implementation of accept.
2295 */
db_accept(DB_data * data,PyObject * pyargs)2296 static PyObject* db_accept(DB_data* data, PyObject* pyargs) {
2297 int32_t argc = PyTuple_Size(pyargs);
2298 if (argc < 2 || argc > 3) {
2299 throwinvarg();
2300 return NULL;
2301 }
2302 kc::PolyDB* db = data->db;
2303 if (data->pylock == Py_None) {
2304 db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
2305 if (db_raise(data)) return NULL;
2306 Py_RETURN_NONE;
2307 }
2308 PyObject* pykey = PyTuple_GetItem(pyargs, 0);
2309 SoftString key(pykey);
2310 PyObject* pyvisitor = PyTuple_GetItem(pyargs, 1);
2311 PyObject* pywritable = Py_None;
2312 if (argc > 2) pywritable = PyTuple_GetItem(pyargs, 2);
2313 bool writable = pywritable == Py_None || PyObject_IsTrue(pywritable);
2314 bool rv;
2315 if (PyObject_IsInstance(pyvisitor, cls_vis) || PyCallable_Check(pyvisitor)) {
2316 SoftVisitor visitor(pyvisitor, writable);
2317 NativeFunction nf(data);
2318 rv = db->accept(key.ptr(), key.size(), &visitor, writable);
2319 nf.cleanup();
2320 PyObject* pyextype, *pyexvalue, *pyextrace;
2321 if (visitor.exception(&pyextype, &pyexvalue, &pyextrace)) {
2322 PyErr_SetObject(pyextype, pyexvalue);
2323 return NULL;
2324 }
2325 } else {
2326 throwinvarg();
2327 return NULL;
2328 }
2329 if (rv) Py_RETURN_TRUE;
2330 if (db_raise(data)) return NULL;
2331 Py_RETURN_FALSE;
2332 }
2333
2334
2335 /**
2336 * Implementation of accept_bulk.
2337 */
db_accept_bulk(DB_data * data,PyObject * pyargs)2338 static PyObject* db_accept_bulk(DB_data* data, PyObject* pyargs) {
2339 int32_t argc = PyTuple_Size(pyargs);
2340 if (argc < 2 || argc > 3) {
2341 throwinvarg();
2342 return NULL;
2343 }
2344 kc::PolyDB* db = data->db;
2345 if (data->pylock == Py_None) {
2346 db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
2347 if (db_raise(data)) return NULL;
2348 Py_RETURN_NONE;
2349 }
2350 PyObject* pykeys = PyTuple_GetItem(pyargs, 0);
2351 if (!PySequence_Check(pykeys)) {
2352 throwinvarg();
2353 return NULL;
2354 }
2355 StringVector keys;
2356 int32_t knum = PySequence_Length(pykeys);
2357 for (int32_t i = 0; i < knum; i++) {
2358 PyObject* pykey = PySequence_GetItem(pykeys, i);
2359 SoftString key(pykey);
2360 keys.push_back(std::string(key.ptr(), key.size()));
2361 Py_DECREF(pykey);
2362 }
2363 PyObject* pyvisitor = PyTuple_GetItem(pyargs, 1);
2364 PyObject* pywritable = Py_None;
2365 if (argc > 2) pywritable = PyTuple_GetItem(pyargs, 2);
2366 bool writable = pywritable == Py_None || PyObject_IsTrue(pywritable);
2367 bool rv;
2368 if (PyObject_IsInstance(pyvisitor, cls_vis) || PyCallable_Check(pyvisitor)) {
2369 SoftVisitor visitor(pyvisitor, writable);
2370 NativeFunction nf(data);
2371 rv = db->accept_bulk(keys, &visitor, writable);
2372 nf.cleanup();
2373 PyObject* pyextype, *pyexvalue, *pyextrace;
2374 if (visitor.exception(&pyextype, &pyexvalue, &pyextrace)) {
2375 PyErr_SetObject(pyextype, pyexvalue);
2376 return NULL;
2377 }
2378 } else {
2379 throwinvarg();
2380 return NULL;
2381 }
2382 if (rv) Py_RETURN_TRUE;
2383 if (db_raise(data)) return NULL;
2384 Py_RETURN_FALSE;
2385 }
2386
2387
2388 /**
2389 * Implementation of iterate.
2390 */
db_iterate(DB_data * data,PyObject * pyargs)2391 static PyObject* db_iterate(DB_data* data, PyObject* pyargs) {
2392 int32_t argc = PyTuple_Size(pyargs);
2393 if (argc < 1 || argc > 2) {
2394 throwinvarg();
2395 return NULL;
2396 }
2397 kc::PolyDB* db = data->db;
2398 if (data->pylock == Py_None) {
2399 db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
2400 if (db_raise(data)) return NULL;
2401 Py_RETURN_NONE;
2402 }
2403 PyObject* pyvisitor = PyTuple_GetItem(pyargs, 0);
2404 PyObject* pywritable = Py_None;
2405 if (argc > 1) pywritable = PyTuple_GetItem(pyargs, 1);
2406 bool writable = pywritable == Py_None || PyObject_IsTrue(pywritable);
2407 bool rv;
2408 if (PyObject_IsInstance(pyvisitor, cls_vis) || PyCallable_Check(pyvisitor)) {
2409 SoftVisitor visitor(pyvisitor, writable);
2410 NativeFunction nf(data);
2411 rv = db->iterate(&visitor, writable);
2412 nf.cleanup();
2413 PyObject* pyextype, *pyexvalue, *pyextrace;
2414 if (visitor.exception(&pyextype, &pyexvalue, &pyextrace)) {
2415 PyErr_SetObject(pyextype, pyexvalue);
2416 return NULL;
2417 }
2418 } else {
2419 throwinvarg();
2420 return NULL;
2421 }
2422 if (rv) Py_RETURN_TRUE;
2423 if (db_raise(data)) return NULL;
2424 Py_RETURN_FALSE;
2425 }
2426
2427
2428 /**
2429 * Implementation of set.
2430 */
db_set(DB_data * data,PyObject * pyargs)2431 static PyObject* db_set(DB_data* data, PyObject* pyargs) {
2432 int32_t argc = PyTuple_Size(pyargs);
2433 if (argc != 2) {
2434 throwinvarg();
2435 return NULL;
2436 }
2437 kc::PolyDB* db = data->db;
2438 PyObject* pykey = PyTuple_GetItem(pyargs, 0);
2439 PyObject* pyvalue = PyTuple_GetItem(pyargs, 1);
2440 SoftString key(pykey);
2441 SoftString value(pyvalue);
2442 NativeFunction nf(data);
2443 bool rv = db->set(key.ptr(), key.size(), value.ptr(), value.size());
2444 nf.cleanup();
2445 if (rv) Py_RETURN_TRUE;
2446 if (db_raise(data)) return NULL;
2447 Py_RETURN_FALSE;
2448 }
2449
2450
2451 /**
2452 * Implementation of add.
2453 */
db_add(DB_data * data,PyObject * pyargs)2454 static PyObject* db_add(DB_data* data, PyObject* pyargs) {
2455 int32_t argc = PyTuple_Size(pyargs);
2456 if (argc != 2) {
2457 throwinvarg();
2458 return NULL;
2459 }
2460 kc::PolyDB* db = data->db;
2461 PyObject* pykey = PyTuple_GetItem(pyargs, 0);
2462 PyObject* pyvalue = PyTuple_GetItem(pyargs, 1);
2463 SoftString key(pykey);
2464 SoftString value(pyvalue);
2465 NativeFunction nf(data);
2466 bool rv = db->add(key.ptr(), key.size(), value.ptr(), value.size());
2467 nf.cleanup();
2468 if (rv) Py_RETURN_TRUE;
2469 if (db_raise(data)) return NULL;
2470 Py_RETURN_FALSE;
2471 }
2472
2473
2474 /**
2475 * Implementation of replace.
2476 */
db_replace(DB_data * data,PyObject * pyargs)2477 static PyObject* db_replace(DB_data* data, PyObject* pyargs) {
2478 int32_t argc = PyTuple_Size(pyargs);
2479 if (argc != 2) {
2480 throwinvarg();
2481 return NULL;
2482 }
2483 kc::PolyDB* db = data->db;
2484 PyObject* pykey = PyTuple_GetItem(pyargs, 0);
2485 PyObject* pyvalue = PyTuple_GetItem(pyargs, 1);
2486 SoftString key(pykey);
2487 SoftString value(pyvalue);
2488 NativeFunction nf(data);
2489 bool rv = db->replace(key.ptr(), key.size(), value.ptr(), value.size());
2490 nf.cleanup();
2491 if (rv) Py_RETURN_TRUE;
2492 if (db_raise(data)) return NULL;
2493 Py_RETURN_FALSE;
2494 }
2495
2496
2497 /**
2498 * Implementation of append.
2499 */
db_append(DB_data * data,PyObject * pyargs)2500 static PyObject* db_append(DB_data* data, PyObject* pyargs) {
2501 int32_t argc = PyTuple_Size(pyargs);
2502 if (argc != 2) {
2503 throwinvarg();
2504 return NULL;
2505 }
2506 kc::PolyDB* db = data->db;
2507 PyObject* pykey = PyTuple_GetItem(pyargs, 0);
2508 PyObject* pyvalue = PyTuple_GetItem(pyargs, 1);
2509 SoftString key(pykey);
2510 SoftString value(pyvalue);
2511 NativeFunction nf(data);
2512 bool rv = db->append(key.ptr(), key.size(), value.ptr(), value.size());
2513 nf.cleanup();
2514 if (rv) Py_RETURN_TRUE;
2515 if (db_raise(data)) return NULL;
2516 Py_RETURN_FALSE;
2517 }
2518
2519
2520 /**
2521 * Implementation of increment.
2522 */
db_increment(DB_data * data,PyObject * pyargs)2523 static PyObject* db_increment(DB_data* data, PyObject* pyargs) {
2524 int32_t argc = PyTuple_Size(pyargs);
2525 if (argc < 1 || argc > 3) {
2526 throwinvarg();
2527 return NULL;
2528 }
2529 kc::PolyDB* db = data->db;
2530 PyObject* pykey = PyTuple_GetItem(pyargs, 0);
2531 SoftString key(pykey);
2532 PyObject* pynum = Py_None;
2533 if (argc > 1) pynum = PyTuple_GetItem(pyargs, 1);
2534 int64_t num = pynum == Py_None ? 0 : pyatoi(pynum);
2535 PyObject* pyorig = Py_None;
2536 if (argc > 2) pyorig = PyTuple_GetItem(pyargs, 2);
2537 int64_t orig = pyorig == Py_None ? 0 : pyatoi(pyorig);
2538 PyObject* pyrv;
2539 NativeFunction nf(data);
2540 num = db->increment(key.ptr(), key.size(), num, orig);
2541 nf.cleanup();
2542 if (num == kc::INT64MIN) {
2543 if (db_raise(data)) return NULL;
2544 Py_INCREF(Py_None);
2545 pyrv = Py_None;
2546 } else {
2547 pyrv = PyLong_FromLongLong(num);
2548 }
2549 return pyrv;
2550 }
2551
2552
2553 /**
2554 * Implementation of increment_double.
2555 */
db_increment_double(DB_data * data,PyObject * pyargs)2556 static PyObject* db_increment_double(DB_data* data, PyObject* pyargs) {
2557 int32_t argc = PyTuple_Size(pyargs);
2558 if (argc < 1 || argc > 3) {
2559 throwinvarg();
2560 return NULL;
2561 }
2562 kc::PolyDB* db = data->db;
2563 PyObject* pykey = PyTuple_GetItem(pyargs, 0);
2564 SoftString key(pykey);
2565 PyObject* pynum = Py_None;
2566 if (argc > 1) pynum = PyTuple_GetItem(pyargs, 1);
2567 double num = pynum == Py_None ? 0 : pyatof(pynum);
2568 PyObject* pyorig = Py_None;
2569 if (argc > 2) pyorig = PyTuple_GetItem(pyargs, 2);
2570 double orig = pyorig == Py_None ? 0 : pyatof(pyorig);
2571 PyObject* pyrv;
2572 NativeFunction nf(data);
2573 num = db->increment_double(key.ptr(), key.size(), num, orig);
2574 nf.cleanup();
2575 if (kc::chknan(num)) {
2576 if (db_raise(data)) return NULL;
2577 Py_INCREF(Py_None);
2578 pyrv = Py_None;
2579 } else {
2580 pyrv = PyFloat_FromDouble(num);
2581 }
2582 return pyrv;
2583 }
2584
2585
2586 /**
2587 * Implementation of cas.
2588 */
db_cas(DB_data * data,PyObject * pyargs)2589 static PyObject* db_cas(DB_data* data, PyObject* pyargs) {
2590 int32_t argc = PyTuple_Size(pyargs);
2591 if (argc != 3) {
2592 throwinvarg();
2593 return NULL;
2594 }
2595 kc::PolyDB* db = data->db;
2596 PyObject* pykey = PyTuple_GetItem(pyargs, 0);
2597 SoftString key(pykey);
2598 PyObject* pyoval = PyTuple_GetItem(pyargs, 1);
2599 SoftString oval(pyoval);
2600 const char* ovbuf = NULL;
2601 size_t ovsiz = 0;
2602 if (pyoval != Py_None) {
2603 ovbuf = oval.ptr();
2604 ovsiz = oval.size();
2605 }
2606 PyObject* pynval = PyTuple_GetItem(pyargs, 2);
2607 SoftString nval(pynval);
2608 const char* nvbuf = NULL;
2609 size_t nvsiz = 0;
2610 if (pynval != Py_None) {
2611 nvbuf = nval.ptr();
2612 nvsiz = nval.size();
2613 }
2614 NativeFunction nf(data);
2615 bool rv = db->cas(key.ptr(), key.size(), ovbuf, ovsiz, nvbuf, nvsiz);
2616 nf.cleanup();
2617 if (rv) Py_RETURN_TRUE;
2618 if (db_raise(data)) return NULL;
2619 Py_RETURN_FALSE;
2620 }
2621
2622
2623 /**
2624 * Implementation of remove.
2625 */
db_remove(DB_data * data,PyObject * pyargs)2626 static PyObject* db_remove(DB_data* data, PyObject* pyargs) {
2627 int32_t argc = PyTuple_Size(pyargs);
2628 if (argc != 1) {
2629 throwinvarg();
2630 return NULL;
2631 }
2632 kc::PolyDB* db = data->db;
2633 PyObject* pykey = PyTuple_GetItem(pyargs, 0);
2634 SoftString key(pykey);
2635 NativeFunction nf(data);
2636 bool rv = db->remove(key.ptr(), key.size());
2637 nf.cleanup();
2638 if (rv) Py_RETURN_TRUE;
2639 if (db_raise(data)) return NULL;
2640 Py_RETURN_FALSE;
2641 }
2642
2643
2644 /**
2645 * Implementation of get.
2646 */
db_get(DB_data * data,PyObject * pyargs)2647 static PyObject* db_get(DB_data* data, PyObject* pyargs) {
2648 int32_t argc = PyTuple_Size(pyargs);
2649 if (argc != 1) {
2650 throwinvarg();
2651 return NULL;
2652 }
2653 kc::PolyDB* db = data->db;
2654 PyObject* pykey = PyTuple_GetItem(pyargs, 0);
2655 SoftString key(pykey);
2656 NativeFunction nf(data);
2657 size_t vsiz;
2658 char* vbuf = db->get(key.ptr(), key.size(), &vsiz);
2659 nf.cleanup();
2660 PyObject* pyrv;
2661 if (vbuf) {
2662 pyrv = newbytes(vbuf, vsiz);
2663 delete[] vbuf;
2664 } else {
2665 if (db_raise(data)) return NULL;
2666 Py_INCREF(Py_None);
2667 pyrv = Py_None;
2668 }
2669 return pyrv;
2670 }
2671
2672
2673 /**
2674 * Implementation of get_str.
2675 */
db_get_str(DB_data * data,PyObject * pyargs)2676 static PyObject* db_get_str(DB_data* data, PyObject* pyargs) {
2677 int32_t argc = PyTuple_Size(pyargs);
2678 if (argc != 1) {
2679 throwinvarg();
2680 return NULL;
2681 }
2682 kc::PolyDB* db = data->db;
2683 PyObject* pykey = PyTuple_GetItem(pyargs, 0);
2684 SoftString key(pykey);
2685 NativeFunction nf(data);
2686 size_t vsiz;
2687 char* vbuf = db->get(key.ptr(), key.size(), &vsiz);
2688 nf.cleanup();
2689 PyObject* pyrv;
2690 if (vbuf) {
2691 pyrv = newstring(vbuf);
2692 delete[] vbuf;
2693 } else {
2694 if (db_raise(data)) return NULL;
2695 Py_INCREF(Py_None);
2696 pyrv = Py_None;
2697 }
2698 return pyrv;
2699 }
2700
2701
2702 /**
2703 * Implementation of check.
2704 */
db_check(DB_data * data,PyObject * pyargs)2705 static PyObject* db_check(DB_data* data, PyObject* pyargs) {
2706 int32_t argc = PyTuple_Size(pyargs);
2707 if (argc != 1) {
2708 throwinvarg();
2709 return NULL;
2710 }
2711 kc::PolyDB* db = data->db;
2712 PyObject* pykey = PyTuple_GetItem(pyargs, 0);
2713 SoftString key(pykey);
2714 NativeFunction nf(data);
2715 int32_t vsiz = db->check(key.ptr(), key.size());
2716 nf.cleanup();
2717 if (vsiz < 0 && db_raise(data)) return NULL;
2718 return PyLong_FromLongLong(vsiz);
2719 }
2720
2721
2722 /**
2723 * Implementation of seize.
2724 */
db_seize(DB_data * data,PyObject * pyargs)2725 static PyObject* db_seize(DB_data* data, PyObject* pyargs) {
2726 int32_t argc = PyTuple_Size(pyargs);
2727 if (argc != 1) {
2728 throwinvarg();
2729 return NULL;
2730 }
2731 kc::PolyDB* db = data->db;
2732 PyObject* pykey = PyTuple_GetItem(pyargs, 0);
2733 SoftString key(pykey);
2734 NativeFunction nf(data);
2735 size_t vsiz;
2736 char* vbuf = db->seize(key.ptr(), key.size(), &vsiz);
2737 nf.cleanup();
2738 PyObject* pyrv;
2739 if (vbuf) {
2740 pyrv = newbytes(vbuf, vsiz);
2741 delete[] vbuf;
2742 } else {
2743 if (db_raise(data)) return NULL;
2744 Py_INCREF(Py_None);
2745 pyrv = Py_None;
2746 }
2747 return pyrv;
2748 }
2749
2750
2751 /**
2752 * Implementation of seize_str.
2753 */
db_seize_str(DB_data * data,PyObject * pyargs)2754 static PyObject* db_seize_str(DB_data* data, PyObject* pyargs) {
2755 int32_t argc = PyTuple_Size(pyargs);
2756 if (argc != 1) {
2757 throwinvarg();
2758 return NULL;
2759 }
2760 kc::PolyDB* db = data->db;
2761 PyObject* pykey = PyTuple_GetItem(pyargs, 0);
2762 SoftString key(pykey);
2763 NativeFunction nf(data);
2764 size_t vsiz;
2765 char* vbuf = db->seize(key.ptr(), key.size(), &vsiz);
2766 nf.cleanup();
2767 PyObject* pyrv;
2768 if (vbuf) {
2769 pyrv = newstring(vbuf);
2770 delete[] vbuf;
2771 } else {
2772 if (db_raise(data)) return NULL;
2773 Py_INCREF(Py_None);
2774 pyrv = Py_None;
2775 }
2776 return pyrv;
2777 }
2778
2779
2780 /**
2781 * Implementation of set_bulk.
2782 */
db_set_bulk(DB_data * data,PyObject * pyargs)2783 static PyObject* db_set_bulk(DB_data* data, PyObject* pyargs) {
2784 int32_t argc = PyTuple_Size(pyargs);
2785 if (argc < 1 || argc > 2) {
2786 throwinvarg();
2787 return NULL;
2788 }
2789 kc::PolyDB* db = data->db;
2790 PyObject* pyrecs = PyTuple_GetItem(pyargs, 0);
2791 if (!PyMapping_Check(pyrecs)) {
2792 throwinvarg();
2793 return NULL;
2794 }
2795 StringMap recs;
2796 PyObject* pyitems = PyMapping_Items(pyrecs);
2797 int32_t rnum = PySequence_Length(pyitems);
2798 for (int32_t i = 0; i < rnum; i++) {
2799 PyObject* pyitem = PySequence_GetItem(pyitems, i);
2800 if (PyTuple_Size(pyitem) == 2) {
2801 PyObject* pykey = PyTuple_GetItem(pyitem, 0);
2802 PyObject* pyvalue = PyTuple_GetItem(pyitem, 1);
2803 SoftString key(pykey);
2804 SoftString value(pyvalue);
2805 recs[std::string(key.ptr(), key.size())] = std::string(value.ptr(), value.size());
2806 }
2807 Py_DECREF(pyitem);
2808 }
2809 Py_DECREF(pyitems);
2810 PyObject* pyatomic = Py_True;
2811 if (argc > 1) pyatomic = PyTuple_GetItem(pyargs, 1);
2812 bool atomic = PyObject_IsTrue(pyatomic);
2813 NativeFunction nf(data);
2814 int64_t rv = db->set_bulk(recs, atomic);
2815 nf.cleanup();
2816 if (rv < 0 && db_raise(data)) return NULL;
2817 return PyLong_FromLongLong(rv);
2818 }
2819
2820
2821 /**
2822 * Implementation of remove_bulk.
2823 */
db_remove_bulk(DB_data * data,PyObject * pyargs)2824 static PyObject* db_remove_bulk(DB_data* data, PyObject* pyargs) {
2825 int32_t argc = PyTuple_Size(pyargs);
2826 if (argc < 1 || argc > 2) {
2827 throwinvarg();
2828 return NULL;
2829 }
2830 kc::PolyDB* db = data->db;
2831 PyObject* pykeys = PyTuple_GetItem(pyargs, 0);
2832 if (!PySequence_Check(pykeys)) {
2833 throwinvarg();
2834 return NULL;
2835 }
2836 StringVector keys;
2837 int32_t knum = PySequence_Length(pykeys);
2838 for (int32_t i = 0; i < knum; i++) {
2839 PyObject* pykey = PySequence_GetItem(pykeys, i);
2840 SoftString key(pykey);
2841 keys.push_back(std::string(key.ptr(), key.size()));
2842 Py_DECREF(pykey);
2843 }
2844 PyObject* pyatomic = Py_True;
2845 if (argc > 1) pyatomic = PyTuple_GetItem(pyargs, 1);
2846 bool atomic = PyObject_IsTrue(pyatomic);
2847 NativeFunction nf(data);
2848 int64_t rv = db->remove_bulk(keys, atomic);
2849 nf.cleanup();
2850 if (rv < 0 && db_raise(data)) return NULL;
2851 return PyLong_FromLongLong(rv);
2852 }
2853
2854
2855 /**
2856 * Implementation of get_bulk.
2857 */
db_get_bulk(DB_data * data,PyObject * pyargs)2858 static PyObject* db_get_bulk(DB_data* data, PyObject* pyargs) {
2859 int32_t argc = PyTuple_Size(pyargs);
2860 if (argc < 1 || argc > 2) {
2861 throwinvarg();
2862 return NULL;
2863 }
2864 kc::PolyDB* db = data->db;
2865 PyObject* pykeys = PyTuple_GetItem(pyargs, 0);
2866 if (!PySequence_Check(pykeys)) {
2867 throwinvarg();
2868 return NULL;
2869 }
2870 StringVector keys;
2871 int32_t knum = PySequence_Length(pykeys);
2872 for (int32_t i = 0; i < knum; i++) {
2873 PyObject* pykey = PySequence_GetItem(pykeys, i);
2874 SoftString key(pykey);
2875 keys.push_back(std::string(key.ptr(), key.size()));
2876 Py_DECREF(pykey);
2877 }
2878 PyObject* pyatomic = Py_True;
2879 if (argc > 1) pyatomic = PyTuple_GetItem(pyargs, 1);
2880 bool atomic = PyObject_IsTrue(pyatomic);
2881 NativeFunction nf(data);
2882 StringMap recs;
2883 int64_t rv = db->get_bulk(keys, &recs, atomic);
2884 nf.cleanup();
2885 if (rv < 0) {
2886 if (db_raise(data)) return NULL;
2887 Py_RETURN_NONE;
2888 }
2889 PyObject* pyrecs = PyDict_New();
2890 StringMap::const_iterator it = recs.begin();
2891 StringMap::const_iterator itend = recs.end();
2892 while (it != itend) {
2893 PyObject* pykey = newbytes(it->first.data(), it->first.size());
2894 PyObject* pyvalue = newbytes(it->second.data(), it->second.size());
2895 PyDict_SetItem(pyrecs, pykey, pyvalue);
2896 Py_DECREF(pyvalue);
2897 Py_DECREF(pykey);
2898 it++;
2899 }
2900 return pyrecs;
2901 }
2902
2903
2904 /**
2905 * Implementation of get_bulk_str.
2906 */
db_get_bulk_str(DB_data * data,PyObject * pyargs)2907 static PyObject* db_get_bulk_str(DB_data* data, PyObject* pyargs) {
2908 int32_t argc = PyTuple_Size(pyargs);
2909 if (argc < 1 || argc > 2) {
2910 throwinvarg();
2911 return NULL;
2912 }
2913 kc::PolyDB* db = data->db;
2914 PyObject* pykeys = PyTuple_GetItem(pyargs, 0);
2915 if (!PySequence_Check(pykeys)) {
2916 throwinvarg();
2917 return NULL;
2918 }
2919 StringVector keys;
2920 int32_t knum = PySequence_Length(pykeys);
2921 for (int32_t i = 0; i < knum; i++) {
2922 PyObject* pykey = PySequence_GetItem(pykeys, i);
2923 SoftString key(pykey);
2924 keys.push_back(std::string(key.ptr(), key.size()));
2925 Py_DECREF(pykey);
2926 }
2927 PyObject* pyatomic = Py_True;
2928 if (argc > 1) pyatomic = PyTuple_GetItem(pyargs, 1);
2929 bool atomic = PyObject_IsTrue(pyatomic);
2930 NativeFunction nf(data);
2931 StringMap recs;
2932 int64_t rv = db->get_bulk(keys, &recs, atomic);
2933 nf.cleanup();
2934 if (rv < 0) {
2935 if (db_raise(data)) return NULL;
2936 Py_RETURN_NONE;
2937 }
2938 return maptopymap(&recs);
2939 }
2940
2941
2942 /**
2943 * Implementation of clear.
2944 */
db_clear(DB_data * data)2945 static PyObject* db_clear(DB_data* data) {
2946 kc::PolyDB* db = data->db;
2947 NativeFunction nf(data);
2948 bool rv = db->clear();
2949 nf.cleanup();
2950 if (rv) Py_RETURN_TRUE;
2951 if (db_raise(data)) return NULL;
2952 Py_RETURN_FALSE;
2953 }
2954
2955
2956 /**
2957 * Implementation of synchronize.
2958 */
db_synchronize(DB_data * data,PyObject * pyargs)2959 static PyObject* db_synchronize(DB_data* data, PyObject* pyargs) {
2960 int32_t argc = PyTuple_Size(pyargs);
2961 if (argc > 2) {
2962 throwinvarg();
2963 return NULL;
2964 }
2965 PyObject* pyhard = Py_None;
2966 if (argc > 0) pyhard = PyTuple_GetItem(pyargs, 0);
2967 PyObject* pyproc = Py_None;
2968 if (argc > 1) pyproc = PyTuple_GetItem(pyargs, 1);
2969 kc::PolyDB* db = data->db;
2970 bool hard = PyObject_IsTrue(pyhard);
2971 bool rv;
2972 if (PyObject_IsInstance(pyproc, cls_fproc) || PyCallable_Check(pyproc)) {
2973 if (data->pylock == Py_None) {
2974 db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
2975 if (db_raise(data)) return NULL;
2976 Py_RETURN_NONE;
2977 }
2978 SoftFileProcessor proc(pyproc);
2979 NativeFunction nf(data);
2980 rv = db->synchronize(hard, &proc);
2981 nf.cleanup();
2982 PyObject* pyextype, *pyexvalue, *pyextrace;
2983 if (proc.exception(&pyextype, &pyexvalue, &pyextrace)) {
2984 PyErr_SetObject(pyextype, pyexvalue);
2985 return NULL;
2986 }
2987 } else {
2988 NativeFunction nf(data);
2989 rv = db->synchronize(hard, NULL);
2990 nf.cleanup();
2991 }
2992 if (rv) Py_RETURN_TRUE;
2993 if (db_raise(data)) return NULL;
2994 Py_RETURN_FALSE;
2995 }
2996
2997
2998 /**
2999 * Implementation of occupy.
3000 */
db_occupy(DB_data * data,PyObject * pyargs)3001 static PyObject* db_occupy(DB_data* data, PyObject* pyargs) {
3002 int32_t argc = PyTuple_Size(pyargs);
3003 if (argc > 2) {
3004 throwinvarg();
3005 return NULL;
3006 }
3007 PyObject* pywritable = Py_None;
3008 if (argc > 0) pywritable = PyTuple_GetItem(pyargs, 0);
3009 PyObject* pyproc = Py_None;
3010 if (argc > 1) pyproc = PyTuple_GetItem(pyargs, 1);
3011 kc::PolyDB* db = data->db;
3012 bool writable = PyObject_IsTrue(pywritable);
3013 bool rv;
3014 if (PyObject_IsInstance(pyproc, cls_fproc) || PyCallable_Check(pyproc)) {
3015 if (data->pylock == Py_None) {
3016 db->set_error(kc::PolyDB::Error::INVALID, "unsupported method");
3017 if (db_raise(data)) return NULL;
3018 Py_RETURN_NONE;
3019 }
3020 SoftFileProcessor proc(pyproc);
3021 NativeFunction nf(data);
3022 rv = db->occupy(writable, &proc);
3023 nf.cleanup();
3024 PyObject* pyextype, *pyexvalue, *pyextrace;
3025 if (proc.exception(&pyextype, &pyexvalue, &pyextrace)) {
3026 PyErr_SetObject(pyextype, pyexvalue);
3027 return NULL;
3028 }
3029 } else {
3030 NativeFunction nf(data);
3031 rv = db->occupy(writable, NULL);
3032 nf.cleanup();
3033 }
3034 if (rv) Py_RETURN_TRUE;
3035 if (db_raise(data)) return NULL;
3036 Py_RETURN_FALSE;
3037 }
3038
3039
3040 /**
3041 * Implementation of copy.
3042 */
db_copy(DB_data * data,PyObject * pyargs)3043 static PyObject* db_copy(DB_data* data, PyObject* pyargs) {
3044 int32_t argc = PyTuple_Size(pyargs);
3045 if (argc != 1) {
3046 throwinvarg();
3047 return NULL;
3048 }
3049 PyObject* pydest = PyTuple_GetItem(pyargs, 0);
3050 kc::PolyDB* db = data->db;
3051 SoftString dest(pydest);
3052 NativeFunction nf(data);
3053 bool rv = db->copy(dest.ptr());
3054 nf.cleanup();
3055 if (rv) Py_RETURN_TRUE;
3056 if (db_raise(data)) return NULL;
3057 Py_RETURN_FALSE;
3058 }
3059
3060
3061 /**
3062 * Implementation of begin_transaction.
3063 */
db_begin_transaction(DB_data * data,PyObject * pyargs)3064 static PyObject* db_begin_transaction(DB_data* data, PyObject* pyargs) {
3065 int32_t argc = PyTuple_Size(pyargs);
3066 if (argc > 1) {
3067 throwinvarg();
3068 return NULL;
3069 }
3070 PyObject* pyhard = Py_None;
3071 if (argc > 0) pyhard = PyTuple_GetItem(pyargs, 0);
3072 kc::PolyDB* db = data->db;
3073 bool hard = PyObject_IsTrue(pyhard);
3074 bool err = false;
3075 while (true) {
3076 NativeFunction nf(data);
3077 bool rv = db->begin_transaction_try(hard);
3078 nf.cleanup();
3079 if (rv) break;
3080 if (db->error() != kc::PolyDB::Error::LOGIC) {
3081 err = true;
3082 break;
3083 }
3084 threadyield();
3085 }
3086 if (err) {
3087 if (db_raise(data)) return NULL;
3088 Py_RETURN_FALSE;
3089 }
3090 Py_RETURN_TRUE;
3091 }
3092
3093
3094 /**
3095 * Implementation of end_transaction.
3096 */
db_end_transaction(DB_data * data,PyObject * pyargs)3097 static PyObject* db_end_transaction(DB_data* data, PyObject* pyargs) {
3098 int32_t argc = PyTuple_Size(pyargs);
3099 if (argc > 1) {
3100 throwinvarg();
3101 return NULL;
3102 }
3103 PyObject* pycommit = Py_None;
3104 if (argc > 0) pycommit = PyTuple_GetItem(pyargs, 0);
3105 kc::PolyDB* db = data->db;
3106 bool commit = pycommit == Py_None || PyObject_IsTrue(pycommit);
3107 NativeFunction nf(data);
3108 bool rv = db->end_transaction(commit);
3109 nf.cleanup();
3110 if (rv) Py_RETURN_TRUE;
3111 if (db_raise(data)) return NULL;
3112 Py_RETURN_FALSE;
3113 }
3114
3115
3116 /**
3117 * Implementation of transaction.
3118 */
db_transaction(DB_data * data,PyObject * pyargs)3119 static PyObject* db_transaction(DB_data* data, PyObject* pyargs) {
3120 int32_t argc = PyTuple_Size(pyargs);
3121 if (argc < 1 || argc > 2) {
3122 throwinvarg();
3123 return NULL;
3124 }
3125 PyObject* pyproc = PyTuple_GetItem(pyargs, 0);
3126 PyObject* pyhard = Py_None;
3127 if (argc > 1) pyhard = PyTuple_GetItem(pyargs, 1);
3128 PyObject* pyrv = PyObject_CallMethod((PyObject*)data, (char*)"begin_transaction",
3129 (char*)"(O)", pyhard);
3130 if (!pyrv) return NULL;
3131 if (!PyObject_IsTrue(pyrv)) {
3132 Py_DECREF(pyrv);
3133 Py_RETURN_FALSE;
3134 }
3135 Py_DECREF(pyrv);
3136 pyrv = PyObject_CallFunction(pyproc, NULL);
3137 bool commit = false;
3138 if (pyrv) commit = PyObject_IsTrue(pyrv);
3139 Py_DECREF(pyrv);
3140 pyrv = PyObject_CallMethod((PyObject*)data, (char*)"end_transaction",
3141 (char*)"(O)", commit ? Py_True : Py_False);
3142 if (!pyrv) return NULL;
3143 if (!PyObject_IsTrue(pyrv)) {
3144 Py_DECREF(pyrv);
3145 Py_RETURN_FALSE;
3146 }
3147 Py_DECREF(pyrv);
3148 Py_RETURN_TRUE;
3149 }
3150
3151
3152 /**
3153 * Implementation of dump_snapshot.
3154 */
db_dump_snapshot(DB_data * data,PyObject * pyargs)3155 static PyObject* db_dump_snapshot(DB_data* data, PyObject* pyargs) {
3156 int32_t argc = PyTuple_Size(pyargs);
3157 if (argc != 1) {
3158 throwinvarg();
3159 return NULL;
3160 }
3161 PyObject* pydest = PyTuple_GetItem(pyargs, 0);
3162 kc::PolyDB* db = data->db;
3163 SoftString dest(pydest);
3164 NativeFunction nf(data);
3165 bool rv = db->dump_snapshot(dest.ptr());
3166 nf.cleanup();
3167 if (rv) Py_RETURN_TRUE;
3168 if (db_raise(data)) return NULL;
3169 Py_RETURN_FALSE;
3170 }
3171
3172
3173 /**
3174 * Implementation of load_snapshot.
3175 */
db_load_snapshot(DB_data * data,PyObject * pyargs)3176 static PyObject* db_load_snapshot(DB_data* data, PyObject* pyargs) {
3177 int32_t argc = PyTuple_Size(pyargs);
3178 if (argc != 1) {
3179 throwinvarg();
3180 return NULL;
3181 }
3182 PyObject* pysrc = PyTuple_GetItem(pyargs, 0);
3183 kc::PolyDB* db = data->db;
3184 SoftString src(pysrc);
3185 NativeFunction nf(data);
3186 bool rv = db->load_snapshot(src.ptr());
3187 nf.cleanup();
3188 if (rv) Py_RETURN_TRUE;
3189 if (db_raise(data)) return NULL;
3190 Py_RETURN_FALSE;
3191 }
3192
3193
3194 /**
3195 * Implementation of count.
3196 */
db_count(DB_data * data)3197 static PyObject* db_count(DB_data* data) {
3198 kc::PolyDB* db = data->db;
3199 NativeFunction nf(data);
3200 int64_t count = db->count();
3201 nf.cleanup();
3202 if (count < 0 && db_raise(data)) return NULL;
3203 return PyLong_FromLongLong(count);
3204 }
3205
3206
3207 /**
3208 * Implementation of size.
3209 */
db_size(DB_data * data)3210 static PyObject* db_size(DB_data* data) {
3211 kc::PolyDB* db = data->db;
3212 NativeFunction nf(data);
3213 int64_t size = db->size();
3214 nf.cleanup();
3215 if (size < 0 && db_raise(data)) return NULL;
3216 return PyLong_FromLongLong(size);
3217 }
3218
3219
3220 /**
3221 * Implementation of path.
3222 */
db_path(DB_data * data)3223 static PyObject* db_path(DB_data* data) {
3224 kc::PolyDB* db = data->db;
3225 NativeFunction nf(data);
3226 const std::string& path = db->path();
3227 nf.cleanup();
3228 if (path.size() < 1) {
3229 if (db_raise(data)) return NULL;
3230 Py_RETURN_NONE;
3231 }
3232 return PyUnicode_FromString(path.c_str());
3233 }
3234
3235
3236 /**
3237 * Implementation of status.
3238 */
db_status(DB_data * data)3239 static PyObject* db_status(DB_data* data) {
3240 kc::PolyDB* db = data->db;
3241 StringMap status;
3242 NativeFunction nf(data);
3243 bool rv = db->status(&status);
3244 nf.cleanup();
3245 if (rv) return maptopymap(&status);
3246 if (db_raise(data)) return NULL;
3247 Py_RETURN_NONE;
3248 }
3249
3250
3251 /**
3252 * Implementation of match_prefix.
3253 */
db_match_prefix(DB_data * data,PyObject * pyargs)3254 static PyObject* db_match_prefix(DB_data* data, PyObject* pyargs) {
3255 int32_t argc = PyTuple_Size(pyargs);
3256 if (argc < 1 || argc > 2) {
3257 throwinvarg();
3258 return NULL;
3259 }
3260 kc::PolyDB* db = data->db;
3261 PyObject* pyprefix = PyTuple_GetItem(pyargs, 0);
3262 SoftString prefix(pyprefix);
3263 PyObject* pymax = Py_None;
3264 if (argc > 1) pymax = PyTuple_GetItem(pyargs, 1);
3265 int64_t max = pymax == Py_None ? -1 : pyatoi(pymax);
3266 PyObject* pyrv;
3267 NativeFunction nf(data);
3268 StringVector keys;
3269 max = db->match_prefix(std::string(prefix.ptr(), prefix.size()), &keys, max);
3270 nf.cleanup();
3271 if (max >= 0) {
3272 pyrv = vectortopylist(&keys);
3273 } else {
3274 if (db_raise(data)) return NULL;
3275 Py_INCREF(Py_None);
3276 pyrv = Py_None;
3277 }
3278 return pyrv;
3279 }
3280
3281
3282 /**
3283 * Implementation of match_regex.
3284 */
db_match_regex(DB_data * data,PyObject * pyargs)3285 static PyObject* db_match_regex(DB_data* data, PyObject* pyargs) {
3286 int32_t argc = PyTuple_Size(pyargs);
3287 if (argc < 1 || argc > 2) {
3288 throwinvarg();
3289 return NULL;
3290 }
3291 kc::PolyDB* db = data->db;
3292 PyObject* pyregex = PyTuple_GetItem(pyargs, 0);
3293 SoftString regex(pyregex);
3294 PyObject* pymax = Py_None;
3295 if (argc > 1) pymax = PyTuple_GetItem(pyargs, 1);
3296 int64_t max = pymax == Py_None ? -1 : pyatoi(pymax);
3297 PyObject* pyrv;
3298 NativeFunction nf(data);
3299 StringVector keys;
3300 max = db->match_regex(std::string(regex.ptr(), regex.size()), &keys, max);
3301 nf.cleanup();
3302 if (max >= 0) {
3303 pyrv = vectortopylist(&keys);
3304 } else {
3305 if (db_raise(data)) return NULL;
3306 Py_INCREF(Py_None);
3307 pyrv = Py_None;
3308 }
3309 return pyrv;
3310 }
3311
3312
3313 /**
3314 * Implementation of match_similar.
3315 */
db_match_similar(DB_data * data,PyObject * pyargs)3316 static PyObject* db_match_similar(DB_data* data, PyObject* pyargs) {
3317 int32_t argc = PyTuple_Size(pyargs);
3318 if (argc < 1 || argc > 4) {
3319 throwinvarg();
3320 return NULL;
3321 }
3322 kc::PolyDB* db = data->db;
3323 PyObject* pyorigin = PyTuple_GetItem(pyargs, 0);
3324 SoftString origin(pyorigin);
3325 PyObject* pyrange = Py_None;
3326 if (argc > 1) pyrange = PyTuple_GetItem(pyargs, 1);
3327 int64_t range = pyrange == Py_None ? 1 : pyatoi(pyrange);
3328 PyObject* pyutf = Py_None;
3329 if (argc > 2) pyutf = PyTuple_GetItem(pyargs, 2);
3330 bool utf = PyObject_IsTrue(pyutf);
3331 PyObject* pymax = Py_None;
3332 if (argc > 3) pymax = PyTuple_GetItem(pyargs, 3);
3333 int64_t max = pymax == Py_None ? -1 : pyatoi(pymax);
3334 PyObject* pyrv;
3335 NativeFunction nf(data);
3336 StringVector keys;
3337 max = db->match_similar(std::string(origin.ptr(), origin.size()), range, utf, &keys, max);
3338 nf.cleanup();
3339 if (max >= 0) {
3340 pyrv = vectortopylist(&keys);
3341 } else {
3342 if (db_raise(data)) return NULL;
3343 Py_INCREF(Py_None);
3344 pyrv = Py_None;
3345 }
3346 return pyrv;
3347 }
3348
3349
3350 /**
3351 * Implementation of merge.
3352 */
db_merge(DB_data * data,PyObject * pyargs)3353 static PyObject* db_merge(DB_data* data, PyObject* pyargs) {
3354 int32_t argc = PyTuple_Size(pyargs);
3355 if (argc < 1 || argc > 2) {
3356 throwinvarg();
3357 return NULL;
3358 }
3359 PyObject* pysrcary = PyTuple_GetItem(pyargs, 0);
3360 if (!PySequence_Check(pysrcary)) {
3361 throwinvarg();
3362 return NULL;
3363 }
3364 PyObject* pymode = Py_None;
3365 if (argc > 1) pymode = PyTuple_GetItem(pyargs, 1);
3366 uint32_t mode = PyLong_Check(pymode) ? (uint32_t)PyLong_AsLong(pymode) :
3367 kc::PolyDB::OWRITER | kc::PolyDB::OCREATE;
3368 kc::PolyDB* db = data->db;
3369 int32_t num = PySequence_Length(pysrcary);
3370 if (num < 1) Py_RETURN_TRUE;
3371 kc::BasicDB** srcary = new kc::BasicDB*[num];
3372 size_t srcnum = 0;
3373 for (int32_t i = 0; i < num; i++) {
3374 PyObject* pysrcdb = PySequence_GetItem(pysrcary, i);
3375 if (PyObject_IsInstance(pysrcdb, cls_db)) {
3376 DB_data* srcdbdata = (DB_data*)pysrcdb;
3377 srcary[srcnum++] = srcdbdata->db;
3378 }
3379 Py_DECREF(pysrcdb);
3380 }
3381 NativeFunction nf(data);
3382 bool rv = db->merge(srcary, srcnum, (kc::PolyDB::MergeMode)mode);
3383 nf.cleanup();
3384 delete[] srcary;
3385 if (rv) Py_RETURN_TRUE;
3386 if (db_raise(data)) return NULL;
3387 Py_RETURN_FALSE;
3388 }
3389
3390
3391 /**
3392 * Implementation of cursor.
3393 */
db_cursor(DB_data * data)3394 static PyObject* db_cursor(DB_data* data) {
3395 PyObject* pycur = PyObject_CallMethod(mod_kc, (char*)"Cursor",
3396 (char*)"(O)", (PyObject*)data);
3397 return pycur;
3398 }
3399
3400
3401 /**
3402 * Implementation of cursor_process.
3403 */
db_cursor_process(DB_data * data,PyObject * pyargs)3404 static PyObject* db_cursor_process(DB_data* data, PyObject* pyargs) {
3405 int32_t argc = PyTuple_Size(pyargs);
3406 if (argc != 1) {
3407 throwinvarg();
3408 return NULL;
3409 }
3410 PyObject* pyproc = PyTuple_GetItem(pyargs, 0);
3411 if (!PyCallable_Check(pyproc)) {
3412 throwinvarg();
3413 return NULL;
3414 }
3415 PyObject* pycur = PyObject_CallMethod(mod_kc, (char*)"Cursor",
3416 (char*)"(O)", (PyObject*)data);
3417 if (!pycur) return NULL;
3418 PyObject* pyrv = PyObject_CallFunction(pyproc, (char*)"(O)", pycur);
3419 if (!pyrv) {
3420 Py_DECREF(pycur);
3421 return NULL;
3422 }
3423 Py_DECREF(pyrv);
3424 pyrv = PyObject_CallMethod(pycur, (char*)"disable", NULL);
3425 if (!pyrv) {
3426 Py_DECREF(pycur);
3427 return NULL;
3428 }
3429 Py_DECREF(pyrv);
3430 Py_DECREF(pycur);
3431 Py_RETURN_NONE;
3432 }
3433
3434
3435 /**
3436 * Implementation of shift.
3437 */
db_shift(DB_data * data)3438 static PyObject* db_shift(DB_data* data) {
3439 kc::PolyDB* db = data->db;
3440 NativeFunction nf(data);
3441 char* kbuf;
3442 const char* vbuf;
3443 size_t ksiz, vsiz;
3444 kbuf = db_shift_impl(db, &ksiz, &vbuf, &vsiz);
3445 nf.cleanup();
3446 PyObject* pyrv;
3447 if (kbuf) {
3448 pyrv = PyTuple_New(2);
3449 PyObject* pykey = newbytes(kbuf, ksiz);
3450 PyObject* pyvalue = newbytes(vbuf, vsiz);
3451 PyTuple_SetItem(pyrv, 0, pykey);
3452 PyTuple_SetItem(pyrv, 1, pyvalue);
3453 delete[] kbuf;
3454 } else {
3455 if (db_raise(data)) return NULL;
3456 Py_INCREF(Py_None);
3457 pyrv = Py_None;
3458 }
3459 return pyrv;
3460 }
3461
3462
3463 /**
3464 * Implementation of shift_str.
3465 */
db_shift_str(DB_data * data)3466 static PyObject* db_shift_str(DB_data* data) {
3467 kc::PolyDB* db = data->db;
3468 NativeFunction nf(data);
3469 char* kbuf;
3470 const char* vbuf;
3471 size_t ksiz, vsiz;
3472 kbuf = db_shift_impl(db, &ksiz, &vbuf, &vsiz);
3473 nf.cleanup();
3474 PyObject* pyrv;
3475 if (kbuf) {
3476 pyrv = PyTuple_New(2);
3477 PyObject* pykey = newstring(kbuf);
3478 PyObject* pyvalue = newstring(vbuf);
3479 PyTuple_SetItem(pyrv, 0, pykey);
3480 PyTuple_SetItem(pyrv, 1, pyvalue);
3481 delete[] kbuf;
3482 } else {
3483 if (db_raise(data)) return NULL;
3484 Py_INCREF(Py_None);
3485 pyrv = Py_None;
3486 }
3487 return pyrv;
3488 }
3489
3490
3491 /**
3492 * Common implementation of shift and shift_str.
3493 */
db_shift_impl(kc::PolyDB * db,size_t * ksp,const char ** vbp,size_t * vsp)3494 static char* db_shift_impl(kc::PolyDB* db, size_t* ksp, const char** vbp, size_t* vsp) {
3495 kc::PolyDB::Cursor cur(db);
3496 if (!cur.jump()) return NULL;
3497 class VisitorImpl : public kc::PolyDB::Visitor {
3498 public:
3499 explicit VisitorImpl() : kbuf_(NULL), ksiz_(0), vbuf_(NULL), vsiz_(0) {}
3500 char* rv(size_t* ksp, const char** vbp, size_t* vsp) {
3501 *ksp = ksiz_;
3502 *vbp = vbuf_;
3503 *vsp = vsiz_;
3504 return kbuf_;
3505 }
3506 private:
3507 const char* visit_full(const char* kbuf, size_t ksiz,
3508 const char* vbuf, size_t vsiz, size_t* sp) {
3509 size_t rsiz = ksiz + 1 + vsiz + 1;
3510 kbuf_ = new char[rsiz];
3511 std::memcpy(kbuf_, kbuf, ksiz);
3512 kbuf_[ksiz] = '\0';
3513 ksiz_ = ksiz;
3514 vbuf_ = kbuf_ + ksiz + 1;
3515 std::memcpy(vbuf_, vbuf, vsiz);
3516 vbuf_[vsiz] = '\0';
3517 vsiz_ = vsiz;
3518 return REMOVE;
3519 }
3520 char* kbuf_;
3521 size_t ksiz_;
3522 char* vbuf_;
3523 size_t vsiz_;
3524 } visitor;
3525 if (!cur.accept(&visitor, true, false)) {
3526 *ksp = 0;
3527 *vbp = NULL;
3528 *vsp = 0;
3529 return NULL;
3530 }
3531 return visitor.rv(ksp, vbp, vsp);
3532 }
3533
3534
3535 /**
3536 * Implementation of tune_exception_rule.
3537 */
db_tune_exception_rule(DB_data * data,PyObject * pyargs)3538 static PyObject* db_tune_exception_rule(DB_data* data, PyObject* pyargs) {
3539 int32_t argc = PyTuple_Size(pyargs);
3540 if (argc != 1) {
3541 throwinvarg();
3542 return NULL;
3543 }
3544 PyObject* pycodes = PyTuple_GetItem(pyargs, 0);
3545 if (!PySequence_Check(pycodes)) Py_RETURN_FALSE;
3546 uint32_t exbits = 0;
3547 int32_t num = PySequence_Length(pycodes);
3548 for (int32_t i = 0; i < num; i++) {
3549 PyObject* pycode = PySequence_GetItem(pycodes, i);
3550 if (PyLong_Check(pycode)) {
3551 uint32_t code = PyLong_AsLong(pycode);
3552 if (code <= kc::PolyDB::Error::MISC) exbits |= 1 << code;
3553 }
3554 Py_DECREF(pycode);
3555 }
3556 data->exbits = exbits;
3557 Py_RETURN_TRUE;
3558 }
3559
3560
3561 /**
3562 * Implementation of __len__.
3563 */
db_op_len(DB_data * data)3564 static Py_ssize_t db_op_len(DB_data* data) {
3565 kc::PolyDB* db = data->db;
3566 NativeFunction nf(data);
3567 int64_t count = db->count();
3568 nf.cleanup();
3569 return count;
3570 }
3571
3572
3573 /**
3574 * Implementation of __getitem__.
3575 */
db_op_getitem(DB_data * data,PyObject * pykey)3576 static PyObject* db_op_getitem(DB_data* data, PyObject* pykey) {
3577 kc::PolyDB* db = data->db;
3578 SoftString key(pykey);
3579 NativeFunction nf(data);
3580 size_t vsiz;
3581 char* vbuf = db->get(key.ptr(), key.size(), &vsiz);
3582 nf.cleanup();
3583 PyObject* pyrv;
3584 if (vbuf) {
3585 pyrv = newbytes(vbuf, vsiz);
3586 delete[] vbuf;
3587 } else {
3588 Py_INCREF(Py_None);
3589 pyrv = Py_None;
3590 }
3591 return pyrv;
3592 }
3593
3594
3595 /**
3596 * Implementation of __setitem__.
3597 */
db_op_setitem(DB_data * data,PyObject * pykey,PyObject * pyvalue)3598 static int db_op_setitem(DB_data* data, PyObject* pykey, PyObject* pyvalue) {
3599 kc::PolyDB* db = data->db;
3600 if (pyvalue) {
3601 SoftString key(pykey);
3602 SoftString value(pyvalue);
3603 NativeFunction nf(data);
3604 bool rv = db->set(key.ptr(), key.size(), value.ptr(), value.size());
3605 nf.cleanup();
3606 if (rv) return 0;
3607 throwruntime("DB::set failed");
3608 return -1;
3609 } else {
3610 SoftString key(pykey);
3611 NativeFunction nf(data);
3612 bool rv = db->remove(key.ptr(), key.size());
3613 nf.cleanup();
3614 if (rv) return 0;
3615 throwruntime("DB::remove failed");
3616 return -1;
3617 }
3618 }
3619
3620
3621 /**
3622 * Implementation of __iter__.
3623 */
db_op_iter(DB_data * data)3624 static PyObject* db_op_iter(DB_data* data) {
3625 PyObject* pycur = PyObject_CallMethod(mod_kc, (char*)"Cursor",
3626 (char*)"(O)", (PyObject*)data);
3627 PyObject* pyrv = PyObject_CallMethod(pycur, (char*)"jump", NULL);
3628 if (pyrv) Py_DECREF(pyrv);
3629 return pycur;
3630 }
3631
3632
3633 /**
3634 * Implementation of process.
3635 */
db_process(PyObject * cls,PyObject * pyargs)3636 static PyObject* db_process(PyObject* cls, PyObject* pyargs) {
3637 int32_t argc = PyTuple_Size(pyargs);
3638 if (argc < 1 || argc > 4) {
3639 throwinvarg();
3640 return NULL;
3641 }
3642 PyObject* pyproc = PyTuple_GetItem(pyargs, 0);
3643 if (!PyCallable_Check(pyproc)) {
3644 throwinvarg();
3645 return NULL;
3646 }
3647 PyObject* pypath = Py_None;
3648 if (argc > 1) pypath = PyTuple_GetItem(pyargs, 1);
3649 PyObject* pymode = Py_None;
3650 if (argc > 2) pymode = PyTuple_GetItem(pyargs, 2);
3651 PyObject* pyopts = Py_None;
3652 if (argc > 3) pyopts = PyTuple_GetItem(pyargs, 3);
3653 PyObject* pydb = PyObject_CallMethod(mod_kc, (char*)"DB", (char*)"(O)", pyopts);
3654 if (!pydb) return NULL;
3655 PyObject* pyrv = PyObject_CallMethod(pydb, (char*)"open", (char*)"(OO)", pypath, pymode);
3656 if (!PyObject_IsTrue(pyrv)) {
3657 Py_DECREF(pyrv);
3658 PyObject* pyerr = PyObject_CallMethod(pydb, (char*)"error", NULL);
3659 Py_DECREF(pydb);
3660 return pyerr;
3661 }
3662 pyrv = PyObject_CallFunction(pyproc, (char*)"(O)", pydb);
3663 if (!pyrv) {
3664 Py_DECREF(pydb);
3665 return NULL;
3666 }
3667 Py_DECREF(pyrv);
3668 pyrv = PyObject_CallMethod(pydb, (char*)"close", NULL);
3669 if (!pyrv) {
3670 Py_DECREF(pydb);
3671 return NULL;
3672 }
3673 if (!PyObject_IsTrue(pyrv)) {
3674 Py_DECREF(pyrv);
3675 PyObject* pyerr = PyObject_CallMethod(pydb, (char*)"error", NULL);
3676 Py_DECREF(pydb);
3677 return pyerr;
3678 }
3679 Py_DECREF(pyrv);
3680 Py_DECREF(pydb);
3681 Py_RETURN_NONE;
3682 }
3683
3684
3685 }
3686
3687
3688 // END OF FILE
3689