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