Header And Logo

PostgreSQL
| The world's most advanced open source database.

misc.c

Go to the documentation of this file.
00001 /* src/interfaces/ecpg/ecpglib/misc.c */
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   /* LLONG_MIN */
00027 #endif   /* LONG_LONG_MIN */
00028 #endif   /* HAVE_LONG_LONG_INT */
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);                  /* sqlca structure allocated in ECPGget_sqlca */
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     /* are we connected? */
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         /* transaction status is unknown */
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     /* if we have no connection we just simulate the command */
00201     if (con && con->connection)
00202     {
00203         /*
00204          * If we got a transaction command but have no open transaction, we
00205          * have to start one, unless we are in autocommit, where the
00206          * developers have to take care themselves. However, if the command is
00207          * a begin statement, we just execute it once.
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     /* internationalize the error message string */
00264     intl_format = ecpg_gettext(format);
00265 
00266     /*
00267      * Insert PID into the format, unless ecpg_internal_regression_mode is set
00268      * (regression tests want unchanging output).
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     /* dump out internal sqlca variables */
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   /* HAVE_LONG_LONG_INT */
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   /* HAVE_LONG_LONG_INT */
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   /* ENABLE_THREAD_SAFETY */
00468 #endif   /* WIN32 */
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         /* dgettext() preserves errno, but bindtextdomain() doesn't */
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         /* No relocatable lookup here because the binary could be anywhere */
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   /* ENABLE_NLS */
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             /* already known => just change pointer value */
00516             ptr->pointer = pointer;
00517             return;
00518         }
00519     }
00520 
00521     /* a new one has to be added */
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         /* free all memory we have allocated for the user */
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 }