Age Owner 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
2118 tgl 98 CBC 1604206 : ecpg_init_sqlca(struct sqlca_t *sqlca)
99 : {
7188 bruce 100 1604206 : memcpy((char *) sqlca, (char *) &sqlca_init, sizeof(struct sqlca_t));
7329 meskes 101 1604206 : }
102 :
103 : bool
2118 tgl 104 3813 : ecpg_init(const struct connection *con, const char *connection_name, const int lineno)
105 : {
7238 bruce 106 3813 : struct sqlca_t *sqlca = ECPGget_sqlca();
107 :
2855 meskes 108 3813 : if (sqlca == NULL)
109 : {
2855 meskes 110 UBC 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY,
111 : NULL);
2061 peter_e 112 0 : return false;
113 : }
114 :
5667 meskes 115 CBC 3813 : ecpg_init_sqlca(sqlca);
7329 116 3813 : if (con == NULL)
117 : {
5667 118 20 : ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
5197 peter_e 119 6 : connection_name ? connection_name : ecpg_gettext("NULL"));
2061 120 14 : return false;
121 : }
122 :
123 3799 : return true;
124 : }
125 :
126 : #ifdef ENABLE_THREAD_SAFETY
127 : static void
6797 bruce 128 68 : ecpg_sqlca_key_destructor(void *arg)
129 : {
5624 130 68 : free(arg); /* sqlca structure allocated in ECPGget_sqlca */
6965 meskes 131 68 : }
132 :
133 : static void
6797 bruce 134 62 : ecpg_sqlca_key_init(void)
135 : {
136 62 : pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor);
7238 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 :
7188 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));
2855 meskes 152 128 : if (sqlca == NULL)
2855 meskes 153 UBC 0 : return NULL;
5667 meskes 154 CBC 128 : ecpg_init_sqlca(sqlca);
7188 bruce 155 128 : pthread_setspecific(sqlca_key, sqlca);
156 : }
2061 peter_e 157 3229077 : return sqlca;
158 : #else
159 : return &sqlca;
160 : #endif
161 : }
162 :
163 : bool
7329 meskes 164 UBC 0 : ECPGstatus(int lineno, const char *connection_name)
165 : {
5667 166 0 : struct connection *con = ecpg_get_connection(connection_name);
167 :
168 0 : if (!ecpg_init(con, connection_name, lineno))
2061 peter_e 169 0 : return false;
170 :
171 : /* are we connected? */
7329 meskes 172 0 : if (con->connection == NULL)
173 : {
5667 174 0 : ecpg_raise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, con->name);
7329 175 0 : return false;
176 : }
177 :
2061 peter_e 178 0 : return true;
179 : }
180 :
181 : PGTransactionStatusType
4951 meskes 182 0 : ECPGtransactionStatus(const char *connection_name)
183 : {
184 : const struct connection *con;
185 :
186 0 : con = ecpg_get_connection(connection_name);
4790 bruce 187 0 : if (con == NULL)
188 : {
189 : /* transaction status is unknown */
4951 meskes 190 0 : return PQTRANS_UNKNOWN;
191 : }
192 :
193 0 : return PQtransactionStatus(con->connection);
194 : }
195 :
196 : bool
7329 meskes 197 CBC 122 : ECPGtrans(int lineno, const char *connection_name, const char *transaction)
198 : {
199 : PGresult *res;
5667 200 122 : struct connection *con = ecpg_get_connection(connection_name);
201 :
202 122 : if (!ecpg_init(con, connection_name, lineno))
2061 peter_e 203 UBC 0 : return false;
204 :
5197 peter_e 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 */
7329 meskes 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 : */
2218 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 &&
2218 meskes 222 UBC 0 : strncmp(transaction, "rollback prepared", 17) != 0)
223 : {
6418 224 0 : res = PQexec(con->connection, "begin transaction");
5667 225 0 : if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
2062 peter_e 226 0 : return false;
7329 meskes 227 0 : PQclear(res);
228 : }
229 :
6418 meskes 230 CBC 122 : res = PQexec(con->connection, transaction);
5667 231 122 : if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
2062 peter_e 232 UBC 0 : return false;
6418 meskes 233 CBC 122 : PQclear(res);
234 : }
235 :
7329 236 122 : return true;
237 : }
238 :
239 :
240 : void
241 57 : ECPGdebug(int n, FILE *dbgs)
242 : {
243 : #ifdef ENABLE_THREAD_SAFETY
7222 244 57 : pthread_mutex_lock(&debug_init_mutex);
245 : #endif
246 :
5624 bruce 247 57 : if (n > 100)
248 : {
5931 meskes 249 57 : ecpg_internal_regression_mode = true;
5624 bruce 250 57 : simple_debug = n - 100;
251 : }
252 : else
5931 meskes 253 UBC 0 : simple_debug = n;
254 :
7329 meskes 255 CBC 57 : debugstream = dbgs;
256 :
5667 257 57 : ecpg_log("ECPGdebug: set to %d\n", simple_debug);
258 :
259 : #ifdef ENABLE_THREAD_SAFETY
7222 260 57 : pthread_mutex_unlock(&debug_init_mutex);
261 : #endif
7329 262 57 : }
263 :
264 : void
5667 265 14499 : ecpg_log(const char *format,...)
266 : {
267 : va_list ap;
5050 bruce 268 14499 : struct sqlca_t *sqlca = ECPGget_sqlca();
269 : const char *intl_format;
270 : int bufsize;
271 : char *fmt;
272 :
5228 tgl 273 14499 : if (!simple_debug)
meskes 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 : */
tgl 283 3228 : bufsize = strlen(intl_format) + 100;
284 3228 : fmt = (char *) malloc(bufsize);
285 3228 : if (fmt == NULL)
5228 tgl 286 UBC 0 : return;
287 :
5228 meskes 288 CBC 3228 : if (ecpg_internal_regression_mode)
tgl 289 3228 : snprintf(fmt, bufsize, "[NO_PID]: %s", intl_format);
290 : else
5228 tgl 291 UBC 0 : snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format);
292 :
293 : #ifdef ENABLE_THREAD_SAFETY
5228 meskes 294 CBC 3228 : pthread_mutex_lock(&debug_mutex);
295 : #endif
296 :
297 3228 : va_start(ap, format);
tgl 298 3228 : vfprintf(debugstream, fmt, ap);
meskes 299 3228 : va_end(ap);
300 :
301 : /* dump out internal sqlca variables */
2855 302 3228 : if (ecpg_internal_regression_mode && sqlca != NULL)
303 : {
5228 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 :
tgl 314 3228 : free(fmt);
315 : }
316 :
317 : void
6860 meskes 318 1785 : ECPGset_noind_null(enum ECPGttype type, void *ptr)
319 : {
7228 320 1785 : switch (type)
321 : {
7188 bruce 322 945 : case ECPGt_char:
323 : case ECPGt_unsigned_char:
324 : case ECPGt_string:
7184 peter_e 325 945 : *((char *) ptr) = '\0';
7228 meskes 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;
7228 meskes 340 UBC 0 : case ECPGt_long_long:
341 : case ECPGt_unsigned_long_long:
342 0 : *((long long *) ptr) = LONG_LONG_MIN;
343 0 : break;
7228 meskes 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;
7228 meskes 350 UBC 0 : case ECPGt_varchar:
351 0 : *(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
6860 352 0 : ((struct ECPGgeneric_varchar *) ptr)->len = 0;
7228 353 0 : break;
1511 354 0 : case ECPGt_bytea:
355 0 : ((struct ECPGgeneric_bytea *) ptr)->len = 0;
356 0 : break;
7222 meskes 357 CBC 819 : case ECPGt_decimal:
7152 358 819 : memset((char *) ptr, 0, sizeof(decimal));
4814 359 819 : ((decimal *) ptr)->sign = NUMERIC_NULL;
7222 360 819 : break;
7228 361 2 : case ECPGt_numeric:
7152 362 2 : memset((char *) ptr, 0, sizeof(numeric));
4814 363 2 : ((numeric *) ptr)->sign = NUMERIC_NULL;
7228 364 2 : break;
7228 meskes 365 UBC 0 : case ECPGt_interval:
7152 366 0 : memset((char *) ptr, 0xff, sizeof(interval));
7228 367 0 : break;
7228 meskes 368 CBC 3 : case ECPGt_timestamp:
7152 369 3 : memset((char *) ptr, 0xff, sizeof(timestamp));
7228 370 3 : break;
371 1 : default:
372 1 : break;
373 : }
374 1785 : }
375 :
376 : static bool
1986 peter_e 377 11 : _check(const unsigned char *ptr, int length)
378 : {
4884 meskes 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
1986 peter_e 387 2763 : ECPGis_noind_null(enum ECPGttype type, const void *ptr)
388 : {
7228 meskes 389 2763 : switch (type)
390 : {
7188 bruce 391 20 : case ECPGt_char:
392 : case ECPGt_unsigned_char:
393 : case ECPGt_string:
1986 peter_e 394 20 : if (*((const char *) ptr) == '\0')
7188 bruce 395 2 : return true;
7228 meskes 396 18 : break;
397 4 : case ECPGt_short:
398 : case ECPGt_unsigned_short:
1986 peter_e 399 4 : if (*((const short int *) ptr) == SHRT_MIN)
7188 bruce 400 2 : return true;
7228 meskes 401 2 : break;
402 18 : case ECPGt_int:
403 : case ECPGt_unsigned_int:
1986 peter_e 404 18 : if (*((const int *) ptr) == INT_MIN)
7188 bruce 405 2 : return true;
7228 meskes 406 16 : break;
407 18 : case ECPGt_long:
408 : case ECPGt_unsigned_long:
409 : case ECPGt_date:
1986 peter_e 410 18 : if (*((const long *) ptr) == LONG_MIN)
7188 bruce 411 5 : return true;
7228 meskes 412 13 : break;
7228 meskes 413 UBC 0 : case ECPGt_long_long:
414 : case ECPGt_unsigned_long_long:
1986 peter_e 415 0 : if (*((const long long *) ptr) == LONG_LONG_MIN)
7188 bruce 416 0 : return true;
7228 meskes 417 0 : break;
7228 meskes 418 CBC 4 : case ECPGt_float:
2061 peter_e 419 4 : return _check(ptr, sizeof(float));
420 : break;
7228 meskes 421 4 : case ECPGt_double:
2061 peter_e 422 4 : return _check(ptr, sizeof(double));
423 : break;
7228 meskes 424 UBC 0 : case ECPGt_varchar:
1986 peter_e 425 0 : if (*(((const struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
7188 bruce 426 0 : return true;
7228 meskes 427 0 : break;
1511 428 0 : case ECPGt_bytea:
1507 peter 429 0 : if (((const struct ECPGgeneric_bytea *) ptr)->len == 0)
1511 meskes 430 0 : return true;
431 0 : break;
7222 meskes 432 CBC 2688 : case ECPGt_decimal:
1986 peter_e 433 2688 : if (((const decimal *) ptr)->sign == NUMERIC_NULL)
7188 bruce 434 260 : return true;
7222 meskes 435 2428 : break;
7228 meskes 436 UBC 0 : case ECPGt_numeric:
1986 peter_e 437 0 : if (((const numeric *) ptr)->sign == NUMERIC_NULL)
7188 bruce 438 0 : return true;
7228 meskes 439 0 : break;
440 0 : case ECPGt_interval:
2061 peter_e 441 0 : return _check(ptr, sizeof(interval));
442 : break;
7228 meskes 443 CBC 3 : case ECPGt_timestamp:
2061 peter_e 444 3 : return _check(ptr, sizeof(timestamp));
445 : break;
7228 meskes 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 *
5441 peter_e 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)
5441 peter_e 515 UBC 0 : ldir = LOCALEDIR;
5210 peter_e 516 CBC 56 : bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir);
443 tgl 517 56 : already_bound = true;
518 : #ifdef WIN32
519 : SetLastError(save_errno);
520 : #else
5441 peter_e 521 56 : errno = save_errno;
522 : #endif
523 : }
524 :
3724 meskes 525 3284 : return dgettext(PG_TEXTDOMAIN("ecpglib"), msgid);
526 : }
527 : #endif /* ENABLE_NLS */
528 :
529 : struct var_list *ivlist = NULL;
530 :
531 : void
4821 532 14 : ECPGset_var(int number, void *pointer, int lineno)
533 : {
534 : struct var_list *ptr;
535 :
1530 536 14 : struct sqlca_t *sqlca = ECPGget_sqlca();
537 :
538 14 : if (sqlca == NULL)
539 : {
1500 peter 540 UBC 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
541 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
542 0 : return;
543 : }
544 :
1500 peter 545 CBC 14 : ecpg_init_sqlca(sqlca);
546 :
4821 meskes 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 */
4821 meskes 552 UBC 0 : ptr->pointer = pointer;
553 0 : return;
554 : }
555 : }
556 :
557 : /* a new one has to be added */
4821 meskes 558 CBC 14 : ptr = (struct var_list *) calloc(1L, sizeof(struct var_list));
559 14 : if (!ptr)
560 : {
186 drowley 561 UNC 0 : sqlca = ECPGget_sqlca();
562 :
2855 meskes 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 :
4821 570 0 : sqlca->sqlcode = ECPG_OUT_OF_MEMORY;
4049 peter_e 571 0 : strncpy(sqlca->sqlstate, "YE001", sizeof(sqlca->sqlstate));
4821 meskes 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 : {
4821 meskes 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);
4790 bruce 592 51 : return (ptr) ? ptr->pointer : NULL;
593 : }
|