Line data Source code
1 : /* src/interfaces/ecpg/ecpglib/misc.c */
2 :
3 : #define POSTGRES_ECPG_INTERNAL
4 : #include "postgres_fe.h"
5 :
6 : #include <limits.h>
7 : #include <unistd.h>
8 :
9 : #include "ecpg-pthread-win32.h"
10 : #include "ecpgerrno.h"
11 : #include "ecpglib.h"
12 : #include "ecpglib_extern.h"
13 : #include "ecpgtype.h"
14 : #include "pg_config_paths.h"
15 : #include "pgtypes_date.h"
16 : #include "pgtypes_interval.h"
17 : #include "pgtypes_numeric.h"
18 : #include "pgtypes_timestamp.h"
19 : #include "sqlca.h"
20 :
21 : #ifndef LONG_LONG_MIN
22 : #ifdef LLONG_MIN
23 : #define LONG_LONG_MIN LLONG_MIN
24 : #else
25 : #define LONG_LONG_MIN LONGLONG_MIN
26 : #endif /* LLONG_MIN */
27 : #endif /* LONG_LONG_MIN */
28 :
29 : bool ecpg_internal_regression_mode = false;
30 :
31 : static struct sqlca_t sqlca_init =
32 : {
33 : {
34 : 'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
35 : },
36 : sizeof(struct sqlca_t),
37 : 0,
38 : {
39 : 0,
40 : {
41 : 0
42 : }
43 : },
44 : {
45 : 'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '
46 : },
47 : {
48 : 0, 0, 0, 0, 0, 0
49 : },
50 : {
51 : 0, 0, 0, 0, 0, 0, 0, 0
52 : },
53 : {
54 : '0', '0', '0', '0', '0'
55 : }
56 : };
57 :
58 : static pthread_key_t sqlca_key;
59 : static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT;
60 :
61 : static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
62 : static pthread_mutex_t debug_init_mutex = PTHREAD_MUTEX_INITIALIZER;
63 : static volatile int simple_debug = 0;
64 : static FILE *debugstream = NULL;
65 :
66 : void
67 6417004 : ecpg_init_sqlca(struct sqlca_t *sqlca)
68 : {
69 6417004 : memcpy((char *) sqlca, (char *) &sqlca_init, sizeof(struct sqlca_t));
70 6417004 : }
71 :
72 : bool
73 15400 : ecpg_init(const struct connection *con, const char *connection_name, const int lineno)
74 : {
75 15400 : struct sqlca_t *sqlca = ECPGget_sqlca();
76 :
77 15400 : if (sqlca == NULL)
78 : {
79 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY,
80 : NULL);
81 0 : return false;
82 : }
83 :
84 15400 : ecpg_init_sqlca(sqlca);
85 15400 : if (con == NULL)
86 : {
87 86 : ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
88 24 : connection_name ? connection_name : ecpg_gettext("NULL"));
89 62 : return false;
90 : }
91 :
92 15338 : return true;
93 : }
94 :
95 : static void
96 272 : ecpg_sqlca_key_destructor(void *arg)
97 : {
98 272 : free(arg); /* sqlca structure allocated in ECPGget_sqlca */
99 272 : }
100 :
101 : static void
102 254 : ecpg_sqlca_key_init(void)
103 : {
104 254 : pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor);
105 254 : }
106 :
107 : struct sqlca_t *
108 12872416 : ECPGget_sqlca(void)
109 : {
110 : struct sqlca_t *sqlca;
111 :
112 12872416 : pthread_once(&sqlca_key_once, ecpg_sqlca_key_init);
113 :
114 12872416 : sqlca = pthread_getspecific(sqlca_key);
115 12872416 : if (sqlca == NULL)
116 : {
117 518 : sqlca = malloc(sizeof(struct sqlca_t));
118 518 : if (sqlca == NULL)
119 0 : return NULL;
120 518 : ecpg_init_sqlca(sqlca);
121 518 : pthread_setspecific(sqlca_key, sqlca);
122 : }
123 12872416 : return sqlca;
124 : }
125 :
126 : bool
127 0 : ECPGstatus(int lineno, const char *connection_name)
128 : {
129 0 : struct connection *con = ecpg_get_connection(connection_name);
130 :
131 0 : if (!ecpg_init(con, connection_name, lineno))
132 0 : return false;
133 :
134 : /* are we connected? */
135 0 : if (con->connection == NULL)
136 : {
137 0 : ecpg_raise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, con->name);
138 0 : return false;
139 : }
140 :
141 0 : return true;
142 : }
143 :
144 : PGTransactionStatusType
145 0 : ECPGtransactionStatus(const char *connection_name)
146 : {
147 : const struct connection *con;
148 :
149 0 : con = ecpg_get_connection(connection_name);
150 0 : if (con == NULL)
151 : {
152 : /* transaction status is unknown */
153 0 : return PQTRANS_UNKNOWN;
154 : }
155 :
156 0 : return PQtransactionStatus(con->connection);
157 : }
158 :
159 : bool
160 492 : ECPGtrans(int lineno, const char *connection_name, const char *transaction)
161 : {
162 : PGresult *res;
163 492 : struct connection *con = ecpg_get_connection(connection_name);
164 :
165 492 : if (!ecpg_init(con, connection_name, lineno))
166 0 : return false;
167 :
168 492 : ecpg_log("ECPGtrans on line %d: action \"%s\"; connection \"%s\"\n", lineno, transaction, con ? con->name : "null");
169 :
170 : /* if we have no connection we just simulate the command */
171 492 : if (con && con->connection)
172 : {
173 : /*
174 : * If we got a transaction command but have no open transaction, we
175 : * have to start one, unless we are in autocommit, where the
176 : * developers have to take care themselves. However, if the command is
177 : * a begin statement, we just execute it once. And if the command is
178 : * commit or rollback prepared, we don't execute it.
179 : */
180 492 : if (PQtransactionStatus(con->connection) == PQTRANS_IDLE &&
181 108 : !con->autocommit &&
182 96 : strncmp(transaction, "begin", 5) != 0 &&
183 4 : strncmp(transaction, "start", 5) != 0 &&
184 4 : strncmp(transaction, "commit prepared", 15) != 0 &&
185 0 : strncmp(transaction, "rollback prepared", 17) != 0)
186 : {
187 0 : res = PQexec(con->connection, "begin transaction");
188 0 : if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
189 0 : return false;
190 0 : PQclear(res);
191 : }
192 :
193 492 : res = PQexec(con->connection, transaction);
194 492 : if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
195 0 : return false;
196 492 : PQclear(res);
197 : }
198 :
199 492 : return true;
200 : }
201 :
202 :
203 : void
204 234 : ECPGdebug(int n, FILE *dbgs)
205 : {
206 : /* Interlock against concurrent executions of ECPGdebug() */
207 234 : pthread_mutex_lock(&debug_init_mutex);
208 :
209 : /* Prevent ecpg_log() from printing while we change settings */
210 234 : pthread_mutex_lock(&debug_mutex);
211 :
212 234 : if (n > 100)
213 : {
214 234 : ecpg_internal_regression_mode = true;
215 234 : simple_debug = n - 100;
216 : }
217 : else
218 0 : simple_debug = n;
219 :
220 234 : debugstream = dbgs;
221 :
222 : /* We must release debug_mutex before invoking ecpg_log() ... */
223 234 : pthread_mutex_unlock(&debug_mutex);
224 :
225 : /* ... but keep holding debug_init_mutex to avoid racy printout */
226 234 : ecpg_log("ECPGdebug: set to %d\n", simple_debug);
227 :
228 234 : pthread_mutex_unlock(&debug_init_mutex);
229 234 : }
230 :
231 : void
232 58572 : ecpg_log(const char *format,...)
233 : {
234 : va_list ap;
235 : const char *intl_format;
236 : int bufsize;
237 : char *fmt;
238 : struct sqlca_t *sqlca;
239 :
240 : /*
241 : * For performance reasons, inspect simple_debug without taking the mutex.
242 : * This could be problematic if fetching an int isn't atomic, but we
243 : * assume that it is in many other places too.
244 : */
245 58572 : if (!simple_debug)
246 45084 : return;
247 :
248 : /* localize the error message string */
249 13488 : intl_format = ecpg_gettext(format);
250 :
251 : /*
252 : * Insert PID into the format, unless ecpg_internal_regression_mode is set
253 : * (regression tests want unchanging output).
254 : */
255 13488 : bufsize = strlen(intl_format) + 100;
256 13488 : fmt = (char *) malloc(bufsize);
257 13488 : if (fmt == NULL)
258 0 : return;
259 :
260 13488 : if (ecpg_internal_regression_mode)
261 13488 : snprintf(fmt, bufsize, "[NO_PID]: %s", intl_format);
262 : else
263 0 : snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format);
264 :
265 13488 : sqlca = ECPGget_sqlca();
266 :
267 13488 : pthread_mutex_lock(&debug_mutex);
268 :
269 : /* Now that we hold the mutex, recheck simple_debug */
270 13488 : if (simple_debug)
271 : {
272 13488 : va_start(ap, format);
273 13488 : vfprintf(debugstream, fmt, ap);
274 13488 : va_end(ap);
275 :
276 : /* dump out internal sqlca variables */
277 13488 : if (ecpg_internal_regression_mode && sqlca != NULL)
278 : {
279 13488 : fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n",
280 13488 : sqlca->sqlcode, sqlca->sqlstate);
281 : }
282 :
283 13488 : fflush(debugstream);
284 : }
285 :
286 13488 : pthread_mutex_unlock(&debug_mutex);
287 :
288 13488 : free(fmt);
289 : }
290 :
291 : void
292 7140 : ECPGset_noind_null(enum ECPGttype type, void *ptr)
293 : {
294 7140 : switch (type)
295 : {
296 3780 : case ECPGt_char:
297 : case ECPGt_unsigned_char:
298 : case ECPGt_string:
299 3780 : *((char *) ptr) = '\0';
300 3780 : break;
301 8 : case ECPGt_short:
302 : case ECPGt_unsigned_short:
303 8 : *((short int *) ptr) = SHRT_MIN;
304 8 : break;
305 8 : case ECPGt_int:
306 : case ECPGt_unsigned_int:
307 8 : *((int *) ptr) = INT_MIN;
308 8 : break;
309 20 : case ECPGt_long:
310 : case ECPGt_unsigned_long:
311 : case ECPGt_date:
312 20 : *((long *) ptr) = LONG_MIN;
313 20 : break;
314 0 : case ECPGt_long_long:
315 : case ECPGt_unsigned_long_long:
316 0 : *((long long *) ptr) = LONG_LONG_MIN;
317 0 : break;
318 8 : case ECPGt_float:
319 8 : memset((char *) ptr, 0xff, sizeof(float));
320 8 : break;
321 16 : case ECPGt_double:
322 16 : memset((char *) ptr, 0xff, sizeof(double));
323 16 : break;
324 0 : case ECPGt_varchar:
325 0 : *(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
326 0 : ((struct ECPGgeneric_varchar *) ptr)->len = 0;
327 0 : break;
328 0 : case ECPGt_bytea:
329 0 : ((struct ECPGgeneric_bytea *) ptr)->len = 0;
330 0 : break;
331 3276 : case ECPGt_decimal:
332 3276 : memset((char *) ptr, 0, sizeof(decimal));
333 3276 : ((decimal *) ptr)->sign = NUMERIC_NULL;
334 3276 : break;
335 8 : case ECPGt_numeric:
336 8 : memset((char *) ptr, 0, sizeof(numeric));
337 8 : ((numeric *) ptr)->sign = NUMERIC_NULL;
338 8 : break;
339 0 : case ECPGt_interval:
340 0 : memset((char *) ptr, 0xff, sizeof(interval));
341 0 : break;
342 12 : case ECPGt_timestamp:
343 12 : memset((char *) ptr, 0xff, sizeof(timestamp));
344 12 : break;
345 4 : default:
346 4 : break;
347 : }
348 7140 : }
349 :
350 : static bool
351 44 : _check(const unsigned char *ptr, int length)
352 : {
353 236 : for (length--; length >= 0; length--)
354 208 : if (ptr[length] != 0xff)
355 16 : return false;
356 :
357 28 : return true;
358 : }
359 :
360 : bool
361 11052 : ECPGis_noind_null(enum ECPGttype type, const void *ptr)
362 : {
363 11052 : switch (type)
364 : {
365 80 : case ECPGt_char:
366 : case ECPGt_unsigned_char:
367 : case ECPGt_string:
368 80 : if (*((const char *) ptr) == '\0')
369 8 : return true;
370 72 : break;
371 16 : case ECPGt_short:
372 : case ECPGt_unsigned_short:
373 16 : if (*((const short int *) ptr) == SHRT_MIN)
374 8 : return true;
375 8 : break;
376 72 : case ECPGt_int:
377 : case ECPGt_unsigned_int:
378 72 : if (*((const int *) ptr) == INT_MIN)
379 8 : return true;
380 64 : break;
381 72 : case ECPGt_long:
382 : case ECPGt_unsigned_long:
383 : case ECPGt_date:
384 72 : if (*((const long *) ptr) == LONG_MIN)
385 20 : return true;
386 52 : break;
387 0 : case ECPGt_long_long:
388 : case ECPGt_unsigned_long_long:
389 0 : if (*((const long long *) ptr) == LONG_LONG_MIN)
390 0 : return true;
391 0 : break;
392 16 : case ECPGt_float:
393 16 : return _check(ptr, sizeof(float));
394 : break;
395 16 : case ECPGt_double:
396 16 : return _check(ptr, sizeof(double));
397 : break;
398 0 : case ECPGt_varchar:
399 0 : if (*(((const struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
400 0 : return true;
401 0 : break;
402 0 : case ECPGt_bytea:
403 0 : if (((const struct ECPGgeneric_bytea *) ptr)->len == 0)
404 0 : return true;
405 0 : break;
406 10752 : case ECPGt_decimal:
407 10752 : if (((const decimal *) ptr)->sign == NUMERIC_NULL)
408 1040 : return true;
409 9712 : break;
410 0 : case ECPGt_numeric:
411 0 : if (((const numeric *) ptr)->sign == NUMERIC_NULL)
412 0 : return true;
413 0 : break;
414 0 : case ECPGt_interval:
415 0 : return _check(ptr, sizeof(interval));
416 : break;
417 12 : case ECPGt_timestamp:
418 12 : return _check(ptr, sizeof(timestamp));
419 : break;
420 16 : default:
421 16 : break;
422 : }
423 :
424 9924 : return false;
425 : }
426 :
427 : #ifdef WIN32
428 :
429 : int
430 : pthread_mutex_init(pthread_mutex_t *mp, void *attr)
431 : {
432 : mp->initstate = 0;
433 : return 0;
434 : }
435 :
436 : int
437 : pthread_mutex_lock(pthread_mutex_t *mp)
438 : {
439 : /* Initialize the csection if not already done */
440 : if (mp->initstate != 1)
441 : {
442 : LONG istate;
443 :
444 : while ((istate = InterlockedExchange(&mp->initstate, 2)) == 2)
445 : Sleep(0); /* wait, another thread is doing this */
446 : if (istate != 1)
447 : InitializeCriticalSection(&mp->csection);
448 : InterlockedExchange(&mp->initstate, 1);
449 : }
450 : EnterCriticalSection(&mp->csection);
451 : return 0;
452 : }
453 :
454 : int
455 : pthread_mutex_unlock(pthread_mutex_t *mp)
456 : {
457 : if (mp->initstate != 1)
458 : return EINVAL;
459 : LeaveCriticalSection(&mp->csection);
460 : return 0;
461 : }
462 :
463 : static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;
464 :
465 : void
466 : win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void))
467 : {
468 : if (!*once)
469 : {
470 : pthread_mutex_lock(&win32_pthread_once_lock);
471 : if (!*once)
472 : {
473 : fn();
474 : *once = true;
475 : }
476 : pthread_mutex_unlock(&win32_pthread_once_lock);
477 : }
478 : }
479 : #endif /* WIN32 */
480 :
481 : #ifdef ENABLE_NLS
482 :
483 : char *
484 13778 : ecpg_gettext(const char *msgid)
485 : {
486 : /*
487 : * At least on Windows, there are gettext implementations that fail if
488 : * multiple threads call bindtextdomain() concurrently. Use a mutex and
489 : * flag variable to ensure that we call it just once per process. It is
490 : * not known that similar bugs exist on non-Windows platforms, but we
491 : * might as well do it the same way everywhere.
492 : */
493 : static volatile bool already_bound = false;
494 : static pthread_mutex_t binddomain_mutex = PTHREAD_MUTEX_INITIALIZER;
495 :
496 13778 : if (!already_bound)
497 : {
498 : /* dgettext() preserves errno, but bindtextdomain() doesn't */
499 : #ifdef WIN32
500 : int save_errno = GetLastError();
501 : #else
502 230 : int save_errno = errno;
503 : #endif
504 :
505 230 : (void) pthread_mutex_lock(&binddomain_mutex);
506 :
507 230 : if (!already_bound)
508 : {
509 : const char *ldir;
510 :
511 : /*
512 : * No relocatable lookup here because the calling executable could
513 : * be anywhere
514 : */
515 230 : ldir = getenv("PGLOCALEDIR");
516 230 : if (!ldir)
517 0 : ldir = LOCALEDIR;
518 230 : bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir);
519 230 : already_bound = true;
520 : }
521 :
522 230 : (void) pthread_mutex_unlock(&binddomain_mutex);
523 :
524 : #ifdef WIN32
525 : SetLastError(save_errno);
526 : #else
527 230 : errno = save_errno;
528 : #endif
529 : }
530 :
531 13778 : return dgettext(PG_TEXTDOMAIN("ecpglib"), msgid);
532 : }
533 : #endif /* ENABLE_NLS */
534 :
535 : struct var_list *ivlist = NULL;
536 :
537 : void
538 56 : ECPGset_var(int number, void *pointer, int lineno)
539 : {
540 : struct var_list *ptr;
541 :
542 56 : struct sqlca_t *sqlca = ECPGget_sqlca();
543 :
544 56 : if (sqlca == NULL)
545 : {
546 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
547 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
548 0 : return;
549 : }
550 :
551 56 : ecpg_init_sqlca(sqlca);
552 :
553 156 : for (ptr = ivlist; ptr != NULL; ptr = ptr->next)
554 : {
555 100 : if (ptr->number == number)
556 : {
557 : /* already known => just change pointer value */
558 0 : ptr->pointer = pointer;
559 0 : return;
560 : }
561 : }
562 :
563 : /* a new one has to be added */
564 56 : ptr = (struct var_list *) calloc(1L, sizeof(struct var_list));
565 56 : if (!ptr)
566 : {
567 0 : sqlca = ECPGget_sqlca();
568 :
569 0 : if (sqlca == NULL)
570 : {
571 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
572 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
573 0 : return;
574 : }
575 :
576 0 : sqlca->sqlcode = ECPG_OUT_OF_MEMORY;
577 0 : strncpy(sqlca->sqlstate, "YE001", sizeof(sqlca->sqlstate));
578 0 : snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), "out of memory on line %d", lineno);
579 0 : sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
580 : /* free all memory we have allocated for the user */
581 0 : ECPGfree_auto_mem();
582 : }
583 : else
584 : {
585 56 : ptr->number = number;
586 56 : ptr->pointer = pointer;
587 56 : ptr->next = ivlist;
588 56 : ivlist = ptr;
589 : }
590 : }
591 :
592 : void *
593 204 : ECPGget_var(int number)
594 : {
595 : struct var_list *ptr;
596 :
597 304 : for (ptr = ivlist; ptr != NULL && ptr->number != number; ptr = ptr->next);
598 204 : return (ptr) ? ptr->pointer : NULL;
599 : }
|