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