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

Generated by: LCOV version 1.13