/Users/erlendaasland/src/cpython.git/Modules/_sqlite/row.c
Line | Count | Source (jump to first uncovered line) |
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 | 18 | #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 | | row_clear(pysqlite_Row *self) |
39 | 16 | { |
40 | 16 | Py_CLEAR(self->data); |
41 | 16 | Py_CLEAR(self->description); |
42 | 16 | return 0; |
43 | 16 | } |
44 | | |
45 | | static int |
46 | | row_traverse(pysqlite_Row *self, visitproc visit, void *arg) |
47 | 0 | { |
48 | 0 | Py_VISIT(Py_TYPE(self)); |
49 | 0 | Py_VISIT(self->data); |
50 | 0 | Py_VISIT(self->description); |
51 | 0 | return 0; |
52 | 0 | } |
53 | | |
54 | | static void |
55 | | pysqlite_row_dealloc(PyObject *self) |
56 | 16 | { |
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 | | pysqlite_row_new_impl(PyTypeObject *type, pysqlite_Cursor *cursor, |
76 | | PyObject *data) |
77 | | /*[clinic end generated code: output=10d58b09a819a4c1 input=b9e954ca31345dbf]*/ |
78 | 16 | { |
79 | 16 | pysqlite_Row *self; |
80 | | |
81 | 16 | assert(type != NULL && type->tp_alloc != NULL); |
82 | | |
83 | 0 | 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 | 16 | } |
92 | | |
93 | | PyObject* pysqlite_row_item(pysqlite_Row* self, Py_ssize_t idx) |
94 | 2 | { |
95 | 2 | PyObject *item = PyTuple_GetItem(self->data, idx); |
96 | 2 | return Py_XNewRef(item); |
97 | 2 | } |
98 | | |
99 | | static int |
100 | | equal_ignore_case(PyObject *left, PyObject *right) |
101 | 24 | { |
102 | 24 | int eq = PyObject_RichCompareBool(left, right, Py_EQ); |
103 | 24 | if (eq) { /* equal or error */ |
104 | 9 | return eq; |
105 | 9 | } |
106 | 15 | if (!PyUnicode_Check(left) || !PyUnicode_Check(right)) { |
107 | 0 | return 0; |
108 | 0 | } |
109 | 15 | if (!PyUnicode_IS_ASCII(left) || !PyUnicode_IS_ASCII(right)) { |
110 | 2 | return 0; |
111 | 2 | } |
112 | | |
113 | 13 | Py_ssize_t len = PyUnicode_GET_LENGTH(left); |
114 | 13 | if (PyUnicode_GET_LENGTH(right) != len) { |
115 | 5 | return 0; |
116 | 5 | } |
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 | 6 | } |
123 | 13 | } |
124 | 2 | return 1; |
125 | 8 | } |
126 | | |
127 | | static PyObject * |
128 | | pysqlite_row_subscript(pysqlite_Row *self, PyObject *idx) |
129 | 38 | { |
130 | 38 | Py_ssize_t _idx; |
131 | 38 | 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 | 24 | PyObject *obj; |
147 | 24 | obj = PyTuple_GET_ITEM(self->description, i); |
148 | 24 | obj = PyTuple_GET_ITEM(obj, 0); |
149 | 0 | int eq = equal_ignore_case(idx, obj); |
150 | 24 | if (eq < 0) { |
151 | 0 | return NULL; |
152 | 0 | } |
153 | 24 | if (eq) { |
154 | | /* found item */ |
155 | 11 | PyObject *item = PyTuple_GetItem(self->data, i); |
156 | 11 | return Py_XNewRef(item); |
157 | 11 | } |
158 | 24 | } |
159 | | |
160 | 5 | PyErr_SetString(PyExc_IndexError, "No item with that key"); |
161 | 5 | return NULL; |
162 | 16 | } |
163 | 11 | else if (PySlice_Check(idx)) { |
164 | 10 | return PyObject_GetItem(self->data, idx); |
165 | 10 | } |
166 | 1 | else { |
167 | 1 | PyErr_SetString(PyExc_IndexError, "Index must be int or string"); |
168 | 1 | return NULL; |
169 | 1 | } |
170 | 38 | } |
171 | | |
172 | | static Py_ssize_t |
173 | | pysqlite_row_length(pysqlite_Row* self) |
174 | 4 | { |
175 | 4 | return PyTuple_GET_SIZE(self->data); |
176 | 4 | } |
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 | | pysqlite_row_keys_impl(pysqlite_Row *self) |
186 | | /*[clinic end generated code: output=efe3dfb3af6edc07 input=7549a122827c5563]*/ |
187 | 1 | { |
188 | 1 | PyObject* list; |
189 | 1 | Py_ssize_t nitems, i; |
190 | | |
191 | 1 | list = PyList_New(0); |
192 | 1 | if (!list) { |
193 | 0 | return NULL; |
194 | 0 | } |
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 | 0 | } |
202 | 2 | } |
203 | | |
204 | 1 | return list; |
205 | 1 | } |
206 | | |
207 | | static PyObject* pysqlite_iter(pysqlite_Row* self) |
208 | 3 | { |
209 | 3 | return PyObject_GetIter(self->data); |
210 | 3 | } |
211 | | |
212 | | static Py_hash_t pysqlite_row_hash(pysqlite_Row *self) |
213 | 2 | { |
214 | 2 | return PyObject_Hash(self->description) ^ PyObject_Hash(self->data); |
215 | 2 | } |
216 | | |
217 | | static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other, int opid) |
218 | 20 | { |
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 | 0 | } |
229 | 10 | if (eq) { |
230 | 6 | return PyObject_RichCompare(self->data, other->data, opid); |
231 | 6 | } |
232 | 4 | return PyBool_FromLong(opid != Py_EQ); |
233 | 10 | } |
234 | 12 | Py_RETURN_NOTIMPLEMENTED; |
235 | 12 | } |
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 | | pysqlite_row_setup_types(PyObject *module) |
268 | 1 | { |
269 | 1 | PyObject *type = PyType_FromModuleAndSpec(module, &row_spec, NULL); |
270 | 1 | if (type == NULL) { |
271 | 0 | return -1; |
272 | 0 | } |
273 | 1 | pysqlite_state *state = pysqlite_get_state(module); |
274 | 1 | state->RowType = (PyTypeObject *)type; |
275 | 1 | return 0; |
276 | 1 | } |