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
30bool ecpg_internal_regression_mode = false;
31
32static 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
60static pthread_key_t sqlca_key;
61static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT;
62#else
63static 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
92static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
93static pthread_mutex_t debug_init_mutex = PTHREAD_MUTEX_INITIALIZER;
94#endif
95static int simple_debug = 0;
96static FILE *debugstream = NULL;
97
98void
99ecpg_init_sqlca(struct sqlca_t *sqlca)
100{
101 memcpy((char *) sqlca, (char *) &sqlca_init, sizeof(struct sqlca_t));
102}
103
104bool
105ecpg_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
128static void
129ecpg_sqlca_key_destructor(void *arg)
130{
131 free(arg); /* sqlca structure allocated in ECPGget_sqlca */
132}
133
134static void
135ecpg_sqlca_key_init(void)
136{
137 pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor);
138}
139#endif
140
141struct sqlca_t *
142ECPGget_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
164bool
165ECPGstatus(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
182PGTransactionStatusType
183ECPGtransactionStatus(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
198bool
199ECPGtrans(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
242void
243ECPGdebug(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
266void
267ecpg_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
319void
320ECPGset_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
380static bool
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
390bool
391ECPGis_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
462void
463win32_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
475static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;
476
477void
478win32_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 *once = true;
486 fn();
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
496char *
497ecpg_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
528struct var_list *ivlist = NULL;
529
530void
531ECPGset_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
585void *
586ECPGget_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