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