~ubuntu-branches/ubuntu/hardy/psycopg2/hardy

« back to all changes in this revision

Viewing changes to psycopg/adapter_qstring.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabio Tranchitella
  • Date: 2006-08-09 10:28:30 UTC
  • Revision ID: james.westby@ubuntu.com-20060809102830-grac1dsp24uyqfp4
Tags: upstream-2.0.4
ImportĀ upstreamĀ versionĀ 2.0.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* adapter_qstring.c - QuotedString objects
 
2
 *
 
3
 * Copyright (C) 2003-2004 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
#include <libpq-fe.h>
 
27
#include <string.h>
 
28
 
 
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_qstring.h"
 
35
#include "psycopg/microprotocols_proto.h"
 
36
 
 
37
 
 
38
/** the quoting code */
 
39
 
 
40
#ifndef PSYCOPG_OWN_QUOTING
 
41
static size_t
 
42
qstring_escape(char *to, char *from, size_t len, PGconn *conn)
 
43
{
 
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)
 
47
    int err;
 
48
    if (conn)
 
49
        return PQescapeStringConn(conn, to, from, len, &err);
 
50
    else
 
51
#endif
 
52
        return PQescapeString(to, from, len);
 
53
}
 
54
#else
 
55
static size_t
 
56
qstring_escape(char *to, char *from, size_t len, PGconn *conn)
 
57
{
 
58
    int i, j;
 
59
 
 
60
    for (i=0, j=0; i<len; i++) {
 
61
        switch(from[i]) {
 
62
 
 
63
        case '\'':
 
64
            to[j++] = '\'';
 
65
            to[j++] = '\'';
 
66
            break;
 
67
 
 
68
        case '\\':
 
69
            to[j++] = '\\';
 
70
            to[j++] = '\\';
 
71
            break;
 
72
 
 
73
        case '\0':
 
74
            /* do nothing, embedded \0 are discarded */
 
75
            break;
 
76
 
 
77
        default:
 
78
            to[j++] = from[i];
 
79
        }
 
80
    }
 
81
    to[j] = '\0';
 
82
 
 
83
    Dprintf("qstring_quote: to = %s", to);
 
84
    return strlen(to);
 
85
}
 
86
#endif
 
87
 
 
88
/* qstring_quote - do the quote process on plain and unicode strings */
 
89
 
 
90
static PyObject *
 
91
qstring_quote(qstringObject *self)
 
92
{
 
93
    PyObject *str;
 
94
    char *s, *buffer;
 
95
    int len;
 
96
 
 
97
    /* if the wrapped object is an unicode object we can encode it to match
 
98
       self->encoding but if the encoding is not specified we don't know what
 
99
       to do and we raise an exception */
 
100
 
 
101
    /* TODO: we need a real translation table from postgres encoding names to
 
102
           python ones here */
 
103
    
 
104
    if (PyUnicode_Check(self->wrapped) && self->encoding) {
 
105
        PyObject *enc = PyDict_GetItemString(psycoEncodings, self->encoding);
 
106
        /* note that pgenc is a borrowed reference */
 
107
 
 
108
        if (enc) {
 
109
            char *s = PyString_AsString(enc);
 
110
            Dprintf("qstring_quote: encoding unicode object to %s", s);
 
111
            str = PyUnicode_AsEncodedString(self->wrapped, s, NULL);
 
112
            Dprintf("qstring_quote: got encoded object at %p", str);
 
113
            if (str == NULL) return NULL;
 
114
        }
 
115
        else {
 
116
            /* can't find the right encoder, raise exception */
 
117
            PyErr_Format(InterfaceError,
 
118
                         "can't encode unicode string to %s", self->encoding);
 
119
            return NULL;
 
120
        }
 
121
    }
 
122
 
 
123
    /* if the wrapped object is a simple string, we don't know how to
 
124
       (re)encode it, so we pass it as-is */
 
125
    else if (PyString_Check(self->wrapped)) {
 
126
        str = self->wrapped;
 
127
        /* INCREF to make it ref-wise identical to unicode one */
 
128
        Py_INCREF(str);
 
129
    }
 
130
    
 
131
    /* if the wrapped object is not a string, this is an error */ 
 
132
    else {
 
133
        PyErr_SetString(PyExc_TypeError,
 
134
                        "can't quote non-string object (or missing encoding)");
 
135
        return NULL;
 
136
    }
 
137
 
 
138
    /* encode the string into buffer */
 
139
    PyString_AsStringAndSize(str, &s, &len);
 
140
        
 
141
    buffer = (char *)PyMem_Malloc((len*2+3) * sizeof(char));
 
142
    if (buffer == NULL) {
 
143
        Py_DECREF(str);
 
144
        PyErr_NoMemory();
 
145
        return NULL;
 
146
    }
 
147
 
 
148
    Py_BEGIN_ALLOW_THREADS;
 
149
    len = qstring_escape(buffer+1, s, len,
 
150
        self->conn ? ((connectionObject*)self->conn)->pgconn : NULL);
 
151
    buffer[0] = '\'' ; buffer[len+1] = '\'';
 
152
    Py_END_ALLOW_THREADS;
 
153
    
 
154
    self->buffer = PyString_FromStringAndSize(buffer, len+2);
 
155
    PyMem_Free(buffer);
 
156
    Py_DECREF(str);
 
157
        
 
158
    return self->buffer;
 
159
}
 
160
 
 
161
/* qstring_str, qstring_getquoted - return result of quoting */
 
162
 
 
163
static PyObject *
 
164
qstring_str(qstringObject *self)
 
165
{
 
166
    if (self->buffer == NULL) {
 
167
        qstring_quote(self);
 
168
    }
 
169
    Py_XINCREF(self->buffer);
 
170
    return self->buffer;
 
171
}
 
172
 
 
173
PyObject *
 
174
qstring_getquoted(qstringObject *self, PyObject *args)
 
175
{
 
176
    if (!PyArg_ParseTuple(args, "")) return NULL;
 
177
    return qstring_str(self);
 
178
}
 
179
 
 
180
PyObject *
 
181
qstring_prepare(qstringObject *self, PyObject *args)
 
182
{
 
183
    connectionObject *conn;
 
184
 
 
185
    if (!PyArg_ParseTuple(args, "O", &conn))
 
186
        return NULL;
 
187
 
 
188
    /* we bother copying the encoding only if the wrapped string is unicode,
 
189
       we don't need the encoding if that's not the case */
 
190
    if (PyUnicode_Check(self->wrapped)) {
 
191
        if (self->encoding) free(self->encoding);
 
192
        self->encoding = strdup(conn->encoding);
 
193
        Dprintf("qstring_prepare: set encoding to %s", conn->encoding);
 
194
    }
 
195
 
 
196
    Py_XDECREF(self->conn);
 
197
    if (conn) {
 
198
        self->conn = (PyObject*)conn;
 
199
        Py_INCREF(self->conn);
 
200
    }
 
201
 
 
202
    Py_INCREF(Py_None);
 
203
    return Py_None;
 
204
}
 
205
    
 
206
PyObject *
 
207
qstring_conform(qstringObject *self, PyObject *args)
 
208
{
 
209
    PyObject *res, *proto;
 
210
    
 
211
    if (!PyArg_ParseTuple(args, "O", &proto)) return NULL;
 
212
 
 
213
    if (proto == (PyObject*)&isqlquoteType)
 
214
        res = (PyObject*)self;
 
215
    else
 
216
        res = Py_None;
 
217
    
 
218
    Py_INCREF(res);
 
219
    return res;
 
220
}
 
221
 
 
222
/** the QuotedString object **/
 
223
 
 
224
/* object member list */
 
225
 
 
226
static struct PyMemberDef qstringObject_members[] = {
 
227
    {"adapted", T_OBJECT, offsetof(qstringObject, wrapped), RO},
 
228
    {"buffer", T_OBJECT, offsetof(qstringObject, buffer), RO},
 
229
    {"encoding", T_STRING, offsetof(qstringObject, encoding), RO},
 
230
    {NULL}
 
231
};
 
232
 
 
233
/* object method table */
 
234
 
 
235
static PyMethodDef qstringObject_methods[] = {
 
236
    {"getquoted", (PyCFunction)qstring_getquoted, METH_VARARGS,
 
237
     "getquoted() -> wrapped object value as SQL-quoted string"},
 
238
    {"prepare", (PyCFunction)qstring_prepare, METH_VARARGS,
 
239
     "prepare(conn) -> set encoding to conn->encoding and store conn"},
 
240
    {"__conform__", (PyCFunction)qstring_conform, METH_VARARGS, NULL},
 
241
    {NULL}  /* Sentinel */
 
242
};
 
243
 
 
244
/* initialization and finalization methods */
 
245
 
 
246
static int
 
247
qstring_setup(qstringObject *self, PyObject *str, char *enc)
 
248
{
 
249
    Dprintf("qstring_setup: init qstring object at %p, refcnt = %d",
 
250
            self, ((PyObject *)self)->ob_refcnt);
 
251
 
 
252
    self->buffer = NULL;
 
253
    self->conn = NULL;
 
254
 
 
255
    /* FIXME: remove this orrible strdup */
 
256
    if (enc) self->encoding = strdup(enc);
 
257
    
 
258
    self->wrapped = str;
 
259
    Py_INCREF(self->wrapped);
 
260
    
 
261
    Dprintf("qstring_setup: good qstring object at %p, refcnt = %d",
 
262
            self, ((PyObject *)self)->ob_refcnt);
 
263
    return 0;
 
264
}
 
265
 
 
266
static void
 
267
qstring_dealloc(PyObject* obj)
 
268
{
 
269
    qstringObject *self = (qstringObject *)obj;
 
270
 
 
271
    Py_XDECREF(self->wrapped);
 
272
    Py_XDECREF(self->buffer);
 
273
    Py_XDECREF(self->conn);
 
274
 
 
275
    if (self->encoding) free(self->encoding);
 
276
    
 
277
    Dprintf("qstring_dealloc: deleted qstring object at %p, refcnt = %d",
 
278
            obj, obj->ob_refcnt);
 
279
    
 
280
    obj->ob_type->tp_free(obj);
 
281
}
 
282
 
 
283
static int
 
284
qstring_init(PyObject *obj, PyObject *args, PyObject *kwds)
 
285
{
 
286
    PyObject *str;
 
287
    char *enc = "latin-1"; /* default encoding as in Python */
 
288
    
 
289
    if (!PyArg_ParseTuple(args, "O|s", &str, &enc))
 
290
        return -1;
 
291
 
 
292
    return qstring_setup((qstringObject *)obj, str, enc);
 
293
}
 
294
 
 
295
static PyObject *
 
296
qstring_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 
297
{    
 
298
    return type->tp_alloc(type, 0);
 
299
}
 
300
 
 
301
static void
 
302
qstring_del(PyObject* self)
 
303
{
 
304
    PyObject_Del(self);
 
305
}
 
306
 
 
307
static PyObject *
 
308
qstring_repr(qstringObject *self)
 
309
{
 
310
    return PyString_FromFormat("<psycopg2._psycopg.QuotedString object at %p>", 
 
311
                                self);
 
312
}
 
313
 
 
314
/* object type */
 
315
 
 
316
#define qstringType_doc \
 
317
"QuotedString(str, enc) -> new quoted object with 'enc' encoding"
 
318
 
 
319
PyTypeObject qstringType = {
 
320
    PyObject_HEAD_INIT(NULL)
 
321
    0,
 
322
    "psycopg2._psycopg.QuotedString",
 
323
    sizeof(qstringObject),
 
324
    0,
 
325
    qstring_dealloc, /*tp_dealloc*/
 
326
    0,          /*tp_print*/
 
327
    0,          /*tp_getattr*/
 
328
    0,          /*tp_setattr*/   
 
329
 
 
330
    0,          /*tp_compare*/
 
331
    (reprfunc)qstring_repr, /*tp_repr*/
 
332
    0,          /*tp_as_number*/
 
333
    0,          /*tp_as_sequence*/
 
334
    0,          /*tp_as_mapping*/
 
335
    0,          /*tp_hash */
 
336
 
 
337
    0,          /*tp_call*/
 
338
    (reprfunc)qstring_str, /*tp_str*/
 
339
    0,          /*tp_getattro*/
 
340
    0,          /*tp_setattro*/
 
341
    0,          /*tp_as_buffer*/
 
342
 
 
343
    Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
 
344
 
 
345
    qstringType_doc, /*tp_doc*/
 
346
    
 
347
    0,          /*tp_traverse*/
 
348
    0,          /*tp_clear*/
 
349
 
 
350
    0,          /*tp_richcompare*/
 
351
    0,          /*tp_weaklistoffset*/
 
352
 
 
353
    0,          /*tp_iter*/
 
354
    0,          /*tp_iternext*/
 
355
 
 
356
    /* Attribute descriptor and subclassing stuff */
 
357
 
 
358
    qstringObject_methods, /*tp_methods*/
 
359
    qstringObject_members, /*tp_members*/
 
360
    0,          /*tp_getset*/
 
361
    0,          /*tp_base*/
 
362
    0,          /*tp_dict*/
 
363
    
 
364
    0,          /*tp_descr_get*/
 
365
    0,          /*tp_descr_set*/
 
366
    0,          /*tp_dictoffset*/
 
367
    
 
368
    qstring_init, /*tp_init*/
 
369
    0, /*tp_alloc  will be set to PyType_GenericAlloc in module init*/
 
370
    qstring_new, /*tp_new*/
 
371
    (freefunc)qstring_del, /*tp_free  Low-level free-memory routine */
 
372
    0,          /*tp_is_gc For PyObject_IS_GC */
 
373
    0,          /*tp_bases*/
 
374
    0,          /*tp_mro method resolution order */
 
375
    0,          /*tp_cache*/
 
376
    0,          /*tp_subclasses*/
 
377
    0           /*tp_weaklist*/
 
378
};
 
379
 
 
380
 
 
381
/** module-level functions **/
 
382
 
 
383
PyObject *
 
384
psyco_QuotedString(PyObject *module, PyObject *args)
 
385
{
 
386
    PyObject *str;
 
387
    char *enc = "latin-1"; /* default encoding as in Python */
 
388
    
 
389
    if (!PyArg_ParseTuple(args, "O|s", &str, &enc))
 
390
        return NULL;
 
391
  
 
392
    return PyObject_CallFunction((PyObject *)&qstringType, "Os", str, enc);
 
393
}