1 /* row.c - an enhanced tuple for database rows 2 * 3 * Copyright (C) 2005-2010 Gerhard Hring <gh (at) 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 void pysqlite_row_dealloc(pysqlite_Row* self) 28 { 29 Py_XDECREF(self->data); 30 Py_XDECREF(self->description); 31 32 Py_TYPE(self)->tp_free((PyObject*)self); 33 } 34 35 static PyObject * 36 pysqlite_row_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) 37 { 38 pysqlite_Row *self; 39 PyObject* data; 40 pysqlite_Cursor* cursor; 41 42 assert(type != NULL && type->tp_alloc != NULL); 43 44 if (!_PyArg_NoKeywords("Row()", kwargs)) 45 return NULL; 46 if (!PyArg_ParseTuple(args, "OO", &cursor, &data)) 47 return NULL; 48 49 if (!PyObject_TypeCheck((PyObject*)cursor, &pysqlite_CursorType)) { 50 PyErr_SetString(PyExc_TypeError, "instance of cursor required for first argument"); 51 return NULL; 52 } 53 54 if (!PyTuple_Check(data)) { 55 PyErr_SetString(PyExc_TypeError, "tuple required for second argument"); 56 return NULL; 57 } 58 59 self = (pysqlite_Row *) type->tp_alloc(type, 0); 60 if (self == NULL) 61 return NULL; 62 63 Py_INCREF(data); 64 self->data = data; 65 66 Py_INCREF(cursor->description); 67 self->description = cursor->description; 68 69 return (PyObject *) self; 70 } 71 72 PyObject* pysqlite_row_item(pysqlite_Row* self, Py_ssize_t idx) 73 { 74 PyObject* item = PyTuple_GetItem(self->data, idx); 75 Py_XINCREF(item); 76 return item; 77 } 78 79 PyObject* pysqlite_row_subscript(pysqlite_Row* self, PyObject* idx) 80 { 81 Py_ssize_t _idx; 82 char* key; 83 Py_ssize_t nitems, i; 84 char* compare_key; 85 86 char* p1; 87 char* p2; 88 89 PyObject* item; 90 91 if (PyLong_Check(idx)) { 92 _idx = PyNumber_AsSsize_t(idx, PyExc_IndexError); 93 if (_idx == -1 && PyErr_Occurred()) 94 return NULL; 95 if (_idx < 0) 96 _idx += PyTuple_GET_SIZE(self->data); 97 item = PyTuple_GetItem(self->data, _idx); 98 Py_XINCREF(item); 99 return item; 100 } else if (PyUnicode_Check(idx)) { 101 key = PyUnicode_AsUTF8(idx); 102 if (key == NULL) 103 return NULL; 104 105 nitems = PyTuple_Size(self->description); 106 107 for (i = 0; i < nitems; i++) { 108 PyObject *obj; 109 obj = PyTuple_GET_ITEM(self->description, i); 110 obj = PyTuple_GET_ITEM(obj, 0); 111 compare_key = PyUnicode_AsUTF8(obj); 112 if (!compare_key) { 113 return NULL; 114 } 115 116 p1 = key; 117 p2 = compare_key; 118 119 while (1) { 120 if ((*p1 == (char)0) || (*p2 == (char)0)) { 121 break; 122 } 123 124 if ((*p1 | 0x20) != (*p2 | 0x20)) { 125 break; 126 } 127 128 p1++; 129 p2++; 130 } 131 132 if ((*p1 == (char)0) && (*p2 == (char)0)) { 133 /* found item */ 134 item = PyTuple_GetItem(self->data, i); 135 Py_INCREF(item); 136 return item; 137 } 138 139 } 140 141 PyErr_SetString(PyExc_IndexError, "No item with that key"); 142 return NULL; 143 } 144 else if (PySlice_Check(idx)) { 145 return PyObject_GetItem(self->data, idx); 146 } 147 else { 148 PyErr_SetString(PyExc_IndexError, "Index must be int or string"); 149 return NULL; 150 } 151 } 152 153 Py_ssize_t pysqlite_row_length(pysqlite_Row* self, PyObject* args, PyObject* kwargs) 154 { 155 return PyTuple_GET_SIZE(self->data); 156 } 157 158 PyObject* pysqlite_row_keys(pysqlite_Row* self, PyObject* args, PyObject* kwargs) 159 { 160 PyObject* list; 161 Py_ssize_t nitems, i; 162 163 list = PyList_New(0); 164 if (!list) { 165 return NULL; 166 } 167 nitems = PyTuple_Size(self->description); 168 169 for (i = 0; i < nitems; i++) { 170 if (PyList_Append(list, PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)) != 0) { 171 Py_DECREF(list); 172 return NULL; 173 } 174 } 175 176 return list; 177 } 178 179 static int pysqlite_row_print(pysqlite_Row* self, FILE *fp, int flags) 180 { 181 return (&PyTuple_Type)->tp_print(self->data, fp, flags); 182 } 183 184 static PyObject* pysqlite_iter(pysqlite_Row* self) 185 { 186 return PyObject_GetIter(self->data); 187 } 188 189 static Py_hash_t pysqlite_row_hash(pysqlite_Row *self) 190 { 191 return PyObject_Hash(self->description) ^ PyObject_Hash(self->data); 192 } 193 194 static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other, int opid) 195 { 196 if (opid != Py_EQ && opid != Py_NE) 197 Py_RETURN_NOTIMPLEMENTED; 198 199 if (PyType_IsSubtype(Py_TYPE(_other), &pysqlite_RowType)) { 200 pysqlite_Row *other = (pysqlite_Row *)_other; 201 PyObject *res = PyObject_RichCompare(self->description, other->description, opid); 202 if ((opid == Py_EQ && res == Py_True) 203 || (opid == Py_NE && res == Py_False)) { 204 Py_DECREF(res); 205 return PyObject_RichCompare(self->data, other->data, opid); 206 } 207 } 208 Py_RETURN_NOTIMPLEMENTED; 209 } 210 211 PyMappingMethods pysqlite_row_as_mapping = { 212 /* mp_length */ (lenfunc)pysqlite_row_length, 213 /* mp_subscript */ (binaryfunc)pysqlite_row_subscript, 214 /* mp_ass_subscript */ (objobjargproc)0, 215 }; 216 217 static PySequenceMethods pysqlite_row_as_sequence = { 218 /* sq_length */ (lenfunc)pysqlite_row_length, 219 /* sq_concat */ 0, 220 /* sq_repeat */ 0, 221 /* sq_item */ (ssizeargfunc)pysqlite_row_item, 222 }; 223 224 225 static PyMethodDef pysqlite_row_methods[] = { 226 {"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS, 227 PyDoc_STR("Returns the keys of the row.")}, 228 {NULL, NULL} 229 }; 230 231 232 PyTypeObject pysqlite_RowType = { 233 PyVarObject_HEAD_INIT(NULL, 0) 234 MODULE_NAME ".Row", /* tp_name */ 235 sizeof(pysqlite_Row), /* tp_basicsize */ 236 0, /* tp_itemsize */ 237 (destructor)pysqlite_row_dealloc, /* tp_dealloc */ 238 (printfunc)pysqlite_row_print, /* tp_print */ 239 0, /* tp_getattr */ 240 0, /* tp_setattr */ 241 0, /* tp_reserved */ 242 0, /* tp_repr */ 243 0, /* tp_as_number */ 244 0, /* tp_as_sequence */ 245 0, /* tp_as_mapping */ 246 (hashfunc)pysqlite_row_hash, /* tp_hash */ 247 0, /* tp_call */ 248 0, /* tp_str */ 249 0, /* tp_getattro */ 250 0, /* tp_setattro */ 251 0, /* tp_as_buffer */ 252 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ 253 0, /* tp_doc */ 254 (traverseproc)0, /* tp_traverse */ 255 0, /* tp_clear */ 256 (richcmpfunc)pysqlite_row_richcompare, /* tp_richcompare */ 257 0, /* tp_weaklistoffset */ 258 (getiterfunc)pysqlite_iter, /* tp_iter */ 259 0, /* tp_iternext */ 260 pysqlite_row_methods, /* tp_methods */ 261 0, /* tp_members */ 262 0, /* tp_getset */ 263 0, /* tp_base */ 264 0, /* tp_dict */ 265 0, /* tp_descr_get */ 266 0, /* tp_descr_set */ 267 0, /* tp_dictoffset */ 268 0, /* tp_init */ 269 0, /* tp_alloc */ 270 0, /* tp_new */ 271 0 /* tp_free */ 272 }; 273 274 extern int pysqlite_row_setup_types(void) 275 { 276 pysqlite_RowType.tp_new = pysqlite_row_new; 277 pysqlite_RowType.tp_as_mapping = &pysqlite_row_as_mapping; 278 pysqlite_RowType.tp_as_sequence = &pysqlite_row_as_sequence; 279 return PyType_Ready(&pysqlite_RowType); 280 } 281