LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/ecpglib - misc.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 167 238 70.2 %
Date: 2024-04-26 23:11:19 Functions: 14 16 87.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14