00001
00002
00003 #define POSTGRES_ECPG_INTERNAL
00004 #include "postgres_fe.h"
00005
00006 #include <limits.h>
00007 #include <unistd.h>
00008 #include "ecpg-pthread-win32.h"
00009 #include "ecpgtype.h"
00010 #include "ecpglib.h"
00011 #include "ecpgerrno.h"
00012 #include "extern.h"
00013 #include "sqlca.h"
00014 #include "pgtypes_numeric.h"
00015 #include "pgtypes_date.h"
00016 #include "pgtypes_timestamp.h"
00017 #include "pgtypes_interval.h"
00018 #include "pg_config_paths.h"
00019
00020 #ifdef HAVE_LONG_LONG_INT
00021 #ifndef LONG_LONG_MIN
00022 #ifdef LLONG_MIN
00023 #define LONG_LONG_MIN LLONG_MIN
00024 #else
00025 #define LONG_LONG_MIN LONGLONG_MIN
00026 #endif
00027 #endif
00028 #endif
00029
00030 bool ecpg_internal_regression_mode = false;
00031
00032 static struct sqlca_t sqlca_init =
00033 {
00034 {
00035 'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
00036 },
00037 sizeof(struct sqlca_t),
00038 0,
00039 {
00040 0,
00041 {
00042 0
00043 }
00044 },
00045 {
00046 'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '
00047 },
00048 {
00049 0, 0, 0, 0, 0, 0
00050 },
00051 {
00052 0, 0, 0, 0, 0, 0, 0, 0
00053 },
00054 {
00055 '0', '0', '0', '0', '0'
00056 }
00057 };
00058
00059 #ifdef ENABLE_THREAD_SAFETY
00060 static pthread_key_t sqlca_key;
00061 static pthread_once_t sqlca_key_once = PTHREAD_ONCE_INIT;
00062 #else
00063 static struct sqlca_t sqlca =
00064 {
00065 {
00066 'S', 'Q', 'L', 'C', 'A', ' ', ' ', ' '
00067 },
00068 sizeof(struct sqlca_t),
00069 0,
00070 {
00071 0,
00072 {
00073 0
00074 }
00075 },
00076 {
00077 'N', 'O', 'T', ' ', 'S', 'E', 'T', ' '
00078 },
00079 {
00080 0, 0, 0, 0, 0, 0
00081 },
00082 {
00083 0, 0, 0, 0, 0, 0, 0, 0
00084 },
00085 {
00086 '0', '0', '0', '0', '0'
00087 }
00088 };
00089 #endif
00090
00091 #ifdef ENABLE_THREAD_SAFETY
00092 static pthread_mutex_t debug_mutex = PTHREAD_MUTEX_INITIALIZER;
00093 static pthread_mutex_t debug_init_mutex = PTHREAD_MUTEX_INITIALIZER;
00094 #endif
00095 static int simple_debug = 0;
00096 static FILE *debugstream = NULL;
00097
00098 void
00099 ecpg_init_sqlca(struct sqlca_t * sqlca)
00100 {
00101 memcpy((char *) sqlca, (char *) &sqlca_init, sizeof(struct sqlca_t));
00102 }
00103
00104 bool
00105 ecpg_init(const struct connection * con, const char *connection_name, const int lineno)
00106 {
00107 struct sqlca_t *sqlca = ECPGget_sqlca();
00108
00109 ecpg_init_sqlca(sqlca);
00110 if (con == NULL)
00111 {
00112 ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
00113 connection_name ? connection_name : ecpg_gettext("NULL"));
00114 return (false);
00115 }
00116
00117 return (true);
00118 }
00119
00120 #ifdef ENABLE_THREAD_SAFETY
00121 static void
00122 ecpg_sqlca_key_destructor(void *arg)
00123 {
00124 free(arg);
00125 }
00126
00127 static void
00128 ecpg_sqlca_key_init(void)
00129 {
00130 pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor);
00131 }
00132 #endif
00133
00134 struct sqlca_t *
00135 ECPGget_sqlca(void)
00136 {
00137 #ifdef ENABLE_THREAD_SAFETY
00138 struct sqlca_t *sqlca;
00139
00140 pthread_once(&sqlca_key_once, ecpg_sqlca_key_init);
00141
00142 sqlca = pthread_getspecific(sqlca_key);
00143 if (sqlca == NULL)
00144 {
00145 sqlca = malloc(sizeof(struct sqlca_t));
00146 ecpg_init_sqlca(sqlca);
00147 pthread_setspecific(sqlca_key, sqlca);
00148 }
00149 return (sqlca);
00150 #else
00151 return (&sqlca);
00152 #endif
00153 }
00154
00155 bool
00156 ECPGstatus(int lineno, const char *connection_name)
00157 {
00158 struct connection *con = ecpg_get_connection(connection_name);
00159
00160 if (!ecpg_init(con, connection_name, lineno))
00161 return (false);
00162
00163
00164 if (con->connection == NULL)
00165 {
00166 ecpg_raise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, con->name);
00167 return false;
00168 }
00169
00170 return (true);
00171 }
00172
00173 PGTransactionStatusType
00174 ECPGtransactionStatus(const char *connection_name)
00175 {
00176 const struct connection *con;
00177
00178 con = ecpg_get_connection(connection_name);
00179 if (con == NULL)
00180 {
00181
00182 return PQTRANS_UNKNOWN;
00183 }
00184
00185 return PQtransactionStatus(con->connection);
00186
00187 }
00188
00189 bool
00190 ECPGtrans(int lineno, const char *connection_name, const char *transaction)
00191 {
00192 PGresult *res;
00193 struct connection *con = ecpg_get_connection(connection_name);
00194
00195 if (!ecpg_init(con, connection_name, lineno))
00196 return (false);
00197
00198 ecpg_log("ECPGtrans on line %d: action \"%s\"; connection \"%s\"\n", lineno, transaction, con ? con->name : "null");
00199
00200
00201 if (con && con->connection)
00202 {
00203
00204
00205
00206
00207
00208
00209 if (PQtransactionStatus(con->connection) == PQTRANS_IDLE && !con->autocommit && strncmp(transaction, "begin", 5) != 0 && strncmp(transaction, "start", 5) != 0)
00210 {
00211 res = PQexec(con->connection, "begin transaction");
00212 if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
00213 return FALSE;
00214 PQclear(res);
00215 }
00216
00217 res = PQexec(con->connection, transaction);
00218 if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
00219 return FALSE;
00220 PQclear(res);
00221 }
00222
00223 return true;
00224 }
00225
00226
00227 void
00228 ECPGdebug(int n, FILE *dbgs)
00229 {
00230 #ifdef ENABLE_THREAD_SAFETY
00231 pthread_mutex_lock(&debug_init_mutex);
00232 #endif
00233
00234 if (n > 100)
00235 {
00236 ecpg_internal_regression_mode = true;
00237 simple_debug = n - 100;
00238 }
00239 else
00240 simple_debug = n;
00241
00242 debugstream = dbgs;
00243
00244 ecpg_log("ECPGdebug: set to %d\n", simple_debug);
00245
00246 #ifdef ENABLE_THREAD_SAFETY
00247 pthread_mutex_unlock(&debug_init_mutex);
00248 #endif
00249 }
00250
00251 void
00252 ecpg_log(const char *format,...)
00253 {
00254 va_list ap;
00255 struct sqlca_t *sqlca = ECPGget_sqlca();
00256 const char *intl_format;
00257 int bufsize;
00258 char *fmt;
00259
00260 if (!simple_debug)
00261 return;
00262
00263
00264 intl_format = ecpg_gettext(format);
00265
00266
00267
00268
00269
00270 bufsize = strlen(intl_format) + 100;
00271 fmt = (char *) malloc(bufsize);
00272 if (fmt == NULL)
00273 return;
00274
00275 if (ecpg_internal_regression_mode)
00276 snprintf(fmt, bufsize, "[NO_PID]: %s", intl_format);
00277 else
00278 snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format);
00279
00280 #ifdef ENABLE_THREAD_SAFETY
00281 pthread_mutex_lock(&debug_mutex);
00282 #endif
00283
00284 va_start(ap, format);
00285 vfprintf(debugstream, fmt, ap);
00286 va_end(ap);
00287
00288
00289 if (ecpg_internal_regression_mode)
00290 fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n",
00291 sqlca->sqlcode, sqlca->sqlstate);
00292
00293 fflush(debugstream);
00294
00295 #ifdef ENABLE_THREAD_SAFETY
00296 pthread_mutex_unlock(&debug_mutex);
00297 #endif
00298
00299 free(fmt);
00300 }
00301
00302 void
00303 ECPGset_noind_null(enum ECPGttype type, void *ptr)
00304 {
00305 switch (type)
00306 {
00307 case ECPGt_char:
00308 case ECPGt_unsigned_char:
00309 case ECPGt_string:
00310 *((char *) ptr) = '\0';
00311 break;
00312 case ECPGt_short:
00313 case ECPGt_unsigned_short:
00314 *((short int *) ptr) = SHRT_MIN;
00315 break;
00316 case ECPGt_int:
00317 case ECPGt_unsigned_int:
00318 *((int *) ptr) = INT_MIN;
00319 break;
00320 case ECPGt_long:
00321 case ECPGt_unsigned_long:
00322 case ECPGt_date:
00323 *((long *) ptr) = LONG_MIN;
00324 break;
00325 #ifdef HAVE_LONG_LONG_INT
00326 case ECPGt_long_long:
00327 case ECPGt_unsigned_long_long:
00328 *((long long *) ptr) = LONG_LONG_MIN;
00329 break;
00330 #endif
00331 case ECPGt_float:
00332 memset((char *) ptr, 0xff, sizeof(float));
00333 break;
00334 case ECPGt_double:
00335 memset((char *) ptr, 0xff, sizeof(double));
00336 break;
00337 case ECPGt_varchar:
00338 *(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
00339 ((struct ECPGgeneric_varchar *) ptr)->len = 0;
00340 break;
00341 case ECPGt_decimal:
00342 memset((char *) ptr, 0, sizeof(decimal));
00343 ((decimal *) ptr)->sign = NUMERIC_NULL;
00344 break;
00345 case ECPGt_numeric:
00346 memset((char *) ptr, 0, sizeof(numeric));
00347 ((numeric *) ptr)->sign = NUMERIC_NULL;
00348 break;
00349 case ECPGt_interval:
00350 memset((char *) ptr, 0xff, sizeof(interval));
00351 break;
00352 case ECPGt_timestamp:
00353 memset((char *) ptr, 0xff, sizeof(timestamp));
00354 break;
00355 default:
00356 break;
00357 }
00358 }
00359
00360 static bool
00361 _check(unsigned char *ptr, int length)
00362 {
00363 for (length--; length >= 0; length--)
00364 if (ptr[length] != 0xff)
00365 return false;
00366
00367 return true;
00368 }
00369
00370 bool
00371 ECPGis_noind_null(enum ECPGttype type, void *ptr)
00372 {
00373 switch (type)
00374 {
00375 case ECPGt_char:
00376 case ECPGt_unsigned_char:
00377 case ECPGt_string:
00378 if (*((char *) ptr) == '\0')
00379 return true;
00380 break;
00381 case ECPGt_short:
00382 case ECPGt_unsigned_short:
00383 if (*((short int *) ptr) == SHRT_MIN)
00384 return true;
00385 break;
00386 case ECPGt_int:
00387 case ECPGt_unsigned_int:
00388 if (*((int *) ptr) == INT_MIN)
00389 return true;
00390 break;
00391 case ECPGt_long:
00392 case ECPGt_unsigned_long:
00393 case ECPGt_date:
00394 if (*((long *) ptr) == LONG_MIN)
00395 return true;
00396 break;
00397 #ifdef HAVE_LONG_LONG_INT
00398 case ECPGt_long_long:
00399 case ECPGt_unsigned_long_long:
00400 if (*((long long *) ptr) == LONG_LONG_MIN)
00401 return true;
00402 break;
00403 #endif
00404 case ECPGt_float:
00405 return (_check(ptr, sizeof(float)));
00406 break;
00407 case ECPGt_double:
00408 return (_check(ptr, sizeof(double)));
00409 break;
00410 case ECPGt_varchar:
00411 if (*(((struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
00412 return true;
00413 break;
00414 case ECPGt_decimal:
00415 if (((decimal *) ptr)->sign == NUMERIC_NULL)
00416 return true;
00417 break;
00418 case ECPGt_numeric:
00419 if (((numeric *) ptr)->sign == NUMERIC_NULL)
00420 return true;
00421 break;
00422 case ECPGt_interval:
00423 return (_check(ptr, sizeof(interval)));
00424 break;
00425 case ECPGt_timestamp:
00426 return (_check(ptr, sizeof(timestamp)));
00427 break;
00428 default:
00429 break;
00430 }
00431
00432 return false;
00433 }
00434
00435 #ifdef WIN32
00436 #ifdef ENABLE_THREAD_SAFETY
00437
00438 void
00439 win32_pthread_mutex(volatile pthread_mutex_t *mutex)
00440 {
00441 if (mutex->handle == NULL)
00442 {
00443 while (InterlockedExchange((LONG *) &mutex->initlock, 1) == 1)
00444 Sleep(0);
00445 if (mutex->handle == NULL)
00446 mutex->handle = CreateMutex(NULL, FALSE, NULL);
00447 InterlockedExchange((LONG *) &mutex->initlock, 0);
00448 }
00449 }
00450
00451 static pthread_mutex_t win32_pthread_once_lock = PTHREAD_MUTEX_INITIALIZER;
00452
00453 void
00454 win32_pthread_once(volatile pthread_once_t *once, void (*fn) (void))
00455 {
00456 if (!*once)
00457 {
00458 pthread_mutex_lock(&win32_pthread_once_lock);
00459 if (!*once)
00460 {
00461 *once = true;
00462 fn();
00463 }
00464 pthread_mutex_unlock(&win32_pthread_once_lock);
00465 }
00466 }
00467 #endif
00468 #endif
00469
00470 #ifdef ENABLE_NLS
00471
00472 char *
00473 ecpg_gettext(const char *msgid)
00474 {
00475 static bool already_bound = false;
00476
00477 if (!already_bound)
00478 {
00479
00480 #ifdef WIN32
00481 int save_errno = GetLastError();
00482 #else
00483 int save_errno = errno;
00484 #endif
00485 const char *ldir;
00486
00487 already_bound = true;
00488
00489 ldir = getenv("PGLOCALEDIR");
00490 if (!ldir)
00491 ldir = LOCALEDIR;
00492 bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir);
00493 #ifdef WIN32
00494 SetLastError(save_errno);
00495 #else
00496 errno = save_errno;
00497 #endif
00498 }
00499
00500 return dgettext(PG_TEXTDOMAIN("ecpglib"), msgid);
00501 }
00502 #endif
00503
00504 struct var_list *ivlist = NULL;
00505
00506 void
00507 ECPGset_var(int number, void *pointer, int lineno)
00508 {
00509 struct var_list *ptr;
00510
00511 for (ptr = ivlist; ptr != NULL; ptr = ptr->next)
00512 {
00513 if (ptr->number == number)
00514 {
00515
00516 ptr->pointer = pointer;
00517 return;
00518 }
00519 }
00520
00521
00522 ptr = (struct var_list *) calloc(1L, sizeof(struct var_list));
00523 if (!ptr)
00524 {
00525 struct sqlca_t *sqlca = ECPGget_sqlca();
00526
00527 sqlca->sqlcode = ECPG_OUT_OF_MEMORY;
00528 strncpy(sqlca->sqlstate, "YE001", sizeof(sqlca->sqlstate));
00529 snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), "out of memory on line %d", lineno);
00530 sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
00531
00532 ECPGfree_auto_mem();
00533 }
00534 else
00535 {
00536 ptr->number = number;
00537 ptr->pointer = pointer;
00538 ptr->next = ivlist;
00539 ivlist = ptr;
00540 }
00541 }
00542
00543 void *
00544 ECPGget_var(int number)
00545 {
00546 struct var_list *ptr;
00547
00548 for (ptr = ivlist; ptr != NULL && ptr->number != number; ptr = ptr->next);
00549 return (ptr) ? ptr->pointer : NULL;
00550 }