LCOV - differential code coverage report
Current view: top level - src/interfaces/ecpg/ecpglib - prepare.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 80.8 % 245 198 47 198
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 17 17 17
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /* src/interfaces/ecpg/ecpglib/prepare.c */
       2                 : 
       3                 : #define POSTGRES_ECPG_INTERNAL
       4                 : #include "postgres_fe.h"
       5                 : 
       6                 : #include <ctype.h>
       7                 : 
       8                 : #include "ecpgerrno.h"
       9                 : #include "ecpglib.h"
      10                 : #include "ecpglib_extern.h"
      11                 : #include "ecpgtype.h"
      12                 : #include "sqlca.h"
      13                 : 
      14                 : #define STMTID_SIZE 32
      15                 : 
      16                 : /*
      17                 :  * The statement cache contains stmtCacheNBuckets hash buckets, each
      18                 :  * having stmtCacheEntPerBucket entries, which we recycle as needed,
      19                 :  * giving up the least-executed entry in the bucket.
      20                 :  * stmtCacheEntries[0] is never used, so that zero can be a "not found"
      21                 :  * indicator.
      22                 :  */
      23                 : #define stmtCacheNBuckets       2039    /* should be a prime number */
      24                 : #define stmtCacheEntPerBucket   8
      25                 : 
      26                 : #define stmtCacheArraySize (stmtCacheNBuckets * stmtCacheEntPerBucket + 1)
      27                 : 
      28                 : typedef struct
      29                 : {
      30                 :     int         lineno;
      31                 :     char        stmtID[STMTID_SIZE];
      32                 :     char       *ecpgQuery;
      33                 :     long        execs;          /* # of executions */
      34                 :     const char *connection;     /* connection for the statement */
      35                 : } stmtCacheEntry;
      36                 : 
      37                 : static int  nextStmtID = 1;
      38                 : static stmtCacheEntry *stmtCacheEntries = NULL;
      39                 : 
      40                 : static bool deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con,
      41                 :                            struct prepared_statement *prev, struct prepared_statement *this);
      42                 : 
      43                 : static bool
      44 CBC         827 : isvarchar(unsigned char c)
      45                 : {
      46             827 :     if (isalnum(c))
      47               3 :         return true;
      48                 : 
      49             824 :     if (c == '_' || c == '>' || c == '-' || c == '.')
      50 UBC           0 :         return true;
      51                 : 
      52 CBC         824 :     if (c >= 128)
      53 UBC           0 :         return true;
      54                 : 
      55 CBC         824 :     return false;
      56                 : }
      57                 : 
      58                 : bool
      59               5 : ecpg_register_prepared_stmt(struct statement *stmt)
      60                 : {
      61                 :     struct statement *prep_stmt;
      62                 :     struct prepared_statement *this;
      63               5 :     struct connection *con = stmt->connection;
      64               5 :     struct prepared_statement *prev = NULL;
      65               5 :     int         lineno = stmt->lineno;
      66                 : 
      67                 :     /* check if we already have prepared this statement */
      68               5 :     this = ecpg_find_prepared_statement(stmt->name, con, &prev);
      69               5 :     if (this && !deallocate_one(lineno, ECPG_COMPAT_PGSQL, con, prev, this))
      70 UBC           0 :         return false;
      71                 : 
      72                 :     /* allocate new statement */
      73 CBC           5 :     this = (struct prepared_statement *) ecpg_alloc(sizeof(struct prepared_statement), lineno);
      74               5 :     if (!this)
      75 UBC           0 :         return false;
      76                 : 
      77 CBC           5 :     prep_stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno);
      78               5 :     if (!prep_stmt)
      79                 :     {
      80 UBC           0 :         ecpg_free(this);
      81               0 :         return false;
      82                 :     }
      83 CBC           5 :     memset(prep_stmt, 0, sizeof(struct statement));
      84                 : 
      85                 :     /* create statement */
      86               5 :     prep_stmt->lineno = lineno;
      87               5 :     prep_stmt->connection = con;
      88               5 :     prep_stmt->command = ecpg_strdup(stmt->command, lineno);
      89               5 :     prep_stmt->inlist = prep_stmt->outlist = NULL;
      90               5 :     this->name = ecpg_strdup(stmt->name, lineno);
      91               5 :     this->stmt = prep_stmt;
      92               5 :     this->prepared = true;
      93                 : 
      94               5 :     if (con->prep_stmts == NULL)
      95 UBC           0 :         this->next = NULL;
      96                 :     else
      97 CBC           5 :         this->next = con->prep_stmts;
      98                 : 
      99               5 :     con->prep_stmts = this;
     100               5 :     return true;
     101                 : }
     102                 : 
     103                 : static bool
     104             854 : replace_variables(char **text, int lineno)
     105                 : {
     106             854 :     bool        string = false;
     107             854 :     int         counter = 1,
     108             854 :                 ptr = 0;
     109                 : 
     110           24163 :     for (; (*text)[ptr] != '\0'; ptr++)
     111                 :     {
     112           23309 :         if ((*text)[ptr] == '\'')
     113 UBC           0 :             string = string ? false : true;
     114                 : 
     115 CBC       23309 :         if (string || (((*text)[ptr] != ':') && ((*text)[ptr] != '?')))
     116           22481 :             continue;
     117                 : 
     118             828 :         if (((*text)[ptr] == ':') && ((*text)[ptr + 1] == ':'))
     119 UBC           0 :             ptr += 2;           /* skip  '::' */
     120                 :         else
     121                 :         {
     122                 :             /* a rough guess of the size we need: */
     123 CBC         828 :             int         buffersize = sizeof(int) * CHAR_BIT * 10 / 3;
     124                 :             int         len;
     125                 :             char       *buffer,
     126                 :                        *newcopy;
     127                 : 
     128             828 :             if (!(buffer = (char *) ecpg_alloc(buffersize, lineno)))
     129 UBC           0 :                 return false;
     130                 : 
     131 CBC         828 :             snprintf(buffer, buffersize, "$%d", counter++);
     132                 : 
     133             831 :             for (len = 1; (*text)[ptr + len] && isvarchar((*text)[ptr + len]); len++)
     134                 :                  /* skip */ ;
     135             828 :             if (!(newcopy = (char *) ecpg_alloc(strlen(*text) - len + strlen(buffer) + 1, lineno)))
     136                 :             {
     137 UBC           0 :                 ecpg_free(buffer);
     138               0 :                 return false;
     139                 :             }
     140                 : 
     141 CBC         828 :             memcpy(newcopy, *text, ptr);
     142             828 :             strcpy(newcopy + ptr, buffer);
     143             828 :             strcat(newcopy, (*text) +ptr + len);
     144                 : 
     145             828 :             ecpg_free(*text);
     146             828 :             ecpg_free(buffer);
     147                 : 
     148             828 :             *text = newcopy;
     149                 : 
     150             828 :             if ((*text)[ptr] == '\0')   /* we reached the end */
     151 UBC           0 :                 ptr--;          /* since we will (*text)[ptr]++ in the top
     152                 :                                  * level for loop */
     153                 :         }
     154                 :     }
     155 CBC         854 :     return true;
     156                 : }
     157                 : 
     158                 : static bool
     159             854 : prepare_common(int lineno, struct connection *con, const char *name, const char *variable)
     160                 : {
     161                 :     struct statement *stmt;
     162                 :     struct prepared_statement *this;
     163                 :     PGresult   *query;
     164                 : 
     165                 :     /* allocate new statement */
     166             854 :     this = (struct prepared_statement *) ecpg_alloc(sizeof(struct prepared_statement), lineno);
     167             854 :     if (!this)
     168 UBC           0 :         return false;
     169                 : 
     170 CBC         854 :     stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno);
     171             854 :     if (!stmt)
     172                 :     {
     173 UBC           0 :         ecpg_free(this);
     174               0 :         return false;
     175                 :     }
     176                 : 
     177                 :     /* create statement */
     178 CBC         854 :     stmt->lineno = lineno;
     179             854 :     stmt->connection = con;
     180             854 :     stmt->command = ecpg_strdup(variable, lineno);
     181             854 :     stmt->inlist = stmt->outlist = NULL;
     182                 : 
     183                 :     /* if we have C variables in our statement replace them with '?' */
     184             854 :     replace_variables(&(stmt->command), lineno);
     185                 : 
     186                 :     /* add prepared statement to our list */
     187             854 :     this->name = ecpg_strdup(name, lineno);
     188             854 :     this->stmt = stmt;
     189                 : 
     190                 :     /* and finally really prepare the statement */
     191             854 :     query = PQprepare(stmt->connection->connection, name, stmt->command, 0, NULL);
     192             854 :     if (!ecpg_check_PQresult(query, stmt->lineno, stmt->connection->connection, stmt->compat))
     193                 :     {
     194 UBC           0 :         ecpg_free(stmt->command);
     195               0 :         ecpg_free(this->name);
     196               0 :         ecpg_free(this);
     197               0 :         ecpg_free(stmt);
     198               0 :         return false;
     199                 :     }
     200                 : 
     201 CBC         854 :     ecpg_log("prepare_common on line %d: name %s; query: \"%s\"\n", stmt->lineno, name, stmt->command);
     202             854 :     PQclear(query);
     203             854 :     this->prepared = true;
     204                 : 
     205             854 :     if (con->prep_stmts == NULL)
     206             828 :         this->next = NULL;
     207                 :     else
     208              26 :         this->next = con->prep_stmts;
     209                 : 
     210             854 :     con->prep_stmts = this;
     211             854 :     return true;
     212                 : }
     213                 : 
     214                 : /* handle the EXEC SQL PREPARE statement */
     215                 : /* questionmarks is not needed but remains in there for the time being to not change the API */
     216                 : bool
     217             851 : ECPGprepare(int lineno, const char *connection_name, const bool questionmarks,
     218                 :             const char *name, const char *variable)
     219                 : {
     220                 :     struct connection *con;
     221                 :     struct prepared_statement *this,
     222                 :                *prev;
     223                 : 
     224                 :     (void) questionmarks;       /* quiet the compiler */
     225                 : 
     226             851 :     con = ecpg_get_connection(connection_name);
     227             851 :     if (!ecpg_init(con, connection_name, lineno))
     228 UBC           0 :         return false;
     229                 : 
     230                 :     /* check if we already have prepared this statement */
     231 CBC         851 :     this = ecpg_find_prepared_statement(name, con, &prev);
     232             851 :     if (this && !deallocate_one(lineno, ECPG_COMPAT_PGSQL, con, prev, this))
     233 UBC           0 :         return false;
     234                 : 
     235 CBC         851 :     return prepare_common(lineno, con, name, variable);
     236                 : }
     237                 : 
     238                 : struct prepared_statement *
     239            1787 : ecpg_find_prepared_statement(const char *name,
     240                 :                              struct connection *con, struct prepared_statement **prev_)
     241                 : {
     242                 :     struct prepared_statement *this,
     243                 :                *prev;
     244                 : 
     245            1787 :     for (this = con->prep_stmts, prev = NULL;
     246            1854 :          this != NULL;
     247              67 :          prev = this, this = this->next)
     248                 :     {
     249            1781 :         if (strcmp(this->name, name) == 0)
     250                 :         {
     251            1714 :             if (prev_)
     252             839 :                 *prev_ = prev;
     253            1714 :             return this;
     254                 :         }
     255                 :     }
     256              73 :     return NULL;
     257                 : }
     258                 : 
     259                 : static bool
     260             857 : deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con,
     261                 :                struct prepared_statement *prev, struct prepared_statement *this)
     262                 : {
     263             857 :     bool        r = false;
     264                 : 
     265             857 :     ecpg_log("deallocate_one on line %d: name %s\n", lineno, this->name);
     266                 : 
     267                 :     /* first deallocate the statement in the backend */
     268             857 :     if (this->prepared)
     269                 :     {
     270                 :         char       *text;
     271                 :         PGresult   *query;
     272                 : 
     273             857 :         text = (char *) ecpg_alloc(strlen("deallocate \"\" ") + strlen(this->name), this->stmt->lineno);
     274                 : 
     275             857 :         if (text)
     276                 :         {
     277             857 :             sprintf(text, "deallocate \"%s\"", this->name);
     278             857 :             query = PQexec(this->stmt->connection->connection, text);
     279             857 :             ecpg_free(text);
     280             857 :             if (ecpg_check_PQresult(query, lineno,
     281             857 :                                     this->stmt->connection->connection,
     282             857 :                                     this->stmt->compat))
     283                 :             {
     284             857 :                 PQclear(query);
     285             857 :                 r = true;
     286                 :             }
     287                 :         }
     288                 :     }
     289                 : 
     290                 :     /*
     291                 :      * Just ignore all errors since we do not know the list of cursors we are
     292                 :      * allowed to free. We have to trust the software.
     293                 :      */
     294             857 :     if (!r && !INFORMIX_MODE(c))
     295                 :     {
     296 UBC           0 :         ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, this->name);
     297               0 :         return false;
     298                 :     }
     299                 : 
     300                 :     /* okay, free all the resources */
     301 CBC         857 :     ecpg_free(this->stmt->command);
     302             857 :     ecpg_free(this->stmt);
     303             857 :     ecpg_free(this->name);
     304             857 :     if (prev != NULL)
     305               3 :         prev->next = this->next;
     306                 :     else
     307             854 :         con->prep_stmts = this->next;
     308                 : 
     309             857 :     ecpg_free(this);
     310             857 :     return true;
     311                 : }
     312                 : 
     313                 : /* handle the EXEC SQL DEALLOCATE PREPARE statement */
     314                 : bool
     315              53 : ECPGdeallocate(int lineno, int c, const char *connection_name, const char *name)
     316                 : {
     317                 :     struct connection *con;
     318                 :     struct prepared_statement *this,
     319                 :                *prev;
     320                 : 
     321              53 :     con = ecpg_get_connection(connection_name);
     322              53 :     if (!ecpg_init(con, connection_name, lineno))
     323 UBC           0 :         return false;
     324                 : 
     325 CBC          53 :     this = ecpg_find_prepared_statement(name, con, &prev);
     326              53 :     if (this)
     327              52 :         return deallocate_one(lineno, c, con, prev, this);
     328                 : 
     329                 :     /* prepared statement is not found */
     330               1 :     if (INFORMIX_MODE(c))
     331 UBC           0 :         return true;
     332 CBC           1 :     ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, name);
     333               1 :     return false;
     334                 : }
     335                 : 
     336                 : bool
     337             123 : ecpg_deallocate_all_conn(int lineno, enum COMPAT_MODE c, struct connection *con)
     338                 : {
     339                 :     /* deallocate all prepared statements */
     340             141 :     while (con->prep_stmts)
     341                 :     {
     342              18 :         if (!deallocate_one(lineno, c, con, NULL, con->prep_stmts))
     343 UBC           0 :             return false;
     344                 :     }
     345                 : 
     346 CBC         123 :     return true;
     347                 : }
     348                 : 
     349                 : bool
     350               1 : ECPGdeallocate_all(int lineno, int compat, const char *connection_name)
     351                 : {
     352               1 :     return ecpg_deallocate_all_conn(lineno, compat,
     353                 :                                     ecpg_get_connection(connection_name));
     354                 : }
     355                 : 
     356                 : char *
     357             852 : ecpg_prepared(const char *name, struct connection *con)
     358                 : {
     359                 :     struct prepared_statement *this;
     360                 : 
     361             852 :     this = ecpg_find_prepared_statement(name, con, NULL);
     362             852 :     return this ? this->stmt->command : NULL;
     363                 : }
     364                 : 
     365                 : /* return the prepared statement */
     366                 : /* lineno is not used here, but kept in to not break API */
     367                 : char *
     368              20 : ECPGprepared_statement(const char *connection_name, const char *name, int lineno)
     369                 : {
     370                 :     (void) lineno;              /* keep the compiler quiet */
     371                 : 
     372              20 :     return ecpg_prepared(name, ecpg_get_connection(connection_name));
     373                 : }
     374                 : 
     375                 : /*
     376                 :  * hash a SQL statement -  returns entry # of first entry in the bucket
     377                 :  */
     378                 : static int
     379              10 : HashStmt(const char *ecpgQuery)
     380                 : {
     381                 :     int         stmtIx,
     382                 :                 bucketNo,
     383                 :                 hashLeng,
     384                 :                 stmtLeng;
     385                 :     uint64      hashVal,
     386                 :                 rotVal;
     387                 : 
     388              10 :     stmtLeng = strlen(ecpgQuery);
     389              10 :     hashLeng = 50;              /* use 1st 50 characters of statement */
     390              10 :     if (hashLeng > stmtLeng) /* if the statement isn't that long */
     391              10 :         hashLeng = stmtLeng;    /* use its actual length */
     392                 : 
     393              10 :     hashVal = 0;
     394             371 :     for (stmtIx = 0; stmtIx < hashLeng; ++stmtIx)
     395                 :     {
     396             361 :         hashVal = hashVal + (unsigned char) ecpgQuery[stmtIx];
     397                 :         /* rotate 32-bit hash value left 13 bits */
     398             361 :         hashVal = hashVal << 13;
     399             361 :         rotVal = (hashVal & UINT64CONST(0x1fff00000000)) >> 32;
     400             361 :         hashVal = (hashVal & UINT64CONST(0xffffffff)) | rotVal;
     401                 :     }
     402                 : 
     403              10 :     bucketNo = hashVal % stmtCacheNBuckets;
     404                 : 
     405                 :     /* Add 1 so that array entry 0 is never used */
     406              10 :     return bucketNo * stmtCacheEntPerBucket + 1;
     407                 : }
     408                 : 
     409                 : /*
     410                 :  * search the statement cache - search for entry with matching ECPG-format query
     411                 :  * Returns entry # in cache if found
     412                 :  *   OR  zero if not present (zero'th entry isn't used)
     413                 :  */
     414                 : static int
     415               8 : SearchStmtCache(const char *ecpgQuery)
     416                 : {
     417                 :     int         entNo,
     418                 :                 entIx;
     419                 : 
     420                 :     /* quick failure if cache not set up */
     421               8 :     if (stmtCacheEntries == NULL)
     422               1 :         return 0;
     423                 : 
     424                 :     /* hash the statement */
     425               7 :     entNo = HashStmt(ecpgQuery);
     426                 : 
     427                 :     /* search the cache */
     428              23 :     for (entIx = 0; entIx < stmtCacheEntPerBucket; ++entIx)
     429                 :     {
     430              21 :         if (stmtCacheEntries[entNo].stmtID[0])  /* check if entry is in use */
     431                 :         {
     432               5 :             if (strcmp(ecpgQuery, stmtCacheEntries[entNo].ecpgQuery) == 0)
     433               5 :                 break;          /* found it */
     434                 :         }
     435              16 :         ++entNo;                /* incr entry # */
     436                 :     }
     437                 : 
     438                 :     /* if entry wasn't found - set entry # to zero */
     439               7 :     if (entIx >= stmtCacheEntPerBucket)
     440               2 :         entNo = 0;
     441                 : 
     442               7 :     return entNo;
     443                 : }
     444                 : 
     445                 : /*
     446                 :  * free an entry in the statement cache
     447                 :  * Returns entry # in cache used
     448                 :  *   OR  negative error code
     449                 :  */
     450                 : static int
     451               3 : ecpg_freeStmtCacheEntry(int lineno, int compat,
     452                 :                         int entNo)  /* entry # to free */
     453                 : {
     454                 :     stmtCacheEntry *entry;
     455                 :     struct connection *con;
     456                 :     struct prepared_statement *this,
     457                 :                *prev;
     458                 : 
     459                 :     /* fail if cache isn't set up */
     460               3 :     if (stmtCacheEntries == NULL)
     461 UBC           0 :         return -1;
     462                 : 
     463 CBC           3 :     entry = &stmtCacheEntries[entNo];
     464               3 :     if (!entry->stmtID[0])       /* return if the entry isn't in use */
     465               3 :         return 0;
     466                 : 
     467 UBC           0 :     con = ecpg_get_connection(entry->connection);
     468                 : 
     469                 :     /* free the 'prepared_statement' list entry */
     470               0 :     this = ecpg_find_prepared_statement(entry->stmtID, con, &prev);
     471               0 :     if (this && !deallocate_one(lineno, compat, con, prev, this))
     472               0 :         return -1;
     473                 : 
     474               0 :     entry->stmtID[0] = '\0';
     475                 : 
     476                 :     /* free the memory used by the cache entry */
     477               0 :     if (entry->ecpgQuery)
     478                 :     {
     479               0 :         ecpg_free(entry->ecpgQuery);
     480               0 :         entry->ecpgQuery = 0;
     481                 :     }
     482                 : 
     483               0 :     return entNo;
     484                 : }
     485                 : 
     486                 : /*
     487                 :  * add an entry to the statement cache
     488                 :  * returns entry # in cache used  OR  negative error code
     489                 :  */
     490                 : static int
     491 CBC           3 : AddStmtToCache(int lineno,      /* line # of statement */
     492                 :                const char *stmtID,  /* statement ID */
     493                 :                const char *connection,  /* connection */
     494                 :                int compat,      /* compatibility level */
     495                 :                const char *ecpgQuery)   /* query */
     496                 : {
     497                 :     int         ix,
     498                 :                 initEntNo,
     499                 :                 luEntNo,
     500                 :                 entNo;
     501                 :     stmtCacheEntry *entry;
     502                 : 
     503                 :     /* allocate and zero cache array if we haven't already */
     504               3 :     if (stmtCacheEntries == NULL)
     505                 :     {
     506               1 :         stmtCacheEntries = (stmtCacheEntry *)
     507               1 :             ecpg_alloc(sizeof(stmtCacheEntry) * stmtCacheArraySize, lineno);
     508               1 :         if (stmtCacheEntries == NULL)
     509 UBC           0 :             return -1;
     510                 :     }
     511                 : 
     512                 :     /* hash the statement */
     513 CBC           3 :     initEntNo = HashStmt(ecpgQuery);
     514                 : 
     515                 :     /* search for an unused entry */
     516               3 :     entNo = initEntNo;          /* start with the initial entry # for the
     517                 :                                  * bucket */
     518               3 :     luEntNo = initEntNo;        /* use it as the initial 'least used' entry */
     519               3 :     for (ix = 0; ix < stmtCacheEntPerBucket; ++ix)
     520                 :     {
     521               3 :         entry = &stmtCacheEntries[entNo];
     522               3 :         if (!entry->stmtID[0])   /* unused entry  -  use it */
     523               3 :             break;
     524 UBC           0 :         if (entry->execs < stmtCacheEntries[luEntNo].execs)
     525               0 :             luEntNo = entNo;    /* save new 'least used' entry */
     526               0 :         ++entNo;                /* increment entry # */
     527                 :     }
     528                 : 
     529                 :     /*
     530                 :      * if no unused entries were found, re-use the 'least used' entry found in
     531                 :      * the bucket
     532                 :      */
     533 CBC           3 :     if (ix >= stmtCacheEntPerBucket)
     534 UBC           0 :         entNo = luEntNo;
     535                 : 
     536                 :     /* 'entNo' is the entry to use - make sure its free */
     537 CBC           3 :     if (ecpg_freeStmtCacheEntry(lineno, compat, entNo) < 0)
     538 UBC           0 :         return -1;
     539                 : 
     540                 :     /* add the query to the entry */
     541 CBC           3 :     entry = &stmtCacheEntries[entNo];
     542               3 :     entry->lineno = lineno;
     543               3 :     entry->ecpgQuery = ecpg_strdup(ecpgQuery, lineno);
     544               3 :     entry->connection = connection;
     545               3 :     entry->execs = 0;
     546               3 :     memcpy(entry->stmtID, stmtID, sizeof(entry->stmtID));
     547                 : 
     548               3 :     return entNo;
     549                 : }
     550                 : 
     551                 : /* handle cache and preparation of statements in auto-prepare mode */
     552                 : bool
     553               8 : ecpg_auto_prepare(int lineno, const char *connection_name, const int compat, char **name, const char *query)
     554                 : {
     555                 :     int         entNo;
     556                 : 
     557                 :     /* search the statement cache for this statement */
     558               8 :     entNo = SearchStmtCache(query);
     559                 : 
     560                 :     /* if not found - add the statement to the cache */
     561               8 :     if (entNo)
     562                 :     {
     563                 :         char       *stmtID;
     564                 :         struct connection *con;
     565                 :         struct prepared_statement *prep;
     566                 : 
     567               5 :         ecpg_log("ecpg_auto_prepare on line %d: statement found in cache; entry %d\n", lineno, entNo);
     568                 : 
     569               5 :         stmtID = stmtCacheEntries[entNo].stmtID;
     570                 : 
     571               5 :         con = ecpg_get_connection(connection_name);
     572               5 :         prep = ecpg_find_prepared_statement(stmtID, con, NULL);
     573                 :         /* This prepared name doesn't exist on this connection. */
     574               5 :         if (!prep && !prepare_common(lineno, con, stmtID, query))
     575 UBC           0 :             return false;
     576                 : 
     577 CBC           5 :         *name = ecpg_strdup(stmtID, lineno);
     578                 :     }
     579                 :     else
     580                 :     {
     581                 :         char        stmtID[STMTID_SIZE];
     582                 : 
     583               3 :         ecpg_log("ecpg_auto_prepare on line %d: statement not in cache; inserting\n", lineno);
     584                 : 
     585                 :         /* generate a statement ID */
     586               3 :         sprintf(stmtID, "ecpg%d", nextStmtID++);
     587                 : 
     588               3 :         if (!ECPGprepare(lineno, connection_name, 0, stmtID, query))
     589 UBC           0 :             return false;
     590                 : 
     591 CBC           3 :         entNo = AddStmtToCache(lineno, stmtID, connection_name, compat, query);
     592               3 :         if (entNo < 0)
     593 UBC           0 :             return false;
     594                 : 
     595 CBC           3 :         *name = ecpg_strdup(stmtID, lineno);
     596                 :     }
     597                 : 
     598                 :     /* increase usage counter */
     599               8 :     stmtCacheEntries[entNo].execs++;
     600                 : 
     601               8 :     return true;
     602                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a