• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* row.c - an enhanced tuple for database rows
2  *
3  * Copyright (C) 2005-2010 Gerhard H�ring <gh@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 
pysqlite_row_dealloc(pysqlite_Row * self)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 *
pysqlite_row_new(PyTypeObject * type,PyObject * args,PyObject * kwargs)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 
pysqlite_row_item(pysqlite_Row * self,Py_ssize_t idx)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 
pysqlite_row_subscript(pysqlite_Row * self,PyObject * idx)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 
pysqlite_row_length(pysqlite_Row * self,PyObject * args,PyObject * kwargs)155 Py_ssize_t pysqlite_row_length(pysqlite_Row* self, PyObject* args, PyObject* kwargs)
156 {
157     return PyTuple_GET_SIZE(self->data);
158 }
159 
pysqlite_row_keys(pysqlite_Row * self,PyObject * args,PyObject * kwargs)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 
pysqlite_row_print(pysqlite_Row * self,FILE * fp,int flags)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 
pysqlite_iter(pysqlite_Row * self)186 static PyObject* pysqlite_iter(pysqlite_Row* self)
187 {
188     return PyObject_GetIter(self->data);
189 }
190 
pysqlite_row_hash(pysqlite_Row * self)191 static long pysqlite_row_hash(pysqlite_Row *self)
192 {
193     return PyObject_Hash(self->description) ^ PyObject_Hash(self->data);
194 }
195 
pysqlite_row_richcompare(pysqlite_Row * self,PyObject * _other,int opid)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 
pysqlite_row_setup_types(void)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