LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/ecpglib - misc.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 164 235 69.8 %
Date: 2020-01-25 22:06:23 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             : #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
      98     6416588 : ecpg_init_sqlca(struct sqlca_t *sqlca)
      99             : {
     100     6416588 :     memcpy((char *) sqlca, (char *) &sqlca_init, sizeof(struct sqlca_t));
     101     6416588 : }
     102             : 
     103             : bool
     104       15044 : ecpg_init(const struct connection *con, const char *connection_name, const int lineno)
     105             : {
     106       15044 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     107             : 
     108       15044 :     if (sqlca == NULL)
     109             :     {
     110           0 :         ecpg_raise(lineno, ECPG_OUT_OF_MEMORY, ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY,
     111             :                    NULL);
     112           0 :         return false;
     113             :     }
     114             : 
     115       15044 :     ecpg_init_sqlca(sqlca);
     116       15044 :     if (con == NULL)
     117             :     {
     118          90 :         ecpg_raise(lineno, ECPG_NO_CONN, ECPG_SQLSTATE_CONNECTION_DOES_NOT_EXIST,
     119          24 :                    connection_name ? connection_name : ecpg_gettext("NULL"));
     120          66 :         return false;
     121             :     }
     122             : 
     123       14978 :     return true;
     124             : }
     125             : 
     126             : #ifdef ENABLE_THREAD_SAFETY
     127             : static void
     128         272 : ecpg_sqlca_key_destructor(void *arg)
     129             : {
     130         272 :     free(arg);                  /* sqlca structure allocated in ECPGget_sqlca */
     131         272 : }
     132             : 
     133             : static void
     134         242 : ecpg_sqlca_key_init(void)
     135             : {
     136         242 :     pthread_key_create(&sqlca_key, ecpg_sqlca_key_destructor);
     137         242 : }
     138             : #endif
     139             : 
     140             : struct sqlca_t *
     141    12914732 : ECPGget_sqlca(void)
     142             : {
     143             : #ifdef ENABLE_THREAD_SAFETY
     144             :     struct sqlca_t *sqlca;
     145             : 
     146    12914732 :     pthread_once(&sqlca_key_once, ecpg_sqlca_key_init);
     147             : 
     148    12914732 :     sqlca = pthread_getspecific(sqlca_key);
     149    12914732 :     if (sqlca == NULL)
     150             :     {
     151         506 :         sqlca = malloc(sizeof(struct sqlca_t));
     152         506 :         if (sqlca == NULL)
     153           0 :             return NULL;
     154         506 :         ecpg_init_sqlca(sqlca);
     155         506 :         pthread_setspecific(sqlca_key, sqlca);
     156             :     }
     157    12914732 :     return sqlca;
     158             : #else
     159             :     return &sqlca;
     160             : #endif
     161             : }
     162             : 
     163             : bool
     164           0 : ECPGstatus(int lineno, const char *connection_name)
     165             : {
     166           0 :     struct connection *con = ecpg_get_connection(connection_name);
     167             : 
     168           0 :     if (!ecpg_init(con, connection_name, lineno))
     169           0 :         return false;
     170             : 
     171             :     /* are we connected? */
     172           0 :     if (con->connection == NULL)
     173             :     {
     174           0 :         ecpg_raise(lineno, ECPG_NOT_CONN, ECPG_SQLSTATE_ECPG_INTERNAL_ERROR, con->name);
     175           0 :         return false;
     176             :     }
     177             : 
     178           0 :     return true;
     179             : }
     180             : 
     181             : PGTransactionStatusType
     182           0 : ECPGtransactionStatus(const char *connection_name)
     183             : {
     184             :     const struct connection *con;
     185             : 
     186           0 :     con = ecpg_get_connection(connection_name);
     187           0 :     if (con == NULL)
     188             :     {
     189             :         /* transaction status is unknown */
     190           0 :         return PQTRANS_UNKNOWN;
     191             :     }
     192             : 
     193           0 :     return PQtransactionStatus(con->connection);
     194             : 
     195             : }
     196             : 
     197             : bool
     198         472 : ECPGtrans(int lineno, const char *connection_name, const char *transaction)
     199             : {
     200             :     PGresult   *res;
     201         472 :     struct connection *con = ecpg_get_connection(connection_name);
     202             : 
     203         472 :     if (!ecpg_init(con, connection_name, lineno))
     204           0 :         return false;
     205             : 
     206         472 :     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         472 :     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         472 :         if (PQtransactionStatus(con->connection) == PQTRANS_IDLE &&
     219         108 :             !con->autocommit &&
     220          96 :             strncmp(transaction, "begin", 5) != 0 &&
     221           4 :             strncmp(transaction, "start", 5) != 0 &&
     222           4 :             strncmp(transaction, "commit prepared", 15) != 0 &&
     223           0 :             strncmp(transaction, "rollback prepared", 17) != 0)
     224             :         {
     225           0 :             res = PQexec(con->connection, "begin transaction");
     226           0 :             if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
     227           0 :                 return false;
     228           0 :             PQclear(res);
     229             :         }
     230             : 
     231         472 :         res = PQexec(con->connection, transaction);
     232         472 :         if (!ecpg_check_PQresult(res, lineno, con->connection, ECPG_COMPAT_PGSQL))
     233           0 :             return false;
     234         472 :         PQclear(res);
     235             :     }
     236             : 
     237         472 :     return true;
     238             : }
     239             : 
     240             : 
     241             : void
     242         222 : ECPGdebug(int n, FILE *dbgs)
     243             : {
     244             : #ifdef ENABLE_THREAD_SAFETY
     245         222 :     pthread_mutex_lock(&debug_init_mutex);
     246             : #endif
     247             : 
     248         222 :     if (n > 100)
     249             :     {
     250         222 :         ecpg_internal_regression_mode = true;
     251         222 :         simple_debug = n - 100;
     252             :     }
     253             :     else
     254           0 :         simple_debug = n;
     255             : 
     256         222 :     debugstream = dbgs;
     257             : 
     258         222 :     ecpg_log("ECPGdebug: set to %d\n", simple_debug);
     259             : 
     260             : #ifdef ENABLE_THREAD_SAFETY
     261         222 :     pthread_mutex_unlock(&debug_init_mutex);
     262             : #endif
     263         222 : }
     264             : 
     265             : void
     266       57264 : ecpg_log(const char *format,...)
     267             : {
     268             :     va_list     ap;
     269       57264 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     270             :     const char *intl_format;
     271             :     int         bufsize;
     272             :     char       *fmt;
     273             : 
     274       57264 :     if (!simple_debug)
     275       45084 :         return;
     276             : 
     277             :     /* localize the error message string */
     278       12180 :     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       12180 :     bufsize = strlen(intl_format) + 100;
     285       12180 :     fmt = (char *) malloc(bufsize);
     286       12180 :     if (fmt == NULL)
     287           0 :         return;
     288             : 
     289       12180 :     if (ecpg_internal_regression_mode)
     290       12180 :         snprintf(fmt, bufsize, "[NO_PID]: %s", intl_format);
     291             :     else
     292           0 :         snprintf(fmt, bufsize, "[%d]: %s", (int) getpid(), intl_format);
     293             : 
     294             : #ifdef ENABLE_THREAD_SAFETY
     295       12180 :     pthread_mutex_lock(&debug_mutex);
     296             : #endif
     297             : 
     298       12180 :     va_start(ap, format);
     299       12180 :     vfprintf(debugstream, fmt, ap);
     300       12180 :     va_end(ap);
     301             : 
     302             :     /* dump out internal sqlca variables */
     303       12180 :     if (ecpg_internal_regression_mode && sqlca != NULL)
     304             :     {
     305       12180 :         fprintf(debugstream, "[NO_PID]: sqlca: code: %ld, state: %s\n",
     306       12180 :                 sqlca->sqlcode, sqlca->sqlstate);
     307             :     }
     308             : 
     309       12180 :     fflush(debugstream);
     310             : 
     311             : #ifdef ENABLE_THREAD_SAFETY
     312       12180 :     pthread_mutex_unlock(&debug_mutex);
     313             : #endif
     314             : 
     315       12180 :     free(fmt);
     316             : }
     317             : 
     318             : void
     319        7140 : ECPGset_noind_null(enum ECPGttype type, void *ptr)
     320             : {
     321        7140 :     switch (type)
     322             :     {
     323        3780 :         case ECPGt_char:
     324             :         case ECPGt_unsigned_char:
     325             :         case ECPGt_string:
     326        3780 :             *((char *) ptr) = '\0';
     327        3780 :             break;
     328           8 :         case ECPGt_short:
     329             :         case ECPGt_unsigned_short:
     330           8 :             *((short int *) ptr) = SHRT_MIN;
     331           8 :             break;
     332           8 :         case ECPGt_int:
     333             :         case ECPGt_unsigned_int:
     334           8 :             *((int *) ptr) = INT_MIN;
     335           8 :             break;
     336          20 :         case ECPGt_long:
     337             :         case ECPGt_unsigned_long:
     338             :         case ECPGt_date:
     339          20 :             *((long *) ptr) = LONG_MIN;
     340          20 :             break;
     341           0 :         case ECPGt_long_long:
     342             :         case ECPGt_unsigned_long_long:
     343           0 :             *((long long *) ptr) = LONG_LONG_MIN;
     344           0 :             break;
     345           8 :         case ECPGt_float:
     346           8 :             memset((char *) ptr, 0xff, sizeof(float));
     347           8 :             break;
     348          16 :         case ECPGt_double:
     349          16 :             memset((char *) ptr, 0xff, sizeof(double));
     350          16 :             break;
     351           0 :         case ECPGt_varchar:
     352           0 :             *(((struct ECPGgeneric_varchar *) ptr)->arr) = 0x00;
     353           0 :             ((struct ECPGgeneric_varchar *) ptr)->len = 0;
     354           0 :             break;
     355           0 :         case ECPGt_bytea:
     356           0 :             ((struct ECPGgeneric_bytea *) ptr)->len = 0;
     357           0 :             break;
     358        3276 :         case ECPGt_decimal:
     359        3276 :             memset((char *) ptr, 0, sizeof(decimal));
     360        3276 :             ((decimal *) ptr)->sign = NUMERIC_NULL;
     361        3276 :             break;
     362           8 :         case ECPGt_numeric:
     363           8 :             memset((char *) ptr, 0, sizeof(numeric));
     364           8 :             ((numeric *) ptr)->sign = NUMERIC_NULL;
     365           8 :             break;
     366           0 :         case ECPGt_interval:
     367           0 :             memset((char *) ptr, 0xff, sizeof(interval));
     368           0 :             break;
     369          12 :         case ECPGt_timestamp:
     370          12 :             memset((char *) ptr, 0xff, sizeof(timestamp));
     371          12 :             break;
     372           4 :         default:
     373           4 :             break;
     374             :     }
     375        7140 : }
     376             : 
     377             : static bool
     378          44 : _check(const unsigned char *ptr, int length)
     379             : {
     380         236 :     for (length--; length >= 0; length--)
     381         208 :         if (ptr[length] != 0xff)
     382          16 :             return false;
     383             : 
     384          28 :     return true;
     385             : }
     386             : 
     387             : bool
     388       11052 : ECPGis_noind_null(enum ECPGttype type, const void *ptr)
     389             : {
     390       11052 :     switch (type)
     391             :     {
     392          80 :         case ECPGt_char:
     393             :         case ECPGt_unsigned_char:
     394             :         case ECPGt_string:
     395          80 :             if (*((const char *) ptr) == '\0')
     396           8 :                 return true;
     397          72 :             break;
     398          16 :         case ECPGt_short:
     399             :         case ECPGt_unsigned_short:
     400          16 :             if (*((const short int *) ptr) == SHRT_MIN)
     401           8 :                 return true;
     402           8 :             break;
     403          72 :         case ECPGt_int:
     404             :         case ECPGt_unsigned_int:
     405          72 :             if (*((const int *) ptr) == INT_MIN)
     406           8 :                 return true;
     407          64 :             break;
     408          72 :         case ECPGt_long:
     409             :         case ECPGt_unsigned_long:
     410             :         case ECPGt_date:
     411          72 :             if (*((const long *) ptr) == LONG_MIN)
     412          20 :                 return true;
     413          52 :             break;
     414           0 :         case ECPGt_long_long:
     415             :         case ECPGt_unsigned_long_long:
     416           0 :             if (*((const long long *) ptr) == LONG_LONG_MIN)
     417           0 :                 return true;
     418           0 :             break;
     419          16 :         case ECPGt_float:
     420          16 :             return _check(ptr, sizeof(float));
     421             :             break;
     422          16 :         case ECPGt_double:
     423          16 :             return _check(ptr, sizeof(double));
     424             :             break;
     425           0 :         case ECPGt_varchar:
     426           0 :             if (*(((const struct ECPGgeneric_varchar *) ptr)->arr) == 0x00)
     427           0 :                 return true;
     428           0 :             break;
     429           0 :         case ECPGt_bytea:
     430           0 :             if (((const struct ECPGgeneric_bytea *) ptr)->len == 0)
     431           0 :                 return true;
     432           0 :             break;
     433       10752 :         case ECPGt_decimal:
     434       10752 :             if (((const decimal *) ptr)->sign == NUMERIC_NULL)
     435        1040 :                 return true;
     436        9712 :             break;
     437           0 :         case ECPGt_numeric:
     438           0 :             if (((const numeric *) ptr)->sign == NUMERIC_NULL)
     439           0 :                 return true;
     440           0 :             break;
     441           0 :         case ECPGt_interval:
     442           0 :             return _check(ptr, sizeof(interval));
     443             :             break;
     444          12 :         case ECPGt_timestamp:
     445          12 :             return _check(ptr, sizeof(timestamp));
     446             :             break;
     447          16 :         default:
     448          16 :             break;
     449             :     }
     450             : 
     451        9924 :     return false;
     452             : }
     453             : 
     454             : #ifdef WIN32
     455             : #ifdef ENABLE_THREAD_SAFETY
     456             : 
     457             : void
     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
     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             :             *once = true;
     481             :             fn();
     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 *
     492       12410 : ecpg_gettext(const char *msgid)
     493             : {
     494             :     static bool already_bound = false;
     495             : 
     496       12410 :     if (!already_bound)
     497             :     {
     498             :         /* dgettext() preserves errno, but bindtextdomain() doesn't */
     499             : #ifdef WIN32
     500             :         int         save_errno = GetLastError();
     501             : #else
     502         218 :         int         save_errno = errno;
     503             : #endif
     504             :         const char *ldir;
     505             : 
     506         218 :         already_bound = true;
     507             :         /* No relocatable lookup here because the binary could be anywhere */
     508         218 :         ldir = getenv("PGLOCALEDIR");
     509         218 :         if (!ldir)
     510           0 :             ldir = LOCALEDIR;
     511         218 :         bindtextdomain(PG_TEXTDOMAIN("ecpglib"), ldir);
     512             : #ifdef WIN32
     513             :         SetLastError(save_errno);
     514             : #else
     515         218 :         errno = save_errno;
     516             : #endif
     517             :     }
     518             : 
     519       12410 :     return dgettext(PG_TEXTDOMAIN("ecpglib"), msgid);
     520             : }
     521             : #endif                          /* ENABLE_NLS */
     522             : 
     523             : struct var_list *ivlist = NULL;
     524             : 
     525             : void
     526          52 : ECPGset_var(int number, void *pointer, int lineno)
     527             : {
     528             :     struct var_list *ptr;
     529             : 
     530          52 :     struct sqlca_t *sqlca = ECPGget_sqlca();
     531             : 
     532          52 :     if (sqlca == NULL)
     533             :     {
     534           0 :         ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
     535             :                    ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
     536           0 :         return;
     537             :     }
     538             : 
     539          52 :     ecpg_init_sqlca(sqlca);
     540             : 
     541         152 :     for (ptr = ivlist; ptr != NULL; ptr = ptr->next)
     542             :     {
     543         100 :         if (ptr->number == number)
     544             :         {
     545             :             /* already known => just change pointer value */
     546           0 :             ptr->pointer = pointer;
     547           0 :             return;
     548             :         }
     549             :     }
     550             : 
     551             :     /* a new one has to be added */
     552          52 :     ptr = (struct var_list *) calloc(1L, sizeof(struct var_list));
     553          52 :     if (!ptr)
     554             :     {
     555           0 :         struct sqlca_t *sqlca = ECPGget_sqlca();
     556             : 
     557           0 :         if (sqlca == NULL)
     558             :         {
     559           0 :             ecpg_raise(lineno, ECPG_OUT_OF_MEMORY,
     560             :                        ECPG_SQLSTATE_ECPG_OUT_OF_MEMORY, NULL);
     561           0 :             return;
     562             :         }
     563             : 
     564           0 :         sqlca->sqlcode = ECPG_OUT_OF_MEMORY;
     565           0 :         strncpy(sqlca->sqlstate, "YE001", sizeof(sqlca->sqlstate));
     566           0 :         snprintf(sqlca->sqlerrm.sqlerrmc, sizeof(sqlca->sqlerrm.sqlerrmc), "out of memory on line %d", lineno);
     567           0 :         sqlca->sqlerrm.sqlerrml = strlen(sqlca->sqlerrm.sqlerrmc);
     568             :         /* free all memory we have allocated for the user */
     569           0 :         ECPGfree_auto_mem();
     570             :     }
     571             :     else
     572             :     {
     573          52 :         ptr->number = number;
     574          52 :         ptr->pointer = pointer;
     575          52 :         ptr->next = ivlist;
     576          52 :         ivlist = ptr;
     577             :     }
     578             : }
     579             : 
     580             : void *
     581         204 : ECPGget_var(int number)
     582             : {
     583             :     struct var_list *ptr;
     584             : 
     585         304 :     for (ptr = ivlist; ptr != NULL && ptr->number != number; ptr = ptr->next);
     586         204 :     return (ptr) ? ptr->pointer : NULL;
     587             : }

Generated by: LCOV version 1.13