LCOV - code coverage report
Current view: top level - src/interfaces/ecpg/ecpglib - prepare.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 207 272 76.1 %
Date: 2025-09-01 09:18:58 Functions: 17 17 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.16