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 
     27 void pysqlite_row_dealloc(pysqlite_Row* self)
     28 {
     29     Py_XDECREF(self->data);
     30     Py_XDECREF(self->description);
     31 
     32     Py_TYPE(self)->tp_free((PyObject*)self);
     33 }
     34 
     35 static PyObject *
     36 pysqlite_row_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
     37 {
     38     pysqlite_Row *self;
     39     PyObject* data;
     40     pysqlite_Cursor* cursor;
     41 
     42     assert(type != NULL && type->tp_alloc != NULL);
     43 
     44     if (!_PyArg_NoKeywords("Row()", kwargs))
     45         return NULL;
     46     if (!PyArg_ParseTuple(args, "OO", &cursor, &data))
     47         return NULL;
     48 
     49     if (!PyObject_TypeCheck((PyObject*)cursor, &pysqlite_CursorType)) {
     50         PyErr_SetString(PyExc_TypeError, "instance of cursor required for first argument");
     51         return NULL;
     52     }
     53 
     54     if (!PyTuple_Check(data)) {
     55         PyErr_SetString(PyExc_TypeError, "tuple required for second argument");
     56         return NULL;
     57     }
     58 
     59     self = (pysqlite_Row *) type->tp_alloc(type, 0);
     60     if (self == NULL)
     61         return NULL;
     62 
     63     Py_INCREF(data);
     64     self->data = data;
     65 
     66     Py_INCREF(cursor->description);
     67     self->description = cursor->description;
     68 
     69     return (PyObject *) self;
     70 }
     71 
     72 PyObject* pysqlite_row_item(pysqlite_Row* self, Py_ssize_t idx)
     73 {
     74    PyObject* item = PyTuple_GetItem(self->data, idx);
     75    Py_XINCREF(item);
     76    return item;
     77 }
     78 
     79 PyObject* pysqlite_row_subscript(pysqlite_Row* self, PyObject* idx)
     80 {
     81     Py_ssize_t _idx;
     82     char* key;
     83     Py_ssize_t nitems, i;
     84     char* compare_key;
     85 
     86     char* p1;
     87     char* p2;
     88 
     89     PyObject* item;
     90 
     91     if (PyLong_Check(idx)) {
     92         _idx = PyNumber_AsSsize_t(idx, PyExc_IndexError);
     93         if (_idx == -1 && PyErr_Occurred())
     94             return NULL;
     95         if (_idx < 0)
     96            _idx += PyTuple_GET_SIZE(self->data);
     97         item = PyTuple_GetItem(self->data, _idx);
     98         Py_XINCREF(item);
     99         return item;
    100     } else if (PyUnicode_Check(idx)) {
    101         key = PyUnicode_AsUTF8(idx);
    102         if (key == NULL)
    103             return NULL;
    104 
    105         nitems = PyTuple_Size(self->description);
    106 
    107         for (i = 0; i < nitems; i++) {
    108             PyObject *obj;
    109             obj = PyTuple_GET_ITEM(self->description, i);
    110             obj = PyTuple_GET_ITEM(obj, 0);
    111             compare_key = PyUnicode_AsUTF8(obj);
    112             if (!compare_key) {
    113                 return NULL;
    114             }
    115 
    116             p1 = key;
    117             p2 = compare_key;
    118 
    119             while (1) {
    120                 if ((*p1 == (char)0) || (*p2 == (char)0)) {
    121                     break;
    122                 }
    123 
    124                 if ((*p1 | 0x20) != (*p2 | 0x20)) {
    125                     break;
    126                 }
    127 
    128                 p1++;
    129                 p2++;
    130             }
    131 
    132             if ((*p1 == (char)0) && (*p2 == (char)0)) {
    133                 /* found item */
    134                 item = PyTuple_GetItem(self->data, i);
    135                 Py_INCREF(item);
    136                 return item;
    137             }
    138 
    139         }
    140 
    141         PyErr_SetString(PyExc_IndexError, "No item with that key");
    142         return NULL;
    143     }
    144     else if (PySlice_Check(idx)) {
    145         return PyObject_GetItem(self->data, idx);
    146     }
    147     else {
    148         PyErr_SetString(PyExc_IndexError, "Index must be int or string");
    149         return NULL;
    150     }
    151 }
    152 
    153 Py_ssize_t pysqlite_row_length(pysqlite_Row* self, PyObject* args, PyObject* kwargs)
    154 {
    155     return PyTuple_GET_SIZE(self->data);
    156 }
    157 
    158 PyObject* pysqlite_row_keys(pysqlite_Row* self, PyObject* args, PyObject* kwargs)
    159 {
    160     PyObject* list;
    161     Py_ssize_t nitems, i;
    162 
    163     list = PyList_New(0);
    164     if (!list) {
    165         return NULL;
    166     }
    167     nitems = PyTuple_Size(self->description);
    168 
    169     for (i = 0; i < nitems; i++) {
    170         if (PyList_Append(list, PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)) != 0) {
    171             Py_DECREF(list);
    172             return NULL;
    173         }
    174     }
    175 
    176     return list;
    177 }
    178 
    179 static int pysqlite_row_print(pysqlite_Row* self, FILE *fp, int flags)
    180 {
    181     return (&PyTuple_Type)->tp_print(self->data, fp, flags);
    182 }
    183 
    184 static PyObject* pysqlite_iter(pysqlite_Row* self)
    185 {
    186     return PyObject_GetIter(self->data);
    187 }
    188 
    189 static Py_hash_t pysqlite_row_hash(pysqlite_Row *self)
    190 {
    191     return PyObject_Hash(self->description) ^ PyObject_Hash(self->data);
    192 }
    193 
    194 static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other, int opid)
    195 {
    196     if (opid != Py_EQ && opid != Py_NE)
    197         Py_RETURN_NOTIMPLEMENTED;
    198 
    199     if (PyType_IsSubtype(Py_TYPE(_other), &pysqlite_RowType)) {
    200         pysqlite_Row *other = (pysqlite_Row *)_other;
    201         PyObject *res = PyObject_RichCompare(self->description, other->description, opid);
    202         if ((opid == Py_EQ && res == Py_True)
    203             || (opid == Py_NE && res == Py_False)) {
    204             Py_DECREF(res);
    205             return PyObject_RichCompare(self->data, other->data, opid);
    206         }
    207     }
    208     Py_RETURN_NOTIMPLEMENTED;
    209 }
    210 
    211 PyMappingMethods pysqlite_row_as_mapping = {
    212     /* mp_length        */ (lenfunc)pysqlite_row_length,
    213     /* mp_subscript     */ (binaryfunc)pysqlite_row_subscript,
    214     /* mp_ass_subscript */ (objobjargproc)0,
    215 };
    216 
    217 static PySequenceMethods pysqlite_row_as_sequence = {
    218    /* sq_length */         (lenfunc)pysqlite_row_length,
    219    /* sq_concat */         0,
    220    /* sq_repeat */         0,
    221    /* sq_item */           (ssizeargfunc)pysqlite_row_item,
    222 };
    223 
    224 
    225 static PyMethodDef pysqlite_row_methods[] = {
    226     {"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS,
    227         PyDoc_STR("Returns the keys of the row.")},
    228     {NULL, NULL}
    229 };
    230 
    231 
    232 PyTypeObject pysqlite_RowType = {
    233         PyVarObject_HEAD_INIT(NULL, 0)
    234         MODULE_NAME ".Row",                             /* tp_name */
    235         sizeof(pysqlite_Row),                           /* tp_basicsize */
    236         0,                                              /* tp_itemsize */
    237         (destructor)pysqlite_row_dealloc,               /* tp_dealloc */
    238         (printfunc)pysqlite_row_print,                  /* tp_print */
    239         0,                                              /* tp_getattr */
    240         0,                                              /* tp_setattr */
    241         0,                                              /* tp_reserved */
    242         0,                                              /* tp_repr */
    243         0,                                              /* tp_as_number */
    244         0,                                              /* tp_as_sequence */
    245         0,                                              /* tp_as_mapping */
    246         (hashfunc)pysqlite_row_hash,                    /* tp_hash */
    247         0,                                              /* tp_call */
    248         0,                                              /* tp_str */
    249         0,                                              /* tp_getattro */
    250         0,                                              /* tp_setattro */
    251         0,                                              /* tp_as_buffer */
    252         Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE,         /* tp_flags */
    253         0,                                              /* tp_doc */
    254         (traverseproc)0,                                /* tp_traverse */
    255         0,                                              /* tp_clear */
    256         (richcmpfunc)pysqlite_row_richcompare,          /* tp_richcompare */
    257         0,                                              /* tp_weaklistoffset */
    258         (getiterfunc)pysqlite_iter,                     /* tp_iter */
    259         0,                                              /* tp_iternext */
    260         pysqlite_row_methods,                           /* tp_methods */
    261         0,                                              /* tp_members */
    262         0,                                              /* tp_getset */
    263         0,                                              /* tp_base */
    264         0,                                              /* tp_dict */
    265         0,                                              /* tp_descr_get */
    266         0,                                              /* tp_descr_set */
    267         0,                                              /* tp_dictoffset */
    268         0,                                              /* tp_init */
    269         0,                                              /* tp_alloc */
    270         0,                                              /* tp_new */
    271         0                                               /* tp_free */
    272 };
    273 
    274 extern int pysqlite_row_setup_types(void)
    275 {
    276     pysqlite_RowType.tp_new = pysqlite_row_new;
    277     pysqlite_RowType.tp_as_mapping = &pysqlite_row_as_mapping;
    278     pysqlite_RowType.tp_as_sequence = &pysqlite_row_as_sequence;
    279     return PyType_Ready(&pysqlite_RowType);
    280 }
    281