Merge remote-tracking branch 'origin/pycurl' into planetlab-4_0-branch
[plcapi.git] / psycopg2 / psycopg / adapter_list.c
1 /* adapter_list.c - python list objects
2  *
3  * Copyright (C) 2004-2005 Federico Di Gregorio <fog@debian.org>
4  *
5  * This file is part of psycopg.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2,
10  * or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21
22 #include <Python.h>
23 #include <structmember.h>
24 #include <stringobject.h>
25
26 #define PSYCOPG_MODULE
27 #include "psycopg/config.h"
28 #include "psycopg/python.h"
29 #include "psycopg/psycopg.h"
30 #include "psycopg/adapter_list.h"
31 #include "psycopg/microprotocols.h"
32 #include "psycopg/microprotocols_proto.h"
33
34
35 /* list_str, list_getquoted - return result of quoting */
36
37 static PyObject *
38 list_quote(listObject *self)
39 {
40     /*  adapt the list by calling adapt() recursively and then wrapping
41         everything into "ARRAY[]" */
42     PyObject *tmp = NULL, *str = NULL, *joined = NULL, *res = NULL;
43     int i, len;
44
45     len = PyList_GET_SIZE(self->wrapped);
46     
47     /* empty arrays are converted to NULLs (still searching for a way to
48        insert an empty array in postgresql */
49     if (len == 0) return PyString_FromString("'{}'");
50     
51     tmp = PyTuple_New(len);
52     
53     for (i=0; i<len; i++) {
54         PyObject *quoted =
55             microprotocol_getquoted(PyList_GET_ITEM(self->wrapped, i),
56                                     (connectionObject*)self->connection);
57         if (quoted == NULL) goto error;
58
59         /* here we don't loose a refcnt: SET_ITEM does not change the
60            reference count and we are just transferring ownership of the tmp
61            object to the tuple */
62         PyTuple_SET_ITEM(tmp, i, quoted);
63     }
64
65     /* now that we have a tuple of adapted objects we just need to join them
66        and put "ARRAY[] around the result */
67     str = PyString_FromString(", ");
68     joined = PyObject_CallMethod(str, "join", "(O)", tmp);
69     if (joined == NULL) goto error;
70
71     res = PyString_FromFormat("ARRAY[%s]", PyString_AsString(joined));
72     
73  error:
74     Py_XDECREF(tmp);
75     Py_XDECREF(str);
76     Py_XDECREF(joined);
77     return res;
78 }
79
80 PyObject *
81 list_str(listObject *self, PyObject *args)
82 {
83     if (!PyArg_ParseTuple(args, "")) return NULL;
84     return list_quote(self);
85 }
86
87 PyObject *
88 list_getquoted(listObject *self, PyObject *args)
89 {
90     if (!PyArg_ParseTuple(args, "")) return NULL;
91     return list_quote(self);
92 }
93
94 PyObject *
95 list_prepare(listObject *self, PyObject *args)
96 {
97     connectionObject *conn;
98
99     if (!PyArg_ParseTuple(args, "O", &conn))
100         return NULL;
101
102     /* note that we don't copy the encoding from the connection, but take a
103        reference to it; we'll need it during the recursive adapt() call (the
104        encoding is here for a future expansion that will make .getquoted()
105        work even without a connection to the backend. */
106     Py_XDECREF(self->connection);
107     self->connection = (PyObject*)conn;
108     Py_INCREF(self->connection);
109     
110     Py_INCREF(Py_None);
111     return Py_None;
112 }
113
114 PyObject *
115 list_conform(listObject *self, PyObject *args)
116 {
117     PyObject *res, *proto;
118     
119     if (!PyArg_ParseTuple(args, "O", &proto)) return NULL;
120
121     if (proto == (PyObject*)&isqlquoteType)
122         res = (PyObject*)self;
123     else
124         res = Py_None;
125     
126     Py_INCREF(res);
127     return res;
128 }
129
130 /** the DateTime wrapper object **/
131
132 /* object member list */
133
134 static struct PyMemberDef listObject_members[] = {
135     {"adapted", T_OBJECT, offsetof(listObject, wrapped), RO},
136     {NULL}
137 };
138
139 /* object method table */
140
141 static PyMethodDef listObject_methods[] = {
142     {"getquoted", (PyCFunction)list_getquoted, METH_VARARGS,
143      "getquoted() -> wrapped object value as SQL date/time"},
144     {"prepare", (PyCFunction)list_prepare, METH_VARARGS,
145      "prepare(conn) -> set encoding to conn->encoding"},    
146     {"__conform__", (PyCFunction)list_conform, METH_VARARGS, NULL},
147     {NULL}  /* Sentinel */
148 };
149
150 /* initialization and finalization methods */
151
152 static int
153 list_setup(listObject *self, PyObject *obj, char *enc)
154 {
155     Dprintf("list_setup: init list object at %p, refcnt = %d",
156             self, ((PyObject *)self)->ob_refcnt);
157
158     if (!PyList_Check(obj))
159         return -1;
160
161     /* FIXME: remove this orrible strdup */
162     if (enc) self->encoding = strdup(enc);
163
164     self->connection = NULL;
165     self->wrapped = obj;
166     Py_INCREF(self->wrapped);
167     
168     Dprintf("list_setup: good list object at %p, refcnt = %d",
169             self, ((PyObject *)self)->ob_refcnt);
170     return 0;
171 }
172
173 static void
174 list_dealloc(PyObject* obj)
175 {
176     listObject *self = (listObject *)obj;
177
178     Py_XDECREF(self->wrapped);
179     Py_XDECREF(self->connection);
180     if (self->encoding) free(self->encoding);
181     
182     Dprintf("list_dealloc: deleted list object at %p, "
183             "refcnt = %d", obj, obj->ob_refcnt);
184     
185     obj->ob_type->tp_free(obj);
186 }
187
188 static int
189 list_init(PyObject *obj, PyObject *args, PyObject *kwds)
190 {
191     PyObject *l;
192     char *enc = "latin-1"; /* default encoding as in Python */
193     
194     if (!PyArg_ParseTuple(args, "O|s", &l, &enc))
195         return -1;
196
197     return list_setup((listObject *)obj, l, enc);
198 }
199
200 static PyObject *
201 list_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
202 {    
203     return type->tp_alloc(type, 0);
204 }
205
206 static void
207 list_del(PyObject* self)
208 {
209     PyObject_Del(self);
210 }
211
212 static PyObject *
213 list_repr(listObject *self)
214 {
215     return PyString_FromFormat("<psycopg2._psycopg.List object at %p>", self);
216 }
217
218 /* object type */
219
220 #define listType_doc \
221 "List(list) -> new list wrapper object"
222
223 PyTypeObject listType = {
224     PyObject_HEAD_INIT(NULL)
225     0,
226     "psycopg2._psycopg.List",
227     sizeof(listObject),
228     0,
229     list_dealloc, /*tp_dealloc*/
230     0,          /*tp_print*/
231     0,          /*tp_getattr*/
232     0,          /*tp_setattr*/   
233
234     0,          /*tp_compare*/
235     (reprfunc)list_repr, /*tp_repr*/
236     0,          /*tp_as_number*/
237     0,          /*tp_as_sequence*/
238     0,          /*tp_as_mapping*/
239     0,          /*tp_hash */
240
241     0,          /*tp_call*/
242     (reprfunc)list_str, /*tp_str*/
243     0,          /*tp_getattro*/
244     0,          /*tp_setattro*/
245     0,          /*tp_as_buffer*/
246
247     Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
248
249     listType_doc, /*tp_doc*/
250     
251     0,          /*tp_traverse*/
252     0,          /*tp_clear*/
253
254     0,          /*tp_richcompare*/
255     0,          /*tp_weaklistoffset*/
256
257     0,          /*tp_iter*/
258     0,          /*tp_iternext*/
259
260     /* Attribute descriptor and subclassing stuff */
261
262     listObject_methods, /*tp_methods*/
263     listObject_members, /*tp_members*/
264     0,          /*tp_getset*/
265     0,          /*tp_base*/
266     0,          /*tp_dict*/
267     
268     0,          /*tp_descr_get*/
269     0,          /*tp_descr_set*/
270     0,          /*tp_dictoffset*/
271     
272     list_init, /*tp_init*/
273     0, /*tp_alloc  will be set to PyType_GenericAlloc in module init*/
274     list_new, /*tp_new*/
275     (freefunc)list_del, /*tp_free  Low-level free-memory routine */
276     0,          /*tp_is_gc For PyObject_IS_GC */
277     0,          /*tp_bases*/
278     0,          /*tp_mro method resolution order */
279     0,          /*tp_cache*/
280     0,          /*tp_subclasses*/
281     0           /*tp_weaklist*/
282 };
283
284
285 /** module-level functions **/
286
287 PyObject *
288 psyco_List(PyObject *module, PyObject *args)
289 {
290     PyObject *str;
291     char *enc = "latin-1"; /* default encoding as in Python */
292     
293     if (!PyArg_ParseTuple(args, "O|s", &str, &enc))
294         return NULL;
295   
296     return PyObject_CallFunction((PyObject *)&listType, "Os", str, enc);
297 }