1 /*
2  * the PLyResult class
3  *
4  * src/pl/plpython/plpy_resultobject.c
5  */
6 
7 #include "postgres.h"
8 
9 #include "plpython.h"
10 
11 #include "plpy_resultobject.h"
12 #include "plpy_elog.h"
13 
14 
15 static void PLy_result_dealloc(PyObject *arg);
16 static PyObject *PLy_result_colnames(PyObject *self, PyObject *unused);
17 static PyObject *PLy_result_coltypes(PyObject *self, PyObject *unused);
18 static PyObject *PLy_result_coltypmods(PyObject *self, PyObject *unused);
19 static PyObject *PLy_result_nrows(PyObject *self, PyObject *args);
20 static PyObject *PLy_result_status(PyObject *self, PyObject *args);
21 static Py_ssize_t PLy_result_length(PyObject *arg);
22 static PyObject *PLy_result_item(PyObject *arg, Py_ssize_t idx);
23 static PyObject *PLy_result_slice(PyObject *arg, Py_ssize_t lidx, Py_ssize_t hidx);
24 static int	PLy_result_ass_slice(PyObject *arg, Py_ssize_t lidx, Py_ssize_t hidx, PyObject *slice);
25 static PyObject *PLy_result_str(PyObject *arg);
26 static PyObject *PLy_result_subscript(PyObject *arg, PyObject *item);
27 static int	PLy_result_ass_subscript(PyObject *self, PyObject *item, PyObject *value);
28 
29 static char PLy_result_doc[] = {
30 	"Results of a PostgreSQL query"
31 };
32 
33 static PySequenceMethods PLy_result_as_sequence = {
34 	PLy_result_length,			/* sq_length */
35 	NULL,						/* sq_concat */
36 	NULL,						/* sq_repeat */
37 	PLy_result_item,			/* sq_item */
38 	PLy_result_slice,			/* sq_slice */
39 	NULL,						/* sq_ass_item */
40 	PLy_result_ass_slice,		/* sq_ass_slice */
41 };
42 
43 static PyMappingMethods PLy_result_as_mapping = {
44 	PLy_result_length,			/* mp_length */
45 	PLy_result_subscript,		/* mp_subscript */
46 	PLy_result_ass_subscript,	/* mp_ass_subscript */
47 };
48 
49 static PyMethodDef PLy_result_methods[] = {
50 	{"colnames", PLy_result_colnames, METH_NOARGS, NULL},
51 	{"coltypes", PLy_result_coltypes, METH_NOARGS, NULL},
52 	{"coltypmods", PLy_result_coltypmods, METH_NOARGS, NULL},
53 	{"nrows", PLy_result_nrows, METH_VARARGS, NULL},
54 	{"status", PLy_result_status, METH_VARARGS, NULL},
55 	{NULL, NULL, 0, NULL}
56 };
57 
58 static PyTypeObject PLy_ResultType = {
59 	PyVarObject_HEAD_INIT(NULL, 0)
60 	"PLyResult",				/* tp_name */
61 	sizeof(PLyResultObject),	/* tp_size */
62 	0,							/* tp_itemsize */
63 
64 	/*
65 	 * methods
66 	 */
67 	PLy_result_dealloc,			/* tp_dealloc */
68 	0,							/* tp_print */
69 	0,							/* tp_getattr */
70 	0,							/* tp_setattr */
71 	0,							/* tp_compare */
72 	0,							/* tp_repr */
73 	0,							/* tp_as_number */
74 	&PLy_result_as_sequence,	/* tp_as_sequence */
75 	&PLy_result_as_mapping,		/* tp_as_mapping */
76 	0,							/* tp_hash */
77 	0,							/* tp_call */
78 	&PLy_result_str,			/* tp_str */
79 	0,							/* tp_getattro */
80 	0,							/* tp_setattro */
81 	0,							/* tp_as_buffer */
82 	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,	/* tp_flags */
83 	PLy_result_doc,				/* tp_doc */
84 	0,							/* tp_traverse */
85 	0,							/* tp_clear */
86 	0,							/* tp_richcompare */
87 	0,							/* tp_weaklistoffset */
88 	0,							/* tp_iter */
89 	0,							/* tp_iternext */
90 	PLy_result_methods,			/* tp_tpmethods */
91 };
92 
93 void
94 PLy_result_init_type(void)
95 {
96 	if (PyType_Ready(&PLy_ResultType) < 0)
97 		elog(ERROR, "could not initialize PLy_ResultType");
98 }
99 
100 PyObject *
101 PLy_result_new(void)
102 {
103 	PLyResultObject *ob;
104 
105 	if ((ob = PyObject_New(PLyResultObject, &PLy_ResultType)) == NULL)
106 		return NULL;
107 
108 	/* ob->tuples = NULL; */
109 
110 	Py_INCREF(Py_None);
111 	ob->status = Py_None;
112 	ob->nrows = PyInt_FromLong(-1);
113 	ob->rows = PyList_New(0);
114 	ob->tupdesc = NULL;
115 	if (!ob->rows)
116 	{
117 		Py_DECREF(ob);
118 		return NULL;
119 	}
120 
121 	return (PyObject *) ob;
122 }
123 
124 static void
125 PLy_result_dealloc(PyObject *arg)
126 {
127 	PLyResultObject *ob = (PLyResultObject *) arg;
128 
129 	Py_XDECREF(ob->nrows);
130 	Py_XDECREF(ob->rows);
131 	Py_XDECREF(ob->status);
132 	if (ob->tupdesc)
133 	{
134 		FreeTupleDesc(ob->tupdesc);
135 		ob->tupdesc = NULL;
136 	}
137 
138 	arg->ob_type->tp_free(arg);
139 }
140 
141 static PyObject *
142 PLy_result_colnames(PyObject *self, PyObject *unused)
143 {
144 	PLyResultObject *ob = (PLyResultObject *) self;
145 	PyObject   *list;
146 	int			i;
147 
148 	if (!ob->tupdesc)
149 	{
150 		PLy_exception_set(PLy_exc_error, "command did not produce a result set");
151 		return NULL;
152 	}
153 
154 	list = PyList_New(ob->tupdesc->natts);
155 	if (!list)
156 		return NULL;
157 	for (i = 0; i < ob->tupdesc->natts; i++)
158 	{
159 		Form_pg_attribute attr = TupleDescAttr(ob->tupdesc, i);
160 
161 		PyList_SET_ITEM(list, i, PyString_FromString(NameStr(attr->attname)));
162 	}
163 
164 	return list;
165 }
166 
167 static PyObject *
168 PLy_result_coltypes(PyObject *self, PyObject *unused)
169 {
170 	PLyResultObject *ob = (PLyResultObject *) self;
171 	PyObject   *list;
172 	int			i;
173 
174 	if (!ob->tupdesc)
175 	{
176 		PLy_exception_set(PLy_exc_error, "command did not produce a result set");
177 		return NULL;
178 	}
179 
180 	list = PyList_New(ob->tupdesc->natts);
181 	if (!list)
182 		return NULL;
183 	for (i = 0; i < ob->tupdesc->natts; i++)
184 	{
185 		Form_pg_attribute attr = TupleDescAttr(ob->tupdesc, i);
186 
187 		PyList_SET_ITEM(list, i, PyInt_FromLong(attr->atttypid));
188 	}
189 
190 	return list;
191 }
192 
193 static PyObject *
194 PLy_result_coltypmods(PyObject *self, PyObject *unused)
195 {
196 	PLyResultObject *ob = (PLyResultObject *) self;
197 	PyObject   *list;
198 	int			i;
199 
200 	if (!ob->tupdesc)
201 	{
202 		PLy_exception_set(PLy_exc_error, "command did not produce a result set");
203 		return NULL;
204 	}
205 
206 	list = PyList_New(ob->tupdesc->natts);
207 	if (!list)
208 		return NULL;
209 	for (i = 0; i < ob->tupdesc->natts; i++)
210 	{
211 		Form_pg_attribute attr = TupleDescAttr(ob->tupdesc, i);
212 
213 		PyList_SET_ITEM(list, i, PyInt_FromLong(attr->atttypmod));
214 	}
215 
216 	return list;
217 }
218 
219 static PyObject *
220 PLy_result_nrows(PyObject *self, PyObject *args)
221 {
222 	PLyResultObject *ob = (PLyResultObject *) self;
223 
224 	Py_INCREF(ob->nrows);
225 	return ob->nrows;
226 }
227 
228 static PyObject *
229 PLy_result_status(PyObject *self, PyObject *args)
230 {
231 	PLyResultObject *ob = (PLyResultObject *) self;
232 
233 	Py_INCREF(ob->status);
234 	return ob->status;
235 }
236 
237 static Py_ssize_t
238 PLy_result_length(PyObject *arg)
239 {
240 	PLyResultObject *ob = (PLyResultObject *) arg;
241 
242 	return PyList_Size(ob->rows);
243 }
244 
245 static PyObject *
246 PLy_result_item(PyObject *arg, Py_ssize_t idx)
247 {
248 	PyObject   *rv;
249 	PLyResultObject *ob = (PLyResultObject *) arg;
250 
251 	rv = PyList_GetItem(ob->rows, idx);
252 	if (rv != NULL)
253 		Py_INCREF(rv);
254 	return rv;
255 }
256 
257 static PyObject *
258 PLy_result_slice(PyObject *arg, Py_ssize_t lidx, Py_ssize_t hidx)
259 {
260 	PLyResultObject *ob = (PLyResultObject *) arg;
261 
262 	return PyList_GetSlice(ob->rows, lidx, hidx);
263 }
264 
265 static int
266 PLy_result_ass_slice(PyObject *arg, Py_ssize_t lidx, Py_ssize_t hidx, PyObject *slice)
267 {
268 	int			rv;
269 	PLyResultObject *ob = (PLyResultObject *) arg;
270 
271 	rv = PyList_SetSlice(ob->rows, lidx, hidx, slice);
272 	return rv;
273 }
274 
275 static PyObject *
276 PLy_result_str(PyObject *arg)
277 {
278 	PLyResultObject *ob = (PLyResultObject *) arg;
279 
280 #if PY_MAJOR_VERSION >= 3
281 	return PyUnicode_FromFormat("<%s status=%S nrows=%S rows=%S>",
282 								Py_TYPE(ob)->tp_name,
283 								ob->status,
284 								ob->nrows,
285 								ob->rows);
286 #else
287 	return PyString_FromFormat("<%s status=%ld nrows=%ld rows=%s>",
288 							   ob->ob_type->tp_name,
289 							   PyInt_AsLong(ob->status),
290 							   PyInt_AsLong(ob->nrows),
291 							   PyString_AsString(PyObject_Str(ob->rows)));
292 #endif
293 }
294 
295 static PyObject *
296 PLy_result_subscript(PyObject *arg, PyObject *item)
297 {
298 	PLyResultObject *ob = (PLyResultObject *) arg;
299 
300 	return PyObject_GetItem(ob->rows, item);
301 }
302 
303 static int
304 PLy_result_ass_subscript(PyObject *arg, PyObject *item, PyObject *value)
305 {
306 	PLyResultObject *ob = (PLyResultObject *) arg;
307 
308 	return PyObject_SetItem(ob->rows, item, value);
309 }
310