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 "ecpglib_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_bytea:
359 			((struct ECPGgeneric_bytea *) ptr)->len = 0;
360 			break;
361 		case ECPGt_decimal:
362 			memset((char *) ptr, 0, sizeof(decimal));
363 			((decimal *) ptr)->sign = NUMERIC_NULL;
364 			break;
365 		case ECPGt_numeric:
366 			memset((char *) ptr, 0, sizeof(numeric));
367 			((numeric *) ptr)->sign = NUMERIC_NULL;
368 			break;
369 		case ECPGt_interval:
370 			memset((char *) ptr, 0xff, sizeof(interval));
371 			break;
372 		case ECPGt_timestamp:
373 			memset((char *) ptr, 0xff, sizeof(timestamp));
374 			break;
375 		default:
376 			break;
377 	}
378 }
379 
380 static bool
_check(const unsigned char * ptr,int length)381 _check(const unsigned char *ptr, int length)
382 {
383 	for (length--; length >= 0; length--)
384 		if (ptr[length] != 0xff)
385 			return false;
386 
387 	return true;
388 }
389 
390 bool
ECPGis_noind_null(enum ECPGttype type,const void * ptr)391 ECPGis_noind_null(enum ECPGttype type, const void *ptr)
392 {
393 	switch (type)
394 	{
395 		case ECPGt_char:
396 		case ECPGt_unsigned_char:
397 		case ECPGt_string:
398 			if (*((const char *) ptr) == '\0')
399 				return true;
400 			break;
401 		case ECPGt_short:
402 		case ECPGt_unsigned_short:
403 			if (*((const short int *) ptr) == SHRT_MIN)
404 				return true;
405 			break;
406 		case ECPGt_int:
407 		case ECPGt_unsigned_int:
408 			if (*((const int *) ptr) == INT_MIN)
409 				return true;
410 			break;
411 		case ECPGt_long:
412 		case ECPGt_unsigned_long:
413 		case ECPGt_date:
414 			if (*((const long *) ptr) == LONG_MIN)
415 				return true;
416 			break;
417 #ifdef HAVE_LONG_LONG_INT
418 		case ECPGt_long_long:
419 		case ECPGt_unsigned_long_long:
420 			if (*((const long long *) ptr) == LONG_LONG_MIN)
421 				return true;
422 			break;
423 #endif							/* HAVE_LONG_LONG_INT */
424 		case ECPGt_float:
425 			return _check(ptr, sizeof(float));
426 			break;
427 		case ECPGt_double:
428 			return _check(ptr, sizeof(double));
429 			break;
430 		case ECPGt_varchar:
431 			if (*(((const struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
432 				return true;
433 			break;
434 		case ECPGt_bytea:
435 			if (((const struct ECPGgeneric_bytea *) ptr)->len == 0)
436 				return true;
437 			break;
438 		case ECPGt_decimal:
439 			if (((const decimal *) ptr)->sign == NUMERIC_NULL)
440 				return true;
441 			break;
442 		case ECPGt_numeric:
443 			if (((const numeric *) ptr)->sign == NUMERIC_NULL)
444 				return true;
445 			break;
446 		case ECPGt_interval:
447 			return _check(ptr, sizeof(interval));
448 			break;
449 		case ECPGt_timestamp:
450 			return _check(ptr, sizeof(timestamp));
451 			break;
452 		default:
453 			break;
454 	}
455 
456 	return false;
457 }
458 
459 #ifdef WIN32
460 #ifdef ENABLE_THREAD_SAFETY
461 
462 void
win32_pthread_mutex(volatile pthread_mutex_t * mutex)463 win32_pthread_mutex(volatile pthread_mutex_t *mutex)
464 {
465 	if (mutex->handle == NULL)
466 	{
467 		while (InterlockedExchange((LONG *) &mutex->initlock, 1) == 1)
468 			Sleep(0);
469 		if (mutex->handle == NULL)
470 			mutex->handle = CreateMutex(NULL, FALSE, NULL);
471 		InterlockedExchange((LONG *) &mutex->initlock, 0);
472 	}
473 }
474 
475 static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;
476 
477 void
win32_pthread_once(volatile pthread_once_t * once,void (* fn)(void))478 win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void))
479 {
480 	if (!*once)
481 	{
482 		pthread_mutex_lock(&win32_pthread_once_lock);
483 		if (!*once)
484 		{
485 			fn();
486 			*once = true;
487 		}
488 		pthread_mutex_unlock(&win32_pthread_once_lock);
489 	}
490 }
491 #endif							/* ENABLE_THREAD_SAFETY */
492 #endif							/* WIN32 */
493 
494 #ifdef ENABLE_NLS
495 
496 char *
ecpg_gettext(const char * msgid)497 ecpg_gettext(const char *msgid)
498 {
499 	static bool already_bound = false;
500 
501 	if (!already_bound)
502 	{
503 		/* dgettext() preserves errno, but bindtextdomain() doesn't */
504 #ifdef WIN32
505 		int			save_errno = GetLastError();
506 #else
507 		int			save_errno = errno;
508 #endif
509 		const char *ldir;
510 
511 		already_bound = true;
512 		/* No relocatable lookup here because the binary could be anywhere */
513 		ldir = getenv("PGLOCALEDIR");
514 		if (!ldir)
515 			ldir = LOCALEDIR;
516 		bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir);
517 #ifdef WIN32
518 		SetLastError(save_errno);
519 #else
520 		errno = save_errno;
521 #endif
522 	}
523 
524 	return dgettext(PG_TEXTDOMAIN("ecpglib"), msgid);
525 }
526 #endif							/* ENABLE_NLS */
527 
528 struct var_list *ivlist = NULL;
529 
530 void
ECPGset_var(int number,void * pointer,int lineno)531 ECPGset_var(int number, void *pointer, int lineno)
532 {
533 	struct var_list *ptr;
534 
535 	struct sqlca_t *sqlca = ECPGget_sqlca();
536 
537 	if (sqlca == NULL)
538 	{
539 		ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
540 				   ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
541 		return;
542 	}
543 
544 	ecpg_init_sqlca(sqlca);
545 
546 	for (ptr = ivlist; ptr != NULL; ptr = ptr->next)
547 	{
548 		if (ptr->number == number)
549 		{
550 			/* already known => just change pointer value */
551 			ptr->pointer = pointer;
552 			return;
553 		}
554 	}
555 
556 	/* a new one has to be added */
557 	ptr = (struct var_list *) calloc(1L, sizeof(struct var_list));
558 	if (!ptr)
559 	{
560 		struct sqlca_t *sqlca = ECPGget_sqlca();
561 
562 		if (sqlca == NULL)
563 		{
564 			ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
565 					   ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
566 			return;
567 		}
568 
569 		sqlca->sqlcode = ECPG_OUT_OF_MEMORY;
570 		strncpy(sqlca->sqlstate, "YE001", sizeof(sqlca->sqlstate));
571 		snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), "out of memory on line %d", lineno);
572 		sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
573 		/* free all memory we have allocated for the user */
574 		ECPGfree_auto_mem();
575 	}
576 	else
577 	{
578 		ptr->number = number;
579 		ptr->pointer = pointer;
580 		ptr->next = ivlist;
581 		ivlist = ptr;
582 	}
583 }
584 
585 void *
ECPGget_var(int number)586 ECPGget_var(int number)
587 {
588 	struct var_list *ptr;
589 
590 	for (ptr = ivlist; ptr != NULL && ptr->number != number; ptr = ptr->next);
591 	return (ptr) ? ptr->pointer : NULL;
592 }
593