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
PLy_result_init_type(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 *
PLy_result_new(void)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 
116 	return (PyObject *) ob;
117 }
118 
119 static void
PLy_result_dealloc(PyObject * arg)120 PLy_result_dealloc(PyObject *arg)
121 {
122 	PLyResultObject *ob = (PLyResultObject *) arg;
123 
124 	Py_XDECREF(ob->nrows);
125 	Py_XDECREF(ob->rows);
126 	Py_XDECREF(ob->status);
127 	if (ob->tupdesc)
128 	{
129 		FreeTupleDesc(ob->tupdesc);
130 		ob->tupdesc = NULL;
131 	}
132 
133 	arg->ob_type->tp_free(arg);
134 }
135 
136 static PyObject *
PLy_result_colnames(PyObject * self,PyObject * unused)137 PLy_result_colnames(PyObject *self, PyObject *unused)
138 {
139 	PLyResultObject *ob = (PLyResultObject *) self;
140 	PyObject   *list;
141 	int			i;
142 
143 	if (!ob->tupdesc)
144 	{
145 		PLy_exception_set(PLy_exc_error, "command did not produce a result set");
146 		return NULL;
147 	}
148 
149 	list = PyList_New(ob->tupdesc->natts);
150 	for (i = 0; i < ob->tupdesc->natts; i++)
151 		PyList_SET_ITEM(list, i, PyString_FromString(NameStr(ob->tupdesc->attrs[i]->attname)));
152 
153 	return list;
154 }
155 
156 static PyObject *
PLy_result_coltypes(PyObject * self,PyObject * unused)157 PLy_result_coltypes(PyObject *self, PyObject *unused)
158 {
159 	PLyResultObject *ob = (PLyResultObject *) self;
160 	PyObject   *list;
161 	int			i;
162 
163 	if (!ob->tupdesc)
164 	{
165 		PLy_exception_set(PLy_exc_error, "command did not produce a result set");
166 		return NULL;
167 	}
168 
169 	list = PyList_New(ob->tupdesc->natts);
170 	for (i = 0; i < ob->tupdesc->natts; i++)
171 		PyList_SET_ITEM(list, i, PyInt_FromLong(ob->tupdesc->attrs[i]->atttypid));
172 
173 	return list;
174 }
175 
176 static PyObject *
PLy_result_coltypmods(PyObject * self,PyObject * unused)177 PLy_result_coltypmods(PyObject *self, PyObject *unused)
178 {
179 	PLyResultObject *ob = (PLyResultObject *) self;
180 	PyObject   *list;
181 	int			i;
182 
183 	if (!ob->tupdesc)
184 	{
185 		PLy_exception_set(PLy_exc_error, "command did not produce a result set");
186 		return NULL;
187 	}
188 
189 	list = PyList_New(ob->tupdesc->natts);
190 	for (i = 0; i < ob->tupdesc->natts; i++)
191 		PyList_SET_ITEM(list, i, PyInt_FromLong(ob->tupdesc->attrs[i]->atttypmod));
192 
193 	return list;
194 }
195 
196 static PyObject *
PLy_result_nrows(PyObject * self,PyObject * args)197 PLy_result_nrows(PyObject *self, PyObject *args)
198 {
199 	PLyResultObject *ob = (PLyResultObject *) self;
200 
201 	Py_INCREF(ob->nrows);
202 	return ob->nrows;
203 }
204 
205 static PyObject *
PLy_result_status(PyObject * self,PyObject * args)206 PLy_result_status(PyObject *self, PyObject *args)
207 {
208 	PLyResultObject *ob = (PLyResultObject *) self;
209 
210 	Py_INCREF(ob->status);
211 	return ob->status;
212 }
213 
214 static Py_ssize_t
PLy_result_length(PyObject * arg)215 PLy_result_length(PyObject *arg)
216 {
217 	PLyResultObject *ob = (PLyResultObject *) arg;
218 
219 	return PyList_Size(ob->rows);
220 }
221 
222 static PyObject *
PLy_result_item(PyObject * arg,Py_ssize_t idx)223 PLy_result_item(PyObject *arg, Py_ssize_t idx)
224 {
225 	PyObject   *rv;
226 	PLyResultObject *ob = (PLyResultObject *) arg;
227 
228 	rv = PyList_GetItem(ob->rows, idx);
229 	if (rv != NULL)
230 		Py_INCREF(rv);
231 	return rv;
232 }
233 
234 static PyObject *
PLy_result_slice(PyObject * arg,Py_ssize_t lidx,Py_ssize_t hidx)235 PLy_result_slice(PyObject *arg, Py_ssize_t lidx, Py_ssize_t hidx)
236 {
237 	PLyResultObject *ob = (PLyResultObject *) arg;
238 
239 	return PyList_GetSlice(ob->rows, lidx, hidx);
240 }
241 
242 static int
PLy_result_ass_slice(PyObject * arg,Py_ssize_t lidx,Py_ssize_t hidx,PyObject * slice)243 PLy_result_ass_slice(PyObject *arg, Py_ssize_t lidx, Py_ssize_t hidx, PyObject *slice)
244 {
245 	int			rv;
246 	PLyResultObject *ob = (PLyResultObject *) arg;
247 
248 	rv = PyList_SetSlice(ob->rows, lidx, hidx, slice);
249 	return rv;
250 }
251 
252 static PyObject *
PLy_result_str(PyObject * arg)253 PLy_result_str(PyObject *arg)
254 {
255 	PLyResultObject *ob = (PLyResultObject *) arg;
256 
257 #if PY_MAJOR_VERSION >= 3
258 	return PyUnicode_FromFormat("<%s status=%S nrows=%S rows=%S>",
259 								Py_TYPE(ob)->tp_name,
260 								ob->status,
261 								ob->nrows,
262 								ob->rows);
263 #else
264 	return PyString_FromFormat("<%s status=%ld nrows=%ld rows=%s>",
265 							   ob->ob_type->tp_name,
266 							   PyInt_AsLong(ob->status),
267 							   PyInt_AsLong(ob->nrows),
268 							   PyString_AsString(PyObject_Str(ob->rows)));
269 #endif
270 }
271 
272 static PyObject *
PLy_result_subscript(PyObject * arg,PyObject * item)273 PLy_result_subscript(PyObject *arg, PyObject *item)
274 {
275 	PLyResultObject *ob = (PLyResultObject *) arg;
276 
277 	return PyObject_GetItem(ob->rows, item);
278 }
279 
280 static int
PLy_result_ass_subscript(PyObject * arg,PyObject * item,PyObject * value)281 PLy_result_ass_subscript(PyObject *arg, PyObject *item, PyObject *value)
282 {
283 	PLyResultObject *ob = (PLyResultObject *) arg;
284 
285 	return PyObject_SetItem(ob->rows, item, value);
286 }
287