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