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