1 /* utils.c - miscellaneous utility functions
2  *
3  * Copyright (C) 2008-2019 Federico Di Gregorio <fog@debian.org>
4  * Copyright (C) 2020-2021 The Psycopg Team
5  *
6  * This file is part of psycopg.
7  *
8  * psycopg2 is free software: you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published
10  * by the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * In addition, as a special exception, the copyright holders give
14  * permission to link this program with the OpenSSL library (or with
15  * modified versions of OpenSSL that use the same license as OpenSSL),
16  * and distribute linked combinations including the two.
17  *
18  * You must obey the GNU Lesser General Public License in all respects for
19  * all of the code used other than OpenSSL.
20  *
21  * psycopg2 is distributed in the hope that it will be useful, but WITHOUT
22  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
24  * License for more details.
25  */
26 
27 #define PSYCOPG_MODULE
28 #include "psycopg/psycopg.h"
29 
30 #include "psycopg/connection.h"
31 #include "psycopg/cursor.h"
32 #include "psycopg/pgtypes.h"
33 #include "psycopg/error.h"
34 
35 #include <string.h>
36 #include <stdlib.h>
37 
38 /* Escape a string for sql inclusion.
39  *
40  * The function must be called holding the GIL.
41  *
42  * Return a pointer to a new string on the Python heap on success, else NULL
43  * and set an exception. The returned string includes quotes and leading E if
44  * needed.
45  *
46  * `len` is optional: if < 0 it will be calculated.
47  *
48  * If tolen is set, it will contain the length of the escaped string,
49  * including quotes.
50  */
51 char *
psyco_escape_string(connectionObject * conn,const char * from,Py_ssize_t len,char * to,Py_ssize_t * tolen)52 psyco_escape_string(connectionObject *conn, const char *from, Py_ssize_t len,
53                        char *to, Py_ssize_t *tolen)
54 {
55     Py_ssize_t ql;
56     int eq = (conn && (conn->equote)) ? 1 : 0;
57 
58     if (len < 0) {
59         len = strlen(from);
60     } else if (strchr(from, '\0') != from + len) {
61         PyErr_Format(PyExc_ValueError,
62             "A string literal cannot contain NUL (0x00) characters.");
63         return NULL;
64     }
65 
66     if (to == NULL) {
67         to = (char *)PyMem_Malloc((len * 2 + 4) * sizeof(char));
68         if (to == NULL) {
69             PyErr_NoMemory();
70             return NULL;
71         }
72     }
73 
74     {
75         int err;
76         if (conn && conn->pgconn)
77             ql = PQescapeStringConn(conn->pgconn, to+eq+1, from, len, &err);
78         else
79             ql = PQescapeString(to+eq+1, from, len);
80     }
81 
82     if (eq) {
83         to[0] = 'E';
84         to[1] = to[ql+2] = '\'';
85         to[ql+3] = '\0';
86     }
87     else {
88         to[0] = to[ql+1] = '\'';
89         to[ql+2] = '\0';
90     }
91 
92     if (tolen)
93         *tolen = ql+eq+2;
94 
95     return to;
96 }
97 
98 /* Escape a string for inclusion in a query as identifier.
99  *
100  * 'len' is optional: if < 0 it will be calculated.
101  *
102  * Return a string allocated by Postgres: free it using PQfreemem
103  * In case of error set a Python exception.
104  */
105 char *
psyco_escape_identifier(connectionObject * conn,const char * str,Py_ssize_t len)106 psyco_escape_identifier(connectionObject *conn, const char *str, Py_ssize_t len)
107 {
108     char *rv = NULL;
109 
110     if (!conn || !conn->pgconn) {
111         PyErr_SetString(InterfaceError, "connection not valid");
112         goto exit;
113     }
114 
115     if (len < 0) { len = strlen(str); }
116 
117     rv = PQescapeIdentifier(conn->pgconn, str, len);
118     if (!rv) {
119         char *msg;
120         msg = PQerrorMessage(conn->pgconn);
121         if (!msg || !msg[0]) {
122             msg = "no message provided";
123         }
124         PyErr_Format(InterfaceError, "failed to escape identifier: %s", msg);
125     }
126 
127 exit:
128     return rv;
129 }
130 
131 
132 /* Duplicate a string.
133  *
134  * Allocate a new buffer on the Python heap containing the new string.
135  * 'len' is optional: if < 0 the length is calculated.
136  *
137  * Store the return in 'to' and return 0 in case of success, else return -1
138  * and raise an exception.
139  *
140  * If from is null, store null into to.
141  */
142 RAISES_NEG int
psyco_strdup(char ** to,const char * from,Py_ssize_t len)143 psyco_strdup(char **to, const char *from, Py_ssize_t len)
144 {
145     if (!from) {
146         *to = NULL;
147         return 0;
148     }
149     if (len < 0) { len = strlen(from); }
150     if (!(*to = PyMem_Malloc(len + 1))) {
151         PyErr_NoMemory();
152         return -1;
153     }
154     strcpy(*to, from);
155     return 0;
156 }
157 
158 /* Ensure a Python object is a bytes string.
159  *
160  * Useful when a char * is required out of it.
161  *
162  * The function is ref neutral: steals a ref from obj and adds one to the
163  * return value. This also means that you shouldn't call the function on a
164  * borrowed ref, if having the object unallocated is not what you want.
165  *
166  * It is safe to call the function on NULL.
167  */
168 STEALS(1) PyObject *
psyco_ensure_bytes(PyObject * obj)169 psyco_ensure_bytes(PyObject *obj)
170 {
171     PyObject *rv = NULL;
172     if (!obj) { return NULL; }
173 
174     if (PyUnicode_Check(obj)) {
175         rv = PyUnicode_AsUTF8String(obj);
176         Py_DECREF(obj);
177     }
178     else if (Bytes_Check(obj)) {
179         rv = obj;
180     }
181     else {
182         PyErr_Format(PyExc_TypeError,
183             "Expected bytes or unicode string, got %s instead",
184             Py_TYPE(obj)->tp_name);
185         Py_DECREF(obj);  /* steal the ref anyway */
186     }
187 
188     return rv;
189 }
190 
191 /* Take a Python object and return text from it.
192  *
193  * This means converting bytes to unicode.
194  *
195  * The function is ref neutral: steals a ref from obj and adds one to the
196  * return value.  It is safe to call it on NULL.
197  */
198 STEALS(1) PyObject *
psyco_ensure_text(PyObject * obj)199 psyco_ensure_text(PyObject *obj)
200 {
201     if (obj) {
202         /* bytes to unicode in Py3 */
203         PyObject *rv = PyUnicode_FromEncodedObject(obj, "utf8", "replace");
204         Py_DECREF(obj);
205         return rv;
206     }
207     else {
208         return NULL;
209     }
210 }
211 
212 /* Check if a file derives from TextIOBase.
213  *
214  * Return 1 if it does, else 0, -1 on errors.
215  */
216 int
psyco_is_text_file(PyObject * f)217 psyco_is_text_file(PyObject *f)
218 {
219     /* NULL before any call.
220      * then io.TextIOBase if exists, else None. */
221     static PyObject *base;
222 
223     /* Try to import os.TextIOBase */
224     if (NULL == base) {
225         PyObject *m;
226         Dprintf("psyco_is_text_file: importing io.TextIOBase");
227         if (!(m = PyImport_ImportModule("io"))) {
228             Dprintf("psyco_is_text_file: io module not found");
229             PyErr_Clear();
230             Py_INCREF(Py_None);
231             base = Py_None;
232         }
233         else {
234             if (!(base = PyObject_GetAttrString(m, "TextIOBase"))) {
235                 Dprintf("psyco_is_text_file: io.TextIOBase not found");
236                 PyErr_Clear();
237                 Py_INCREF(Py_None);
238                 base = Py_None;
239             }
240         }
241         Py_XDECREF(m);
242     }
243 
244     if (base != Py_None) {
245         return PyObject_IsInstance(f, base);
246     } else {
247         return 0;
248     }
249 }
250 
251 /* Make a dict out of PQconninfoOption array */
252 PyObject *
psyco_dict_from_conninfo_options(PQconninfoOption * options,int include_password)253 psyco_dict_from_conninfo_options(PQconninfoOption *options, int include_password)
254 {
255     PyObject *dict, *res = NULL;
256     PQconninfoOption *o;
257 
258     if (!(dict = PyDict_New())) { goto exit; }
259     for (o = options; o->keyword != NULL; o++) {
260         if (o->val != NULL &&
261             (include_password || strcmp(o->keyword, "password") != 0)) {
262             PyObject *value;
263             if (!(value = Text_FromUTF8(o->val))) { goto exit; }
264             if (PyDict_SetItemString(dict, o->keyword, value) != 0) {
265                 Py_DECREF(value);
266                 goto exit;
267             }
268             Py_DECREF(value);
269         }
270     }
271 
272     res = dict;
273     dict = NULL;
274 
275 exit:
276     Py_XDECREF(dict);
277 
278     return res;
279 }
280 
281 
282 /* Make a connection string out of a string and a dictionary of arguments.
283  *
284  * Helper to call psycopg2.extensions.make_dsn()
285  */
286 PyObject *
psyco_make_dsn(PyObject * dsn,PyObject * kwargs)287 psyco_make_dsn(PyObject *dsn, PyObject *kwargs)
288 {
289     PyObject *ext = NULL, *make_dsn = NULL;
290     PyObject *args = NULL, *rv = NULL;
291 
292     if (!(ext = PyImport_ImportModule("psycopg2.extensions"))) { goto exit; }
293     if (!(make_dsn = PyObject_GetAttrString(ext, "make_dsn"))) { goto exit; }
294 
295     if (!(args = PyTuple_Pack(1, dsn))) { goto exit; }
296     rv = PyObject_Call(make_dsn, args, kwargs);
297 
298 exit:
299     Py_XDECREF(args);
300     Py_XDECREF(make_dsn);
301     Py_XDECREF(ext);
302 
303     return rv;
304 }
305 
306 /* Convert a C string into Python Text using a specified codec.
307  *
308  * The codec is the python function codec.getdecoder(enc).
309  *
310  * len is optional: use -1 to have it calculated by the function.
311  */
312 PyObject *
psyco_text_from_chars_safe(const char * str,Py_ssize_t len,PyObject * decoder)313 psyco_text_from_chars_safe(const char *str, Py_ssize_t len, PyObject *decoder)
314 {
315     static PyObject *replace = NULL;
316     PyObject *rv = NULL;
317     PyObject *b = NULL;
318     PyObject *t = NULL;
319 
320     if (!str) { Py_RETURN_NONE; }
321 
322     if (len < 0) { len = strlen(str); }
323 
324     if (decoder) {
325         if (!replace) {
326             if (!(replace = PyUnicode_FromString("replace"))) { goto exit; }
327         }
328         if (!(b = PyBytes_FromStringAndSize(str, len))) { goto exit; }
329         if (!(t = PyObject_CallFunctionObjArgs(decoder, b, replace, NULL))) {
330             goto exit;
331         }
332 
333         if (!(rv = PyTuple_GetItem(t, 0))) { goto exit; }
334         Py_INCREF(rv);
335     }
336     else {
337         rv = PyUnicode_DecodeASCII(str, len, "replace");
338     }
339 
340 exit:
341     Py_XDECREF(t);
342     Py_XDECREF(b);
343     return rv;
344 }
345 
346 
347 /* psyco_set_error
348  *
349  * Create a new error of the given type with extra attributes.
350  */
351 
352 RAISES BORROWED PyObject *
psyco_set_error(PyObject * exc,cursorObject * curs,const char * msg)353 psyco_set_error(PyObject *exc, cursorObject *curs, const char *msg)
354 {
355     PyObject *pymsg;
356     PyObject *err = NULL;
357     connectionObject *conn = NULL;
358 
359     if (curs) {
360         conn = ((cursorObject *)curs)->conn;
361     }
362 
363     if ((pymsg = conn_text_from_chars(conn, msg))) {
364         err = PyObject_CallFunctionObjArgs(exc, pymsg, NULL);
365         Py_DECREF(pymsg);
366     }
367     else {
368         /* what's better than an error in an error handler in the morning?
369          * Anyway, some error was set, refcount is ok... get outta here. */
370         return NULL;
371     }
372 
373     if (err && PyObject_TypeCheck(err, &errorType)) {
374         errorObject *perr = (errorObject *)err;
375         if (curs) {
376             Py_CLEAR(perr->cursor);
377             Py_INCREF(curs);
378             perr->cursor = curs;
379         }
380     }
381 
382     if (err) {
383         PyErr_SetObject(exc, err);
384         Py_DECREF(err);
385     }
386 
387     return err;
388 }
389 
390 
391 /* Return nonzero if the current one is the main interpreter */
392 static int
psyco_is_main_interp(void)393 psyco_is_main_interp(void)
394 {
395 #if PY_VERSION_HEX >= 0x03080000
396     /* tested with Python 3.8.0a2 */
397     return _PyInterpreterState_Get() == PyInterpreterState_Main();
398 #else
399     static PyInterpreterState *main_interp = NULL;  /* Cached reference */
400     PyInterpreterState *interp;
401 
402     if (main_interp) {
403         return (main_interp == PyThreadState_Get()->interp);
404     }
405 
406     /* No cached value: cache the proper value and try again. */
407     interp = PyInterpreterState_Head();
408     while (interp->next)
409         interp = interp->next;
410 
411     main_interp = interp;
412     assert (main_interp);
413     return psyco_is_main_interp();
414 #endif
415 }
416 
417 /* psyco_get_decimal_type
418 
419    Return a new reference to the decimal type.
420 
421    The function returns a cached version of the object, but only in the main
422    interpreter because subinterpreters are confusing.
423 */
424 
425 PyObject *
psyco_get_decimal_type(void)426 psyco_get_decimal_type(void)
427 {
428     static PyObject *cachedType = NULL;
429     PyObject *decimalType = NULL;
430     PyObject *decimal;
431 
432     /* Use the cached object if running from the main interpreter. */
433     int can_cache = psyco_is_main_interp();
434     if (can_cache && cachedType) {
435         Py_INCREF(cachedType);
436         return cachedType;
437     }
438 
439     /* Get a new reference to the Decimal type. */
440     decimal = PyImport_ImportModule("decimal");
441     if (decimal) {
442         decimalType = PyObject_GetAttrString(decimal, "Decimal");
443         Py_DECREF(decimal);
444     }
445     else {
446         decimalType = NULL;
447     }
448 
449     /* Store the object from future uses. */
450     if (can_cache && !cachedType && decimalType) {
451         Py_INCREF(decimalType);
452         cachedType = decimalType;
453     }
454 
455     return decimalType;
456 }
457