| /* row.c - an enhanced tuple for database rows |
| * |
| * Copyright (C) 2005-2006 Gerhard Häring <gh@ghaering.de> |
| * |
| * This file is part of pysqlite. |
| * |
| * This software is provided 'as-is', without any express or implied |
| * warranty. In no event will the authors be held liable for any damages |
| * arising from the use of this software. |
| * |
| * Permission is granted to anyone to use this software for any purpose, |
| * including commercial applications, and to alter it and redistribute it |
| * freely, subject to the following restrictions: |
| * |
| * 1. The origin of this software must not be misrepresented; you must not |
| * claim that you wrote the original software. If you use this software |
| * in a product, an acknowledgment in the product documentation would be |
| * appreciated but is not required. |
| * 2. Altered source versions must be plainly marked as such, and must not be |
| * misrepresented as being the original software. |
| * 3. This notice may not be removed or altered from any source distribution. |
| */ |
| |
| #include "row.h" |
| #include "cursor.h" |
| #include "sqlitecompat.h" |
| |
| void pysqlite_row_dealloc(pysqlite_Row* self) |
| { |
| Py_XDECREF(self->data); |
| Py_XDECREF(self->description); |
| |
| Py_TYPE(self)->tp_free((PyObject*)self); |
| } |
| |
| int pysqlite_row_init(pysqlite_Row* self, PyObject* args, PyObject* kwargs) |
| { |
| PyObject* data; |
| pysqlite_Cursor* cursor; |
| |
| self->data = 0; |
| self->description = 0; |
| |
| if (!PyArg_ParseTuple(args, "OO", &cursor, &data)) { |
| return -1; |
| } |
| |
| if (!PyObject_IsInstance((PyObject*)cursor, (PyObject*)&pysqlite_CursorType)) { |
| PyErr_SetString(PyExc_TypeError, "instance of cursor required for first argument"); |
| return -1; |
| } |
| |
| if (!PyTuple_Check(data)) { |
| PyErr_SetString(PyExc_TypeError, "tuple required for second argument"); |
| return -1; |
| } |
| |
| Py_INCREF(data); |
| self->data = data; |
| |
| Py_INCREF(cursor->description); |
| self->description = cursor->description; |
| |
| return 0; |
| } |
| |
| PyObject* pysqlite_row_subscript(pysqlite_Row* self, PyObject* idx) |
| { |
| long _idx; |
| char* key; |
| int nitems, i; |
| char* compare_key; |
| |
| char* p1; |
| char* p2; |
| |
| PyObject* item; |
| |
| if (PyInt_Check(idx)) { |
| _idx = PyInt_AsLong(idx); |
| item = PyTuple_GetItem(self->data, _idx); |
| Py_XINCREF(item); |
| return item; |
| } else if (PyLong_Check(idx)) { |
| _idx = PyLong_AsLong(idx); |
| item = PyTuple_GetItem(self->data, _idx); |
| Py_XINCREF(item); |
| return item; |
| } else if (PyString_Check(idx)) { |
| key = PyString_AsString(idx); |
| |
| nitems = PyTuple_Size(self->description); |
| |
| for (i = 0; i < nitems; i++) { |
| compare_key = PyString_AsString(PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)); |
| if (!compare_key) { |
| return NULL; |
| } |
| |
| p1 = key; |
| p2 = compare_key; |
| |
| while (1) { |
| if ((*p1 == (char)0) || (*p2 == (char)0)) { |
| break; |
| } |
| |
| if ((*p1 | 0x20) != (*p2 | 0x20)) { |
| break; |
| } |
| |
| p1++; |
| p2++; |
| } |
| |
| if ((*p1 == (char)0) && (*p2 == (char)0)) { |
| /* found item */ |
| item = PyTuple_GetItem(self->data, i); |
| Py_INCREF(item); |
| return item; |
| } |
| |
| } |
| |
| PyErr_SetString(PyExc_IndexError, "No item with that key"); |
| return NULL; |
| } else if (PySlice_Check(idx)) { |
| PyErr_SetString(PyExc_ValueError, "slices not implemented, yet"); |
| return NULL; |
| } else { |
| PyErr_SetString(PyExc_IndexError, "Index must be int or string"); |
| return NULL; |
| } |
| } |
| |
| Py_ssize_t pysqlite_row_length(pysqlite_Row* self, PyObject* args, PyObject* kwargs) |
| { |
| return PyTuple_GET_SIZE(self->data); |
| } |
| |
| PyObject* pysqlite_row_keys(pysqlite_Row* self, PyObject* args, PyObject* kwargs) |
| { |
| PyObject* list; |
| int nitems, i; |
| |
| list = PyList_New(0); |
| if (!list) { |
| return NULL; |
| } |
| nitems = PyTuple_Size(self->description); |
| |
| for (i = 0; i < nitems; i++) { |
| if (PyList_Append(list, PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)) != 0) { |
| Py_DECREF(list); |
| return NULL; |
| } |
| } |
| |
| return list; |
| } |
| |
| static int pysqlite_row_print(pysqlite_Row* self, FILE *fp, int flags) |
| { |
| return (&PyTuple_Type)->tp_print(self->data, fp, flags); |
| } |
| |
| static PyObject* pysqlite_iter(pysqlite_Row* self) |
| { |
| return PyObject_GetIter(self->data); |
| } |
| |
| static long pysqlite_row_hash(pysqlite_Row *self) |
| { |
| return PyObject_Hash(self->description) ^ PyObject_Hash(self->data); |
| } |
| |
| static PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other, int opid) |
| { |
| if (opid != Py_EQ && opid != Py_NE) { |
| Py_INCREF(Py_NotImplemented); |
| return Py_NotImplemented; |
| } |
| if (PyType_IsSubtype(Py_TYPE(_other), &pysqlite_RowType)) { |
| pysqlite_Row *other = (pysqlite_Row *)_other; |
| PyObject *res = PyObject_RichCompare(self->description, other->description, opid); |
| if ((opid == Py_EQ && res == Py_True) |
| || (opid == Py_NE && res == Py_False)) { |
| Py_DECREF(res); |
| return PyObject_RichCompare(self->data, other->data, opid); |
| } |
| } |
| Py_INCREF(Py_NotImplemented); |
| return Py_NotImplemented; |
| } |
| |
| PyMappingMethods pysqlite_row_as_mapping = { |
| /* mp_length */ (lenfunc)pysqlite_row_length, |
| /* mp_subscript */ (binaryfunc)pysqlite_row_subscript, |
| /* mp_ass_subscript */ (objobjargproc)0, |
| }; |
| |
| static PyMethodDef pysqlite_row_methods[] = { |
| {"keys", (PyCFunction)pysqlite_row_keys, METH_NOARGS, |
| PyDoc_STR("Returns the keys of the row.")}, |
| {NULL, NULL} |
| }; |
| |
| |
| PyTypeObject pysqlite_RowType = { |
| PyVarObject_HEAD_INIT(NULL, 0) |
| MODULE_NAME ".Row", /* tp_name */ |
| sizeof(pysqlite_Row), /* tp_basicsize */ |
| 0, /* tp_itemsize */ |
| (destructor)pysqlite_row_dealloc, /* tp_dealloc */ |
| (printfunc)pysqlite_row_print, /* tp_print */ |
| 0, /* tp_getattr */ |
| 0, /* tp_setattr */ |
| 0, /* tp_compare */ |
| 0, /* tp_repr */ |
| 0, /* tp_as_number */ |
| 0, /* tp_as_sequence */ |
| 0, /* tp_as_mapping */ |
| (hashfunc)pysqlite_row_hash, /* tp_hash */ |
| 0, /* tp_call */ |
| 0, /* tp_str */ |
| 0, /* tp_getattro */ |
| 0, /* tp_setattro */ |
| 0, /* tp_as_buffer */ |
| Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ |
| 0, /* tp_doc */ |
| (traverseproc)0, /* tp_traverse */ |
| 0, /* tp_clear */ |
| (richcmpfunc)pysqlite_row_richcompare, /* tp_richcompare */ |
| 0, /* tp_weaklistoffset */ |
| (getiterfunc)pysqlite_iter, /* tp_iter */ |
| 0, /* tp_iternext */ |
| pysqlite_row_methods, /* tp_methods */ |
| 0, /* tp_members */ |
| 0, /* tp_getset */ |
| 0, /* tp_base */ |
| 0, /* tp_dict */ |
| 0, /* tp_descr_get */ |
| 0, /* tp_descr_set */ |
| 0, /* tp_dictoffset */ |
| (initproc)pysqlite_row_init, /* tp_init */ |
| 0, /* tp_alloc */ |
| 0, /* tp_new */ |
| 0 /* tp_free */ |
| }; |
| |
| extern int pysqlite_row_setup_types(void) |
| { |
| pysqlite_RowType.tp_new = PyType_GenericNew; |
| pysqlite_RowType.tp_as_mapping = &pysqlite_row_as_mapping; |
| return PyType_Ready(&pysqlite_RowType); |
| } |