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 
197 bool
198 ECPGtrans(int lineno, const char *connection_name, const char *transaction)
199 {
200  PGresult *res;
201  struct connection *con = ecpg_get_connection(connection_name);
202 
203  if (!ecpg_init(con, connection_name, lineno))
204  return false;
205 
206  ecpg_log("ECPGtrans on line %d: action \"%s\"; connection \"%s\"\n", lineno, transaction, con ? con->name : "null");
207 
208  /* if we have no connection we just simulate the command */
209  if (con && con->connection)
210  {
211  /*
212  * If we got a transaction command but have no open transaction, we
213  * have to start one, unless we are in autocommit, where the
214  * developers have to take care themselves. However, if the command is
215  * a begin statement, we just execute it once. And if the command is
216  * commit or rollback prepared, we don't execute it.
217  */
219  !con->autocommit &&
220  strncmp(transaction, "begin", 5) != 0 &&
221  strncmp(transaction, "start", 5) != 0 &&
222  strncmp(transaction, "commit prepared", 15) != 0 &&
223  strncmp(transaction, "rollback prepared", 17) != 0)
224  {
225  res = PQexec(con->connection, "begin transaction");
227  return false;
228  PQclear(res);
229  }
230 
231  res = PQexec(con->connection, transaction);
233  return false;
234  PQclear(res);
235  }
236 
237  return true;
238 }
239 
240 
241 void
242 ECPGdebug(int n, FILE *dbgs)
243 {
244 #ifdef ENABLE_THREAD_SAFETY
245  pthread_mutex_lock(&debug_init_mutex);
246 #endif
247 
248  if (n > 100)
249  {
251  simple_debug = n - 100;
252  }
253  else
254  simple_debug = n;
255 
256  debugstream = dbgs;
257 
258  ecpg_log("ECPGdebug: set to %d\n", simple_debug);
259 
260 #ifdef ENABLE_THREAD_SAFETY
261  pthread_mutex_unlock(&debug_init_mutex);
262 #endif
263 }
264 
265 void
266 ecpg_log(const char *format,...)
267 {
268  va_list ap;
269  struct sqlca_t *sqlca = ECPGget_sqlca();
270  const char *intl_format;
271  int bufsize;
272  char *fmt;
273 
274  if (!simple_debug)
275  return;
276 
277  /* localize the error message string */
278  intl_format = ecpg_gettext(format);
279 
280  /*
281  * Insert PID into the format, unless ecpg_internal_regression_mode is set
282  * (regression tests want unchanging output).
283  */
284  bufsize = strlen(intl_format) + 100;
285  fmt = (char *) malloc(bufsize);
286  if (fmt == NULL)
287  return;
288 
290  snprintf(fmt, bufsize, "[NO_PID]: %s", intl_format);
291  else
292  snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format);
293 
294 #ifdef ENABLE_THREAD_SAFETY
295  pthread_mutex_lock(&debug_mutex);
296 #endif
297 
298  va_start(ap, format);
299  vfprintf(debugstream, fmt, ap);
300  va_end(ap);
301 
302  /* dump out internal sqlca variables */
303  if (ecpg_internal_regression_mode && sqlca != NULL)
304  {
305  fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n",
307  }
308 
310 
311 #ifdef ENABLE_THREAD_SAFETY
312  pthread_mutex_unlock(&debug_mutex);
313 #endif
314 
315  free(fmt);
316 }
317 
318 void
320 {
321  switch (type)
322  {
323  case ECPGt_char:
324  case ECPGt_unsigned_char:
325  case ECPGt_string:
326  *((char *) ptr) = '\0';
327  break;
328  case ECPGt_short:
330  *((short int *) ptr) = SHRT_MIN;
331  break;
332  case ECPGt_int:
333  case ECPGt_unsigned_int:
334  *((int *) ptr) = INT_MIN;
335  break;
336  case ECPGt_long:
337  case ECPGt_unsigned_long:
338  case ECPGt_date:
339  *((long *) ptr) = LONG_MIN;
340  break;
341  case ECPGt_long_long:
343  *((long long *) ptr) = LONG_LONG_MIN;
344  break;
345  case ECPGt_float:
346  memset((char *) ptr, 0xff, sizeof(float));
347  break;
348  case ECPGt_double:
349  memset((char *) ptr, 0xff, sizeof(double));
350  break;
351  case ECPGt_varchar:
352  *(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
353  ((struct ECPGgeneric_varchar *) ptr)->len = 0;
354  break;
355  case ECPGt_bytea:
356  ((struct ECPGgeneric_bytea *) ptr)->len = 0;
357  break;
358  case ECPGt_decimal:
359  memset((char *) ptr, 0, sizeof(decimal));
360  ((decimal *) ptr)->sign = NUMERIC_NULL;
361  break;
362  case ECPGt_numeric:
363  memset((char *) ptr, 0, sizeof(numeric));
364  ((numeric *) ptr)->sign = NUMERIC_NULL;
365  break;
366  case ECPGt_interval:
367  memset((char *) ptr, 0xff, sizeof(interval));
368  break;
369  case ECPGt_timestamp:
370  memset((char *) ptr, 0xff, sizeof(timestamp));
371  break;
372  default:
373  break;
374  }
375 }
376 
377 static bool
378 _check(const unsigned char *ptr, int length)
379 {
380  for (length--; length >= 0; length--)
381  if (ptr[length] != 0xff)
382  return false;
383 
384  return true;
385 }
386 
387 bool
388 ECPGis_noind_null(enum ECPGttype type, const void *ptr)
389 {
390  switch (type)
391  {
392  case ECPGt_char:
393  case ECPGt_unsigned_char:
394  case ECPGt_string:
395  if (*((const char *) ptr) == '\0')
396  return true;
397  break;
398  case ECPGt_short:
400  if (*((const short int *) ptr) == SHRT_MIN)
401  return true;
402  break;
403  case ECPGt_int:
404  case ECPGt_unsigned_int:
405  if (*((const int *) ptr) == INT_MIN)
406  return true;
407  break;
408  case ECPGt_long:
409  case ECPGt_unsigned_long:
410  case ECPGt_date:
411  if (*((const long *) ptr) == LONG_MIN)
412  return true;
413  break;
414  case ECPGt_long_long:
416  if (*((const long long *) ptr) == LONG_LONG_MIN)
417  return true;
418  break;
419  case ECPGt_float:
420  return _check(ptr, sizeof(float));
421  break;
422  case ECPGt_double:
423  return _check(ptr, sizeof(double));
424  break;
425  case ECPGt_varchar:
426  if (*(((const struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
427  return true;
428  break;
429  case ECPGt_bytea:
430  if (((const struct ECPGgeneric_bytea *) ptr)->len == 0)
431  return true;
432  break;
433  case ECPGt_decimal:
434  if (((const decimal *) ptr)->sign == NUMERIC_NULL)
435  return true;
436  break;
437  case ECPGt_numeric:
438  if (((const numeric *) ptr)->sign == NUMERIC_NULL)
439  return true;
440  break;
441  case ECPGt_interval:
442  return _check(ptr, sizeof(interval));
443  break;
444  case ECPGt_timestamp:
445  return _check(ptr, sizeof(timestamp));
446  break;
447  default:
448  break;
449  }
450 
451  return false;
452 }
453 
454 #ifdef WIN32
455 #ifdef ENABLE_THREAD_SAFETY
456 
457 void
458 win32_pthread_mutex(volatile pthread_mutex_t *mutex)
459 {
460  if (mutex->handle == NULL)
461  {
462  while (InterlockedExchange((LONG *) &mutex->initlock, 1) == 1)
463  Sleep(0);
464  if (mutex->handle == NULL)
465  mutex->handle = CreateMutex(NULL, FALSE, NULL);
466  InterlockedExchange((LONG *) &mutex->initlock, 0);
467  }
468 }
469 
470 static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;
471 
472 void
473 win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void))
474 {
475  if (!*once)
476  {
477  pthread_mutex_lock(&win32_pthread_once_lock);
478  if (!*once)
479  {
480  fn();
481  *once = true;
482  }
483  pthread_mutex_unlock(&win32_pthread_once_lock);
484  }
485 }
486 #endif /* ENABLE_THREAD_SAFETY */
487 #endif /* WIN32 */
488 
489 #ifdef ENABLE_NLS
490 
491 char *
492 ecpg_gettext(const char *msgid)
493 {
494  /*
495  * If multiple threads come through here at about the same time, it's okay
496  * for more than one of them to call bindtextdomain(). But it's not okay
497  * for any of them to reach dgettext() before bindtextdomain() is
498  * complete, so don't set the flag till that's done. Use "volatile" just
499  * to be sure the compiler doesn't try to get cute.
500  */
501  static volatile bool already_bound = false;
502 
503  if (!already_bound)
504  {
505  /* dgettext() preserves errno, but bindtextdomain() doesn't */
506 #ifdef WIN32
507  int save_errno = GetLastError();
508 #else
509  int save_errno = errno;
510 #endif
511  const char *ldir;
512 
513  /* No relocatable lookup here because the binary could be anywhere */
514  ldir = getenv("PGLOCALEDIR");
515  if (!ldir)
516  ldir = LOCALEDIR;
517  bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir);
518  already_bound = true;
519 #ifdef WIN32
520  SetLastError(save_errno);
521 #else
522  errno = save_errno;
523 #endif
524  }
525 
526  return dgettext(PG_TEXTDOMAIN("ecpglib"), msgid);
527 }
528 #endif /* ENABLE_NLS */
529 
530 struct var_list *ivlist = NULL;
531 
532 void
533 ECPGset_var(int number, void *pointer, int lineno)
534 {
535  struct var_list *ptr;
536 
537  struct sqlca_t *sqlca = ECPGget_sqlca();
538 
539  if (sqlca == NULL)
540  {
543  return;
544  }
545 
547 
548  for (ptr = ivlist; ptr != NULL; ptr = ptr->next)
549  {
550  if (ptr->number == number)
551  {
552  /* already known => just change pointer value */
553  ptr->pointer = pointer;
554  return;
555  }
556  }
557 
558  /* a new one has to be added */
559  ptr = (struct var_list *) calloc(1L, sizeof(struct var_list));
560  if (!ptr)
561  {
562  struct sqlca_t *sqlca = ECPGget_sqlca();
563 
564  if (sqlca == NULL)
565  {
568  return;
569  }
570 
572  strncpy(sqlca->sqlstate, "YE001", sizeof(sqlca->sqlstate));
573  snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), "out of memory on line %d", lineno);
575  /* free all memory we have allocated for the user */
577  }
578  else
579  {
580  ptr->number = number;
581  ptr->pointer = pointer;
582  ptr->next = ivlist;
583  ivlist = ptr;
584  }
585 }
586 
587 void *
588 ECPGget_var(int number)
589 {
590  struct var_list *ptr;
591 
592  for (ptr = ivlist; ptr != NULL && ptr->number != number; ptr = ptr->next);
593  return (ptr) ? ptr->pointer : NULL;
594 }
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1212
#define dgettext(d, x)
Definition: c.h:1178
struct connection * ecpg_get_connection(const char *connection_name)
Definition: connect.c:74
#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 *, int, PGconn *, enum COMPAT_MODE)
Definition: error.c:282
#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:6870
void PQclear(PGresult *res)
Definition: fe-exec.c:694
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2193
#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:533
PGTransactionStatusType ECPGtransactionStatus(const char *connection_name)
Definition: misc.c:182
void ECPGdebug(int n, FILE *dbgs)
Definition: misc.c:242
void ECPGset_noind_null(enum ECPGttype type, void *ptr)
Definition: misc.c:319
static struct sqlca_t sqlca_init
Definition: misc.c:31
bool ECPGtrans(int lineno, const char *connection_name, const char *transaction)
Definition: misc.c:198
static bool _check(const unsigned char *ptr, int length)
Definition: misc.c:378
static int simple_debug
Definition: misc.c:94
bool ECPGis_noind_null(enum ECPGttype type, const void *ptr)
Definition: misc.c:388
void ecpg_log(const char *format,...)
Definition: misc.c:266
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:588
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:530
bool ecpg_internal_regression_mode
Definition: misc.c:29
PGTransactionStatusType
Definition: libpq-fe.h:115
@ PQTRANS_IDLE
Definition: libpq-fe.h:116
@ PQTRANS_UNKNOWN
Definition: libpq-fe.h:120
static void const char fflush(stdout)
va_end(args)
vfprintf(stderr, fmt, args)
static void const char * fmt
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:225
#define fprintf
Definition: port.h:229
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
char sqlstate[5]
Definition: sqlca.h:53
char sqlerrmc[SQLERRMC_LEN]
Definition: sqlca.h:27
long sqlcode
Definition: sqlca.h:23
struct sqlca_t::@145 sqlerrm
int sqlerrml
Definition: sqlca.h:26
struct var_list * next
void * pointer
static void * fn(void *arg)