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 "pgtypes_date.h"
15 #include "pgtypes_interval.h"
16 #include "pgtypes_numeric.h"
17 #include "pgtypes_timestamp.h"
18 #include "pg_config_paths.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
98 ecpg_init_sqlca(struct sqlca_t *sqlca)
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 
115  ecpg_init_sqlca(sqlca);
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;
154  ecpg_init_sqlca(sqlca);
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");
226  if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
227  return false;
228  PQclear(res);
229  }
230 
231  res = PQexec(con->connection, transaction);
232  if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
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",
306  sqlca->sqlcode, sqlca->sqlstate);
307  }
308 
309  fflush(debugstream);
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  *once = true;
481  fn();
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  static bool already_bound = false;
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  const char *ldir;
505 
506  already_bound = true;
507  /* No relocatable lookup here because the binary could be anywhere */
508  ldir = getenv("PGLOCALEDIR");
509  if (!ldir)
510  ldir = LOCALEDIR;
511  bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir);
512 #ifdef WIN32
513  SetLastError(save_errno);
514 #else
515  errno = save_errno;
516 #endif
517  }
518 
519  return dgettext(PG_TEXTDOMAIN("ecpglib"), msgid);
520 }
521 #endif /* ENABLE_NLS */
522 
523 struct var_list *ivlist = NULL;
524 
525 void
526 ECPGset_var(int number, void *pointer, int lineno)
527 {
528  struct var_list *ptr;
529 
530  struct sqlca_t *sqlca = ECPGget_sqlca();
531 
532  if (sqlca == NULL)
533  {
536  return;
537  }
538 
539  ecpg_init_sqlca(sqlca);
540 
541  for (ptr = ivlist; ptr != NULL; ptr = ptr->next)
542  {
543  if (ptr->number == number)
544  {
545  /* already known => just change pointer value */
546  ptr->pointer = pointer;
547  return;
548  }
549  }
550 
551  /* a new one has to be added */
552  ptr = (struct var_list *) calloc(1L, sizeof(struct var_list));
553  if (!ptr)
554  {
555  struct sqlca_t *sqlca = ECPGget_sqlca();
556 
557  if (sqlca == NULL)
558  {
561  return;
562  }
563 
564  sqlca->sqlcode = ECPG_OUT_OF_MEMORY;
565  strncpy(sqlca->sqlstate, "YE001", sizeof(sqlca->sqlstate));
566  snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), "out of memory on line %d", lineno);
567  sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
568  /* free all memory we have allocated for the user */
570  }
571  else
572  {
573  ptr->number = number;
574  ptr->pointer = pointer;
575  ptr->next = ivlist;
576  ivlist = ptr;
577  }
578 }
579 
580 void *
581 ECPGget_var(int number)
582 {
583  struct var_list *ptr;
584 
585  for (ptr = ivlist; ptr != NULL && ptr->number != number; ptr = ptr->next);
586  return (ptr) ? ptr->pointer : NULL;
587 }
#define calloc(a, b)
Definition: header.h:55
CRITICAL_SECTION * pthread_mutex_t
Definition: pthread-win32.h:8
struct var_list * next
#define LONG_LONG_MIN
Definition: misc.c:25
bool ECPGstatus(int lineno, const char *connection_name)
Definition: misc.c:164
#define ECPG_NOT_CONN
Definition: ecpgerrno.h:37
void * ECPGget_var(int number)
Definition: misc.c:581
#define ECPG_SQLSTATE_ECPG_INTERNAL_ERROR
void ecpg_raise(int line, int code, const char *sqlstate, const char *str)
Definition: error.c:13
void ECPGfree_auto_mem(void)
Definition: memory.c:138
int64 timestamp
ULONG pthread_key_t
Definition: pthread-win32.h:7
void * pointer
void ECPGset_var(int number, void *pointer, int lineno)
Definition: misc.c:526
void ecpg_init_sqlca(struct sqlca_t *sqlca)
Definition: misc.c:98
int sqlerrml
Definition: sqlca.h:26
#define NUMERIC_NULL
void ECPGdebug(int n, FILE *dbgs)
Definition: misc.c:242
#define fprintf
Definition: port.h:196
#define ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY
#define malloc(a)
Definition: header.h:50
#define ecpg_gettext(x)
static bool _check(const unsigned char *ptr, int length)
Definition: misc.c:378
#define ECPG_OUT_OF_MEMORY
Definition: ecpgerrno.h:15
struct sqlca_t * ECPGget_sqlca(void)
Definition: misc.c:141
Definition: sqlca.h:19
#define ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST
char sign
Definition: informix.c:688
int pthread_mutex_lock(pthread_mutex_t *mp)
Definition: pthread-win32.c:45
PGTransactionStatusType ECPGtransactionStatus(const char *connection_name)
Definition: misc.c:182
static int simple_debug
Definition: misc.c:94
char sqlstate[5]
Definition: sqlca.h:53
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:6572
int pthread_mutex_unlock(pthread_mutex_t *mp)
Definition: pthread-win32.c:54
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1160
long sqlcode
Definition: sqlca.h:23
static FILE * debugstream
Definition: misc.c:95
#define dgettext(d, x)
Definition: c.h:1127
static struct sqlca_t sqlca_init
Definition: misc.c:31
void ecpg_log(const char *format,...)
Definition: misc.c:266
void PQclear(PGresult *res)
Definition: fe-exec.c:694
static void * fn(void *arg)
#define free(a)
Definition: header.h:65
PGTransactionStatusType
Definition: libpq-fe.h:103
bool ecpg_check_PQresult(PGresult *, int, PGconn *, enum COMPAT_MODE)
Definition: error.c:283
PGconn * connection
bool ecpg_init(const struct connection *con, const char *connection_name, const int lineno)
Definition: misc.c:104
int pthread_once_t
Definition: pthread-win32.h:9
void * pthread_getspecific(pthread_key_t key)
Definition: pthread-win32.c:29
bool ECPGtrans(int lineno, const char *connection_name, const char *transaction)
Definition: misc.c:198
void ECPGset_noind_null(enum ECPGttype type, void *ptr)
Definition: misc.c:319
bool ECPGis_noind_null(enum ECPGttype type, const void *ptr)
Definition: misc.c:388
char arr[FLEXIBLE_ARRAY_MEMBER]
static struct sqlca_t sqlca
Definition: misc.c:62
void pthread_setspecific(pthread_key_t key, void *val)
Definition: pthread-win32.c:24
struct sqlca_t::@148 sqlerrm
struct connection * ecpg_get_connection(const char *connection_name)
Definition: connect.c:74
char sqlerrmc[SQLERRMC_LEN]
Definition: sqlca.h:27
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1939
void * arg
bool ecpg_internal_regression_mode
Definition: misc.c:29
static char format
Definition: pg_basebackup.c:85
#define vfprintf
Definition: port.h:195
#define ECPG_NO_CONN
Definition: ecpgerrno.h:36
#define snprintf
Definition: port.h:192
struct var_list * ivlist
Definition: misc.c:523
ECPGttype
Definition: ecpgtype.h:41