Age Owner Branch data TLA Line data Source code
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 : :
29 : : bool ecpg_internal_regression_mode = false;
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 : : static pthread_key_t sqlca_key;
59 : : static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT;
60 : :
61 : : static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
62 : : static pthread_mutex_t debug_init_mutex = PTHREAD_MUTEX_INITIALIZER;
63 : : static volatile int simple_debug = 0;
64 : : static FILE *debugstream = NULL;
65 : :
66 : : void
2999 tgl@sss.pgh.pa.us 67 :GIC 1604240 : ecpg_init_sqlca(struct sqlca_t *sqlca)
68 : : {
206 peter@eisentraut.org 69 : 1604240 : memcpy(sqlca, &sqlca_init, sizeof(struct sqlca_t));
8210 meskes@postgresql.or 70 : 1604240 : }
71 : :
72 : : bool
2999 tgl@sss.pgh.pa.us 73 : 3845 : ecpg_init(const struct connection *con, const char *connection_name, const int lineno)
74 : : {
8119 bruce@momjian.us 75 : 3845 : struct sqlca_t *sqlca = ECPGget_sqlca();
76 : :
3736 meskes@postgresql.or 77 [ - + ]: 3845 : if (sqlca == NULL)
78 : : {
3736 meskes@postgresql.or 79 :UIC 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY,
80 : : NULL);
2942 peter_e@gmx.net 81 : 0 : return false;
82 : : }
83 : :
6548 meskes@postgresql.or 84 :GIC 3845 : ecpg_init_sqlca(sqlca);
8210 85 [ + + ]: 3845 : if (con == NULL)
86 : : {
6548 87 [ + + ]: 20 : ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
6078 peter_e@gmx.net 88 : 6 : connection_name ? connection_name : ecpg_gettext("NULL"));
2942 89 : 14 : return false;
90 : : }
91 : :
92 : 3831 : return true;
93 : : }
94 : :
95 : : static void
7678 bruce@momjian.us 96 : 68 : ecpg_sqlca_key_destructor(void *arg)
97 : : {
6505 98 : 68 : free(arg); /* sqlca structure allocated in ECPGget_sqlca */
7846 meskes@postgresql.or 99 : 68 : }
100 : :
101 : : static void
7678 bruce@momjian.us 102 : 63 : ecpg_sqlca_key_init(void)
103 : : {
104 : 63 : pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor);
8119 105 : 63 : }
106 : :
107 : : struct sqlca_t *
108 : 3218067 : ECPGget_sqlca(void)
109 : : {
110 : : struct sqlca_t *sqlca;
111 : :
8069 112 : 3218067 : pthread_once(&sqlca_key_once, ecpg_sqlca_key_init);
113 : :
114 : 3218067 : sqlca = pthread_getspecific(sqlca_key);
115 [ + + ]: 3218067 : if (sqlca == NULL)
116 : : {
117 : 129 : sqlca = malloc(sizeof(struct sqlca_t));
3736 meskes@postgresql.or 118 [ - + ]: 129 : if (sqlca == NULL)
3736 meskes@postgresql.or 119 :UIC 0 : return NULL;
6548 meskes@postgresql.or 120 :GIC 129 : ecpg_init_sqlca(sqlca);
8069 bruce@momjian.us 121 : 129 : pthread_setspecific(sqlca_key, sqlca);
122 : : }
2942 peter_e@gmx.net 123 : 3218067 : return sqlca;
124 : : }
125 : :
126 : : bool
8210 meskes@postgresql.or 127 :UIC 0 : ECPGstatus(int lineno, const char *connection_name)
128 : : {
6548 129 : 0 : struct connection *con = ecpg_get_connection(connection_name);
130 : :
131 [ # # ]: 0 : if (!ecpg_init(con, connection_name, lineno))
2942 peter_e@gmx.net 132 : 0 : return false;
133 : :
134 : : /* are we connected? */
8210 meskes@postgresql.or 135 [ # # ]: 0 : if (con->connection == NULL)
136 : : {
6548 137 : 0 : ecpg_raise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, con->name);
8210 138 : 0 : return false;
139 : : }
140 : :
2942 peter_e@gmx.net 141 : 0 : return true;
142 : : }
143 : :
144 : : PGTransactionStatusType
5832 meskes@postgresql.or 145 : 0 : ECPGtransactionStatus(const char *connection_name)
146 : : {
147 : : const struct connection *con;
148 : :
149 : 0 : con = ecpg_get_connection(connection_name);
5671 bruce@momjian.us 150 [ # # ]: 0 : if (con == NULL)
151 : : {
152 : : /* transaction status is unknown */
5832 meskes@postgresql.or 153 : 0 : return PQTRANS_UNKNOWN;
154 : : }
155 : :
156 : 0 : return PQtransactionStatus(con->connection);
157 : : }
158 : :
159 : : bool
8210 meskes@postgresql.or 160 :GIC 123 : ECPGtrans(int lineno, const char *connection_name, const char *transaction)
161 : : {
162 : : PGresult *res;
6548 163 : 123 : struct connection *con = ecpg_get_connection(connection_name);
164 : :
165 [ - + ]: 123 : if (!ecpg_init(con, connection_name, lineno))
2942 peter_e@gmx.net 166 :UIC 0 : return false;
167 : :
6078 peter_e@gmx.net 168 [ + - ]:GIC 123 : 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 */
8210 meskes@postgresql.or 171 [ + - + - ]: 123 : 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 : : */
3099 180 [ + + ]: 123 : if (PQtransactionStatus(con->connection) == PQTRANS_IDLE &&
181 [ + + ]: 27 : !con->autocommit &&
182 [ + + ]: 24 : strncmp(transaction, "begin", 5) != 0 &&
183 [ + - ]: 1 : strncmp(transaction, "start", 5) != 0 &&
184 [ - + ]: 1 : strncmp(transaction, "commit prepared", 15) != 0 &&
3099 meskes@postgresql.or 185 [ # # ]:UIC 0 : strncmp(transaction, "rollback prepared", 17) != 0)
186 : : {
7299 187 : 0 : res = PQexec(con->connection, "begin transaction");
6548 188 [ # # ]: 0 : if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
2943 peter_e@gmx.net 189 : 0 : return false;
8210 meskes@postgresql.or 190 : 0 : PQclear(res);
191 : : }
192 : :
7299 meskes@postgresql.or 193 :GIC 123 : res = PQexec(con->connection, transaction);
6548 194 [ - + ]: 123 : if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
2943 peter_e@gmx.net 195 :UIC 0 : return false;
7299 meskes@postgresql.or 196 :GIC 123 : PQclear(res);
197 : : }
198 : :
8210 199 : 123 : return true;
200 : : }
201 : :
202 : :
203 : : void
204 : 58 : ECPGdebug(int n, FILE *dbgs)
205 : : {
206 : : /* Interlock against concurrent executions of ECPGdebug() */
8103 207 : 58 : pthread_mutex_lock(&debug_init_mutex);
208 : :
209 : : /* Prevent ecpg_log() from printing while we change settings */
471 tgl@sss.pgh.pa.us 210 : 58 : pthread_mutex_lock(&debug_mutex);
211 : :
6505 bruce@momjian.us 212 [ + - ]: 58 : if (n > 100)
213 : : {
6812 meskes@postgresql.or 214 : 58 : ecpg_internal_regression_mode = true;
6505 bruce@momjian.us 215 : 58 : simple_debug = n - 100;
216 : : }
217 : : else
6812 meskes@postgresql.or 218 :UIC 0 : simple_debug = n;
219 : :
8210 meskes@postgresql.or 220 :GIC 58 : debugstream = dbgs;
221 : :
222 : : /* We must release debug_mutex before invoking ecpg_log() ... */
471 tgl@sss.pgh.pa.us 223 : 58 : pthread_mutex_unlock(&debug_mutex);
224 : :
225 : : /* ... but keep holding debug_init_mutex to avoid racy printout */
6548 meskes@postgresql.or 226 : 58 : ecpg_log("ECPGdebug: set to %d\n", simple_debug);
227 : :
8103 228 : 58 : pthread_mutex_unlock(&debug_init_mutex);
8210 229 : 58 : }
230 : :
231 : : void
6548 232 : 14625 : ecpg_log(const char *format,...)
233 : : {
234 : : va_list ap;
235 : : const char *intl_format;
236 : : int bufsize;
237 : : char *fmt;
238 : : struct sqlca_t *sqlca;
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 : : */
6109 tgl@sss.pgh.pa.us 245 [ + + ]: 14625 : if (!simple_debug)
meskes@postgresql.or 246 : 11271 : return;
247 : :
248 : : /* localize the error message string */
249 : 3354 : 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 : : */
tgl@sss.pgh.pa.us 255 : 3354 : bufsize = strlen(intl_format) + 100;
256 : 3354 : fmt = (char *) malloc(bufsize);
257 [ - + ]: 3354 : if (fmt == NULL)
6109 tgl@sss.pgh.pa.us 258 :UIC 0 : return;
259 : :
6109 meskes@postgresql.or 260 [ + - ]:GIC 3354 : if (ecpg_internal_regression_mode)
tgl@sss.pgh.pa.us 261 : 3354 : snprintf(fmt, bufsize, "[NO_PID]: %s", intl_format);
262 : : else
6109 tgl@sss.pgh.pa.us 263 :UIC 0 : snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format);
264 : :
319 fujii@postgresql.org 265 :GIC 3354 : sqlca = ECPGget_sqlca();
266 : :
6109 meskes@postgresql.or 267 : 3354 : pthread_mutex_lock(&debug_mutex);
268 : :
269 : : /* Now that we hold the mutex, recheck simple_debug */
471 tgl@sss.pgh.pa.us 270 [ + - ]: 3354 : if (simple_debug)
271 : : {
272 : 3354 : va_start(ap, format);
273 : 3354 : vfprintf(debugstream, fmt, ap);
274 : 3354 : va_end(ap);
275 : :
276 : : /* dump out internal sqlca variables */
277 [ + - + - ]: 3354 : if (ecpg_internal_regression_mode && sqlca != NULL)
278 : : {
279 : 3354 : fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n",
280 : 3354 : sqlca->sqlcode, sqlca->sqlstate);
281 : : }
282 : :
283 : 3354 : fflush(debugstream);
284 : : }
285 : :
6109 meskes@postgresql.or 286 : 3354 : pthread_mutex_unlock(&debug_mutex);
287 : :
tgl@sss.pgh.pa.us 288 : 3354 : free(fmt);
289 : : }
290 : :
291 : : void
7741 meskes@postgresql.or 292 : 2685 : ECPGset_noind_null(enum ECPGttype type, void *ptr)
293 : : {
8109 294 [ + + + + : 2685 : switch (type)
- + + - -
+ + - +
+ ]
295 : : {
8069 bruce@momjian.us 296 : 945 : case ECPGt_char:
297 : : case ECPGt_unsigned_char:
298 : : case ECPGt_string:
8065 peter_e@gmx.net 299 : 945 : *((char *) ptr) = '\0';
8109 meskes@postgresql.or 300 : 945 : break;
301 : 2 : case ECPGt_short:
302 : : case ECPGt_unsigned_short:
303 : 2 : *((short int *) ptr) = SHRT_MIN;
304 : 2 : break;
305 : 2 : case ECPGt_int:
306 : : case ECPGt_unsigned_int:
307 : 2 : *((int *) ptr) = INT_MIN;
308 : 2 : break;
309 : 5 : case ECPGt_long:
310 : : case ECPGt_unsigned_long:
311 : : case ECPGt_date:
312 : 5 : *((long *) ptr) = LONG_MIN;
313 : 5 : break;
8109 meskes@postgresql.or 314 :UIC 0 : case ECPGt_long_long:
315 : : case ECPGt_unsigned_long_long:
316 : 0 : *((long long *) ptr) = LONG_LONG_MIN;
317 : 0 : break;
8109 meskes@postgresql.or 318 :GIC 2 : case ECPGt_float:
206 peter@eisentraut.org 319 : 2 : memset(ptr, 0xff, sizeof(float));
8109 meskes@postgresql.or 320 : 2 : break;
321 : 4 : case ECPGt_double:
206 peter@eisentraut.org 322 : 4 : memset(ptr, 0xff, sizeof(double));
8109 meskes@postgresql.or 323 : 4 : break;
8109 meskes@postgresql.or 324 :UIC 0 : case ECPGt_varchar:
325 : 0 : *(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
7741 326 : 0 : ((struct ECPGgeneric_varchar *) ptr)->len = 0;
8109 327 : 0 : break;
2392 328 : 0 : case ECPGt_bytea:
329 : 0 : ((struct ECPGgeneric_bytea *) ptr)->len = 0;
330 : 0 : break;
8103 meskes@postgresql.or 331 :GIC 1719 : case ECPGt_decimal:
206 peter@eisentraut.org 332 : 1719 : memset(ptr, 0, sizeof(decimal));
5695 meskes@postgresql.or 333 : 1719 : ((decimal *) ptr)->sign = NUMERIC_NULL;
8103 334 : 1719 : break;
8109 335 : 2 : case ECPGt_numeric:
206 peter@eisentraut.org 336 : 2 : memset(ptr, 0, sizeof(numeric));
5695 meskes@postgresql.or 337 : 2 : ((numeric *) ptr)->sign = NUMERIC_NULL;
8109 338 : 2 : break;
8109 meskes@postgresql.or 339 :UIC 0 : case ECPGt_interval:
206 peter@eisentraut.org 340 : 0 : memset(ptr, 0xff, sizeof(interval));
8109 meskes@postgresql.or 341 : 0 : break;
8109 meskes@postgresql.or 342 :GIC 3 : case ECPGt_timestamp:
206 peter@eisentraut.org 343 : 3 : memset(ptr, 0xff, sizeof(timestamp));
8109 meskes@postgresql.or 344 : 3 : break;
345 : 1 : default:
346 : 1 : break;
347 : : }
348 : 2685 : }
349 : :
350 : : static bool
2867 peter_e@gmx.net 351 : 11 : _check(const unsigned char *ptr, int length)
352 : : {
5765 meskes@postgresql.or 353 [ + + ]: 59 : for (length--; length >= 0; length--)
354 [ + + ]: 52 : if (ptr[length] != 0xff)
355 : 4 : return false;
356 : :
357 : 7 : return true;
358 : : }
359 : :
360 : : bool
2867 peter_e@gmx.net 361 : 3663 : ECPGis_noind_null(enum ECPGttype type, const void *ptr)
362 : : {
8109 meskes@postgresql.or 363 [ + + + + : 3663 : switch (type)
- + + - -
+ - - +
+ ]
364 : : {
8069 bruce@momjian.us 365 : 20 : case ECPGt_char:
366 : : case ECPGt_unsigned_char:
367 : : case ECPGt_string:
2867 peter_e@gmx.net 368 [ + + ]: 20 : if (*((const char *) ptr) == '\0')
8069 bruce@momjian.us 369 : 2 : return true;
8109 meskes@postgresql.or 370 : 18 : break;
371 : 4 : case ECPGt_short:
372 : : case ECPGt_unsigned_short:
2867 peter_e@gmx.net 373 [ + + ]: 4 : if (*((const short int *) ptr) == SHRT_MIN)
8069 bruce@momjian.us 374 : 2 : return true;
8109 meskes@postgresql.or 375 : 2 : break;
376 : 918 : case ECPGt_int:
377 : : case ECPGt_unsigned_int:
2867 peter_e@gmx.net 378 [ + + ]: 918 : if (*((const int *) ptr) == INT_MIN)
8069 bruce@momjian.us 379 : 2 : return true;
8109 meskes@postgresql.or 380 : 916 : break;
381 : 18 : case ECPGt_long:
382 : : case ECPGt_unsigned_long:
383 : : case ECPGt_date:
2867 peter_e@gmx.net 384 [ + + ]: 18 : if (*((const long *) ptr) == LONG_MIN)
8069 bruce@momjian.us 385 : 5 : return true;
8109 meskes@postgresql.or 386 : 13 : break;
8109 meskes@postgresql.or 387 :UIC 0 : case ECPGt_long_long:
388 : : case ECPGt_unsigned_long_long:
2867 peter_e@gmx.net 389 [ # # ]: 0 : if (*((const long long *) ptr) == LONG_LONG_MIN)
8069 bruce@momjian.us 390 : 0 : return true;
8109 meskes@postgresql.or 391 : 0 : break;
8109 meskes@postgresql.or 392 :GIC 4 : case ECPGt_float:
2942 peter_e@gmx.net 393 : 4 : return _check(ptr, sizeof(float));
394 : : break;
8109 meskes@postgresql.or 395 : 4 : case ECPGt_double:
2942 peter_e@gmx.net 396 : 4 : return _check(ptr, sizeof(double));
397 : : break;
8109 meskes@postgresql.or 398 :UIC 0 : case ECPGt_varchar:
2867 peter_e@gmx.net 399 [ # # ]: 0 : if (*(((const struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
8069 bruce@momjian.us 400 : 0 : return true;
8109 meskes@postgresql.or 401 : 0 : break;
2392 402 : 0 : case ECPGt_bytea:
2388 peter@eisentraut.org 403 [ # # ]: 0 : if (((const struct ECPGgeneric_bytea *) ptr)->len == 0)
2392 meskes@postgresql.or 404 : 0 : return true;
405 : 0 : break;
8103 meskes@postgresql.or 406 :GIC 2688 : case ECPGt_decimal:
2867 peter_e@gmx.net 407 [ + + ]: 2688 : if (((const decimal *) ptr)->sign == NUMERIC_NULL)
8069 bruce@momjian.us 408 : 219 : return true;
8103 meskes@postgresql.or 409 : 2469 : break;
8109 meskes@postgresql.or 410 :UIC 0 : case ECPGt_numeric:
2867 peter_e@gmx.net 411 [ # # ]: 0 : if (((const numeric *) ptr)->sign == NUMERIC_NULL)
8069 bruce@momjian.us 412 : 0 : return true;
8109 meskes@postgresql.or 413 : 0 : break;
414 : 0 : case ECPGt_interval:
2942 peter_e@gmx.net 415 : 0 : return _check(ptr, sizeof(interval));
416 : : break;
8109 meskes@postgresql.or 417 :GIC 3 : case ECPGt_timestamp:
2942 peter_e@gmx.net 418 : 3 : return _check(ptr, sizeof(timestamp));
419 : : break;
8109 meskes@postgresql.or 420 : 4 : default:
421 : 4 : break;
422 : : }
423 : :
424 : 3422 : return false;
425 : : }
426 : :
427 : : #ifdef WIN32
428 : :
429 : : int
430 : : pthread_mutex_init(pthread_mutex_t *mp, void *attr)
431 : : {
432 : : mp->initstate = 0;
433 : : return 0;
434 : : }
435 : :
436 : : int
437 : : pthread_mutex_lock(pthread_mutex_t *mp)
438 : : {
439 : : /* Initialize the csection if not already done */
440 : : if (mp->initstate != 1)
441 : : {
442 : : LONG istate;
443 : :
444 : : while ((istate = InterlockedExchange(&mp->initstate, 2)) == 2)
445 : : Sleep(0); /* wait, another thread is doing this */
446 : : if (istate != 1)
447 : : InitializeCriticalSection(&mp->csection);
448 : : InterlockedExchange(&mp->initstate, 1);
449 : : }
450 : : EnterCriticalSection(&mp->csection);
451 : : return 0;
452 : : }
453 : :
454 : : int
455 : : pthread_mutex_unlock(pthread_mutex_t *mp)
456 : : {
457 : : if (mp->initstate != 1)
458 : : return EINVAL;
459 : : LeaveCriticalSection(&mp->csection);
460 : : return 0;
461 : : }
462 : :
463 : : static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;
464 : :
465 : : void
466 : : win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void))
467 : : {
468 : : if (!*once)
469 : : {
470 : : pthread_mutex_lock(&win32_pthread_once_lock);
471 : : if (!*once)
472 : : {
473 : : fn();
474 : : *once = true;
475 : : }
476 : : pthread_mutex_unlock(&win32_pthread_once_lock);
477 : : }
478 : : }
479 : : #endif /* WIN32 */
480 : :
481 : : #ifdef ENABLE_NLS
482 : :
483 : : char *
6322 peter_e@gmx.net 484 : 3422 : ecpg_gettext(const char *msgid)
485 : : {
486 : : /*
487 : : * At least on Windows, there are gettext implementations that fail if
488 : : * multiple threads call bindtextdomain() concurrently. Use a mutex and
489 : : * flag variable to ensure that we call it just once per process. It is
490 : : * not known that similar bugs exist on non-Windows platforms, but we
491 : : * might as well do it the same way everywhere.
492 : : */
493 : : static volatile bool already_bound = false;
494 : : static pthread_mutex_t binddomain_mutex = PTHREAD_MUTEX_INITIALIZER;
495 : :
496 [ + + ]: 3422 : if (!already_bound)
497 : : {
498 : : /* dgettext() preserves errno, but bindtextdomain() doesn't */
499 : : #ifdef WIN32
500 : : int save_errno = GetLastError();
501 : : #else
502 : 57 : int save_errno = errno;
503 : : #endif
504 : :
575 tgl@sss.pgh.pa.us 505 : 57 : (void) pthread_mutex_lock(&binddomain_mutex);
506 : :
507 [ + - ]: 57 : if (!already_bound)
508 : : {
509 : : const char *ldir;
510 : :
511 : : /*
512 : : * No relocatable lookup here because the calling executable could
513 : : * be anywhere
514 : : */
515 : 57 : ldir = getenv("PGLOCALEDIR");
516 [ - + ]: 57 : if (!ldir)
575 tgl@sss.pgh.pa.us 517 :UIC 0 : ldir = LOCALEDIR;
575 tgl@sss.pgh.pa.us 518 :GIC 57 : bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir);
519 : 57 : already_bound = true;
520 : : }
521 : :
522 : 57 : (void) pthread_mutex_unlock(&binddomain_mutex);
523 : :
524 : : #ifdef WIN32
525 : : SetLastError(save_errno);
526 : : #else
6322 peter_e@gmx.net 527 : 57 : errno = save_errno;
528 : : #endif
529 : : }
530 : :
4605 meskes@postgresql.or 531 : 3422 : return dgettext(PG_TEXTDOMAIN("ecpglib"), msgid);
532 : : }
533 : : #endif /* ENABLE_NLS */
534 : :
535 : : struct var_list *ivlist = NULL;
536 : :
537 : : void
5702 538 : 14 : ECPGset_var(int number, void *pointer, int lineno)
539 : : {
540 : : struct var_list *ptr;
541 : :
2411 542 : 14 : struct sqlca_t *sqlca = ECPGget_sqlca();
543 : :
544 [ - + ]: 14 : if (sqlca == NULL)
545 : : {
2381 peter@eisentraut.org 546 :UIC 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
547 : : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
548 : 0 : return;
549 : : }
550 : :
2381 peter@eisentraut.org 551 :GIC 14 : ecpg_init_sqlca(sqlca);
552 : :
5702 meskes@postgresql.or 553 [ + + ]: 39 : for (ptr = ivlist; ptr != NULL; ptr = ptr->next)
554 : : {
555 [ - + ]: 25 : if (ptr->number == number)
556 : : {
557 : : /* already known => just change pointer value */
5702 meskes@postgresql.or 558 :UIC 0 : ptr->pointer = pointer;
559 : 0 : return;
560 : : }
561 : : }
562 : :
563 : : /* a new one has to be added */
5702 meskes@postgresql.or 564 :GIC 14 : ptr = (struct var_list *) calloc(1L, sizeof(struct var_list));
565 [ - + ]: 14 : if (!ptr)
566 : : {
1067 drowley@postgresql.o 567 :UIC 0 : sqlca = ECPGget_sqlca();
568 : :
3736 meskes@postgresql.or 569 [ # # ]: 0 : if (sqlca == NULL)
570 : : {
571 : 0 : ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
572 : : ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
573 : 0 : return;
574 : : }
575 : :
5702 576 : 0 : sqlca->sqlcode = ECPG_OUT_OF_MEMORY;
4930 peter_e@gmx.net 577 : 0 : strncpy(sqlca->sqlstate, "YE001", sizeof(sqlca->sqlstate));
5702 meskes@postgresql.or 578 : 0 : snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), "out of memory on line %d", lineno);
579 : 0 : sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
580 : : /* free all memory we have allocated for the user */
581 : 0 : ECPGfree_auto_mem();
582 : : }
583 : : else
584 : : {
5702 meskes@postgresql.or 585 :GIC 14 : ptr->number = number;
586 : 14 : ptr->pointer = pointer;
587 : 14 : ptr->next = ivlist;
588 : 14 : ivlist = ptr;
589 : : }
590 : : }
591 : :
592 : : void *
593 : 51 : ECPGget_var(int number)
594 : : {
595 : : struct var_list *ptr;
596 : :
597 [ + - + + ]: 76 : for (ptr = ivlist; ptr != NULL && ptr->number != number; ptr = ptr->next);
5671 bruce@momjian.us 598 [ + - ]: 51 : return (ptr) ? ptr->pointer : NULL;
599 : : }
|