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