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