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