blob: f9dfcbd5d615e5a2ab9a01c704585a01d4b8b919 [file] [log] [blame]
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001/* row.c - an enhanced tuple for database rows
2 *
Florent Xiclunac934f322010-09-03 23:47:32 +00003 * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00004 *
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"
Erlend Egeberg Aasland84d79cf2020-12-29 14:22:55 +010026#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]*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000033
Erlend Egeberg Aaslandbf838a62021-02-21 01:29:19 +010034static void
35pysqlite_row_dealloc(pysqlite_Row *self)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000036{
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +020037 PyTypeObject *tp = Py_TYPE(self);
38
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000039 Py_XDECREF(self->data);
40 Py_XDECREF(self->description);
41
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +020042 tp->tp_free(self);
43 Py_DECREF(tp);
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000044}
45
Erlend Egeberg Aasland84d79cf2020-12-29 14:22:55 +010046/*[clinic input]
47@classmethod
48_sqlite3.Row.__new__ as pysqlite_row_new
49
50 cursor: object(type='pysqlite_Cursor *', subclass_of='pysqlite_CursorType')
51 data: object(subclass_of='&PyTuple_Type')
52 /
53
54[clinic start generated code]*/
55
Serhiy Storchaka3d4b2d42014-08-06 17:50:39 +030056static PyObject *
Erlend Egeberg Aasland84d79cf2020-12-29 14:22:55 +010057pysqlite_row_new_impl(PyTypeObject *type, pysqlite_Cursor *cursor,
58 PyObject *data)
59/*[clinic end generated code: output=10d58b09a819a4c1 input=f6cd7e6e0935828d]*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000060{
Serhiy Storchaka3d4b2d42014-08-06 17:50:39 +030061 pysqlite_Row *self;
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000062
Serhiy Storchaka3d4b2d42014-08-06 17:50:39 +030063 assert(type != NULL && type->tp_alloc != NULL);
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000064
Serhiy Storchaka3d4b2d42014-08-06 17:50:39 +030065 self = (pysqlite_Row *) type->tp_alloc(type, 0);
66 if (self == NULL)
67 return NULL;
68
Erlend Egeberg Aaslandbf64d902020-12-27 12:05:33 +010069 self->data = Py_NewRef(data);
70 self->description = Py_NewRef(cursor->description);
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000071
Serhiy Storchaka3d4b2d42014-08-06 17:50:39 +030072 return (PyObject *) self;
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000073}
74
Serhiy Storchaka47a98132014-05-28 12:58:34 +030075PyObject* pysqlite_row_item(pysqlite_Row* self, Py_ssize_t idx)
76{
Erlend Egeberg Aaslandbf64d902020-12-27 12:05:33 +010077 PyObject *item = PyTuple_GetItem(self->data, idx);
78 return Py_XNewRef(item);
Serhiy Storchaka47a98132014-05-28 12:58:34 +030079}
80
Serhiy Storchakaf6695812019-09-17 09:20:56 +030081static int
82equal_ignore_case(PyObject *left, PyObject *right)
83{
84 int eq = PyObject_RichCompareBool(left, right, Py_EQ);
85 if (eq) { /* equal or error */
86 return eq;
87 }
88 if (!PyUnicode_Check(left) || !PyUnicode_Check(right)) {
89 return 0;
90 }
91 if (!PyUnicode_IS_ASCII(left) || !PyUnicode_IS_ASCII(right)) {
92 return 0;
93 }
94
95 Py_ssize_t len = PyUnicode_GET_LENGTH(left);
96 if (PyUnicode_GET_LENGTH(right) != len) {
97 return 0;
98 }
99 const Py_UCS1 *p1 = PyUnicode_1BYTE_DATA(left);
100 const Py_UCS1 *p2 = PyUnicode_1BYTE_DATA(right);
101 for (; len; len--, p1++, p2++) {
102 if (Py_TOLOWER(*p1) != Py_TOLOWER(*p2)) {
103 return 0;
104 }
105 }
106 return 1;
107}
108
Erlend Egeberg Aaslandbf838a62021-02-21 01:29:19 +0100109static PyObject *
110pysqlite_row_subscript(pysqlite_Row *self, PyObject *idx)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000111{
Serhiy Storchaka47a98132014-05-28 12:58:34 +0300112 Py_ssize_t _idx;
Victor Stinner83e30bf2013-11-18 01:27:30 +0100113 Py_ssize_t nitems, i;
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000114
Georg Brandle1a0d112007-10-23 19:24:22 +0000115 if (PyLong_Check(idx)) {
Serhiy Storchaka47a98132014-05-28 12:58:34 +0300116 _idx = PyNumber_AsSsize_t(idx, PyExc_IndexError);
117 if (_idx == -1 && PyErr_Occurred())
118 return NULL;
119 if (_idx < 0)
120 _idx += PyTuple_GET_SIZE(self->data);
Erlend Egeberg Aaslandbf64d902020-12-27 12:05:33 +0100121
122 PyObject *item = PyTuple_GetItem(self->data, _idx);
123 return Py_XNewRef(item);
Gerhard Häring6d214562007-08-10 18:15:11 +0000124 } else if (PyUnicode_Check(idx)) {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000125 nitems = PyTuple_Size(self->description);
126
127 for (i = 0; i < nitems; i++) {
Victor Stinner83e30bf2013-11-18 01:27:30 +0100128 PyObject *obj;
129 obj = PyTuple_GET_ITEM(self->description, i);
130 obj = PyTuple_GET_ITEM(obj, 0);
Serhiy Storchakaf6695812019-09-17 09:20:56 +0300131 int eq = equal_ignore_case(idx, obj);
132 if (eq < 0) {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000133 return NULL;
134 }
Serhiy Storchakaf6695812019-09-17 09:20:56 +0300135 if (eq) {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000136 /* found item */
Erlend Egeberg Aaslandbf64d902020-12-27 12:05:33 +0100137 PyObject *item = PyTuple_GetItem(self->data, i);
138 return Py_XNewRef(item);
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000139 }
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000140 }
141
142 PyErr_SetString(PyExc_IndexError, "No item with that key");
143 return NULL;
Victor Stinner83e30bf2013-11-18 01:27:30 +0100144 }
145 else if (PySlice_Check(idx)) {
Serhiy Storchaka72e731c2015-03-31 13:33:11 +0300146 return PyObject_GetItem(self->data, idx);
Victor Stinner83e30bf2013-11-18 01:27:30 +0100147 }
148 else {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000149 PyErr_SetString(PyExc_IndexError, "Index must be int or string");
150 return NULL;
151 }
152}
153
Serhiy Storchakad4f9cf52018-11-27 19:34:35 +0200154static Py_ssize_t
155pysqlite_row_length(pysqlite_Row* self)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000156{
157 return PyTuple_GET_SIZE(self->data);
158}
159
Erlend Egeberg Aasland84d79cf2020-12-29 14:22:55 +0100160/*[clinic input]
161_sqlite3.Row.keys as pysqlite_row_keys
162
163Returns the keys of the row.
164[clinic start generated code]*/
165
166static PyObject *
167pysqlite_row_keys_impl(pysqlite_Row *self)
168/*[clinic end generated code: output=efe3dfb3af6edc07 input=7549a122827c5563]*/
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000169{
170 PyObject* list;
Serhiy Storchaka26861b02015-02-16 20:52:17 +0200171 Py_ssize_t nitems, i;
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000172
173 list = PyList_New(0);
174 if (!list) {
175 return NULL;
176 }
177 nitems = PyTuple_Size(self->description);
178
179 for (i = 0; i < nitems; i++) {
180 if (PyList_Append(list, PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)) != 0) {
181 Py_DECREF(list);
182 return NULL;
183 }
184 }
185
186 return list;
187}
188
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000189static PyObject* pysqlite_iter(pysqlite_Row* self)
190{
191 return PyObject_GetIter(self->data);
192}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000193
Georg Brandl016cec72010-10-18 12:24:53 +0000194static Py_hash_t pysqlite_row_hash(pysqlite_Row *self)
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000195{
196 return PyObject_Hash(self->description) ^ PyObject_Hash(self->data);
197}
198
199static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other, int opid)
200{
Brian Curtindfc80e32011-08-10 20:28:54 -0500201 if (opid != Py_EQ && opid != Py_NE)
202 Py_RETURN_NOTIMPLEMENTED;
203
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +0200204 if (PyObject_TypeCheck(_other, pysqlite_RowType)) {
Gerhard Häringf9cee222010-03-05 15:20:03 +0000205 pysqlite_Row *other = (pysqlite_Row *)_other;
Serhiy Storchaka8debfa52019-09-16 20:15:18 +0300206 int eq = PyObject_RichCompareBool(self->description, other->description, Py_EQ);
207 if (eq < 0) {
208 return NULL;
209 }
210 if (eq) {
Gerhard Häringf9cee222010-03-05 15:20:03 +0000211 return PyObject_RichCompare(self->data, other->data, opid);
212 }
Serhiy Storchaka8debfa52019-09-16 20:15:18 +0300213 return PyBool_FromLong(opid != Py_EQ);
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000214 }
Brian Curtindfc80e32011-08-10 20:28:54 -0500215 Py_RETURN_NOTIMPLEMENTED;
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000216}
217
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +0200218static PyMethodDef row_methods[] = {
Erlend Egeberg Aasland84d79cf2020-12-29 14:22:55 +0100219 PYSQLITE_ROW_KEYS_METHODDEF
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000220 {NULL, NULL}
221};
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000222
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +0200223static PyType_Slot row_slots[] = {
224 {Py_tp_dealloc, pysqlite_row_dealloc},
225 {Py_tp_hash, pysqlite_row_hash},
226 {Py_tp_methods, row_methods},
227 {Py_tp_richcompare, pysqlite_row_richcompare},
228 {Py_tp_iter, pysqlite_iter},
229 {Py_mp_length, pysqlite_row_length},
230 {Py_mp_subscript, pysqlite_row_subscript},
231 {Py_sq_length, pysqlite_row_length},
232 {Py_sq_item, pysqlite_row_item},
233 {Py_tp_new, pysqlite_row_new},
234 {0, NULL},
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000235};
236
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +0200237static PyType_Spec row_spec = {
238 .name = MODULE_NAME ".Row",
239 .basicsize = sizeof(pysqlite_Row),
240 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
241 .slots = row_slots,
242};
243
244PyTypeObject *pysqlite_RowType = NULL;
245
Erlend Egeberg Aasland38b6c2a2021-02-21 11:07:49 +0100246int
247pysqlite_row_setup_types(PyObject *module)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000248{
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +0200249 pysqlite_RowType = (PyTypeObject *)PyType_FromModuleAndSpec(module, &row_spec, NULL);
250 if (pysqlite_RowType == NULL) {
251 return -1;
252 }
253 return 0;
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000254}