Home | History | Annotate | Download | only in _sqlite
      1 /* row.c - an enhanced tuple for database rows
      2  *
      3  * Copyright (C) 2005-2010 Gerhard Hring <gh (at) ghaering.de>
      4  *
      5  * This file is part of pysqlite.
      6  *
      7  * This software is provided 'as-is', without any express or implied
      8  * warranty.  In no event will the authors be held liable for any damages
      9  * arising from the use of this software.
     10  *
     11  * Permission is granted to anyone to use this software for any purpose,
     12  * including commercial applications, and to alter it and redistribute it
     13  * freely, subject to the following restrictions:
     14  *
     15  * 1. The origin of this software must not be misrepresented; you must not
     16  *    claim that you wrote the original software. If you use this software
     17  *    in a product, an acknowledgment in the product documentation would be
     18  *    appreciated but is not required.
     19  * 2. Altered source versions must be plainly marked as such, and must not be
     20  *    misrepresented as being the original software.
     21  * 3. This notice may not be removed or altered from any source distribution.
     22  */
     23 
     24 #include "row.h"
     25 #include "cursor.h"
     26 #include "sqlitecompat.h"
     27 
     28 void pysqlite_row_dealloc(pysqlite_Row* self)
     29 {
     30     Py_XDECREF(self->data);
     31     Py_XDECREF(self->description);
     32 
     33     Py_TYPE(self)->tp_free((PyObject*)self);
     34 }
     35 
     36 static PyObject *
     37 pysqlite_row_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
     38 {
     39     pysqlite_Row *self;
     40     PyObject* data;
     41     pysqlite_Cursor* cursor;
     42 
     43     assert(type != NULL && type->tp_alloc != NULL);
     44 
     45     if (!_PyArg_NoKeywords("Row()", kwargs))
     46         return NULL;
     47     if (!PyArg_ParseTuple(args, "OO", &cursor, &data))
     48         return NULL;
     49 
     50     if (!PyObject_TypeCheck((PyObject*)cursor, &pysqlite_CursorType)) {
     51         PyErr_SetString(PyExc_TypeError, "instance of cursor required for first argument");
     52         return NULL;
     53     }
     54 
     55     if (!PyTuple_Check(data)) {
     56         PyErr_SetString(PyExc_TypeError, "tuple required for second argument");
     57         return NULL;
     58     }
     59 
     60     self = (pysqlite_Row *) type->tp_alloc(type, 0);
     61     if (self == NULL)
     62         return NULL;
     63 
     64     Py_INCREF(data);
     65     self->data = data;
     66 
     67     Py_INCREF(cursor->description);
     68     self->description = cursor->description;
     69 
     70     return (PyObject *) self;
     71 }
     72 
     73 PyObject* pysqlite_row_item(pysqlite_Row* self, Py_ssize_t idx)
     74 {
     75    PyObject* item = PyTuple_GetItem(self->data, idx);
     76    Py_XINCREF(item);
     77    return item;
     78 }
     79 
     80 PyObject* pysqlite_row_subscript(pysqlite_Row* self, PyObject* idx)
     81 {
     82     Py_ssize_t _idx;
     83     char* key;
     84     int nitems, i;
     85     char* compare_key;
     86 
     87     char* p1;
     88     char* p2;
     89 
     90     PyObject* item;
     91 
     92     if (PyInt_Check(idx)) {
     93         _idx = PyInt_AsLong(idx);
     94         if (_idx < 0)
     95            _idx += PyTuple_GET_SIZE(self->data);
     96         item = PyTuple_GetItem(self->data, _idx);
     97         Py_XINCREF(item);
     98         return item;
     99     } else if (PyLong_Check(idx)) {
    100         _idx = PyNumber_AsSsize_t(idx, PyExc_IndexError);
    101         if (_idx == -1 && PyErr_Occurred())
    102             return NULL;
    103         if (_idx < 0)
    104            _idx += PyTuple_GET_SIZE(self->data);
    105         item = PyTuple_GetItem(self->data, _idx);
    106         Py_XINCREF(item);
    107         return item;
    108     } else if (PyString_Check(idx)) {
    109         key = PyString_AsString(idx);
    110 
    111         nitems = PyTuple_Size(self->description);
    112 
    113         for (i = 0; i < nitems; i++) {
    114             compare_key = PyString_AsString(PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0));
    115             if (!compare_key) {
    116                 return NULL;
    117             }
    118 
    119             p1 = key;
    120             p2 = compare_key;
    121 
    122             while (1) {
    123                 if ((*p1 == (char)0) || (*p2 == (char)0)) {
    124                     break;
    125                 }
    126 
    127                 if ((*p1 | 0x20) != (*p2 | 0x20)) {
    128                     break;
    129                 }
    130 
    131                 p1++;
    132                 p2++;
    133             }
    134 
    135             if ((*p1 == (char)0) && (*p2 == (char)0)) {
    136                 /* found item */
    137                 item = PyTuple_GetItem(self->data, i);
    138                 Py_INCREF(item);
    139                 return item;
    140             }
    141 
    142         }
    143 
    144         PyErr_SetString(PyExc_IndexError, "No item with that key");
    145         return NULL;
    146     } else if (PySlice_Check(idx)) {
    147         PyErr_SetString(PyExc_ValueError, "slices not implemented, yet");
    148         return NULL;
    149     } else {
    150         PyErr_SetString(PyExc_IndexError, "Index must be int or string");
    151         return NULL;
    152     }
    153 }
    154 
    155 Py_ssize_t pysqlite_row_length(pysqlite_Row* self, PyObject* args, PyObject* kwargs)
    156 {
    157     return PyTuple_GET_SIZE(self->data);
    158 }
    159 
    160 PyObject* pysqlite_row_keys(pysqlite_Row* self, PyObject* args, PyObject* kwargs)
    161 {
    162     PyObject* list;
    163     int nitems, i;
    164 
    165     list = PyList_New(0);
    166     if (!list) {
    167         return NULL;
    168     }
    169     nitems = PyTuple_Size(self->description);
    170 
    171     for (i = 0; i < nitems; i++) {
    172         if (PyList_Append(list, PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)) != 0) {
    173             Py_DECREF(list);
    174             return NULL;
    175         }
    176     }
    177 
    178     return list;
    179 }
    180 
    181 static int pysqlite_row_print(pysqlite_Row* self, FILE *fp, int flags)
    182 {
    183     return (&PyTuple_Type)->tp_print(self->data, fp, flags);
    184 }
    185 
    186 static PyObject* pysqlite_iter(pysqlite_Row* self)
    187 {
    188     return PyObject_GetIter(self->data);
    189 }
    190 
    191 static long pysqlite_row_hash(pysqlite_Row *self)
    192 {
    193     return PyObject_Hash(self->description) ^ PyObject_Hash(self->data);
    194 }
    195 
    196 static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other, int opid)
    197 {
    198     if (opid != Py_EQ && opid != Py_NE) {
    199         Py_INCREF(Py_NotImplemented);
    200         return Py_NotImplemented;
    201     }
    202     if (PyType_IsSubtype(Py_TYPE(_other), &pysqlite_RowType)) {
    203         pysqlite_Row *other = (pysqlite_Row *)_other;
    204         PyObject *res = PyObject_RichCompare(self->description, other->description, opid);
    205         if ((opid == Py_EQ && res == Py_True)
    206             || (opid == Py_NE && res == Py_False)) {
    207             Py_DECREF(res);
    208             return PyObject_RichCompare(self->data, other->data, opid);
    209         }
    210     }
    211     Py_INCREF(Py_NotImplemented);
    212     return Py_NotImplemented;
    213 }
    214 
    215 PyMappingMethods pysqlite_row_as_mapping = {
    216     /* mp_length        */ (lenfunc)pysqlite_row_length,
    217     /* mp_subscript     */ (binaryfunc)pysqlite_row_subscript,
    218     /* mp_ass_subscript */ (objobjargproc)0,
    219 };
    220 
    221 static PySequenceMethods pysqlite_row_as_sequence = {
    222    /* sq_length */         (lenfunc)pysqlite_row_length,
    223    /* sq_concat */         0,
    224    /* sq_repeat */         0,
    225    /* sq_item */           (ssizeargfunc)pysqlite_row_item,
    226 };
    227 
    228 
    229 static PyMethodDef pysqlite_row_methods[] = {
    230     {"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS,
    231         PyDoc_STR("Returns the keys of the row.")},
    232     {NULL, NULL}
    233 };
    234 
    235 
    236 PyTypeObject pysqlite_RowType = {
    237         PyVarObject_HEAD_INIT(NULL, 0)
    238         MODULE_NAME ".Row",                             /* tp_name */
    239         sizeof(pysqlite_Row),                           /* tp_basicsize */
    240         0,                                              /* tp_itemsize */
    241         (destructor)pysqlite_row_dealloc,               /* tp_dealloc */
    242         (printfunc)pysqlite_row_print,                  /* tp_print */
    243         0,                                              /* tp_getattr */
    244         0,                                              /* tp_setattr */
    245         0,                                              /* tp_compare */
    246         0,                                              /* tp_repr */
    247         0,                                              /* tp_as_number */
    248         0,                                              /* tp_as_sequence */
    249         0,                                              /* tp_as_mapping */
    250         (hashfunc)pysqlite_row_hash,                    /* tp_hash */
    251         0,                                              /* tp_call */
    252         0,                                              /* tp_str */
    253         0,                                              /* tp_getattro */
    254         0,                                              /* tp_setattro */
    255         0,                                              /* tp_as_buffer */
    256         Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,         /* tp_flags */
    257         0,                                              /* tp_doc */
    258         (traverseproc)0,                                /* tp_traverse */
    259         0,                                              /* tp_clear */
    260         (richcmpfunc)pysqlite_row_richcompare,          /* tp_richcompare */
    261         0,                                              /* tp_weaklistoffset */
    262         (getiterfunc)pysqlite_iter,                     /* tp_iter */
    263         0,                                              /* tp_iternext */
    264         pysqlite_row_methods,                           /* tp_methods */
    265         0,                                              /* tp_members */
    266         0,                                              /* tp_getset */
    267         0,                                              /* tp_base */
    268         0,                                              /* tp_dict */
    269         0,                                              /* tp_descr_get */
    270         0,                                              /* tp_descr_set */
    271         0,                                              /* tp_dictoffset */
    272         0,                                              /* tp_init */
    273         0,                                              /* tp_alloc */
    274         0,                                              /* tp_new */
    275         0                                               /* tp_free */
    276 };
    277 
    278 extern int pysqlite_row_setup_types(void)
    279 {
    280     pysqlite_RowType.tp_new = pysqlite_row_new;
    281     pysqlite_RowType.tp_as_mapping = &pysqlite_row_as_mapping;
    282     pysqlite_RowType.tp_as_sequence = &pysqlite_row_as_sequence;
    283     return PyType_Ready(&pysqlite_RowType);
    284 }
    285