1/* row.c - an enhanced tuple for database rows
2 *
3 * Copyright (C) 2005-2010 Gerhard Häring <[email protected]>
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]
29module _sqlite3
30class _sqlite3.Row "pysqlite_Row *" "pysqlite_RowType"
31[clinic start generated code]*/
32/*[clinic end generated code: output=da39a3ee5e6b4b0d input=384227da65f250fd]*/
33
34static int
35row_clear(pysqlite_Row *self)
36{
37 Py_CLEAR(self->data);
38 Py_CLEAR(self->description);
39 return 0;
40}
41
42static int
43row_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
51static void
52pysqlite_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
71static PyObject *
72pysqlite_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
90PyObject* 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
96static int
97equal_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
124static PyObject *
125pysqlite_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
169static Py_ssize_t
170pysqlite_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
178Returns the keys of the row.
179[clinic start generated code]*/
180
181static PyObject *
182pysqlite_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
204static PyObject* pysqlite_iter(pysqlite_Row* self)
205{
206 return PyObject_GetIter(self->data);
207}
208
209static Py_hash_t pysqlite_row_hash(pysqlite_Row *self)
210{
211 return PyObject_Hash(self->description) ^ PyObject_Hash(self->data);
212}
213
214static 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
233static PyMethodDef row_methods[] = {
234 PYSQLITE_ROW_KEYS_METHODDEF
235 {NULL, NULL}
236};
237
238static 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
254static 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
262PyTypeObject *pysqlite_RowType = NULL;
263
264int
265pysqlite_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