blob: 24722be49082cfe756e6dcfdfd581d18a5489b78 [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
Miss Islington (bot)e8d9df02021-05-25 11:08:39 -070034static 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{
Miss Islington (bot)ff359d72021-05-31 02:12:27 -070045 Py_VISIT(Py_TYPE(self));
Miss Islington (bot)e8d9df02021-05-25 11:08:39 -070046 Py_VISIT(self->data);
47 Py_VISIT(self->description);
Miss Islington (bot)e8d9df02021-05-25 11:08:39 -070048 return 0;
49}
50
Erlend Egeberg Aaslandbf838a62021-02-21 01:29:19 +010051static void
Miss Islington (bot)e8d9df02021-05-25 11:08:39 -070052pysqlite_row_dealloc(PyObject *self)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000053{
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +020054 PyTypeObject *tp = Py_TYPE(self);
Miss Islington (bot)e8d9df02021-05-25 11:08:39 -070055 PyObject_GC_UnTrack(self);
56 tp->tp_clear(self);
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +020057 tp->tp_free(self);
58 Py_DECREF(tp);
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000059}
60
Erlend Egeberg Aasland84d79cf2020-12-29 14:22:55 +010061/*[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
Serhiy Storchaka3d4b2d42014-08-06 17:50:39 +030071static PyObject *
Erlend Egeberg Aasland84d79cf2020-12-29 14:22:55 +010072pysqlite_row_new_impl(PyTypeObject *type, pysqlite_Cursor *cursor,
73 PyObject *data)
74/*[clinic end generated code: output=10d58b09a819a4c1 input=f6cd7e6e0935828d]*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000075{
Serhiy Storchaka3d4b2d42014-08-06 17:50:39 +030076 pysqlite_Row *self;
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000077
Serhiy Storchaka3d4b2d42014-08-06 17:50:39 +030078 assert(type != NULL && type->tp_alloc != NULL);
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000079
Serhiy Storchaka3d4b2d42014-08-06 17:50:39 +030080 self = (pysqlite_Row *) type->tp_alloc(type, 0);
81 if (self == NULL)
82 return NULL;
83
Erlend Egeberg Aaslandbf64d902020-12-27 12:05:33 +010084 self->data = Py_NewRef(data);
85 self->description = Py_NewRef(cursor->description);
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000086
Serhiy Storchaka3d4b2d42014-08-06 17:50:39 +030087 return (PyObject *) self;
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000088}
89
Serhiy Storchaka47a98132014-05-28 12:58:34 +030090PyObject* pysqlite_row_item(pysqlite_Row* self, Py_ssize_t idx)
91{
Erlend Egeberg Aaslandbf64d902020-12-27 12:05:33 +010092 PyObject *item = PyTuple_GetItem(self->data, idx);
93 return Py_XNewRef(item);
Serhiy Storchaka47a98132014-05-28 12:58:34 +030094}
95
Serhiy Storchakaf6695812019-09-17 09:20:56 +030096static 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
Erlend Egeberg Aaslandbf838a62021-02-21 01:29:19 +0100124static PyObject *
125pysqlite_row_subscript(pysqlite_Row *self, PyObject *idx)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000126{
Serhiy Storchaka47a98132014-05-28 12:58:34 +0300127 Py_ssize_t _idx;
Victor Stinner83e30bf2013-11-18 01:27:30 +0100128 Py_ssize_t nitems, i;
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000129
Georg Brandle1a0d112007-10-23 19:24:22 +0000130 if (PyLong_Check(idx)) {
Serhiy Storchaka47a98132014-05-28 12:58:34 +0300131 _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);
Erlend Egeberg Aaslandbf64d902020-12-27 12:05:33 +0100136
137 PyObject *item = PyTuple_GetItem(self->data, _idx);
138 return Py_XNewRef(item);
Gerhard Häring6d214562007-08-10 18:15:11 +0000139 } else if (PyUnicode_Check(idx)) {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000140 nitems = PyTuple_Size(self->description);
141
142 for (i = 0; i < nitems; i++) {
Victor Stinner83e30bf2013-11-18 01:27:30 +0100143 PyObject *obj;
144 obj = PyTuple_GET_ITEM(self->description, i);
145 obj = PyTuple_GET_ITEM(obj, 0);
Serhiy Storchakaf6695812019-09-17 09:20:56 +0300146 int eq = equal_ignore_case(idx, obj);
147 if (eq < 0) {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000148 return NULL;
149 }
Serhiy Storchakaf6695812019-09-17 09:20:56 +0300150 if (eq) {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000151 /* found item */
Erlend Egeberg Aaslandbf64d902020-12-27 12:05:33 +0100152 PyObject *item = PyTuple_GetItem(self->data, i);
153 return Py_XNewRef(item);
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000154 }
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000155 }
156
157 PyErr_SetString(PyExc_IndexError, "No item with that key");
158 return NULL;
Victor Stinner83e30bf2013-11-18 01:27:30 +0100159 }
160 else if (PySlice_Check(idx)) {
Serhiy Storchaka72e731c2015-03-31 13:33:11 +0300161 return PyObject_GetItem(self->data, idx);
Victor Stinner83e30bf2013-11-18 01:27:30 +0100162 }
163 else {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000164 PyErr_SetString(PyExc_IndexError, "Index must be int or string");
165 return NULL;
166 }
167}
168
Serhiy Storchakad4f9cf52018-11-27 19:34:35 +0200169static Py_ssize_t
170pysqlite_row_length(pysqlite_Row* self)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000171{
172 return PyTuple_GET_SIZE(self->data);
173}
174
Erlend Egeberg Aasland84d79cf2020-12-29 14:22:55 +0100175/*[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]*/
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000184{
185 PyObject* list;
Serhiy Storchaka26861b02015-02-16 20:52:17 +0200186 Py_ssize_t nitems, i;
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000187
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
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000204static PyObject* pysqlite_iter(pysqlite_Row* self)
205{
206 return PyObject_GetIter(self->data);
207}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000208
Georg Brandl016cec72010-10-18 12:24:53 +0000209static Py_hash_t pysqlite_row_hash(pysqlite_Row *self)
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000210{
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{
Brian Curtindfc80e32011-08-10 20:28:54 -0500216 if (opid != Py_EQ && opid != Py_NE)
217 Py_RETURN_NOTIMPLEMENTED;
218
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +0200219 if (PyObject_TypeCheck(_other, pysqlite_RowType)) {
Gerhard Häringf9cee222010-03-05 15:20:03 +0000220 pysqlite_Row *other = (pysqlite_Row *)_other;
Serhiy Storchaka8debfa52019-09-16 20:15:18 +0300221 int eq = PyObject_RichCompareBool(self->description, other->description, Py_EQ);
222 if (eq < 0) {
223 return NULL;
224 }
225 if (eq) {
Gerhard Häringf9cee222010-03-05 15:20:03 +0000226 return PyObject_RichCompare(self->data, other->data, opid);
227 }
Serhiy Storchaka8debfa52019-09-16 20:15:18 +0300228 return PyBool_FromLong(opid != Py_EQ);
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000229 }
Brian Curtindfc80e32011-08-10 20:28:54 -0500230 Py_RETURN_NOTIMPLEMENTED;
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000231}
232
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +0200233static PyMethodDef row_methods[] = {
Erlend Egeberg Aasland84d79cf2020-12-29 14:22:55 +0100234 PYSQLITE_ROW_KEYS_METHODDEF
Thomas Woutersfc7bb8c2007-01-15 15:49:28 +0000235 {NULL, NULL}
236};
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000237
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +0200238static 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},
Miss Islington (bot)e8d9df02021-05-25 11:08:39 -0700249 {Py_tp_traverse, row_traverse},
250 {Py_tp_clear, row_clear},
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +0200251 {0, NULL},
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000252};
253
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +0200254static PyType_Spec row_spec = {
255 .name = MODULE_NAME ".Row",
256 .basicsize = sizeof(pysqlite_Row),
Miss Islington (bot)e8d9df02021-05-25 11:08:39 -0700257 .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +0200258 .slots = row_slots,
259};
260
261PyTypeObject *pysqlite_RowType = NULL;
262
Erlend Egeberg Aasland38b6c2a2021-02-21 11:07:49 +0100263int
264pysqlite_row_setup_types(PyObject *module)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000265{
Erlend Egeberg Aasland9031bd42020-10-01 15:24:31 +0200266 pysqlite_RowType = (PyTypeObject *)PyType_FromModuleAndSpec(module, &row_spec, NULL);
267 if (pysqlite_RowType == NULL) {
268 return -1;
269 }
270 return 0;
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000271}