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