• 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 #ifndef Py_BUILD_CORE_BUILTIN
25 #  define Py_BUILD_CORE_MODULE 1
26 #endif
27 
28 #include "row.h"
29 #include "cursor.h"
30 
31 #define clinic_state() (pysqlite_get_state_by_type(type))
32 #include "clinic/row.c.h"
33 #undef clinic_state
34 
35 /*[clinic input]
36 module _sqlite3
37 class _sqlite3.Row "pysqlite_Row *" "clinic_state()->RowType"
38 [clinic start generated code]*/
39 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=966c53403d7f3a40]*/
40 
41 static int
row_clear(pysqlite_Row * self)42 row_clear(pysqlite_Row *self)
43 {
44     Py_CLEAR(self->data);
45     Py_CLEAR(self->description);
46     return 0;
47 }
48 
49 static int
row_traverse(pysqlite_Row * self,visitproc visit,void * arg)50 row_traverse(pysqlite_Row *self, visitproc visit, void *arg)
51 {
52     Py_VISIT(Py_TYPE(self));
53     Py_VISIT(self->data);
54     Py_VISIT(self->description);
55     return 0;
56 }
57 
58 static void
pysqlite_row_dealloc(PyObject * self)59 pysqlite_row_dealloc(PyObject *self)
60 {
61     PyTypeObject *tp = Py_TYPE(self);
62     PyObject_GC_UnTrack(self);
63     tp->tp_clear(self);
64     tp->tp_free(self);
65     Py_DECREF(tp);
66 }
67 
68 /*[clinic input]
69 @classmethod
70 _sqlite3.Row.__new__ as pysqlite_row_new
71 
72     cursor: object(type='pysqlite_Cursor *', subclass_of='clinic_state()->CursorType')
73     data: object(subclass_of='&PyTuple_Type')
74     /
75 
76 [clinic start generated code]*/
77 
78 static PyObject *
pysqlite_row_new_impl(PyTypeObject * type,pysqlite_Cursor * cursor,PyObject * data)79 pysqlite_row_new_impl(PyTypeObject *type, pysqlite_Cursor *cursor,
80                       PyObject *data)
81 /*[clinic end generated code: output=10d58b09a819a4c1 input=b9e954ca31345dbf]*/
82 {
83     pysqlite_Row *self;
84 
85     assert(type != NULL && type->tp_alloc != NULL);
86 
87     self = (pysqlite_Row *) type->tp_alloc(type, 0);
88     if (self == NULL)
89         return NULL;
90 
91     self->data = Py_NewRef(data);
92     self->description = Py_NewRef(cursor->description);
93 
94     return (PyObject *) self;
95 }
96 
pysqlite_row_item(pysqlite_Row * self,Py_ssize_t idx)97 PyObject* pysqlite_row_item(pysqlite_Row* self, Py_ssize_t idx)
98 {
99    PyObject *item = PyTuple_GetItem(self->data, idx);
100    return Py_XNewRef(item);
101 }
102 
103 static int
equal_ignore_case(PyObject * left,PyObject * right)104 equal_ignore_case(PyObject *left, PyObject *right)
105 {
106     int eq = PyObject_RichCompareBool(left, right, Py_EQ);
107     if (eq) { /* equal or error */
108         return eq;
109     }
110     if (!PyUnicode_Check(left) || !PyUnicode_Check(right)) {
111         return 0;
112     }
113     if (!PyUnicode_IS_ASCII(left) || !PyUnicode_IS_ASCII(right)) {
114         return 0;
115     }
116 
117     Py_ssize_t len = PyUnicode_GET_LENGTH(left);
118     if (PyUnicode_GET_LENGTH(right) != len) {
119         return 0;
120     }
121     const Py_UCS1 *p1 = PyUnicode_1BYTE_DATA(left);
122     const Py_UCS1 *p2 = PyUnicode_1BYTE_DATA(right);
123     for (; len; len--, p1++, p2++) {
124         if (Py_TOLOWER(*p1) != Py_TOLOWER(*p2)) {
125             return 0;
126         }
127     }
128     return 1;
129 }
130 
131 static PyObject *
pysqlite_row_subscript(pysqlite_Row * self,PyObject * idx)132 pysqlite_row_subscript(pysqlite_Row *self, PyObject *idx)
133 {
134     Py_ssize_t _idx;
135     Py_ssize_t nitems, i;
136 
137     if (PyLong_Check(idx)) {
138         _idx = PyNumber_AsSsize_t(idx, PyExc_IndexError);
139         if (_idx == -1 && PyErr_Occurred())
140             return NULL;
141         if (_idx < 0)
142            _idx += PyTuple_GET_SIZE(self->data);
143 
144         PyObject *item = PyTuple_GetItem(self->data, _idx);
145         return Py_XNewRef(item);
146     } else if (PyUnicode_Check(idx)) {
147         nitems = PyTuple_Size(self->description);
148 
149         for (i = 0; i < nitems; i++) {
150             PyObject *obj;
151             obj = PyTuple_GET_ITEM(self->description, i);
152             obj = PyTuple_GET_ITEM(obj, 0);
153             int eq = equal_ignore_case(idx, obj);
154             if (eq < 0) {
155                 return NULL;
156             }
157             if (eq) {
158                 /* found item */
159                 PyObject *item = PyTuple_GetItem(self->data, i);
160                 return Py_XNewRef(item);
161             }
162         }
163 
164         PyErr_SetString(PyExc_IndexError, "No item with that key");
165         return NULL;
166     }
167     else if (PySlice_Check(idx)) {
168         return PyObject_GetItem(self->data, idx);
169     }
170     else {
171         PyErr_SetString(PyExc_IndexError, "Index must be int or string");
172         return NULL;
173     }
174 }
175 
176 static Py_ssize_t
pysqlite_row_length(pysqlite_Row * self)177 pysqlite_row_length(pysqlite_Row* self)
178 {
179     return PyTuple_GET_SIZE(self->data);
180 }
181 
182 /*[clinic input]
183 _sqlite3.Row.keys as pysqlite_row_keys
184 
185 Returns the keys of the row.
186 [clinic start generated code]*/
187 
188 static PyObject *
pysqlite_row_keys_impl(pysqlite_Row * self)189 pysqlite_row_keys_impl(pysqlite_Row *self)
190 /*[clinic end generated code: output=efe3dfb3af6edc07 input=7549a122827c5563]*/
191 {
192     PyObject* list;
193     Py_ssize_t nitems, i;
194 
195     list = PyList_New(0);
196     if (!list) {
197         return NULL;
198     }
199     nitems = PyTuple_Size(self->description);
200 
201     for (i = 0; i < nitems; i++) {
202         if (PyList_Append(list, PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)) != 0) {
203             Py_DECREF(list);
204             return NULL;
205         }
206     }
207 
208     return list;
209 }
210 
pysqlite_iter(pysqlite_Row * self)211 static PyObject* pysqlite_iter(pysqlite_Row* self)
212 {
213     return PyObject_GetIter(self->data);
214 }
215 
pysqlite_row_hash(pysqlite_Row * self)216 static Py_hash_t pysqlite_row_hash(pysqlite_Row *self)
217 {
218     return PyObject_Hash(self->description) ^ PyObject_Hash(self->data);
219 }
220 
pysqlite_row_richcompare(pysqlite_Row * self,PyObject * _other,int opid)221 static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other, int opid)
222 {
223     if (opid != Py_EQ && opid != Py_NE)
224         Py_RETURN_NOTIMPLEMENTED;
225 
226     pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(self));
227     if (PyObject_TypeCheck(_other, state->RowType)) {
228         pysqlite_Row *other = (pysqlite_Row *)_other;
229         int eq = PyObject_RichCompareBool(self->description, other->description, Py_EQ);
230         if (eq < 0) {
231             return NULL;
232         }
233         if (eq) {
234             return PyObject_RichCompare(self->data, other->data, opid);
235         }
236         return PyBool_FromLong(opid != Py_EQ);
237     }
238     Py_RETURN_NOTIMPLEMENTED;
239 }
240 
241 static PyMethodDef row_methods[] = {
242     PYSQLITE_ROW_KEYS_METHODDEF
243     {NULL, NULL}
244 };
245 
246 static PyType_Slot row_slots[] = {
247     {Py_tp_dealloc, pysqlite_row_dealloc},
248     {Py_tp_hash, pysqlite_row_hash},
249     {Py_tp_methods, row_methods},
250     {Py_tp_richcompare, pysqlite_row_richcompare},
251     {Py_tp_iter, pysqlite_iter},
252     {Py_mp_length, pysqlite_row_length},
253     {Py_mp_subscript, pysqlite_row_subscript},
254     {Py_sq_length, pysqlite_row_length},
255     {Py_sq_item, pysqlite_row_item},
256     {Py_tp_new, pysqlite_row_new},
257     {Py_tp_traverse, row_traverse},
258     {Py_tp_clear, row_clear},
259     {0, NULL},
260 };
261 
262 static PyType_Spec row_spec = {
263     .name = MODULE_NAME ".Row",
264     .basicsize = sizeof(pysqlite_Row),
265     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
266               Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
267     .slots = row_slots,
268 };
269 
270 int
pysqlite_row_setup_types(PyObject * module)271 pysqlite_row_setup_types(PyObject *module)
272 {
273     PyObject *type = PyType_FromModuleAndSpec(module, &row_spec, NULL);
274     if (type == NULL) {
275         return -1;
276     }
277     pysqlite_state *state = pysqlite_get_state(module);
278     state->RowType = (PyTypeObject *)type;
279     return 0;
280 }
281