1 /* adapter_binary.c - Binary objects
3 * Copyright (C) 2003 Federico Di Gregorio <fog@debian.org>
5 * This file is part of psycopg.
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.
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.
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.
23 #include <structmember.h>
24 #include <stringobject.h>
29 #define PSYCOPG_MODULE
30 #include "psycopg/config.h"
31 #include "psycopg/python.h"
32 #include "psycopg/psycopg.h"
33 #include "psycopg/connection.h"
34 #include "psycopg/adapter_binary.h"
35 #include "psycopg/microprotocols_proto.h"
37 /** the quoting code */
39 #ifndef PSYCOPG_OWN_QUOTING
40 static unsigned char *
41 binary_escape(unsigned char *from, unsigned int from_length,
42 unsigned int *to_length, PGconn *conn)
44 #if PG_MAJOR_VERSION > 8 || \
45 (PG_MAJOR_VERSION == 8 && PG_MINOR_VERSION > 1) || \
46 (PG_MAJOR_VERSION == 8 && PG_MINOR_VERSION == 1 && PG_PATCH_VERSION >= 4)
48 return PQescapeByteaConn(conn, from, from_length, to_length);
51 return PQescapeBytea(from, from_length, to_length);
54 static unsigned char *
55 binary_escape(unsigned char *from, unsigned int from_length,
56 unsigned int *to_length, PGconn *conn)
58 unsigneed char *quoted, *chptr, *newptr;
59 int i, space, new_space;
61 space = from_length + 2;
63 Py_BEGIN_ALLOW_THREADS;
65 quoted = (unsigned char*)calloc(space, sizeof(char));
66 if (quoted == NULL) return NULL;
70 for (i=0; i < len; i++) {
71 if (chptr - quoted > space - 6) {
72 new_space = space * ((space) / (i + 1)) + 2 + 6;
73 if (new_space - space < 1024) space += 1024;
74 else space = new_space;
75 newptr = (unsigned char *)realloc(quoted, space);
80 /* chptr has to be moved to the new location*/
81 chptr = newptr + (chptr - quoted);
83 Dprintf("binary_escape: reallocated %i bytes at %p", space,quoted);
86 if (from[i] >= ' ' && from[i] <= '~') {
87 if (from[i] == '\'') {
93 else if (from[i] == '\\') {
94 memcpy(chptr, "\\\\\\\\", 4);
98 /* leave it as it is if ascii printable */
106 /* escape to octal notation \nnn */
110 *chptr = ((c >> 6) & 0x07) + 0x30; chptr++;
111 *chptr = ((c >> 3) & 0x07) + 0x30; chptr++;
112 *chptr = ( c & 0x07) + 0x30; chptr++;
116 /* escape null as \\000 */
117 memcpy(chptr, "\\\\000", 5);
123 Py_END_ALLOW_THREADS;
125 *to_size = chptr - quoted + 1;
130 /* binary_quote - do the quote process on plain and unicode strings */
133 binary_quote(binaryObject *self)
140 /* if we got a plain string or a buffer we escape it and save the buffer */
141 if (PyString_Check(self->wrapped) || PyBuffer_Check(self->wrapped)) {
142 /* escape and build quoted buffer */
143 PyObject_AsCharBuffer(self->wrapped, &buffer, &buffer_len);
145 to = (char *)binary_escape((unsigned char*)buffer, buffer_len, &len,
146 self->conn ? ((connectionObject*)self->conn)->pgconn : NULL);
153 self->buffer = PyString_FromFormat("'%s'", to);
155 self->buffer = PyString_FromString("''");
159 /* if the wrapped object is not a string or a buffer, this is an error */
161 PyErr_SetString(PyExc_TypeError, "can't escape non-string object");
168 /* binary_str, binary_getquoted - return result of quoting */
171 binary_str(binaryObject *self)
173 if (self->buffer == NULL) {
176 Py_XINCREF(self->buffer);
181 binary_getquoted(binaryObject *self, PyObject *args)
183 if (!PyArg_ParseTuple(args, "")) return NULL;
184 return binary_str(self);
188 binary_prepare(binaryObject *self, PyObject *args)
190 connectionObject *conn;
192 if (!PyArg_ParseTuple(args, "O", &conn))
195 Py_XDECREF(self->conn);
197 self->conn = (PyObject*)conn;
198 Py_INCREF(self->conn);
206 binary_conform(binaryObject *self, PyObject *args)
208 PyObject *res, *proto;
210 if (!PyArg_ParseTuple(args, "O", &proto)) return NULL;
212 if (proto == (PyObject*)&isqlquoteType)
213 res = (PyObject*)self;
221 /** the Binary object **/
223 /* object member list */
225 static struct PyMemberDef binaryObject_members[] = {
226 {"adapted", T_OBJECT, offsetof(binaryObject, wrapped), RO},
227 {"buffer", T_OBJECT, offsetof(binaryObject, buffer), RO},
231 /* object method table */
233 static PyMethodDef binaryObject_methods[] = {
234 {"getquoted", (PyCFunction)binary_getquoted, METH_VARARGS,
235 "getquoted() -> wrapped object value as SQL-quoted binary string"},
236 {"prepare", (PyCFunction)binary_prepare, METH_VARARGS,
237 "prepare(conn) -> prepare for binary encoding using conn"},
238 {"__conform__", (PyCFunction)binary_conform, METH_VARARGS, NULL},
239 {NULL} /* Sentinel */
242 /* initialization and finalization methods */
245 binary_setup(binaryObject *self, PyObject *str)
247 Dprintf("binary_setup: init binary object at %p, refcnt = %d",
248 self, ((PyObject *)self)->ob_refcnt);
253 Py_INCREF(self->wrapped);
255 Dprintf("binary_setup: good binary object at %p, refcnt = %d",
256 self, ((PyObject *)self)->ob_refcnt);
261 binary_dealloc(PyObject* obj)
263 binaryObject *self = (binaryObject *)obj;
265 Py_XDECREF(self->wrapped);
266 Py_XDECREF(self->buffer);
267 Py_XDECREF(self->conn);
269 Dprintf("binary_dealloc: deleted binary object at %p, refcnt = %d",
270 obj, obj->ob_refcnt);
272 obj->ob_type->tp_free(obj);
276 binary_init(PyObject *obj, PyObject *args, PyObject *kwds)
280 if (!PyArg_ParseTuple(args, "O", &str))
283 return binary_setup((binaryObject *)obj, str);
287 binary_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
289 return type->tp_alloc(type, 0);
293 binary_del(PyObject* self)
299 binary_repr(binaryObject *self)
301 return PyString_FromFormat("<psycopg2._psycopg.Binary object at %p>", self);
306 #define binaryType_doc \
307 "Binary(buffer) -> new binary object"
309 PyTypeObject binaryType = {
310 PyObject_HEAD_INIT(NULL)
312 "psycopg2._psycopg.Binary",
313 sizeof(binaryObject),
315 binary_dealloc, /*tp_dealloc*/
321 (reprfunc)binary_repr, /*tp_repr*/
323 0, /*tp_as_sequence*/
328 (reprfunc)binary_str, /*tp_str*/
333 Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
335 binaryType_doc, /*tp_doc*/
340 0, /*tp_richcompare*/
341 0, /*tp_weaklistoffset*/
346 /* Attribute descriptor and subclassing stuff */
348 binaryObject_methods, /*tp_methods*/
349 binaryObject_members, /*tp_members*/
358 binary_init, /*tp_init*/
359 0, /*tp_alloc will be set to PyType_GenericAlloc in module init*/
360 binary_new, /*tp_new*/
361 (freefunc)binary_del, /*tp_free Low-level free-memory routine */
362 0, /*tp_is_gc For PyObject_IS_GC */
364 0, /*tp_mro method resolution order */
371 /** module-level functions **/
374 psyco_Binary(PyObject *module, PyObject *args)
378 if (!PyArg_ParseTuple(args, "O", &str))
381 return PyObject_CallFunction((PyObject *)&binaryType, "O", str);