• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /* DBM module using dictionary interface */
3 /* Author: Anthony Baxter, after dbmmodule.c */
4 /* Doc strings: Mitch Chapman */
5 
6 #define PY_SSIZE_T_CLEAN
7 #include "Python.h"
8 
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include "gdbm.h"
13 
14 #if defined(WIN32) && !defined(__CYGWIN__)
15 #include "gdbmerrno.h"
16 extern const char * gdbm_strerror(gdbm_error);
17 #endif
18 
19 /*[clinic input]
20 module _gdbm
21 class _gdbm.gdbm "dbmobject *" "&Dbmtype"
22 [clinic start generated code]*/
23 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=113927c6170729b2]*/
24 
25 PyDoc_STRVAR(gdbmmodule__doc__,
26 "This module provides an interface to the GNU DBM (GDBM) library.\n\
27 \n\
28 This module is quite similar to the dbm module, but uses GDBM instead to\n\
29 provide some additional functionality.  Please note that the file formats\n\
30 created by GDBM and dbm are incompatible.\n\
31 \n\
32 GDBM objects behave like mappings (dictionaries), except that keys and\n\
33 values are always immutable bytes-like objects or strings.  Printing\n\
34 a GDBM object doesn't print the keys and values, and the items() and\n\
35 values() methods are not supported.");
36 
37 typedef struct {
38     PyObject_HEAD
39     int di_size;        /* -1 means recompute */
40     GDBM_FILE di_dbm;
41 } dbmobject;
42 
43 static PyTypeObject Dbmtype;
44 
45 #include "clinic/_gdbmmodule.c.h"
46 
47 #define is_dbmobject(v) (Py_TYPE(v) == &Dbmtype)
48 #define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
49     { PyErr_SetString(DbmError, "GDBM object has already been closed"); \
50       return NULL; }
51 
52 
53 
54 static PyObject *DbmError;
55 
56 PyDoc_STRVAR(gdbm_object__doc__,
57 "This object represents a GDBM database.\n\
58 GDBM objects behave like mappings (dictionaries), except that keys and\n\
59 values are always immutable bytes-like objects or strings.  Printing\n\
60 a GDBM object doesn't print the keys and values, and the items() and\n\
61 values() methods are not supported.\n\
62 \n\
63 GDBM objects also support additional operations such as firstkey,\n\
64 nextkey, reorganize, and sync.");
65 
66 static PyObject *
newdbmobject(const char * file,int flags,int mode)67 newdbmobject(const char *file, int flags, int mode)
68 {
69     dbmobject *dp;
70 
71     dp = PyObject_New(dbmobject, &Dbmtype);
72     if (dp == NULL)
73         return NULL;
74     dp->di_size = -1;
75     errno = 0;
76     if ((dp->di_dbm = gdbm_open((char *)file, 0, flags, mode, NULL)) == 0) {
77         if (errno != 0)
78             PyErr_SetFromErrnoWithFilename(DbmError, file);
79         else
80             PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
81         Py_DECREF(dp);
82         return NULL;
83     }
84     return (PyObject *)dp;
85 }
86 
87 /* Methods */
88 
89 static void
dbm_dealloc(dbmobject * dp)90 dbm_dealloc(dbmobject *dp)
91 {
92     if (dp->di_dbm)
93         gdbm_close(dp->di_dbm);
94     PyObject_Del(dp);
95 }
96 
97 static Py_ssize_t
dbm_length(dbmobject * dp)98 dbm_length(dbmobject *dp)
99 {
100     if (dp->di_dbm == NULL) {
101         PyErr_SetString(DbmError, "GDBM object has already been closed");
102         return -1;
103     }
104     if (dp->di_size < 0) {
105         datum key,okey;
106         int size;
107         okey.dsize=0;
108         okey.dptr=NULL;
109 
110         size = 0;
111         for (key=gdbm_firstkey(dp->di_dbm); key.dptr;
112              key = gdbm_nextkey(dp->di_dbm,okey)) {
113             size++;
114             if(okey.dsize) free(okey.dptr);
115             okey=key;
116         }
117         dp->di_size = size;
118     }
119     return dp->di_size;
120 }
121 
122 // Wrapper function for PyArg_Parse(o, "s#", &d.dptr, &d.size).
123 // This function is needed to support PY_SSIZE_T_CLEAN.
124 // Return 1 on success, same to PyArg_Parse().
125 static int
parse_datum(PyObject * o,datum * d,const char * failmsg)126 parse_datum(PyObject *o, datum *d, const char *failmsg)
127 {
128     Py_ssize_t size;
129     if (!PyArg_Parse(o, "s#", &d->dptr, &size)) {
130         if (failmsg != NULL) {
131             PyErr_SetString(PyExc_TypeError, failmsg);
132         }
133         return 0;
134     }
135     if (INT_MAX < size) {
136         PyErr_SetString(PyExc_OverflowError, "size does not fit in an int");
137         return 0;
138     }
139     d->dsize = size;
140     return 1;
141 }
142 
143 static PyObject *
dbm_subscript(dbmobject * dp,PyObject * key)144 dbm_subscript(dbmobject *dp, PyObject *key)
145 {
146     PyObject *v;
147     datum drec, krec;
148 
149     if (!parse_datum(key, &krec, NULL)) {
150         return NULL;
151     }
152     if (dp->di_dbm == NULL) {
153         PyErr_SetString(DbmError,
154                         "GDBM object has already been closed");
155         return NULL;
156     }
157     drec = gdbm_fetch(dp->di_dbm, krec);
158     if (drec.dptr == 0) {
159         PyErr_SetObject(PyExc_KeyError, key);
160         return NULL;
161     }
162     v = PyBytes_FromStringAndSize(drec.dptr, drec.dsize);
163     free(drec.dptr);
164     return v;
165 }
166 
167 /*[clinic input]
168 _gdbm.gdbm.get
169 
170     key: object
171     default: object = None
172     /
173 
174 Get the value for key, or default if not present.
175 [clinic start generated code]*/
176 
177 static PyObject *
_gdbm_gdbm_get_impl(dbmobject * self,PyObject * key,PyObject * default_value)178 _gdbm_gdbm_get_impl(dbmobject *self, PyObject *key, PyObject *default_value)
179 /*[clinic end generated code: output=19b7c585ad4f554a input=a9c20423f34c17b6]*/
180 {
181     PyObject *res;
182 
183     res = dbm_subscript(self, key);
184     if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
185         PyErr_Clear();
186         Py_INCREF(default_value);
187         return default_value;
188     }
189     return res;
190 }
191 
192 static int
dbm_ass_sub(dbmobject * dp,PyObject * v,PyObject * w)193 dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
194 {
195     datum krec, drec;
196     const char *failmsg = "gdbm mappings have bytes or string indices only";
197 
198     if (!parse_datum(v, &krec, failmsg)) {
199         return -1;
200     }
201     if (dp->di_dbm == NULL) {
202         PyErr_SetString(DbmError,
203                         "GDBM object has already been closed");
204         return -1;
205     }
206     dp->di_size = -1;
207     if (w == NULL) {
208         if (gdbm_delete(dp->di_dbm, krec) < 0) {
209             if (gdbm_errno == GDBM_ITEM_NOT_FOUND) {
210                 PyErr_SetObject(PyExc_KeyError, v);
211             }
212             else {
213                 PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
214             }
215             return -1;
216         }
217     }
218     else {
219         if (!parse_datum(w, &drec, failmsg)) {
220             return -1;
221         }
222         errno = 0;
223         if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) {
224             if (errno != 0)
225                 PyErr_SetFromErrno(DbmError);
226             else
227                 PyErr_SetString(DbmError,
228                                 gdbm_strerror(gdbm_errno));
229             return -1;
230         }
231     }
232     return 0;
233 }
234 
235 /*[clinic input]
236 _gdbm.gdbm.setdefault
237 
238     key: object
239     default: object = None
240     /
241 
242 Get value for key, or set it to default and return default if not present.
243 [clinic start generated code]*/
244 
245 static PyObject *
_gdbm_gdbm_setdefault_impl(dbmobject * self,PyObject * key,PyObject * default_value)246 _gdbm_gdbm_setdefault_impl(dbmobject *self, PyObject *key,
247                            PyObject *default_value)
248 /*[clinic end generated code: output=88760ee520329012 input=0db46b69e9680171]*/
249 {
250     PyObject *res;
251 
252     res = dbm_subscript(self, key);
253     if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
254         PyErr_Clear();
255         if (dbm_ass_sub(self, key, default_value) < 0)
256             return NULL;
257         return dbm_subscript(self, key);
258     }
259     return res;
260 }
261 
262 static PyMappingMethods dbm_as_mapping = {
263     (lenfunc)dbm_length,                /*mp_length*/
264     (binaryfunc)dbm_subscript,          /*mp_subscript*/
265     (objobjargproc)dbm_ass_sub,         /*mp_ass_subscript*/
266 };
267 
268 /*[clinic input]
269 _gdbm.gdbm.close
270 
271 Close the database.
272 [clinic start generated code]*/
273 
274 static PyObject *
_gdbm_gdbm_close_impl(dbmobject * self)275 _gdbm_gdbm_close_impl(dbmobject *self)
276 /*[clinic end generated code: output=23512a594598b563 input=0a203447379b45fd]*/
277 {
278     if (self->di_dbm)
279         gdbm_close(self->di_dbm);
280     self->di_dbm = NULL;
281     Py_RETURN_NONE;
282 }
283 
284 /* XXX Should return a set or a set view */
285 /*[clinic input]
286 _gdbm.gdbm.keys
287 
288 Get a list of all keys in the database.
289 [clinic start generated code]*/
290 
291 static PyObject *
_gdbm_gdbm_keys_impl(dbmobject * self)292 _gdbm_gdbm_keys_impl(dbmobject *self)
293 /*[clinic end generated code: output=cb4b1776c3645dcc input=1832ee0a3132cfaf]*/
294 {
295     PyObject *v, *item;
296     datum key, nextkey;
297     int err;
298 
299     if (self == NULL || !is_dbmobject(self)) {
300         PyErr_BadInternalCall();
301         return NULL;
302     }
303     check_dbmobject_open(self);
304 
305     v = PyList_New(0);
306     if (v == NULL)
307         return NULL;
308 
309     key = gdbm_firstkey(self->di_dbm);
310     while (key.dptr) {
311         item = PyBytes_FromStringAndSize(key.dptr, key.dsize);
312         if (item == NULL) {
313             free(key.dptr);
314             Py_DECREF(v);
315             return NULL;
316         }
317         err = PyList_Append(v, item);
318         Py_DECREF(item);
319         if (err != 0) {
320             free(key.dptr);
321             Py_DECREF(v);
322             return NULL;
323         }
324         nextkey = gdbm_nextkey(self->di_dbm, key);
325         free(key.dptr);
326         key = nextkey;
327     }
328     return v;
329 }
330 
331 static int
dbm_contains(PyObject * self,PyObject * arg)332 dbm_contains(PyObject *self, PyObject *arg)
333 {
334     dbmobject *dp = (dbmobject *)self;
335     datum key;
336     Py_ssize_t size;
337 
338     if ((dp)->di_dbm == NULL) {
339         PyErr_SetString(DbmError,
340                         "GDBM object has already been closed");
341         return -1;
342     }
343     if (PyUnicode_Check(arg)) {
344         key.dptr = (char *)PyUnicode_AsUTF8AndSize(arg, &size);
345         key.dsize = size;
346         if (key.dptr == NULL)
347             return -1;
348     }
349     else if (!PyBytes_Check(arg)) {
350         PyErr_Format(PyExc_TypeError,
351                      "gdbm key must be bytes or string, not %.100s",
352                      arg->ob_type->tp_name);
353         return -1;
354     }
355     else {
356         key.dptr = PyBytes_AS_STRING(arg);
357         key.dsize = PyBytes_GET_SIZE(arg);
358     }
359     return gdbm_exists(dp->di_dbm, key);
360 }
361 
362 static PySequenceMethods dbm_as_sequence = {
363         0,                      /* sq_length */
364         0,                      /* sq_concat */
365         0,                      /* sq_repeat */
366         0,                      /* sq_item */
367         0,                      /* sq_slice */
368         0,                      /* sq_ass_item */
369         0,                      /* sq_ass_slice */
370         dbm_contains,           /* sq_contains */
371         0,                      /* sq_inplace_concat */
372         0,                      /* sq_inplace_repeat */
373 };
374 
375 /*[clinic input]
376 _gdbm.gdbm.firstkey
377 
378 Return the starting key for the traversal.
379 
380 It's possible to loop over every key in the database using this method
381 and the nextkey() method.  The traversal is ordered by GDBM's internal
382 hash values, and won't be sorted by the key values.
383 [clinic start generated code]*/
384 
385 static PyObject *
_gdbm_gdbm_firstkey_impl(dbmobject * self)386 _gdbm_gdbm_firstkey_impl(dbmobject *self)
387 /*[clinic end generated code: output=9ff85628d84b65d2 input=0dbd6a335d69bba0]*/
388 {
389     PyObject *v;
390     datum key;
391 
392     check_dbmobject_open(self);
393     key = gdbm_firstkey(self->di_dbm);
394     if (key.dptr) {
395         v = PyBytes_FromStringAndSize(key.dptr, key.dsize);
396         free(key.dptr);
397         return v;
398     }
399     else {
400         Py_RETURN_NONE;
401     }
402 }
403 
404 /*[clinic input]
405 _gdbm.gdbm.nextkey
406 
407     key: str(accept={str, robuffer}, zeroes=True)
408     /
409 
410 Returns the key that follows key in the traversal.
411 
412 The following code prints every key in the database db, without having
413 to create a list in memory that contains them all:
414 
415       k = db.firstkey()
416       while k != None:
417           print(k)
418           k = db.nextkey(k)
419 [clinic start generated code]*/
420 
421 static PyObject *
_gdbm_gdbm_nextkey_impl(dbmobject * self,const char * key,Py_ssize_clean_t key_length)422 _gdbm_gdbm_nextkey_impl(dbmobject *self, const char *key,
423                         Py_ssize_clean_t key_length)
424 /*[clinic end generated code: output=192ab892de6eb2f6 input=1f1606943614e36f]*/
425 {
426     PyObject *v;
427     datum dbm_key, nextkey;
428 
429     dbm_key.dptr = (char *)key;
430     dbm_key.dsize = key_length;
431     check_dbmobject_open(self);
432     nextkey = gdbm_nextkey(self->di_dbm, dbm_key);
433     if (nextkey.dptr) {
434         v = PyBytes_FromStringAndSize(nextkey.dptr, nextkey.dsize);
435         free(nextkey.dptr);
436         return v;
437     }
438     else {
439         Py_RETURN_NONE;
440     }
441 }
442 
443 /*[clinic input]
444 _gdbm.gdbm.reorganize
445 
446 Reorganize the database.
447 
448 If you have carried out a lot of deletions and would like to shrink
449 the space used by the GDBM file, this routine will reorganize the
450 database.  GDBM will not shorten the length of a database file except
451 by using this reorganization; otherwise, deleted file space will be
452 kept and reused as new (key,value) pairs are added.
453 [clinic start generated code]*/
454 
455 static PyObject *
_gdbm_gdbm_reorganize_impl(dbmobject * self)456 _gdbm_gdbm_reorganize_impl(dbmobject *self)
457 /*[clinic end generated code: output=38d9624df92e961d input=f6bea85bcfd40dd2]*/
458 {
459     check_dbmobject_open(self);
460     errno = 0;
461     if (gdbm_reorganize(self->di_dbm) < 0) {
462         if (errno != 0)
463             PyErr_SetFromErrno(DbmError);
464         else
465             PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
466         return NULL;
467     }
468     Py_RETURN_NONE;
469 }
470 
471 /*[clinic input]
472 _gdbm.gdbm.sync
473 
474 Flush the database to the disk file.
475 
476 When the database has been opened in fast mode, this method forces
477 any unwritten data to be written to the disk.
478 [clinic start generated code]*/
479 
480 static PyObject *
_gdbm_gdbm_sync_impl(dbmobject * self)481 _gdbm_gdbm_sync_impl(dbmobject *self)
482 /*[clinic end generated code: output=488b15f47028f125 input=2a47d2c9e153ab8a]*/
483 {
484     check_dbmobject_open(self);
485     gdbm_sync(self->di_dbm);
486     Py_RETURN_NONE;
487 }
488 
489 static PyObject *
dbm__enter__(PyObject * self,PyObject * args)490 dbm__enter__(PyObject *self, PyObject *args)
491 {
492     Py_INCREF(self);
493     return self;
494 }
495 
496 static PyObject *
dbm__exit__(PyObject * self,PyObject * args)497 dbm__exit__(PyObject *self, PyObject *args)
498 {
499     _Py_IDENTIFIER(close);
500     return _PyObject_CallMethodId(self, &PyId_close, NULL);
501 }
502 
503 static PyMethodDef dbm_methods[] = {
504     _GDBM_GDBM_CLOSE_METHODDEF
505     _GDBM_GDBM_KEYS_METHODDEF
506     _GDBM_GDBM_FIRSTKEY_METHODDEF
507     _GDBM_GDBM_NEXTKEY_METHODDEF
508     _GDBM_GDBM_REORGANIZE_METHODDEF
509     _GDBM_GDBM_SYNC_METHODDEF
510     _GDBM_GDBM_GET_METHODDEF
511     _GDBM_GDBM_SETDEFAULT_METHODDEF
512     {"__enter__", dbm__enter__, METH_NOARGS, NULL},
513     {"__exit__",  dbm__exit__, METH_VARARGS, NULL},
514     {NULL,              NULL}           /* sentinel */
515 };
516 
517 static PyTypeObject Dbmtype = {
518     PyVarObject_HEAD_INIT(0, 0)
519     "_gdbm.gdbm",
520     sizeof(dbmobject),
521     0,
522     (destructor)dbm_dealloc,            /*tp_dealloc*/
523     0,                                  /*tp_vectorcall_offset*/
524     0,                                  /*tp_getattr*/
525     0,                                  /*tp_setattr*/
526     0,                                  /*tp_as_async*/
527     0,                                  /*tp_repr*/
528     0,                                  /*tp_as_number*/
529     &dbm_as_sequence,                   /*tp_as_sequence*/
530     &dbm_as_mapping,                    /*tp_as_mapping*/
531     0,                                  /*tp_hash*/
532     0,                                  /*tp_call*/
533     0,                                  /*tp_str*/
534     0,                                  /*tp_getattro*/
535     0,                                  /*tp_setattro*/
536     0,                                  /*tp_as_buffer*/
537     Py_TPFLAGS_DEFAULT,                 /*tp_xxx4*/
538     gdbm_object__doc__,                 /*tp_doc*/
539     0,                                  /*tp_traverse*/
540     0,                                  /*tp_clear*/
541     0,                                  /*tp_richcompare*/
542     0,                                  /*tp_weaklistoffset*/
543     0,                                  /*tp_iter*/
544     0,                                  /*tp_iternext*/
545     dbm_methods,                        /*tp_methods*/
546 };
547 
548 /* ----------------------------------------------------------------- */
549 
550 /*[clinic input]
551 _gdbm.open as dbmopen
552     filename: unicode
553     flags: str="r"
554     mode: int(py_default="0o666") = 0o666
555     /
556 
557 Open a dbm database and return a dbm object.
558 
559 The filename argument is the name of the database file.
560 
561 The optional flags argument can be 'r' (to open an existing database
562 for reading only -- default), 'w' (to open an existing database for
563 reading and writing), 'c' (which creates the database if it doesn't
564 exist), or 'n' (which always creates a new empty database).
565 
566 Some versions of gdbm support additional flags which must be
567 appended to one of the flags described above.  The module constant
568 'open_flags' is a string of valid additional flags.  The 'f' flag
569 opens the database in fast mode; altered data will not automatically
570 be written to the disk after every change.  This results in faster
571 writes to the database, but may result in an inconsistent database
572 if the program crashes while the database is still open.  Use the
573 sync() method to force any unwritten data to be written to the disk.
574 The 's' flag causes all database operations to be synchronized to
575 disk.  The 'u' flag disables locking of the database file.
576 
577 The optional mode argument is the Unix mode of the file, used only
578 when the database has to be created.  It defaults to octal 0o666.
579 [clinic start generated code]*/
580 
581 static PyObject *
dbmopen_impl(PyObject * module,PyObject * filename,const char * flags,int mode)582 dbmopen_impl(PyObject *module, PyObject *filename, const char *flags,
583              int mode)
584 /*[clinic end generated code: output=9527750f5df90764 input=3be0b0875974b928]*/
585 {
586     int iflags;
587 
588     switch (flags[0]) {
589     case 'r':
590         iflags = GDBM_READER;
591         break;
592     case 'w':
593         iflags = GDBM_WRITER;
594         break;
595     case 'c':
596         iflags = GDBM_WRCREAT;
597         break;
598     case 'n':
599         iflags = GDBM_NEWDB;
600         break;
601     default:
602         PyErr_SetString(DbmError,
603                         "First flag must be one of 'r', 'w', 'c' or 'n'");
604         return NULL;
605     }
606     for (flags++; *flags != '\0'; flags++) {
607         char buf[40];
608         switch (*flags) {
609 #ifdef GDBM_FAST
610             case 'f':
611                 iflags |= GDBM_FAST;
612                 break;
613 #endif
614 #ifdef GDBM_SYNC
615             case 's':
616                 iflags |= GDBM_SYNC;
617                 break;
618 #endif
619 #ifdef GDBM_NOLOCK
620             case 'u':
621                 iflags |= GDBM_NOLOCK;
622                 break;
623 #endif
624             default:
625                 PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.",
626                               *flags);
627                 PyErr_SetString(DbmError, buf);
628                 return NULL;
629         }
630     }
631 
632     PyObject *filenamebytes = PyUnicode_EncodeFSDefault(filename);
633     if (filenamebytes == NULL) {
634         return NULL;
635     }
636     const char *name = PyBytes_AS_STRING(filenamebytes);
637     if (strlen(name) != (size_t)PyBytes_GET_SIZE(filenamebytes)) {
638         Py_DECREF(filenamebytes);
639         PyErr_SetString(PyExc_ValueError, "embedded null character");
640         return NULL;
641     }
642     PyObject *self = newdbmobject(name, iflags, mode);
643     Py_DECREF(filenamebytes);
644     return self;
645 }
646 
647 static const char dbmmodule_open_flags[] = "rwcn"
648 #ifdef GDBM_FAST
649                                      "f"
650 #endif
651 #ifdef GDBM_SYNC
652                                      "s"
653 #endif
654 #ifdef GDBM_NOLOCK
655                                      "u"
656 #endif
657                                      ;
658 
659 static PyMethodDef dbmmodule_methods[] = {
660     DBMOPEN_METHODDEF
661     { 0, 0 },
662 };
663 
664 
665 static struct PyModuleDef _gdbmmodule = {
666         PyModuleDef_HEAD_INIT,
667         "_gdbm",
668         gdbmmodule__doc__,
669         -1,
670         dbmmodule_methods,
671         NULL,
672         NULL,
673         NULL,
674         NULL
675 };
676 
677 PyMODINIT_FUNC
PyInit__gdbm(void)678 PyInit__gdbm(void) {
679     PyObject *m;
680 
681     if (PyType_Ready(&Dbmtype) < 0)
682             return NULL;
683     m = PyModule_Create(&_gdbmmodule);
684     if (m == NULL) {
685         return NULL;
686     }
687 
688     DbmError = PyErr_NewException("_gdbm.error", PyExc_OSError, NULL);
689     if (DbmError == NULL) {
690         goto error;
691     }
692     Py_INCREF(DbmError);
693     if (PyModule_AddObject(m, "error", DbmError) < 0) {
694         Py_DECREF(DbmError);
695         goto error;
696     }
697 
698     if (PyModule_AddStringConstant(m, "open_flags",
699                                    dbmmodule_open_flags) < 0) {
700         goto error;
701     }
702 
703 #if defined(GDBM_VERSION_MAJOR) && defined(GDBM_VERSION_MINOR) && \
704     defined(GDBM_VERSION_PATCH)
705     PyObject *obj = Py_BuildValue("iii", GDBM_VERSION_MAJOR,
706                                   GDBM_VERSION_MINOR, GDBM_VERSION_PATCH);
707     if (obj == NULL) {
708         goto error;
709     }
710     if (PyModule_AddObject(m, "_GDBM_VERSION", obj) < 0) {
711         Py_DECREF(obj);
712         goto error;
713     }
714 #endif
715 
716     return m;
717 
718 error:
719     Py_DECREF(m);
720     return NULL;
721 }
722