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