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 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 12917500 : ECPGget_sqlca(void)
109 : {
110 : struct sqlca_t *sqlca;
111 :
112 12917500 : pthread_once(&sqlca_key_once, ecpg_sqlca_key_init);
113 :
114 12917500 : sqlca = pthread_getspecific(sqlca_key);
115 12917500 : 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 12917500 : 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 234 : pthread_mutex_lock(&debug_init_mutex);
207 :
208 234 : if (n > 100)
209 : {
210 234 : ecpg_internal_regression_mode = true;
211 234 : simple_debug = n - 100;
212 : }
213 : else
214 0 : simple_debug = n;
215 :
216 234 : debugstream = dbgs;
217 :
218 234 : ecpg_log("ECPGdebug: set to %d\n", simple_debug);
219 :
220 234 : pthread_mutex_unlock(&debug_init_mutex);
221 234 : }
222 :
223 : void
224 58572 : ecpg_log(const char *format,...)
225 : {
226 : va_list ap;
227 58572 : struct sqlca_t *sqlca = ECPGget_sqlca();
228 : const char *intl_format;
229 : int bufsize;
230 : char *fmt;
231 :
232 58572 : if (!simple_debug)
233 45084 : return;
234 :
235 : /* localize the error message string */
236 13488 : intl_format = ecpg_gettext(format);
237 :
238 : /*
239 : * Insert PID into the format, unless ecpg_internal_regression_mode is set
240 : * (regression tests want unchanging output).
241 : */
242 13488 : bufsize = strlen(intl_format) + 100;
243 13488 : fmt = (char *) malloc(bufsize);
244 13488 : if (fmt == NULL)
245 0 : return;
246 :
247 13488 : if (ecpg_internal_regression_mode)
248 13488 : snprintf(fmt, bufsize, "[NO_PID]: %s", intl_format);
249 : else
250 0 : snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format);
251 :
252 13488 : pthread_mutex_lock(&debug_mutex);
253 :
254 13488 : va_start(ap, format);
255 13488 : vfprintf(debugstream, fmt, ap);
256 13488 : va_end(ap);
257 :
258 : /* dump out internal sqlca variables */
259 13488 : if (ecpg_internal_regression_mode && sqlca != NULL)
260 : {
261 13488 : fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n",
262 13488 : sqlca->sqlcode, sqlca->sqlstate);
263 : }
264 :
265 13488 : fflush(debugstream);
266 :
267 13488 : pthread_mutex_unlock(&debug_mutex);
268 :
269 13488 : free(fmt);
270 : }
271 :
272 : void
273 7140 : ECPGset_noind_null(enum ECPGttype type, void *ptr)
274 : {
275 7140 : switch (type)
276 : {
277 3780 : case ECPGt_char:
278 : case ECPGt_unsigned_char:
279 : case ECPGt_string:
280 3780 : *((char *) ptr) = '\0';
281 3780 : break;
282 8 : case ECPGt_short:
283 : case ECPGt_unsigned_short:
284 8 : *((short int *) ptr) = SHRT_MIN;
285 8 : break;
286 8 : case ECPGt_int:
287 : case ECPGt_unsigned_int:
288 8 : *((int *) ptr) = INT_MIN;
289 8 : break;
290 20 : case ECPGt_long:
291 : case ECPGt_unsigned_long:
292 : case ECPGt_date:
293 20 : *((long *) ptr) = LONG_MIN;
294 20 : break;
295 0 : case ECPGt_long_long:
296 : case ECPGt_unsigned_long_long:
297 0 : *((long long *) ptr) = LONG_LONG_MIN;
298 0 : break;
299 8 : case ECPGt_float:
300 8 : memset((char *) ptr, 0xff, sizeof(float));
301 8 : break;
302 16 : case ECPGt_double:
303 16 : memset((char *) ptr, 0xff, sizeof(double));
304 16 : break;
305 0 : case ECPGt_varchar:
306 0 : *(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
307 0 : ((struct ECPGgeneric_varchar *) ptr)->len = 0;
308 0 : break;
309 0 : case ECPGt_bytea:
310 0 : ((struct ECPGgeneric_bytea *) ptr)->len = 0;
311 0 : break;
312 3276 : case ECPGt_decimal:
313 3276 : memset((char *) ptr, 0, sizeof(decimal));
314 3276 : ((decimal *) ptr)->sign = NUMERIC_NULL;
315 3276 : break;
316 8 : case ECPGt_numeric:
317 8 : memset((char *) ptr, 0, sizeof(numeric));
318 8 : ((numeric *) ptr)->sign = NUMERIC_NULL;
319 8 : break;
320 0 : case ECPGt_interval:
321 0 : memset((char *) ptr, 0xff, sizeof(interval));
322 0 : break;
323 12 : case ECPGt_timestamp:
324 12 : memset((char *) ptr, 0xff, sizeof(timestamp));
325 12 : break;
326 4 : default:
327 4 : break;
328 : }
329 7140 : }
330 :
331 : static bool
332 44 : _check(const unsigned char *ptr, int length)
333 : {
334 236 : for (length--; length >= 0; length--)
335 208 : if (ptr[length] != 0xff)
336 16 : return false;
337 :
338 28 : return true;
339 : }
340 :
341 : bool
342 11052 : ECPGis_noind_null(enum ECPGttype type, const void *ptr)
343 : {
344 11052 : switch (type)
345 : {
346 80 : case ECPGt_char:
347 : case ECPGt_unsigned_char:
348 : case ECPGt_string:
349 80 : if (*((const char *) ptr) == '\0')
350 8 : return true;
351 72 : break;
352 16 : case ECPGt_short:
353 : case ECPGt_unsigned_short:
354 16 : if (*((const short int *) ptr) == SHRT_MIN)
355 8 : return true;
356 8 : break;
357 72 : case ECPGt_int:
358 : case ECPGt_unsigned_int:
359 72 : if (*((const int *) ptr) == INT_MIN)
360 8 : return true;
361 64 : break;
362 72 : case ECPGt_long:
363 : case ECPGt_unsigned_long:
364 : case ECPGt_date:
365 72 : if (*((const long *) ptr) == LONG_MIN)
366 20 : return true;
367 52 : break;
368 0 : case ECPGt_long_long:
369 : case ECPGt_unsigned_long_long:
370 0 : if (*((const long long *) ptr) == LONG_LONG_MIN)
371 0 : return true;
372 0 : break;
373 16 : case ECPGt_float:
374 16 : return _check(ptr, sizeof(float));
375 : break;
376 16 : case ECPGt_double:
377 16 : return _check(ptr, sizeof(double));
378 : break;
379 0 : case ECPGt_varchar:
380 0 : if (*(((const struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
381 0 : return true;
382 0 : break;
383 0 : case ECPGt_bytea:
384 0 : if (((const struct ECPGgeneric_bytea *) ptr)->len == 0)
385 0 : return true;
386 0 : break;
387 10752 : case ECPGt_decimal:
388 10752 : if (((const decimal *) ptr)->sign == NUMERIC_NULL)
389 1040 : return true;
390 9712 : break;
391 0 : case ECPGt_numeric:
392 0 : if (((const numeric *) ptr)->sign == NUMERIC_NULL)
393 0 : return true;
394 0 : break;
395 0 : case ECPGt_interval:
396 0 : return _check(ptr, sizeof(interval));
397 : break;
398 12 : case ECPGt_timestamp:
399 12 : return _check(ptr, sizeof(timestamp));
400 : break;
401 16 : default:
402 16 : break;
403 : }
404 :
405 9924 : return false;
406 : }
407 :
408 : #ifdef WIN32
409 :
410 : int
411 : pthread_mutex_init(pthread_mutex_t *mp, void *attr)
412 : {
413 : mp->initstate = 0;
414 : return 0;
415 : }
416 :
417 : int
418 : pthread_mutex_lock(pthread_mutex_t *mp)
419 : {
420 : /* Initialize the csection if not already done */
421 : if (mp->initstate != 1)
422 : {
423 : LONG istate;
424 :
425 : while ((istate = InterlockedExchange(&mp->initstate, 2)) == 2)
426 : Sleep(0); /* wait, another thread is doing this */
427 : if (istate != 1)
428 : InitializeCriticalSection(&mp->csection);
429 : InterlockedExchange(&mp->initstate, 1);
430 : }
431 : EnterCriticalSection(&mp->csection);
432 : return 0;
433 : }
434 :
435 : int
436 : pthread_mutex_unlock(pthread_mutex_t *mp)
437 : {
438 : if (mp->initstate != 1)
439 : return EINVAL;
440 : LeaveCriticalSection(&mp->csection);
441 : return 0;
442 : }
443 :
444 : static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;
445 :
446 : void
447 : win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void))
448 : {
449 : if (!*once)
450 : {
451 : pthread_mutex_lock(&win32_pthread_once_lock);
452 : if (!*once)
453 : {
454 : fn();
455 : *once = true;
456 : }
457 : pthread_mutex_unlock(&win32_pthread_once_lock);
458 : }
459 : }
460 : #endif /* WIN32 */
461 :
462 : #ifdef ENABLE_NLS
463 :
464 : char *
465 13778 : ecpg_gettext(const char *msgid)
466 : {
467 : /*
468 : * At least on Windows, there are gettext implementations that fail if
469 : * multiple threads call bindtextdomain() concurrently. Use a mutex and
470 : * flag variable to ensure that we call it just once per process. It is
471 : * not known that similar bugs exist on non-Windows platforms, but we
472 : * might as well do it the same way everywhere.
473 : */
474 : static volatile bool already_bound = false;
475 : static pthread_mutex_t binddomain_mutex = PTHREAD_MUTEX_INITIALIZER;
476 :
477 13778 : if (!already_bound)
478 : {
479 : /* dgettext() preserves errno, but bindtextdomain() doesn't */
480 : #ifdef WIN32
481 : int save_errno = GetLastError();
482 : #else
483 230 : int save_errno = errno;
484 : #endif
485 :
486 230 : (void) pthread_mutex_lock(&binddomain_mutex);
487 :
488 230 : if (!already_bound)
489 : {
490 : const char *ldir;
491 :
492 : /*
493 : * No relocatable lookup here because the calling executable could
494 : * be anywhere
495 : */
496 230 : ldir = getenv("PGLOCALEDIR");
497 230 : if (!ldir)
498 0 : ldir = LOCALEDIR;
499 230 : bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir);
500 230 : already_bound = true;
501 : }
502 :
503 230 : (void) pthread_mutex_unlock(&binddomain_mutex);
504 :
505 : #ifdef WIN32
506 : SetLastError(save_errno);
507 : #else
508 230 : errno = save_errno;
509 : #endif
510 : }
511 :
512 13778 : return dgettext(PG_TEXTDOMAIN("ecpglib"), msgid);
513 : }
514 : #endif /* ENABLE_NLS */
515 :
516 : struct var_list *ivlist = NULL;
517 :
518 : void
519 56 : ECPGset_var(int number, void *pointer, int lineno)
520 : {
521 : struct var_list *ptr;
522 :
523 56 : struct sqlca_t *sqlca = ECPGget_sqlca();
524 :
525 56 : if (sqlca == NULL)
526 : {
527 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
528 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
529 0 : return;
530 : }
531 :
532 56 : ecpg_init_sqlca(sqlca);
533 :
534 156 : for (ptr = ivlist; ptr != NULL; ptr = ptr->next)
535 : {
536 100 : if (ptr->number == number)
537 : {
538 : /* already known => just change pointer value */
539 0 : ptr->pointer = pointer;
540 0 : return;
541 : }
542 : }
543 :
544 : /* a new one has to be added */
545 56 : ptr = (struct var_list *) calloc(1L, sizeof(struct var_list));
546 56 : if (!ptr)
547 : {
548 0 : sqlca = ECPGget_sqlca();
549 :
550 0 : if (sqlca == NULL)
551 : {
552 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
553 : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
554 0 : return;
555 : }
556 :
557 0 : sqlca->sqlcode = ECPG_OUT_OF_MEMORY;
558 0 : strncpy(sqlca->sqlstate, "YE001", sizeof(sqlca->sqlstate));
559 0 : snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), "out of memory on line %d", lineno);
560 0 : sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
561 : /* free all memory we have allocated for the user */
562 0 : ECPGfree_auto_mem();
563 : }
564 : else
565 : {
566 56 : ptr->number = number;
567 56 : ptr->pointer = pointer;
568 56 : ptr->next = ivlist;
569 56 : ivlist = ptr;
570 : }
571 : }
572 :
573 : void *
574 204 : ECPGget_var(int number)
575 : {
576 : struct var_list *ptr;
577 :
578 304 : for (ptr = ivlist; ptr != NULL && ptr->number != number; ptr = ptr->next);
579 204 : return (ptr) ? ptr->pointer : NULL;
580 : }
|