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