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