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 #include "ecpg-pthread-win32.h"
9 #include "ecpgtype.h"
10 #include "ecpglib.h"
11 #include "ecpgerrno.h"
12 #include "extern.h"
13 #include "sqlca.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"
19
20 #ifdef HAVE_LONG_LONG_INT
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 #endif /* HAVE_LONG_LONG_INT */
29
30 bool ecpg_internal_regression_mode = false;
31
32 static struct sqlca_t sqlca_init =
33 {
34 {
35 'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
36 },
37 sizeof(struct sqlca_t),
38 0,
39 {
40 0,
41 {
42 0
43 }
44 },
45 {
46 'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '
47 },
48 {
49 0, 0, 0, 0, 0, 0
50 },
51 {
52 0, 0, 0, 0, 0, 0, 0, 0
53 },
54 {
55 '0', '0', '0', '0', '0'
56 }
57 };
58
59 #ifdef ENABLE_THREAD_SAFETY
60 static pthread_key_t sqlca_key;
61 static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT;
62 #else
63 static struct sqlca_t sqlca =
64 {
65 {
66 'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
67 },
68 sizeof(struct sqlca_t),
69 0,
70 {
71 0,
72 {
73 0
74 }
75 },
76 {
77 'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '
78 },
79 {
80 0, 0, 0, 0, 0, 0
81 },
82 {
83 0, 0, 0, 0, 0, 0, 0, 0
84 },
85 {
86 '0', '0', '0', '0', '0'
87 }
88 };
89 #endif
90
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;
94 #endif
95 static int simple_debug = 0;
96 static FILE *debugstream = NULL;
97
98 void
ecpg_init_sqlca(struct sqlca_t * sqlca)99 ecpg_init_sqlca(struct sqlca_t *sqlca)
100 {
101 memcpy((char *) sqlca, (char *) &sqlca_init, sizeof(struct sqlca_t));
102 }
103
104 bool
ecpg_init(const struct connection * con,const char * connection_name,const int lineno)105 ecpg_init(const struct connection *con, const char *connection_name, const int lineno)
106 {
107 struct sqlca_t *sqlca = ECPGget_sqlca();
108
109 if (sqlca == NULL)
110 {
111 ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY,
112 NULL);
113 return (false);
114 }
115
116 ecpg_init_sqlca(sqlca);
117 if (con == NULL)
118 {
119 ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
120 connection_name ? connection_name : ecpg_gettext("NULL"));
121 return (false);
122 }
123
124 return (true);
125 }
126
127 #ifdef ENABLE_THREAD_SAFETY
128 static void
ecpg_sqlca_key_destructor(void * arg)129 ecpg_sqlca_key_destructor(void *arg)
130 {
131 free(arg); /* sqlca structure allocated in ECPGget_sqlca */
132 }
133
134 static void
ecpg_sqlca_key_init(void)135 ecpg_sqlca_key_init(void)
136 {
137 pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor);
138 }
139 #endif
140
141 struct sqlca_t *
ECPGget_sqlca(void)142 ECPGget_sqlca(void)
143 {
144 #ifdef ENABLE_THREAD_SAFETY
145 struct sqlca_t *sqlca;
146
147 pthread_once(&sqlca_key_once, ecpg_sqlca_key_init);
148
149 sqlca = pthread_getspecific(sqlca_key);
150 if (sqlca == NULL)
151 {
152 sqlca = malloc(sizeof(struct sqlca_t));
153 if (sqlca == NULL)
154 return NULL;
155 ecpg_init_sqlca(sqlca);
156 pthread_setspecific(sqlca_key, sqlca);
157 }
158 return (sqlca);
159 #else
160 return (&sqlca);
161 #endif
162 }
163
164 bool
ECPGstatus(int lineno,const char * connection_name)165 ECPGstatus(int lineno, const char *connection_name)
166 {
167 struct connection *con = ecpg_get_connection(connection_name);
168
169 if (!ecpg_init(con, connection_name, lineno))
170 return (false);
171
172 /* are we connected? */
173 if (con->connection == NULL)
174 {
175 ecpg_raise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, con->name);
176 return false;
177 }
178
179 return (true);
180 }
181
182 PGTransactionStatusType
ECPGtransactionStatus(const char * connection_name)183 ECPGtransactionStatus(const char *connection_name)
184 {
185 const struct connection *con;
186
187 con = ecpg_get_connection(connection_name);
188 if (con == NULL)
189 {
190 /* transaction status is unknown */
191 return PQTRANS_UNKNOWN;
192 }
193
194 return PQtransactionStatus(con->connection);
195
196 }
197
198 bool
ECPGtrans(int lineno,const char * connection_name,const char * transaction)199 ECPGtrans(int lineno, const char *connection_name, const char *transaction)
200 {
201 PGresult *res;
202 struct connection *con = ecpg_get_connection(connection_name);
203
204 if (!ecpg_init(con, connection_name, lineno))
205 return (false);
206
207 ecpg_log("ECPGtrans on line %d: action \"%s\"; connection \"%s\"\n", lineno, transaction, con ? con->name : "null");
208
209 /* if we have no connection we just simulate the command */
210 if (con && con->connection)
211 {
212 /*
213 * If we got a transaction command but have no open transaction, we
214 * have to start one, unless we are in autocommit, where the
215 * developers have to take care themselves. However, if the command is
216 * a begin statement, we just execute it once. And if the command is
217 * commit or rollback prepared, we don't execute it.
218 */
219 if (PQtransactionStatus(con->connection) == PQTRANS_IDLE &&
220 !con->autocommit &&
221 strncmp(transaction, "begin", 5) != 0 &&
222 strncmp(transaction, "start", 5) != 0 &&
223 strncmp(transaction, "commit prepared", 15) != 0 &&
224 strncmp(transaction, "rollback prepared", 17) != 0)
225 {
226 res = PQexec(con->connection, "begin transaction");
227 if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
228 return FALSE;
229 PQclear(res);
230 }
231
232 res = PQexec(con->connection, transaction);
233 if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
234 return FALSE;
235 PQclear(res);
236 }
237
238 return true;
239 }
240
241
242 void
ECPGdebug(int n,FILE * dbgs)243 ECPGdebug(int n, FILE *dbgs)
244 {
245 #ifdef ENABLE_THREAD_SAFETY
246 pthread_mutex_lock(&debug_init_mutex);
247 #endif
248
249 if (n > 100)
250 {
251 ecpg_internal_regression_mode = true;
252 simple_debug = n - 100;
253 }
254 else
255 simple_debug = n;
256
257 debugstream = dbgs;
258
259 ecpg_log("ECPGdebug: set to %d\n", simple_debug);
260
261 #ifdef ENABLE_THREAD_SAFETY
262 pthread_mutex_unlock(&debug_init_mutex);
263 #endif
264 }
265
266 void
ecpg_log(const char * format,...)267 ecpg_log(const char *format,...)
268 {
269 va_list ap;
270 struct sqlca_t *sqlca = ECPGget_sqlca();
271 const char *intl_format;
272 int bufsize;
273 char *fmt;
274
275 if (!simple_debug)
276 return;
277
278 /* localize the error message string */
279 intl_format = ecpg_gettext(format);
280
281 /*
282 * Insert PID into the format, unless ecpg_internal_regression_mode is set
283 * (regression tests want unchanging output).
284 */
285 bufsize = strlen(intl_format) + 100;
286 fmt = (char *) malloc(bufsize);
287 if (fmt == NULL)
288 return;
289
290 if (ecpg_internal_regression_mode)
291 snprintf(fmt, bufsize, "[NO_PID]: %s", intl_format);
292 else
293 snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format);
294
295 #ifdef ENABLE_THREAD_SAFETY
296 pthread_mutex_lock(&debug_mutex);
297 #endif
298
299 va_start(ap, format);
300 vfprintf(debugstream, fmt, ap);
301 va_end(ap);
302
303 /* dump out internal sqlca variables */
304 if (ecpg_internal_regression_mode && sqlca != NULL)
305 {
306 fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n",
307 sqlca->sqlcode, sqlca->sqlstate);
308 }
309
310 fflush(debugstream);
311
312 #ifdef ENABLE_THREAD_SAFETY
313 pthread_mutex_unlock(&debug_mutex);
314 #endif
315
316 free(fmt);
317 }
318
319 void
ECPGset_noind_null(enum ECPGttype type,void * ptr)320 ECPGset_noind_null(enum ECPGttype type, void *ptr)
321 {
322 switch (type)
323 {
324 case ECPGt_char:
325 case ECPGt_unsigned_char:
326 case ECPGt_string:
327 *((char *) ptr) = '\0';
328 break;
329 case ECPGt_short:
330 case ECPGt_unsigned_short:
331 *((short int *) ptr) = SHRT_MIN;
332 break;
333 case ECPGt_int:
334 case ECPGt_unsigned_int:
335 *((int *) ptr) = INT_MIN;
336 break;
337 case ECPGt_long:
338 case ECPGt_unsigned_long:
339 case ECPGt_date:
340 *((long *) ptr) = LONG_MIN;
341 break;
342 #ifdef HAVE_LONG_LONG_INT
343 case ECPGt_long_long:
344 case ECPGt_unsigned_long_long:
345 *((long long *) ptr) = LONG_LONG_MIN;
346 break;
347 #endif /* HAVE_LONG_LONG_INT */
348 case ECPGt_float:
349 memset((char *) ptr, 0xff, sizeof(float));
350 break;
351 case ECPGt_double:
352 memset((char *) ptr, 0xff, sizeof(double));
353 break;
354 case ECPGt_varchar:
355 *(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
356 ((struct ECPGgeneric_varchar *) 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
_check(unsigned char * ptr,int length)378 _check(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
ECPGis_noind_null(enum ECPGttype type,void * ptr)388 ECPGis_noind_null(enum ECPGttype type, void *ptr)
389 {
390 switch (type)
391 {
392 case ECPGt_char:
393 case ECPGt_unsigned_char:
394 case ECPGt_string:
395 if (*((char *) ptr) == '\0')
396 return true;
397 break;
398 case ECPGt_short:
399 case ECPGt_unsigned_short:
400 if (*((short int *) ptr) == SHRT_MIN)
401 return true;
402 break;
403 case ECPGt_int:
404 case ECPGt_unsigned_int:
405 if (*((int *) ptr) == INT_MIN)
406 return true;
407 break;
408 case ECPGt_long:
409 case ECPGt_unsigned_long:
410 case ECPGt_date:
411 if (*((long *) ptr) == LONG_MIN)
412 return true;
413 break;
414 #ifdef HAVE_LONG_LONG_INT
415 case ECPGt_long_long:
416 case ECPGt_unsigned_long_long:
417 if (*((long long *) ptr) == LONG_LONG_MIN)
418 return true;
419 break;
420 #endif /* HAVE_LONG_LONG_INT */
421 case ECPGt_float:
422 return (_check(ptr, sizeof(float)));
423 break;
424 case ECPGt_double:
425 return (_check(ptr, sizeof(double)));
426 break;
427 case ECPGt_varchar:
428 if (*(((struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
429 return true;
430 break;
431 case ECPGt_decimal:
432 if (((decimal *) ptr)->sign == NUMERIC_NULL)
433 return true;
434 break;
435 case ECPGt_numeric:
436 if (((numeric *) ptr)->sign == NUMERIC_NULL)
437 return true;
438 break;
439 case ECPGt_interval:
440 return (_check(ptr, sizeof(interval)));
441 break;
442 case ECPGt_timestamp:
443 return (_check(ptr, sizeof(timestamp)));
444 break;
445 default:
446 break;
447 }
448
449 return false;
450 }
451
452 #ifdef WIN32
453 #ifdef ENABLE_THREAD_SAFETY
454
455 void
win32_pthread_mutex(volatile pthread_mutex_t * mutex)456 win32_pthread_mutex(volatile pthread_mutex_t *mutex)
457 {
458 if (mutex->handle == NULL)
459 {
460 while (InterlockedExchange((LONG *) &mutex->initlock, 1) == 1)
461 Sleep(0);
462 if (mutex->handle == NULL)
463 mutex->handle = CreateMutex(NULL, FALSE, NULL);
464 InterlockedExchange((LONG *) &mutex->initlock, 0);
465 }
466 }
467
468 static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;
469
470 void
win32_pthread_once(volatile pthread_once_t * once,void (* fn)(void))471 win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void))
472 {
473 if (!*once)
474 {
475 pthread_mutex_lock(&win32_pthread_once_lock);
476 if (!*once)
477 {
478 fn();
479 *once = true;
480 }
481 pthread_mutex_unlock(&win32_pthread_once_lock);
482 }
483 }
484 #endif /* ENABLE_THREAD_SAFETY */
485 #endif /* WIN32 */
486
487 #ifdef ENABLE_NLS
488
489 char *
ecpg_gettext(const char * msgid)490 ecpg_gettext(const char *msgid)
491 {
492 static bool already_bound = false;
493
494 if (!already_bound)
495 {
496 /* dgettext() preserves errno, but bindtextdomain() doesn't */
497 #ifdef WIN32
498 int save_errno = GetLastError();
499 #else
500 int save_errno = errno;
501 #endif
502 const char *ldir;
503
504 already_bound = true;
505 /* No relocatable lookup here because the binary could be anywhere */
506 ldir = getenv("PGLOCALEDIR");
507 if (!ldir)
508 ldir = LOCALEDIR;
509 bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir);
510 #ifdef WIN32
511 SetLastError(save_errno);
512 #else
513 errno = save_errno;
514 #endif
515 }
516
517 return dgettext(PG_TEXTDOMAIN("ecpglib"), msgid);
518 }
519 #endif /* ENABLE_NLS */
520
521 struct var_list *ivlist = NULL;
522
523 void
ECPGset_var(int number,void * pointer,int lineno)524 ECPGset_var(int number, void *pointer, int lineno)
525 {
526 struct var_list *ptr;
527
528 for (ptr = ivlist; ptr != NULL; ptr = ptr->next)
529 {
530 if (ptr->number == number)
531 {
532 /* already known => just change pointer value */
533 ptr->pointer = pointer;
534 return;
535 }
536 }
537
538 /* a new one has to be added */
539 ptr = (struct var_list *) calloc(1L, sizeof(struct var_list));
540 if (!ptr)
541 {
542 struct sqlca_t *sqlca = ECPGget_sqlca();
543
544 if (sqlca == NULL)
545 {
546 ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
547 ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
548 return;
549 }
550
551 sqlca->sqlcode = ECPG_OUT_OF_MEMORY;
552 strncpy(sqlca->sqlstate, "YE001", sizeof(sqlca->sqlstate));
553 snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), "out of memory on line %d", lineno);
554 sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
555 /* free all memory we have allocated for the user */
556 ECPGfree_auto_mem();
557 }
558 else
559 {
560 ptr->number = number;
561 ptr->pointer = pointer;
562 ptr->next = ivlist;
563 ivlist = ptr;
564 }
565 }
566
567 void *
ECPGget_var(int number)568 ECPGget_var(int number)
569 {
570 struct var_list *ptr;
571
572 for (ptr = ivlist; ptr != NULL && ptr->number != number; ptr = ptr->next);
573 return (ptr) ? ptr->pointer : NULL;
574 }
575