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 
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 
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 
59 static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT;
60 
63 static volatile int simple_debug = 0;
64 static FILE *debugstream = NULL;
65 
66 void
68 {
69  memcpy((char *) sqlca, (char *) &sqlca_init, sizeof(struct sqlca_t));
70 }
71 
72 bool
73 ecpg_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 
95 static void
97 {
98  free(arg); /* sqlca structure allocated in ECPGget_sqlca */
99 }
100 
101 static void
103 {
104  pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor);
105 }
106 
107 struct 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 
126 bool
127 ECPGstatus(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 
145 ECPGtransactionStatus(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 
159 bool
160 ECPGtrans(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");
189  return false;
190  PQclear(res);
191  }
192 
193  res = PQexec(con->connection, transaction);
195  return false;
196  PQclear(res);
197  }
198 
199  return true;
200 }
201 
202 
203 void
204 ECPGdebug(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 
231 void
232 ecpg_log(const char *format,...)
233 {
234  va_list ap;
235  struct sqlca_t *sqlca = ECPGget_sqlca();
236  const char *intl_format;
237  int bufsize;
238  char *fmt;
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 
267  /* Now that we hold the mutex, recheck simple_debug */
268  if (simple_debug)
269  {
270  va_start(ap, format);
271  vfprintf(debugstream, fmt, ap);
272  va_end(ap);
273 
274  /* dump out internal sqlca variables */
275  if (ecpg_internal_regression_mode && sqlca != NULL)
276  {
277  fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n",
278  sqlca->sqlcode, sqlca->sqlstate);
279  }
280 
282  }
283 
285 
286  free(fmt);
287 }
288 
289 void
291 {
292  switch (type)
293  {
294  case ECPGt_char:
295  case ECPGt_unsigned_char:
296  case ECPGt_string:
297  *((char *) ptr) = '\0';
298  break;
299  case ECPGt_short:
301  *((short int *) ptr) = SHRT_MIN;
302  break;
303  case ECPGt_int:
304  case ECPGt_unsigned_int:
305  *((int *) ptr) = INT_MIN;
306  break;
307  case ECPGt_long:
308  case ECPGt_unsigned_long:
309  case ECPGt_date:
310  *((long *) ptr) = LONG_MIN;
311  break;
312  case ECPGt_long_long:
314  *((long long *) ptr) = LONG_LONG_MIN;
315  break;
316  case ECPGt_float:
317  memset((char *) ptr, 0xff, sizeof(float));
318  break;
319  case ECPGt_double:
320  memset((char *) ptr, 0xff, sizeof(double));
321  break;
322  case ECPGt_varchar:
323  *(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
324  ((struct ECPGgeneric_varchar *) ptr)->len = 0;
325  break;
326  case ECPGt_bytea:
327  ((struct ECPGgeneric_bytea *) ptr)->len = 0;
328  break;
329  case ECPGt_decimal:
330  memset((char *) ptr, 0, sizeof(decimal));
331  ((decimal *) ptr)->sign = NUMERIC_NULL;
332  break;
333  case ECPGt_numeric:
334  memset((char *) ptr, 0, sizeof(numeric));
335  ((numeric *) ptr)->sign = NUMERIC_NULL;
336  break;
337  case ECPGt_interval:
338  memset((char *) ptr, 0xff, sizeof(interval));
339  break;
340  case ECPGt_timestamp:
341  memset((char *) ptr, 0xff, sizeof(timestamp));
342  break;
343  default:
344  break;
345  }
346 }
347 
348 static bool
349 _check(const unsigned char *ptr, int length)
350 {
351  for (length--; length >= 0; length--)
352  if (ptr[length] != 0xff)
353  return false;
354 
355  return true;
356 }
357 
358 bool
359 ECPGis_noind_null(enum ECPGttype type, const void *ptr)
360 {
361  switch (type)
362  {
363  case ECPGt_char:
364  case ECPGt_unsigned_char:
365  case ECPGt_string:
366  if (*((const char *) ptr) == '\0')
367  return true;
368  break;
369  case ECPGt_short:
371  if (*((const short int *) ptr) == SHRT_MIN)
372  return true;
373  break;
374  case ECPGt_int:
375  case ECPGt_unsigned_int:
376  if (*((const int *) ptr) == INT_MIN)
377  return true;
378  break;
379  case ECPGt_long:
380  case ECPGt_unsigned_long:
381  case ECPGt_date:
382  if (*((const long *) ptr) == LONG_MIN)
383  return true;
384  break;
385  case ECPGt_long_long:
387  if (*((const long long *) ptr) == LONG_LONG_MIN)
388  return true;
389  break;
390  case ECPGt_float:
391  return _check(ptr, sizeof(float));
392  break;
393  case ECPGt_double:
394  return _check(ptr, sizeof(double));
395  break;
396  case ECPGt_varchar:
397  if (*(((const struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
398  return true;
399  break;
400  case ECPGt_bytea:
401  if (((const struct ECPGgeneric_bytea *) ptr)->len == 0)
402  return true;
403  break;
404  case ECPGt_decimal:
405  if (((const decimal *) ptr)->sign == NUMERIC_NULL)
406  return true;
407  break;
408  case ECPGt_numeric:
409  if (((const numeric *) ptr)->sign == NUMERIC_NULL)
410  return true;
411  break;
412  case ECPGt_interval:
413  return _check(ptr, sizeof(interval));
414  break;
415  case ECPGt_timestamp:
416  return _check(ptr, sizeof(timestamp));
417  break;
418  default:
419  break;
420  }
421 
422  return false;
423 }
424 
425 #ifdef WIN32
426 
427 int
428 pthread_mutex_init(pthread_mutex_t *mp, void *attr)
429 {
430  mp->initstate = 0;
431  return 0;
432 }
433 
434 int
436 {
437  /* Initialize the csection if not already done */
438  if (mp->initstate != 1)
439  {
440  LONG istate;
441 
442  while ((istate = InterlockedExchange(&mp->initstate, 2)) == 2)
443  Sleep(0); /* wait, another thread is doing this */
444  if (istate != 1)
445  InitializeCriticalSection(&mp->csection);
446  InterlockedExchange(&mp->initstate, 1);
447  }
448  EnterCriticalSection(&mp->csection);
449  return 0;
450 }
451 
452 int
454 {
455  if (mp->initstate != 1)
456  return EINVAL;
457  LeaveCriticalSection(&mp->csection);
458  return 0;
459 }
460 
461 static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;
462 
463 void
464 win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void))
465 {
466  if (!*once)
467  {
468  pthread_mutex_lock(&win32_pthread_once_lock);
469  if (!*once)
470  {
471  fn();
472  *once = true;
473  }
474  pthread_mutex_unlock(&win32_pthread_once_lock);
475  }
476 }
477 #endif /* WIN32 */
478 
479 #ifdef ENABLE_NLS
480 
481 char *
482 ecpg_gettext(const char *msgid)
483 {
484  /*
485  * At least on Windows, there are gettext implementations that fail if
486  * multiple threads call bindtextdomain() concurrently. Use a mutex and
487  * flag variable to ensure that we call it just once per process. It is
488  * not known that similar bugs exist on non-Windows platforms, but we
489  * might as well do it the same way everywhere.
490  */
491  static volatile bool already_bound = false;
492  static pthread_mutex_t binddomain_mutex = PTHREAD_MUTEX_INITIALIZER;
493 
494  if (!already_bound)
495  {
496  /* dgettext() preserves errno, but bindtextdomain() doesn't */
497 #ifdef WIN32
498  int save_errno = GetLastError();
499 #else
500  int save_errno = errno;
501 #endif
502 
503  (void) pthread_mutex_lock(&binddomain_mutex);
504 
505  if (!already_bound)
506  {
507  const char *ldir;
508 
509  /*
510  * No relocatable lookup here because the calling executable could
511  * be anywhere
512  */
513  ldir = getenv("PGLOCALEDIR");
514  if (!ldir)
515  ldir = LOCALEDIR;
516  bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir);
517  already_bound = true;
518  }
519 
520  (void) pthread_mutex_unlock(&binddomain_mutex);
521 
522 #ifdef WIN32
523  SetLastError(save_errno);
524 #else
525  errno = save_errno;
526 #endif
527  }
528 
529  return dgettext(PG_TEXTDOMAIN("ecpglib"), msgid);
530 }
531 #endif /* ENABLE_NLS */
532 
533 struct var_list *ivlist = NULL;
534 
535 void
536 ECPGset_var(int number, void *pointer, int lineno)
537 {
538  struct var_list *ptr;
539 
540  struct sqlca_t *sqlca = ECPGget_sqlca();
541 
542  if (sqlca == NULL)
543  {
546  return;
547  }
548 
550 
551  for (ptr = ivlist; ptr != NULL; ptr = ptr->next)
552  {
553  if (ptr->number == number)
554  {
555  /* already known => just change pointer value */
556  ptr->pointer = pointer;
557  return;
558  }
559  }
560 
561  /* a new one has to be added */
562  ptr = (struct var_list *) calloc(1L, sizeof(struct var_list));
563  if (!ptr)
564  {
565  sqlca = ECPGget_sqlca();
566 
567  if (sqlca == NULL)
568  {
571  return;
572  }
573 
574  sqlca->sqlcode = ECPG_OUT_OF_MEMORY;
575  strncpy(sqlca->sqlstate, "YE001", sizeof(sqlca->sqlstate));
576  snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), "out of memory on line %d", lineno);
577  sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
578  /* free all memory we have allocated for the user */
580  }
581  else
582  {
583  ptr->number = number;
584  ptr->pointer = pointer;
585  ptr->next = ivlist;
586  ivlist = ptr;
587  }
588 }
589 
590 void *
592 {
593  struct var_list *ptr;
594 
595  for (ptr = ivlist; ptr != NULL && ptr->number != number; ptr = ptr->next);
596  return (ptr) ? ptr->pointer : NULL;
597 }
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1214
#define dgettext(d, x)
Definition: c.h:1180
struct connection * ecpg_get_connection(const char *connection_name)
Definition: connect.c:71
#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:7122
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:674
void ECPGset_var(int number, void *pointer, int lineno)
Definition: misc.c:536
PGTransactionStatusType ECPGtransactionStatus(const char *connection_name)
Definition: misc.c:145
static pthread_key_t sqlca_key
Definition: misc.c:58
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:290
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:349
static pthread_mutex_t debug_mutex
Definition: misc.c:61
bool ECPGis_noind_null(enum ECPGttype type, const void *ptr)
Definition: misc.c:359
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
void * ECPGget_var(int number)
Definition: misc.c:591
bool ECPGstatus(int lineno, const char *connection_name)
Definition: misc.c:127
struct sqlca_t * ECPGget_sqlca(void)
Definition: misc.c:108
void ecpg_init_sqlca(struct sqlca_t *sqlca)
Definition: misc.c:67
struct var_list * ivlist
Definition: misc.c:533
static volatile int simple_debug
Definition: misc.c:63
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:121
@ PQTRANS_IDLE
Definition: libpq-fe.h:122
@ PQTRANS_UNKNOWN
Definition: libpq-fe.h:126
static void const char * fmt
static void const char fflush(stdout)
va_end(args)
vfprintf(stderr, fmt, args)
va_start(args, fmt)
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 snprintf
Definition: port.h:238
#define fprintf
Definition: port.h:242
int pthread_mutex_unlock(pthread_mutex_t *mp)
Definition: pthread-win32.c:60
void * pthread_getspecific(pthread_key_t key)
Definition: pthread-win32.c:29
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
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