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
99 ecpg_init_sqlca(struct sqlca_t *sqlca)
100 {
101 	memcpy((char *) sqlca, (char *) &sqlca_init, sizeof(struct sqlca_t));
102 }
103 
104 bool
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
129 ecpg_sqlca_key_destructor(void *arg)
130 {
131 	free(arg);					/* sqlca structure allocated in ECPGget_sqlca */
132 }
133 
134 static 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 *
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
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
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
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
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
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
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
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:
399 		case ECPGt_unsigned_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 #ifdef HAVE_LONG_LONG_INT
415 		case ECPGt_long_long:
416 		case ECPGt_unsigned_long_long:
417 			if (*((const 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 (*(((const struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
429 				return true;
430 			break;
431 		case ECPGt_decimal:
432 			if (((const decimal *) ptr)->sign == NUMERIC_NULL)
433 				return true;
434 			break;
435 		case ECPGt_numeric:
436 			if (((const 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
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
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 *
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
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 *
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