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] 32module _sqlite3 33class _sqlite3.Row "pysqlite_Row *" "clinic_state()->RowType" 34[clinic start generated code]*/ 35/*[clinic end generated code: output=da39a3ee5e6b4b0d input=966c53403d7f3a40]*/ 36 37static int 38row_clear(pysqlite_Row *self) 39{ 40 Py_CLEAR(self->data); 41 Py_CLEAR(self->description); 42 return 0; 43} 44 45static int 46row_traverse(pysqlite_Row *self, visitproc visit, void *arg) 47{ 48 Py_VISIT(Py_TYPE(self)); 49 Py_VISIT(self->data); 50 Py_VISIT(self->description); 51 return 0; 52} 53 54static void 55pysqlite_row_dealloc(PyObject *self) 56{ 57 PyTypeObject *tp = Py_TYPE(self); 58 PyObject_GC_UnTrack(self); 59 tp->tp_clear(self); 60 tp->tp_free(self); 61 Py_DECREF(tp); 62} 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 74static PyObject * 75pysqlite_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 self = (pysqlite_Row *) type->tp_alloc(type, 0); 84 if (self == NULL) 85 return NULL; 86 87 self->data = Py_NewRef(data); 88 self->description = Py_NewRef(cursor->description); 89 90 return (PyObject *) self; 91} 92 93PyObject* pysqlite_row_item(pysqlite_Row* self, Py_ssize_t idx) 94{ 95 PyObject *item = PyTuple_GetItem(self->data, idx); 96 return Py_XNewRef(item); 97} 98 99static int 100equal_ignore_case(PyObject *left, PyObject *right) 101{ 102 int eq = PyObject_RichCompareBool(left, right, Py_EQ); 103 if (eq) { /* equal or error */ 104 return eq; 105 } 106 if (!PyUnicode_Check(left) || !PyUnicode_Check(right)) { 107 return 0; 108 } 109 if (!PyUnicode_IS_ASCII(left) || !PyUnicode_IS_ASCII(right)) { 110 return 0; 111 } 112 113 Py_ssize_t len = PyUnicode_GET_LENGTH(left); 114 if (PyUnicode_GET_LENGTH(right) != len) { 115 return 0; 116 } 117 const Py_UCS1 *p1 = PyUnicode_1BYTE_DATA(left); 118 const Py_UCS1 *p2 = PyUnicode_1BYTE_DATA(right); 119 for (; len; len--, p1++, p2++) { 120 if (Py_TOLOWER(*p1) != Py_TOLOWER(*p2)) { 121 return 0; 122 } 123 } 124 return 1; 125} 126 127static PyObject * 128pysqlite_row_subscript(pysqlite_Row *self, PyObject *idx) 129{ 130 Py_ssize_t _idx; 131 Py_ssize_t nitems, i; 132 133 if (PyLong_Check(idx)) { 134 _idx = PyNumber_AsSsize_t(idx, PyExc_IndexError); 135 if (_idx == -1 && PyErr_Occurred()) 136 return NULL; 137 if (_idx < 0) 138 _idx += PyTuple_GET_SIZE(self->data); 139 140 PyObject *item = PyTuple_GetItem(self->data, _idx); 141 return Py_XNewRef(item); 142 } else if (PyUnicode_Check(idx)) { 143 nitems = PyTuple_Size(self->description); 144 145 for (i = 0; i < nitems; i++) { 146 PyObject *obj; 147 obj = PyTuple_GET_ITEM(self->description, i); 148 obj = PyTuple_GET_ITEM(obj, 0); 149 int eq = equal_ignore_case(idx, obj); 150 if (eq < 0) { 151 return NULL; 152 } 153 if (eq) { 154 /* found item */ 155 PyObject *item = PyTuple_GetItem(self->data, i); 156 return Py_XNewRef(item); 157 } 158 } 159 160 PyErr_SetString(PyExc_IndexError, "No item with that key"); 161 return NULL; 162 } 163 else if (PySlice_Check(idx)) { 164 return PyObject_GetItem(self->data, idx); 165 } 166 else { 167 PyErr_SetString(PyExc_IndexError, "Index must be int or string"); 168 return NULL; 169 } 170} 171 172static Py_ssize_t 173pysqlite_row_length(pysqlite_Row* self) 174{ 175 return PyTuple_GET_SIZE(self->data); 176} 177 178/*[clinic input] 179_sqlite3.Row.keys as pysqlite_row_keys 180 181Returns the keys of the row. 182[clinic start generated code]*/ 183 184static PyObject * 185pysqlite_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 list = PyList_New(0); 192 if (!list) { 193 return NULL; 194 } 195 nitems = PyTuple_Size(self->description); 196 197 for (i = 0; i < nitems; i++) { 198 if (PyList_Append(list, PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)) != 0) { 199 Py_DECREF(list); 200 return NULL; 201 } 202 } 203 204 return list; 205} 206 207static PyObject* pysqlite_iter(pysqlite_Row* self) 208{ 209 return PyObject_GetIter(self->data); 210} 211 212static Py_hash_t pysqlite_row_hash(pysqlite_Row *self) 213{ 214 return PyObject_Hash(self->description) ^ PyObject_Hash(self->data); 215} 216 217static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other, int opid) 218{ 219 if (opid != Py_EQ && opid != Py_NE) 220 Py_RETURN_NOTIMPLEMENTED; 221 222 pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(self)); 223 if (PyObject_TypeCheck(_other, state->RowType)) { 224 pysqlite_Row *other = (pysqlite_Row *)_other; 225 int eq = PyObject_RichCompareBool(self->description, other->description, Py_EQ); 226 if (eq < 0) { 227 return NULL; 228 } 229 if (eq) { 230 return PyObject_RichCompare(self->data, other->data, opid); 231 } 232 return PyBool_FromLong(opid != Py_EQ); 233 } 234 Py_RETURN_NOTIMPLEMENTED; 235} 236 237static PyMethodDef row_methods[] = { 238 PYSQLITE_ROW_KEYS_METHODDEF 239 {NULL, NULL} 240}; 241 242static 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 258static 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 266int 267pysqlite_row_setup_types(PyObject *module) 268{ 269 PyObject *type = PyType_FromModuleAndSpec(module, &row_spec, NULL); 270 if (type == NULL) { 271 return -1; 272 } 273 pysqlite_state *state = pysqlite_get_state(module); 274 state->RowType = (PyTypeObject *)type; 275 return 0; 276} 277