1 /* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/misc.c,v 1.49 2009/06/11 14:49:13 momjian Exp $ */
3 #define POSTGRES_ECPG_INTERNAL
4 #include "postgres_fe.h"
8 #include "ecpg-pthread-win32.h"
11 #include "ecpgerrno.h"
14 #include "pgtypes_numeric.h"
15 #include "pgtypes_date.h"
16 #include "pgtypes_timestamp.h"
17 #include "pgtypes_interval.h"
18 #include "pg_config_paths.h"
20 #ifdef HAVE_LONG_LONG_INT_64
23 #define LONG_LONG_MIN LLONG_MIN
25 #define LONG_LONG_MIN LONGLONG_MIN
30 bool ecpg_internal_regression_mode = false;
32 static struct sqlca_t sqlca_init =
35 'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
37 sizeof(struct sqlca_t),
46 'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '
52 0, 0, 0, 0, 0, 0, 0, 0
55 '0', '0', '0', '0', '0'
59 #ifdef ENABLE_THREAD_SAFETY
60 static pthread_key_t sqlca_key;
61 static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT;
63 static struct sqlca_t sqlca =
66 'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
68 sizeof(struct sqlca_t),
77 'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '
83 0, 0, 0, 0, 0, 0, 0, 0
86 '0', '0', '0', '0', '0'
91 #ifdef ENABLE_THREAD_SAFETY
92 static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
93 static pthread_mutex_t debug_init_mutex = PTHREAD_MUTEX_INITIALIZER;
95 static int simple_debug = 0;
96 static FILE *debugstream = NULL;
99 ecpg_init_sqlca(struct sqlca_t * sqlca)
101 memcpy((char *) sqlca, (char *) &sqlca_init, sizeof(struct sqlca_t));
105 ecpg_init(const struct connection * con, const char *connection_name, const int lineno)
107 struct sqlca_t *sqlca = ECPGget_sqlca();
109 ecpg_init_sqlca(sqlca);
112 ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
113 connection_name ? connection_name : ecpg_gettext("NULL"));
120 #ifdef ENABLE_THREAD_SAFETY
122 ecpg_sqlca_key_destructor(void *arg)
124 free(arg); /* sqlca structure allocated in ECPGget_sqlca */
128 ecpg_sqlca_key_init(void)
130 pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor);
137 #ifdef ENABLE_THREAD_SAFETY
138 struct sqlca_t *sqlca;
140 pthread_once(&sqlca_key_once, ecpg_sqlca_key_init);
142 sqlca = pthread_getspecific(sqlca_key);
145 sqlca = malloc(sizeof(struct sqlca_t));
146 ecpg_init_sqlca(sqlca);
147 pthread_setspecific(sqlca_key, sqlca);
156 ECPGstatus(int lineno, const char *connection_name)
158 struct connection *con = ecpg_get_connection(connection_name);
160 if (!ecpg_init(con, connection_name, lineno))
163 /* are we connected? */
164 if (con->connection == NULL)
166 ecpg_raise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, con->name);
174 ECPGtrans(int lineno, const char *connection_name, const char *transaction)
177 struct connection *con = ecpg_get_connection(connection_name);
179 if (!ecpg_init(con, connection_name, lineno))
182 ecpg_log("ECPGtrans on line %d: action \"%s\"; connection \"%s\"\n", lineno, transaction, con ? con->name : "null");
184 /* if we have no connection we just simulate the command */
185 if (con && con->connection)
188 * If we got a transaction command but have no open transaction, we
189 * have to start one, unless we are in autocommit, where the
190 * developers have to take care themselves. However, if the command is
191 * a begin statement, we just execute it once.
193 if (con->committed && !con->autocommit && strncmp(transaction, "begin", 5) != 0 && strncmp(transaction, "start", 5) != 0)
195 res = PQexec(con->connection, "begin transaction");
196 if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
201 res = PQexec(con->connection, transaction);
202 if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
207 if (strncmp(transaction, "commit", 6) == 0 || strncmp(transaction, "rollback", 8) == 0)
208 con->committed = true;
210 con->committed = false;
217 ECPGdebug(int n, FILE *dbgs)
219 #ifdef ENABLE_THREAD_SAFETY
220 pthread_mutex_lock(&debug_init_mutex);
225 ecpg_internal_regression_mode = true;
226 simple_debug = n - 100;
233 ecpg_log("ECPGdebug: set to %d\n", simple_debug);
235 #ifdef ENABLE_THREAD_SAFETY
236 pthread_mutex_unlock(&debug_init_mutex);
241 ecpg_log(const char *format,...)
244 struct sqlca_t *sqlca = ECPGget_sqlca();
245 const char *intl_format;
252 /* internationalize the error message string */
253 intl_format = ecpg_gettext(format);
256 * Insert PID into the format, unless ecpg_internal_regression_mode is set
257 * (regression tests want unchanging output).
259 bufsize = strlen(intl_format) + 100;
260 fmt = (char *) malloc(bufsize);
264 if (ecpg_internal_regression_mode)
265 snprintf(fmt, bufsize, "[NO_PID]: %s", intl_format);
267 snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format);
269 #ifdef ENABLE_THREAD_SAFETY
270 pthread_mutex_lock(&debug_mutex);
273 va_start(ap, format);
274 vfprintf(debugstream, fmt, ap);
277 /* dump out internal sqlca variables */
278 if (ecpg_internal_regression_mode)
279 fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n",
280 sqlca->sqlcode, sqlca->sqlstate);
284 #ifdef ENABLE_THREAD_SAFETY
285 pthread_mutex_unlock(&debug_mutex);
292 ECPGset_noind_null(enum ECPGttype type, void *ptr)
297 case ECPGt_unsigned_char:
298 *((char *) ptr) = '\0';
301 case ECPGt_unsigned_short:
302 *((short int *) ptr) = SHRT_MIN;
305 case ECPGt_unsigned_int:
306 *((int *) ptr) = INT_MIN;
309 case ECPGt_unsigned_long:
311 *((long *) ptr) = LONG_MIN;
313 #ifdef HAVE_LONG_LONG_INT_64
314 case ECPGt_long_long:
315 case ECPGt_unsigned_long_long:
316 *((long long *) ptr) = LONG_LONG_MIN;
318 #endif /* HAVE_LONG_LONG_INT_64 */
320 memset((char *) ptr, 0xff, sizeof(float));
323 memset((char *) ptr, 0xff, sizeof(double));
326 *(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
327 ((struct ECPGgeneric_varchar *) ptr)->len = 0;
330 memset((char *) ptr, 0, sizeof(decimal));
331 ((decimal *) ptr)->sign = NUMERIC_NAN;
334 memset((char *) ptr, 0, sizeof(numeric));
335 ((numeric *) ptr)->sign = NUMERIC_NAN;
338 memset((char *) ptr, 0xff, sizeof(interval));
340 case ECPGt_timestamp:
341 memset((char *) ptr, 0xff, sizeof(timestamp));
349 _check(unsigned char *ptr, int length)
351 for (; length > 0 && ptr[--length] == 0xff;);
358 ECPGis_noind_null(enum ECPGttype type, void *ptr)
363 case ECPGt_unsigned_char:
364 if (*((char *) ptr) == '\0')
368 case ECPGt_unsigned_short:
369 if (*((short int *) ptr) == SHRT_MIN)
373 case ECPGt_unsigned_int:
374 if (*((int *) ptr) == INT_MIN)
378 case ECPGt_unsigned_long:
380 if (*((long *) ptr) == LONG_MIN)
383 #ifdef HAVE_LONG_LONG_INT_64
384 case ECPGt_long_long:
385 case ECPGt_unsigned_long_long:
386 if (*((long long *) ptr) == LONG_LONG_MIN)
389 #endif /* HAVE_LONG_LONG_INT_64 */
391 return (_check(ptr, sizeof(float)));
394 return (_check(ptr, sizeof(double)));
397 if (*(((struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
401 if (((decimal *) ptr)->sign == NUMERIC_NAN)
405 if (((numeric *) ptr)->sign == NUMERIC_NAN)
409 return (_check(ptr, sizeof(interval)));
411 case ECPGt_timestamp:
412 return (_check(ptr, sizeof(timestamp)));
422 #ifdef ENABLE_THREAD_SAFETY
425 win32_pthread_mutex(volatile pthread_mutex_t *mutex)
427 if (mutex->handle == NULL)
429 while (InterlockedExchange((LONG *) &mutex->initlock, 1) == 1)
431 if (mutex->handle == NULL)
432 mutex->handle = CreateMutex(NULL, FALSE, NULL);
433 InterlockedExchange((LONG *) &mutex->initlock, 0);
437 static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;
440 win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void))
444 pthread_mutex_lock(&win32_pthread_once_lock);
450 pthread_mutex_unlock(&win32_pthread_once_lock);
453 #endif /* ENABLE_THREAD_SAFETY */
459 ecpg_gettext(const char *msgid)
461 static bool already_bound = false;
465 /* dgettext() preserves errno, but bindtextdomain() doesn't */
467 int save_errno = GetLastError();
469 int save_errno = errno;
473 already_bound = true;
474 /* No relocatable lookup here because the binary could be anywhere */
475 ldir = getenv("PGLOCALEDIR");
478 bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir);
480 SetLastError(save_errno);
486 return dgettext(PG_TEXTDOMAIN("ecpg"), msgid);
489 #endif /* ENABLE_NLS */