blob: 61de801736745fbd01173de84e638e54e7a2faf2 [file] [log] [blame]
Anthony Baxterc51ee692006-04-01 00:57:31 +00001/* row.c - an enhanced tuple for database rows
2 *
3 * Copyright (C) 2005 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
27void row_dealloc(Row* self)
28{
29 Py_XDECREF(self->data);
30 Py_XDECREF(self->description);
31
32 self->ob_type->tp_free((PyObject*)self);
33}
34
35int row_init(Row* self, PyObject* args, PyObject* kwargs)
36{
37 PyObject* data;
38 Cursor* cursor;
39
40 self->data = 0;
41 self->description = 0;
42
43 if (!PyArg_ParseTuple(args, "OO", &cursor, &data)) {
44 return -1;
45 }
46
47 if (!PyObject_IsInstance((PyObject*)cursor, (PyObject*)&CursorType)) {
48 PyErr_SetString(PyExc_TypeError, "instance of cursor required for first argument");
49 return -1;
50 }
51
52 if (!PyTuple_Check(data)) {
53 PyErr_SetString(PyExc_TypeError, "tuple required for second argument");
54 return -1;
55 }
56
57 Py_INCREF(data);
58 self->data = data;
59
60 Py_INCREF(cursor->description);
61 self->description = cursor->description;
62
63 return 0;
64}
65
66PyObject* row_subscript(Row* self, PyObject* idx)
67{
68 long _idx;
69 char* key;
70 int nitems, i;
71 char* compare_key;
72
73 char* p1;
74 char* p2;
75
76 PyObject* item;
77
78 if (PyInt_Check(idx)) {
79 _idx = PyInt_AsLong(idx);
80 item = PyTuple_GetItem(self->data, _idx);
81 if (item) {
82 Py_INCREF(item);
83 }
84 return item;
85 } else if (PyString_Check(idx)) {
86 key = PyString_AsString(idx);
87
88 nitems = PyTuple_Size(self->description);
89
90 for (i = 0; i < nitems; i++) {
91 compare_key = PyString_AsString(PyTuple_GET_ITEM(PyTuple_GET_ITEM(self->description, i), 0));
92
93 p1 = key;
94 p2 = compare_key;
95
96 while (1) {
97 if ((*p1 == (char)0) || (*p2 == (char)0)) {
98 break;
99 }
100
101 if ((*p1 | 0x20) != (*p2 | 0x20)) {
102 break;
103 }
104
105 p1++;
106 p2++;
107 }
108
109 if ((*p1 == (char)0) && (*p2 == (char)0)) {
110 /* found item */
111 item = PyTuple_GetItem(self->data, i);
112 Py_INCREF(item);
113 return item;
114 }
115
116 }
117
118 PyErr_SetString(PyExc_IndexError, "No item with that key");
119 return NULL;
120 } else if (PySlice_Check(idx)) {
121 PyErr_SetString(PyExc_ValueError, "slices not implemented, yet");
122 return NULL;
123 } else {
124 PyErr_SetString(PyExc_IndexError, "Index must be int or string");
125 return NULL;
126 }
127}
128
Neal Norwitz95f0e4c2006-04-01 09:08:06 +0000129Py_ssize_t row_length(Row* self, PyObject* args, PyObject* kwargs)
Anthony Baxterc51ee692006-04-01 00:57:31 +0000130{
131 return PyTuple_GET_SIZE(self->data);
132}
133
134static int row_print(Row* self, FILE *fp, int flags)
135{
136 return (&PyTuple_Type)->tp_print(self->data, fp, flags);
137}
138
139
140PyMappingMethods row_as_mapping = {
Neal Norwitz95f0e4c2006-04-01 09:08:06 +0000141 /* mp_length */ (lenfunc)row_length,
Anthony Baxterc51ee692006-04-01 00:57:31 +0000142 /* mp_subscript */ (binaryfunc)row_subscript,
143 /* mp_ass_subscript */ (objobjargproc)0,
144};
145
146
147PyTypeObject RowType = {
148 PyObject_HEAD_INIT(NULL)
149 0, /* ob_size */
150 "pysqlite2.dbapi2.Row", /* tp_name */
151 sizeof(Row), /* tp_basicsize */
152 0, /* tp_itemsize */
153 (destructor)row_dealloc, /* tp_dealloc */
154 (printfunc)row_print, /* tp_print */
155 0, /* tp_getattr */
156 0, /* tp_setattr */
157 0, /* tp_compare */
158 0, /* tp_repr */
159 0, /* tp_as_number */
160 0, /* tp_as_sequence */
161 0, /* tp_as_mapping */
162 0, /* tp_hash */
163 0, /* tp_call */
164 0, /* tp_str */
165 0, /* tp_getattro */
166 0, /* tp_setattro */
167 0, /* tp_as_buffer */
168 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
169 0, /* tp_doc */
170 0, /* tp_traverse */
171 0, /* tp_clear */
172 0, /* tp_richcompare */
173 0, /* tp_weaklistoffset */
174 0, /* tp_iter */
175 0, /* tp_iternext */
176 0, /* tp_methods */
177 0, /* tp_members */
178 0, /* tp_getset */
179 0, /* tp_base */
180 0, /* tp_dict */
181 0, /* tp_descr_get */
182 0, /* tp_descr_set */
183 0, /* tp_dictoffset */
184 (initproc)row_init, /* tp_init */
185 0, /* tp_alloc */
186 0, /* tp_new */
187 0 /* tp_free */
188};
189
190extern int row_setup_types(void)
191{
192 RowType.tp_new = PyType_GenericNew;
193 RowType.tp_as_mapping = &row_as_mapping;
194 return PyType_Ready(&RowType);
195}