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