PostgreSQL Source Code git master
misc.c
Go to the documentation of this file.
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
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
30
31static 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
59static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT;
60
63static volatile int simple_debug = 0;
64static FILE *debugstream = NULL;
65
66void
68{
69 memcpy(sqlca, &sqlca_init, sizeof(struct sqlca_t));
70}
71
72bool
73ecpg_init(const struct connection *con, const char *connection_name, const int lineno)
74{
75 struct sqlca_t *sqlca = ECPGget_sqlca();
76
77 if (sqlca == NULL)
78 {
80 NULL);
81 return false;
82 }
83
85 if (con == NULL)
86 {
88 connection_name ? connection_name : ecpg_gettext("NULL"));
89 return false;
90 }
91
92 return true;
93}
94
95static void
97{
98 free(arg); /* sqlca structure allocated in ECPGget_sqlca */
99}
100
101static void
103{
104 pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor);
105}
106
107struct sqlca_t *
109{
110 struct sqlca_t *sqlca;
111
112 pthread_once(&sqlca_key_once, ecpg_sqlca_key_init);
113
115 if (sqlca == NULL)
116 {
117 sqlca = malloc(sizeof(struct sqlca_t));
118 if (sqlca == NULL)
119 return NULL;
122 }
123 return sqlca;
124}
125
126bool
127ECPGstatus(int lineno, const char *connection_name)
128{
129 struct connection *con = ecpg_get_connection(connection_name);
130
131 if (!ecpg_init(con, connection_name, lineno))
132 return false;
133
134 /* are we connected? */
135 if (con->connection == NULL)
136 {
138 return false;
139 }
140
141 return true;
142}
143
145ECPGtransactionStatus(const char *connection_name)
146{
147 const struct connection *con;
148
149 con = ecpg_get_connection(connection_name);
150 if (con == NULL)
151 {
152 /* transaction status is unknown */
153 return PQTRANS_UNKNOWN;
154 }
155
156 return PQtransactionStatus(con->connection);
157}
158
159bool
160ECPGtrans(int lineno, const char *connection_name, const char *transaction)
161{
162 PGresult *res;
163 struct connection *con = ecpg_get_connection(connection_name);
164
165 if (!ecpg_init(con, connection_name, lineno))
166 return false;
167
168 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 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 */
181 !con->autocommit &&
182 strncmp(transaction, "begin", 5) != 0 &&
183 strncmp(transaction, "start", 5) != 0 &&
184 strncmp(transaction, "commit prepared", 15) != 0 &&
185 strncmp(transaction, "rollback prepared", 17) != 0)
186 {
187 res = PQexec(con->connection, "begin transaction");
188 if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
189 return false;
190 PQclear(res);
191 }
192
193 res = PQexec(con->connection, transaction);
194 if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
195 return false;
196 PQclear(res);
197 }
198
199 return true;
200}
201
202
203void
204ECPGdebug(int n, FILE *dbgs)
205{
206 /* Interlock against concurrent executions of ECPGdebug() */
208
209 /* Prevent ecpg_log() from printing while we change settings */
211
212 if (n > 100)
213 {
215 simple_debug = n - 100;
216 }
217 else
218 simple_debug = n;
219
220 debugstream = dbgs;
221
222 /* We must release debug_mutex before invoking ecpg_log() ... */
224
225 /* ... but keep holding debug_init_mutex to avoid racy printout */
226 ecpg_log("ECPGdebug: set to %d\n", simple_debug);
227
229}
230
231void
232ecpg_log(const char *format,...)
233{
234 va_list ap;
235 const char *intl_format;
236 int bufsize;
237 char *fmt;
238 struct sqlca_t *sqlca;
239
240 /*
241 * For performance reasons, inspect simple_debug without taking the mutex.
242 * This could be problematic if fetching an int isn't atomic, but we
243 * assume that it is in many other places too.
244 */
245 if (!simple_debug)
246 return;
247
248 /* localize the error message string */
249 intl_format = ecpg_gettext(format);
250
251 /*
252 * Insert PID into the format, unless ecpg_internal_regression_mode is set
253 * (regression tests want unchanging output).
254 */
255 bufsize = strlen(intl_format) + 100;
256 fmt = (char *) malloc(bufsize);
257 if (fmt == NULL)
258 return;
259
261 snprintf(fmt, bufsize, "[NO_PID]: %s", intl_format);
262 else
263 snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format);
264
266
268
269 /* Now that we hold the mutex, recheck simple_debug */
270 if (simple_debug)
271 {
272 va_start(ap, format);
273 vfprintf(debugstream, fmt, ap);
274 va_end(ap);
275
276 /* dump out internal sqlca variables */
278 {
279 fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n",
280 sqlca->sqlcode, sqlca->sqlstate);
281 }
282
283 fflush(debugstream);
284 }
285
287
288 free(fmt);
289}
290
291void
293{
294 switch (type)
295 {
296 case ECPGt_char:
298 case ECPGt_string:
299 *((char *) ptr) = '\0';
300 break;
301 case ECPGt_short:
303 *((short int *) ptr) = SHRT_MIN;
304 break;
305 case ECPGt_int:
307 *((int *) ptr) = INT_MIN;
308 break;
309 case ECPGt_long:
311 case ECPGt_date:
312 *((long *) ptr) = LONG_MIN;
313 break;
314 case ECPGt_long_long:
316 *((long long *) ptr) = LONG_LONG_MIN;
317 break;
318 case ECPGt_float:
319 memset(ptr, 0xff, sizeof(float));
320 break;
321 case ECPGt_double:
322 memset(ptr, 0xff, sizeof(double));
323 break;
324 case ECPGt_varchar:
325 *(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
326 ((struct ECPGgeneric_varchar *) ptr)->len = 0;
327 break;
328 case ECPGt_bytea:
329 ((struct ECPGgeneric_bytea *) ptr)->len = 0;
330 break;
331 case ECPGt_decimal:
332 memset(ptr, 0, sizeof(decimal));
333 ((decimal *) ptr)->sign = NUMERIC_NULL;
334 break;
335 case ECPGt_numeric:
336 memset(ptr, 0, sizeof(numeric));
337 ((numeric *) ptr)->sign = NUMERIC_NULL;
338 break;
339 case ECPGt_interval:
340 memset(ptr, 0xff, sizeof(interval));
341 break;
342 case ECPGt_timestamp:
343 memset(ptr, 0xff, sizeof(timestamp));
344 break;
345 default:
346 break;
347 }
348}
349
350static bool
351_check(const unsigned char *ptr, int length)
352{
353 for (length--; length >= 0; length--)
354 if (ptr[length] != 0xff)
355 return false;
356
357 return true;
358}
359
360bool
361ECPGis_noind_null(enum ECPGttype type, const void *ptr)
362{
363 switch (type)
364 {
365 case ECPGt_char:
367 case ECPGt_string:
368 if (*((const char *) ptr) == '\0')
369 return true;
370 break;
371 case ECPGt_short:
373 if (*((const short int *) ptr) == SHRT_MIN)
374 return true;
375 break;
376 case ECPGt_int:
378 if (*((const int *) ptr) == INT_MIN)
379 return true;
380 break;
381 case ECPGt_long:
383 case ECPGt_date:
384 if (*((const long *) ptr) == LONG_MIN)
385 return true;
386 break;
387 case ECPGt_long_long:
389 if (*((const long long *) ptr) == LONG_LONG_MIN)
390 return true;
391 break;
392 case ECPGt_float:
393 return _check(ptr, sizeof(float));
394 break;
395 case ECPGt_double:
396 return _check(ptr, sizeof(double));
397 break;
398 case ECPGt_varchar:
399 if (*(((const struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
400 return true;
401 break;
402 case ECPGt_bytea:
403 if (((const struct ECPGgeneric_bytea *) ptr)->len == 0)
404 return true;
405 break;
406 case ECPGt_decimal:
407 if (((const decimal *) ptr)->sign == NUMERIC_NULL)
408 return true;
409 break;
410 case ECPGt_numeric:
411 if (((const numeric *) ptr)->sign == NUMERIC_NULL)
412 return true;
413 break;
414 case ECPGt_interval:
415 return _check(ptr, sizeof(interval));
416 break;
417 case ECPGt_timestamp:
418 return _check(ptr, sizeof(timestamp));
419 break;
420 default:
421 break;
422 }
423
424 return false;
425}
426
427#ifdef WIN32
428
429int
430pthread_mutex_init(pthread_mutex_t *mp, void *attr)
431{
432 mp->initstate = 0;
433 return 0;
434}
435
436int
438{
439 /* Initialize the csection if not already done */
440 if (mp->initstate != 1)
441 {
442 LONG istate;
443
444 while ((istate = InterlockedExchange(&mp->initstate, 2)) == 2)
445 Sleep(0); /* wait, another thread is doing this */
446 if (istate != 1)
447 InitializeCriticalSection(&mp->csection);
448 InterlockedExchange(&mp->initstate, 1);
449 }
450 EnterCriticalSection(&mp->csection);
451 return 0;
452}
453
454int
456{
457 if (mp->initstate != 1)
458 return EINVAL;
459 LeaveCriticalSection(&mp->csection);
460 return 0;
461}
462
463static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;
464
465void
466win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void))
467{
468 if (!*once)
469 {
470 pthread_mutex_lock(&win32_pthread_once_lock);
471 if (!*once)
472 {
473 fn();
474 *once = true;
475 }
476 pthread_mutex_unlock(&win32_pthread_once_lock);
477 }
478}
479#endif /* WIN32 */
480
481#ifdef ENABLE_NLS
482
483char *
484ecpg_gettext(const char *msgid)
485{
486 /*
487 * At least on Windows, there are gettext implementations that fail if
488 * multiple threads call bindtextdomain() concurrently. Use a mutex and
489 * flag variable to ensure that we call it just once per process. It is
490 * not known that similar bugs exist on non-Windows platforms, but we
491 * might as well do it the same way everywhere.
492 */
493 static volatile bool already_bound = false;
494 static pthread_mutex_t binddomain_mutex = PTHREAD_MUTEX_INITIALIZER;
495
496 if (!already_bound)
497 {
498 /* dgettext() preserves errno, but bindtextdomain() doesn't */
499#ifdef WIN32
500 int save_errno = GetLastError();
501#else
502 int save_errno = errno;
503#endif
504
505 (void) pthread_mutex_lock(&binddomain_mutex);
506
507 if (!already_bound)
508 {
509 const char *ldir;
510
511 /*
512 * No relocatable lookup here because the calling executable could
513 * be anywhere
514 */
515 ldir = getenv("PGLOCALEDIR");
516 if (!ldir)
517 ldir = LOCALEDIR;
518 bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir);
519 already_bound = true;
520 }
521
522 (void) pthread_mutex_unlock(&binddomain_mutex);
523
524#ifdef WIN32
525 SetLastError(save_errno);
526#else
527 errno = save_errno;
528#endif
529 }
530
531 return dgettext(PG_TEXTDOMAIN("ecpglib"), msgid);
532}
533#endif /* ENABLE_NLS */
534
535struct var_list *ivlist = NULL;
536
537void
538ECPGset_var(int number, void *pointer, int lineno)
539{
540 struct var_list *ptr;
541
542 struct sqlca_t *sqlca = ECPGget_sqlca();
543
544 if (sqlca == NULL)
545 {
548 return;
549 }
550
552
553 for (ptr = ivlist; ptr != NULL; ptr = ptr->next)
554 {
555 if (ptr->number == number)
556 {
557 /* already known => just change pointer value */
558 ptr->pointer = pointer;
559 return;
560 }
561 }
562
563 /* a new one has to be added */
564 ptr = (struct var_list *) calloc(1L, sizeof(struct var_list));
565 if (!ptr)
566 {
568
569 if (sqlca == NULL)
570 {
573 return;
574 }
575
576 sqlca->sqlcode = ECPG_OUT_OF_MEMORY;
577 strncpy(sqlca->sqlstate, "YE001", sizeof(sqlca->sqlstate));
578 snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), "out of memory on line %d", lineno);
579 sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
580 /* free all memory we have allocated for the user */
582 }
583 else
584 {
585 ptr->number = number;
586 ptr->pointer = pointer;
587 ptr->next = ivlist;
588 ivlist = ptr;
589 }
590}
591
592void *
594{
595 struct var_list *ptr;
596
597 for (ptr = ivlist; ptr != NULL && ptr->number != number; ptr = ptr->next);
598 return (ptr) ? ptr->pointer : NULL;
599}
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1185
#define dgettext(d, x)
Definition: c.h:1151
struct connection * ecpg_get_connection(const char *connection_name)
Definition: connect.c:71
#define fprintf(file, fmt, msg)
Definition: cubescan.l:21
#define ECPG_OUT_OF_MEMORY
Definition: ecpgerrno.h:15
#define ECPG_NOT_CONN
Definition: ecpgerrno.h:37
#define ECPG_NO_CONN
Definition: ecpgerrno.h:36
bool ecpg_check_PQresult(PGresult *results, int lineno, PGconn *connection, enum COMPAT_MODE compat)
Definition: error.c:281
#define ecpg_gettext(x)
#define ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY
@ ECPG_COMPAT_PGSQL
#define ECPG_SQLSTATE_ECPG_INTERNAL_ERROR
#define ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST
void ecpg_raise(int line, int code, const char *sqlstate, const char *str)
Definition: error.c:13
ECPGttype
Definition: ecpgtype.h:42
@ ECPGt_float
Definition: ecpgtype.h:47
@ ECPGt_long_long
Definition: ecpgtype.h:45
@ ECPGt_short
Definition: ecpgtype.h:43
@ ECPGt_decimal
Definition: ecpgtype.h:51
@ ECPGt_bytea
Definition: ecpgtype.h:67
@ ECPGt_numeric
Definition: ecpgtype.h:49
@ ECPGt_varchar
Definition: ecpgtype.h:48
@ ECPGt_timestamp
Definition: ecpgtype.h:54
@ ECPGt_unsigned_short
Definition: ecpgtype.h:43
@ ECPGt_int
Definition: ecpgtype.h:44
@ ECPGt_long
Definition: ecpgtype.h:44
@ ECPGt_unsigned_char
Definition: ecpgtype.h:43
@ ECPGt_double
Definition: ecpgtype.h:47
@ ECPGt_date
Definition: ecpgtype.h:53
@ ECPGt_interval
Definition: ecpgtype.h:55
@ ECPGt_unsigned_long
Definition: ecpgtype.h:44
@ ECPGt_unsigned_long_long
Definition: ecpgtype.h:45
@ ECPGt_unsigned_int
Definition: ecpgtype.h:44
@ ECPGt_char
Definition: ecpgtype.h:43
@ ECPGt_string
Definition: ecpgtype.h:65
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:7498
void PQclear(PGresult *res)
Definition: fe-exec.c:721
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2262
#define calloc(a, b)
Definition: header.h:55
#define free(a)
Definition: header.h:65
#define malloc(a)
Definition: header.h:50
#define bufsize
Definition: indent_globs.h:36
char sign
Definition: informix.c:693
void ECPGset_var(int number, void *pointer, int lineno)
Definition: misc.c:538
PGTransactionStatusType ECPGtransactionStatus(const char *connection_name)
Definition: misc.c:145
static pthread_key_t sqlca_key
Definition: misc.c:58
struct sqlca_t * ECPGget_sqlca(void)
Definition: misc.c:108
static void ecpg_sqlca_key_destructor(void *arg)
Definition: misc.c:96
void ECPGdebug(int n, FILE *dbgs)
Definition: misc.c:204
void ECPGset_noind_null(enum ECPGttype type, void *ptr)
Definition: misc.c:292
static struct sqlca_t sqlca_init
Definition: misc.c:31
static pthread_mutex_t debug_init_mutex
Definition: misc.c:62
bool ECPGtrans(int lineno, const char *connection_name, const char *transaction)
Definition: misc.c:160
static bool _check(const unsigned char *ptr, int length)
Definition: misc.c:351
static pthread_mutex_t debug_mutex
Definition: misc.c:61
bool ECPGis_noind_null(enum ECPGttype type, const void *ptr)
Definition: misc.c:361
void ecpg_log(const char *format,...)
Definition: misc.c:232
bool ecpg_init(const struct connection *con, const char *connection_name, const int lineno)
Definition: misc.c:73
static FILE * debugstream
Definition: misc.c:64
#define LONG_LONG_MIN
Definition: misc.c:25
bool ECPGstatus(int lineno, const char *connection_name)
Definition: misc.c:127
void ecpg_init_sqlca(struct sqlca_t *sqlca)
Definition: misc.c:67
struct var_list * ivlist
Definition: misc.c:535
static volatile int simple_debug
Definition: misc.c:63
void * ECPGget_var(int number)
Definition: misc.c:593
bool ecpg_internal_regression_mode
Definition: misc.c:29
static void ecpg_sqlca_key_init(void)
Definition: misc.c:102
static pthread_once_t sqlca_key_once
Definition: misc.c:59
PGTransactionStatusType
Definition: libpq-fe.h:145
@ PQTRANS_IDLE
Definition: libpq-fe.h:146
@ PQTRANS_UNKNOWN
Definition: libpq-fe.h:150
void ECPGfree_auto_mem(void)
Definition: memory.c:131
void * arg
static char format
const void size_t len
#define NUMERIC_NULL
int64 timestamp
#define vfprintf
Definition: port.h:242
#define snprintf
Definition: port.h:239
int pthread_mutex_unlock(pthread_mutex_t *mp)
Definition: pthread-win32.c:60
int pthread_mutex_lock(pthread_mutex_t *mp)
Definition: pthread-win32.c:42
void pthread_setspecific(pthread_key_t key, void *val)
Definition: pthread-win32.c:24
void * pthread_getspecific(pthread_key_t key)
Definition: pthread-win32.c:29
int pthread_mutex_init(pthread_mutex_t *mp, void *attr)
Definition: pthread-win32.c:35
#define PTHREAD_MUTEX_INITIALIZER
Definition: pthread-win32.h:16
ULONG pthread_key_t
Definition: pthread-win32.h:7
int pthread_once_t
Definition: pthread-win32.h:18
#define sqlca
Definition: sqlca.h:59
char arr[FLEXIBLE_ARRAY_MEMBER]
PGconn * connection
CRITICAL_SECTION csection
Definition: pthread-win32.h:13
Definition: sqlca.h:20
struct var_list * next
void * pointer
static void * fn(void *arg)
Definition: thread-alloc.c:119
const char * type