17db96d56Sopenharmony_ci/* row.c - an enhanced tuple for database rows
27db96d56Sopenharmony_ci *
37db96d56Sopenharmony_ci * Copyright (C) 2005-2010 Gerhard Häring <gh@ghaering.de>
47db96d56Sopenharmony_ci *
57db96d56Sopenharmony_ci * This file is part of pysqlite.
67db96d56Sopenharmony_ci *
77db96d56Sopenharmony_ci * This software is provided 'as-is', without any express or implied
87db96d56Sopenharmony_ci * warranty.  In no event will the authors be held liable for any damages
97db96d56Sopenharmony_ci * arising from the use of this software.
107db96d56Sopenharmony_ci *
117db96d56Sopenharmony_ci * Permission is granted to anyone to use this software for any purpose,
127db96d56Sopenharmony_ci * including commercial applications, and to alter it and redistribute it
137db96d56Sopenharmony_ci * freely, subject to the following restrictions:
147db96d56Sopenharmony_ci *
157db96d56Sopenharmony_ci * 1. The origin of this software must not be misrepresented; you must not
167db96d56Sopenharmony_ci *    claim that you wrote the original software. If you use this software
177db96d56Sopenharmony_ci *    in a product, an acknowledgment in the product documentation would be
187db96d56Sopenharmony_ci *    appreciated but is not required.
197db96d56Sopenharmony_ci * 2. Altered source versions must be plainly marked as such, and must not be
207db96d56Sopenharmony_ci *    misrepresented as being the original software.
217db96d56Sopenharmony_ci * 3. This notice may not be removed or altered from any source distribution.
227db96d56Sopenharmony_ci */
237db96d56Sopenharmony_ci
247db96d56Sopenharmony_ci#include "row.h"
257db96d56Sopenharmony_ci#include "cursor.h"
267db96d56Sopenharmony_ci
277db96d56Sopenharmony_ci#define clinic_state() (pysqlite_get_state_by_type(type))
287db96d56Sopenharmony_ci#include "clinic/row.c.h"
297db96d56Sopenharmony_ci#undef clinic_state
307db96d56Sopenharmony_ci
317db96d56Sopenharmony_ci/*[clinic input]
327db96d56Sopenharmony_cimodule _sqlite3
337db96d56Sopenharmony_ciclass _sqlite3.Row "pysqlite_Row *" "clinic_state()->RowType"
347db96d56Sopenharmony_ci[clinic start generated code]*/
357db96d56Sopenharmony_ci/*[clinic end generated code: output=da39a3ee5e6b4b0d input=966c53403d7f3a40]*/
367db96d56Sopenharmony_ci
377db96d56Sopenharmony_cistatic int
387db96d56Sopenharmony_cirow_clear(pysqlite_Row *self)
397db96d56Sopenharmony_ci{
407db96d56Sopenharmony_ci    Py_CLEAR(self->data);
417db96d56Sopenharmony_ci    Py_CLEAR(self->description);
427db96d56Sopenharmony_ci    return 0;
437db96d56Sopenharmony_ci}
447db96d56Sopenharmony_ci
457db96d56Sopenharmony_cistatic int
467db96d56Sopenharmony_cirow_traverse(pysqlite_Row *self, visitproc visit, void *arg)
477db96d56Sopenharmony_ci{
487db96d56Sopenharmony_ci    Py_VISIT(Py_TYPE(self));
497db96d56Sopenharmony_ci    Py_VISIT(self->data);
507db96d56Sopenharmony_ci    Py_VISIT(self->description);
517db96d56Sopenharmony_ci    return 0;
527db96d56Sopenharmony_ci}
537db96d56Sopenharmony_ci
547db96d56Sopenharmony_cistatic void
557db96d56Sopenharmony_cipysqlite_row_dealloc(PyObject *self)
567db96d56Sopenharmony_ci{
577db96d56Sopenharmony_ci    PyTypeObject *tp = Py_TYPE(self);
587db96d56Sopenharmony_ci    PyObject_GC_UnTrack(self);
597db96d56Sopenharmony_ci    tp->tp_clear(self);
607db96d56Sopenharmony_ci    tp->tp_free(self);
617db96d56Sopenharmony_ci    Py_DECREF(tp);
627db96d56Sopenharmony_ci}
637db96d56Sopenharmony_ci
647db96d56Sopenharmony_ci/*[clinic input]
657db96d56Sopenharmony_ci@classmethod
667db96d56Sopenharmony_ci_sqlite3.Row.__new__ as pysqlite_row_new
677db96d56Sopenharmony_ci
687db96d56Sopenharmony_ci    cursor: object(type='pysqlite_Cursor *', subclass_of='clinic_state()->CursorType')
697db96d56Sopenharmony_ci    data: object(subclass_of='&PyTuple_Type')
707db96d56Sopenharmony_ci    /
717db96d56Sopenharmony_ci
727db96d56Sopenharmony_ci[clinic start generated code]*/
737db96d56Sopenharmony_ci
747db96d56Sopenharmony_cistatic PyObject *
757db96d56Sopenharmony_cipysqlite_row_new_impl(PyTypeObject *type, pysqlite_Cursor *cursor,
767db96d56Sopenharmony_ci                      PyObject *data)
777db96d56Sopenharmony_ci/*[clinic end generated code: output=10d58b09a819a4c1 input=b9e954ca31345dbf]*/
787db96d56Sopenharmony_ci{
797db96d56Sopenharmony_ci    pysqlite_Row *self;
807db96d56Sopenharmony_ci
817db96d56Sopenharmony_ci    assert(type != NULL && type->tp_alloc != NULL);
827db96d56Sopenharmony_ci
837db96d56Sopenharmony_ci    self = (pysqlite_Row *) type->tp_alloc(type, 0);
847db96d56Sopenharmony_ci    if (self == NULL)
857db96d56Sopenharmony_ci        return NULL;
867db96d56Sopenharmony_ci
877db96d56Sopenharmony_ci    self->data = Py_NewRef(data);
887db96d56Sopenharmony_ci    self->description = Py_NewRef(cursor->description);
897db96d56Sopenharmony_ci
907db96d56Sopenharmony_ci    return (PyObject *) self;
917db96d56Sopenharmony_ci}
927db96d56Sopenharmony_ci
937db96d56Sopenharmony_ciPyObject* pysqlite_row_item(pysqlite_Row* self, Py_ssize_t idx)
947db96d56Sopenharmony_ci{
957db96d56Sopenharmony_ci   PyObject *item = PyTuple_GetItem(self->data, idx);
967db96d56Sopenharmony_ci   return Py_XNewRef(item);
977db96d56Sopenharmony_ci}
987db96d56Sopenharmony_ci
997db96d56Sopenharmony_cistatic int
1007db96d56Sopenharmony_ciequal_ignore_case(PyObject *left, PyObject *right)
1017db96d56Sopenharmony_ci{
1027db96d56Sopenharmony_ci    int eq = PyObject_RichCompareBool(left, right, Py_EQ);
1037db96d56Sopenharmony_ci    if (eq) { /* equal or error */
1047db96d56Sopenharmony_ci        return eq;
1057db96d56Sopenharmony_ci    }
1067db96d56Sopenharmony_ci    if (!PyUnicode_Check(left) || !PyUnicode_Check(right)) {
1077db96d56Sopenharmony_ci        return 0;
1087db96d56Sopenharmony_ci    }
1097db96d56Sopenharmony_ci    if (!PyUnicode_IS_ASCII(left) || !PyUnicode_IS_ASCII(right)) {
1107db96d56Sopenharmony_ci        return 0;
1117db96d56Sopenharmony_ci    }
1127db96d56Sopenharmony_ci
1137db96d56Sopenharmony_ci    Py_ssize_t len = PyUnicode_GET_LENGTH(left);
1147db96d56Sopenharmony_ci    if (PyUnicode_GET_LENGTH(right) != len) {
1157db96d56Sopenharmony_ci        return 0;
1167db96d56Sopenharmony_ci    }
1177db96d56Sopenharmony_ci    const Py_UCS1 *p1 = PyUnicode_1BYTE_DATA(left);
1187db96d56Sopenharmony_ci    const Py_UCS1 *p2 = PyUnicode_1BYTE_DATA(right);
1197db96d56Sopenharmony_ci    for (; len; len--, p1++, p2++) {
1207db96d56Sopenharmony_ci        if (Py_TOLOWER(*p1) != Py_TOLOWER(*p2)) {
1217db96d56Sopenharmony_ci            return 0;
1227db96d56Sopenharmony_ci        }
1237db96d56Sopenharmony_ci    }
1247db96d56Sopenharmony_ci    return 1;
1257db96d56Sopenharmony_ci}
1267db96d56Sopenharmony_ci
1277db96d56Sopenharmony_cistatic PyObject *
1287db96d56Sopenharmony_cipysqlite_row_subscript(pysqlite_Row *self, PyObject *idx)
1297db96d56Sopenharmony_ci{
1307db96d56Sopenharmony_ci    Py_ssize_t _idx;
1317db96d56Sopenharmony_ci    Py_ssize_t nitems, i;
1327db96d56Sopenharmony_ci
1337db96d56Sopenharmony_ci    if (PyLong_Check(idx)) {
1347db96d56Sopenharmony_ci        _idx = PyNumber_AsSsize_t(idx, PyExc_IndexError);
1357db96d56Sopenharmony_ci        if (_idx == -1 && PyErr_Occurred())
1367db96d56Sopenharmony_ci            return NULL;
1377db96d56Sopenharmony_ci        if (_idx < 0)
1387db96d56Sopenharmony_ci           _idx += PyTuple_GET_SIZE(self->data);
1397db96d56Sopenharmony_ci
1407db96d56Sopenharmony_ci        PyObject *item = PyTuple_GetItem(self->data, _idx);
1417db96d56Sopenharmony_ci        return Py_XNewRef(item);
1427db96d56Sopenharmony_ci    } else if (PyUnicode_Check(idx)) {
1437db96d56Sopenharmony_ci        nitems = PyTuple_Size(self->description);
1447db96d56Sopenharmony_ci
1457db96d56Sopenharmony_ci        for (i = 0; i < nitems; i++) {
1467db96d56Sopenharmony_ci            PyObject *obj;
1477db96d56Sopenharmony_ci            obj = PyTuple_GET_ITEM(self->description, i);
1487db96d56Sopenharmony_ci            obj = PyTuple_GET_ITEM(obj, 0);
1497db96d56Sopenharmony_ci            int eq = equal_ignore_case(idx, obj);
1507db96d56Sopenharmony_ci            if (eq < 0) {
1517db96d56Sopenharmony_ci                return NULL;
1527db96d56Sopenharmony_ci            }
1537db96d56Sopenharmony_ci            if (eq) {
1547db96d56Sopenharmony_ci                /* found item */
1557db96d56Sopenharmony_ci                PyObject *item = PyTuple_GetItem(self->data, i);
1567db96d56Sopenharmony_ci                return Py_XNewRef(item);
1577db96d56Sopenharmony_ci            }
1587db96d56Sopenharmony_ci        }
1597db96d56Sopenharmony_ci
1607db96d56Sopenharmony_ci        PyErr_SetString(PyExc_IndexError, "No item with that key");
1617db96d56Sopenharmony_ci        return NULL;
1627db96d56Sopenharmony_ci    }
1637db96d56Sopenharmony_ci    else if (PySlice_Check(idx)) {
1647db96d56Sopenharmony_ci        return PyObject_GetItem(self->data, idx);
1657db96d56Sopenharmony_ci    }
1667db96d56Sopenharmony_ci    else {
1677db96d56Sopenharmony_ci        PyErr_SetString(PyExc_IndexError, "Index must be int or string");
1687db96d56Sopenharmony_ci        return NULL;
1697db96d56Sopenharmony_ci    }
1707db96d56Sopenharmony_ci}
1717db96d56Sopenharmony_ci
1727db96d56Sopenharmony_cistatic Py_ssize_t
1737db96d56Sopenharmony_cipysqlite_row_length(pysqlite_Row* self)
1747db96d56Sopenharmony_ci{
1757db96d56Sopenharmony_ci    return PyTuple_GET_SIZE(self->data);
1767db96d56Sopenharmony_ci}
1777db96d56Sopenharmony_ci
1787db96d56Sopenharmony_ci/*[clinic input]
1797db96d56Sopenharmony_ci_sqlite3.Row.keys as pysqlite_row_keys
1807db96d56Sopenharmony_ci
1817db96d56Sopenharmony_ciReturns the keys of the row.
1827db96d56Sopenharmony_ci[clinic start generated code]*/
1837db96d56Sopenharmony_ci
1847db96d56Sopenharmony_cistatic PyObject *
1857db96d56Sopenharmony_cipysqlite_row_keys_impl(pysqlite_Row *self)
1867db96d56Sopenharmony_ci/*[clinic end generated code: output=efe3dfb3af6edc07 input=7549a122827c5563]*/
1877db96d56Sopenharmony_ci{
1887db96d56Sopenharmony_ci    PyObject* list;
1897db96d56Sopenharmony_ci    Py_ssize_t nitems, i;
1907db96d56Sopenharmony_ci
1917db96d56Sopenharmony_ci    list = PyList_New(0);
1927db96d56Sopenharmony_ci    if (!list) {
1937db96d56Sopenharmony_ci        return NULL;
1947db96d56Sopenharmony_ci    }
1957db96d56Sopenharmony_ci    nitems = PyTuple_Size(self->description);
1967db96d56Sopenharmony_ci
1977db96d56Sopenharmony_ci    for (i = 0; i < nitems; i++) {
1987db96d56Sopenharmony_ci        if (PyList_Append(list, PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0)) != 0) {
1997db96d56Sopenharmony_ci            Py_DECREF(list);
2007db96d56Sopenharmony_ci            return NULL;
2017db96d56Sopenharmony_ci        }
2027db96d56Sopenharmony_ci    }
2037db96d56Sopenharmony_ci
2047db96d56Sopenharmony_ci    return list;
2057db96d56Sopenharmony_ci}
2067db96d56Sopenharmony_ci
2077db96d56Sopenharmony_cistatic PyObject* pysqlite_iter(pysqlite_Row* self)
2087db96d56Sopenharmony_ci{
2097db96d56Sopenharmony_ci    return PyObject_GetIter(self->data);
2107db96d56Sopenharmony_ci}
2117db96d56Sopenharmony_ci
2127db96d56Sopenharmony_cistatic Py_hash_t pysqlite_row_hash(pysqlite_Row *self)
2137db96d56Sopenharmony_ci{
2147db96d56Sopenharmony_ci    return PyObject_Hash(self->description) ^ PyObject_Hash(self->data);
2157db96d56Sopenharmony_ci}
2167db96d56Sopenharmony_ci
2177db96d56Sopenharmony_cistatic PyObject* pysqlite_row_richcompare(pysqlite_Row *self, PyObject *_other, int opid)
2187db96d56Sopenharmony_ci{
2197db96d56Sopenharmony_ci    if (opid != Py_EQ && opid != Py_NE)
2207db96d56Sopenharmony_ci        Py_RETURN_NOTIMPLEMENTED;
2217db96d56Sopenharmony_ci
2227db96d56Sopenharmony_ci    pysqlite_state *state = pysqlite_get_state_by_type(Py_TYPE(self));
2237db96d56Sopenharmony_ci    if (PyObject_TypeCheck(_other, state->RowType)) {
2247db96d56Sopenharmony_ci        pysqlite_Row *other = (pysqlite_Row *)_other;
2257db96d56Sopenharmony_ci        int eq = PyObject_RichCompareBool(self->description, other->description, Py_EQ);
2267db96d56Sopenharmony_ci        if (eq < 0) {
2277db96d56Sopenharmony_ci            return NULL;
2287db96d56Sopenharmony_ci        }
2297db96d56Sopenharmony_ci        if (eq) {
2307db96d56Sopenharmony_ci            return PyObject_RichCompare(self->data, other->data, opid);
2317db96d56Sopenharmony_ci        }
2327db96d56Sopenharmony_ci        return PyBool_FromLong(opid != Py_EQ);
2337db96d56Sopenharmony_ci    }
2347db96d56Sopenharmony_ci    Py_RETURN_NOTIMPLEMENTED;
2357db96d56Sopenharmony_ci}
2367db96d56Sopenharmony_ci
2377db96d56Sopenharmony_cistatic PyMethodDef row_methods[] = {
2387db96d56Sopenharmony_ci    PYSQLITE_ROW_KEYS_METHODDEF
2397db96d56Sopenharmony_ci    {NULL, NULL}
2407db96d56Sopenharmony_ci};
2417db96d56Sopenharmony_ci
2427db96d56Sopenharmony_cistatic PyType_Slot row_slots[] = {
2437db96d56Sopenharmony_ci    {Py_tp_dealloc, pysqlite_row_dealloc},
2447db96d56Sopenharmony_ci    {Py_tp_hash, pysqlite_row_hash},
2457db96d56Sopenharmony_ci    {Py_tp_methods, row_methods},
2467db96d56Sopenharmony_ci    {Py_tp_richcompare, pysqlite_row_richcompare},
2477db96d56Sopenharmony_ci    {Py_tp_iter, pysqlite_iter},
2487db96d56Sopenharmony_ci    {Py_mp_length, pysqlite_row_length},
2497db96d56Sopenharmony_ci    {Py_mp_subscript, pysqlite_row_subscript},
2507db96d56Sopenharmony_ci    {Py_sq_length, pysqlite_row_length},
2517db96d56Sopenharmony_ci    {Py_sq_item, pysqlite_row_item},
2527db96d56Sopenharmony_ci    {Py_tp_new, pysqlite_row_new},
2537db96d56Sopenharmony_ci    {Py_tp_traverse, row_traverse},
2547db96d56Sopenharmony_ci    {Py_tp_clear, row_clear},
2557db96d56Sopenharmony_ci    {0, NULL},
2567db96d56Sopenharmony_ci};
2577db96d56Sopenharmony_ci
2587db96d56Sopenharmony_cistatic PyType_Spec row_spec = {
2597db96d56Sopenharmony_ci    .name = MODULE_NAME ".Row",
2607db96d56Sopenharmony_ci    .basicsize = sizeof(pysqlite_Row),
2617db96d56Sopenharmony_ci    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
2627db96d56Sopenharmony_ci              Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
2637db96d56Sopenharmony_ci    .slots = row_slots,
2647db96d56Sopenharmony_ci};
2657db96d56Sopenharmony_ci
2667db96d56Sopenharmony_ciint
2677db96d56Sopenharmony_cipysqlite_row_setup_types(PyObject *module)
2687db96d56Sopenharmony_ci{
2697db96d56Sopenharmony_ci    PyObject *type = PyType_FromModuleAndSpec(module, &row_spec, NULL);
2707db96d56Sopenharmony_ci    if (type == NULL) {
2717db96d56Sopenharmony_ci        return -1;
2727db96d56Sopenharmony_ci    }
2737db96d56Sopenharmony_ci    pysqlite_state *state = pysqlite_get_state(module);
2747db96d56Sopenharmony_ci    state->RowType = (PyTypeObject *)type;
2757db96d56Sopenharmony_ci    return 0;
2767db96d56Sopenharmony_ci}
277