@ -18,13 +18,13 @@ typedef struct
int lineno ;
char stmtID [ STMTID_SIZE ] ;
char * ecpgQuery ;
long execs ; /* # of executions */
const char * connection ; /* connection for the statement */
long execs ; /* # of executions */
const char * connection ; /* connection for the statement */
} stmtCacheEntry ;
static int nextStmtID = 1 ;
static const int stmtCacheNBuckets = 2039 ; /* # buckets - a prime # */
static const int stmtCacheEntPerBucket = 8 ; /* # entries/bucket */
static const int stmtCacheEntPerBucket = 8 ; /* # entries/bucket */
static stmtCacheEntry stmtCacheEntries [ 16384 ] = { { 0 , { 0 } , 0 , 0 , 0 } } ;
static bool deallocate_one ( int lineno , enum COMPAT_MODE c , struct connection * con ,
@ -64,9 +64,9 @@ replace_variables(char **text, int lineno)
ptr + = 2 ; /* skip '::' */
else
{
/* a rough guess of the size we need: */
int buffersize = sizeof ( int ) * CHAR_BIT * 10 / 3 ;
int len ;
int buffersize = sizeof ( int ) * CHAR_BIT * 10 / 3 ; /* a rough guess of the
* size we need */
char * buffer ,
* newcopy ;
@ -75,7 +75,8 @@ replace_variables(char **text, int lineno)
snprintf ( buffer , buffersize , " $%d " , counter + + ) ;
for ( len = 1 ; ( * text ) [ ptr + len ] & & isvarchar ( ( * text ) [ ptr + len ] ) ; len + + ) ;
for ( len = 1 ; ( * text ) [ ptr + len ] & & isvarchar ( ( * text ) [ ptr + len ] ) ; len + + )
/* skip */ ;
if ( ! ( newcopy = ( char * ) ecpg_alloc ( strlen ( * text ) - len + strlen ( buffer ) + 1 , lineno ) ) )
{
ecpg_free ( buffer ) ;
@ -158,13 +159,15 @@ prepare_common(int lineno, struct connection *con, const char *name, const char
/* handle the EXEC SQL PREPARE statement */
/* questionmarks is not needed but remains in there for the time being to not change the API */
bool
ECPGprepare ( int lineno , const char * connection_name , const bool questionmarks , const char * name , const char * variable )
ECPGprepare ( int lineno , const char * connection_name , const bool questionmarks ,
const char * name , const char * variable )
{
struct connection * con ;
struct prepared_statement * this ,
* prev ;
( void ) questionmarks ; /* quiet the compiler */
con = ecpg_get_connection ( connection_name ) ;
if ( ! ecpg_init ( con , connection_name , lineno ) )
@ -185,7 +188,9 @@ ecpg_find_prepared_statement(const char *name,
struct prepared_statement * this ,
* prev ;
for ( this = con - > prep_stmts , prev = NULL ; this ! = NULL ; prev = this , this = this - > next )
for ( this = con - > prep_stmts , prev = NULL ;
this ! = NULL ;
prev = this , this = this - > next )
{
if ( strcmp ( this - > name , name ) = = 0 )
{
@ -198,7 +203,8 @@ ecpg_find_prepared_statement(const char *name,
}
static bool
deallocate_one ( int lineno , enum COMPAT_MODE c , struct connection * con , struct prepared_statement * prev , struct prepared_statement * this )
deallocate_one ( int lineno , enum COMPAT_MODE c , struct connection * con ,
struct prepared_statement * prev , struct prepared_statement * this )
{
bool r = false ;
@ -217,7 +223,9 @@ deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con, struct pr
sprintf ( text , " deallocate \" %s \" " , this - > name ) ;
query = PQexec ( this - > stmt - > connection - > connection , text ) ;
ecpg_free ( text ) ;
if ( ecpg_check_PQresult ( query , lineno , this - > stmt - > connection - > connection , this - > stmt - > compat ) )
if ( ecpg_check_PQresult ( query , lineno ,
this - > stmt - > connection - > connection ,
this - > stmt - > compat ) )
{
PQclear ( query ) ;
r = true ;
@ -288,7 +296,8 @@ ecpg_deallocate_all_conn(int lineno, enum COMPAT_MODE c, struct connection *con)
bool
ECPGdeallocate_all ( int lineno , int compat , const char * connection_name )
{
return ecpg_deallocate_all_conn ( lineno , compat , ecpg_get_connection ( connection_name ) ) ;
return ecpg_deallocate_all_conn ( lineno , compat ,
ecpg_get_connection ( connection_name ) ) ;
}
char *
@ -323,9 +332,9 @@ HashStmt(const char *ecpgQuery)
rotVal ;
stmtLeng = strlen ( ecpgQuery ) ;
hashLeng = 50 ; /* use 1st 50 characters of statement */
if ( hashLeng > stmtLeng ) /* if the statement isn't that long */
hashLeng = stmtLeng ; /* use its actual length */
hashLeng = 50 ; /* use 1st 50 characters of statement */
if ( hashLeng > stmtLeng ) /* if the statement isn't that long */
hashLeng = stmtLeng ; /* use its actual length */
hashVal = 0 ;
for ( stmtIx = 0 ; stmtIx < hashLeng ; + + stmtIx )
@ -337,7 +346,7 @@ HashStmt(const char *ecpgQuery)
}
bucketNo = hashVal % stmtCacheNBuckets ;
bucketNo + = 1 ; /* don't use bucket # 0 */
bucketNo + = 1 ; /* don't use bucket # 0 */
return ( bucketNo * stmtCacheEntPerBucket ) ;
}
@ -353,21 +362,21 @@ SearchStmtCache(const char *ecpgQuery)
int entNo ,
entIx ;
/* hash the statement */
/* hash the statement */
entNo = HashStmt ( ecpgQuery ) ;
/* search the cache */
/* search the cache */
for ( entIx = 0 ; entIx < stmtCacheEntPerBucket ; + + entIx )
{
if ( stmtCacheEntries [ entNo ] . stmtID [ 0 ] ) /* check if entry is in use */
if ( stmtCacheEntries [ entNo ] . stmtID [ 0 ] ) /* check if entry is in use */
{
if ( strcmp ( ecpgQuery , stmtCacheEntries [ entNo ] . ecpgQuery ) = = 0 )
break ; /* found it */
break ; /* found it */
}
+ + entNo ; /* incr entry # */
+ + entNo ; /* incr entry # */
}
/* if entry wasn't found - set entry # to zero */
/* if entry wasn't found - set entry # to zero */
if ( entIx > = stmtCacheEntPerBucket )
entNo = 0 ;
@ -380,7 +389,8 @@ SearchStmtCache(const char *ecpgQuery)
* OR negative error code
*/
static int
ecpg_freeStmtCacheEntry ( int lineno , int compat , int entNo ) /* entry # to free */
ecpg_freeStmtCacheEntry ( int lineno , int compat ,
int entNo ) /* entry # to free */
{
stmtCacheEntry * entry ;
struct connection * con ;
@ -388,19 +398,19 @@ ecpg_freeStmtCacheEntry(int lineno, int compat, int entNo) /* entry # to free */
* prev ;
entry = & stmtCacheEntries [ entNo ] ;
if ( ! entry - > stmtID [ 0 ] ) /* return if the entry isn't in use */
if ( ! entry - > stmtID [ 0 ] ) /* return if the entry isn't in use */
return 0 ;
con = ecpg_get_connection ( entry - > connection ) ;
/* free the 'prepared_statement' list entry */
/* free the 'prepared_statement' list entry */
this = ecpg_find_prepared_statement ( entry - > stmtID , con , & prev ) ;
if ( this & & ! deallocate_one ( lineno , compat , con , prev , this ) )
return - 1 ;
entry - > stmtID [ 0 ] = ' \0 ' ;
/* free the memory used by the cache entry */
/* free the memory used by the cache entry */
if ( entry - > ecpgQuery )
{
ecpg_free ( entry - > ecpgQuery ) ;
@ -415,11 +425,11 @@ ecpg_freeStmtCacheEntry(int lineno, int compat, int entNo) /* entry # to free */
* returns entry # in cache used OR negative error code
*/
static int
AddStmtToCache ( int lineno , /* line # of statement */
const char * stmtID , /* statement ID */
const char * connection , /* connection */
AddStmtToCache ( int lineno , /* line # of statement */
const char * stmtID , /* statement ID */
const char * connection , /* connection */
int compat , /* compatibility level */
const char * ecpgQuery ) /* query */
const char * ecpgQuery ) /* query */
{
int ix ,
initEntNo ,
@ -427,32 +437,35 @@ AddStmtToCache(int lineno, /* line # of statement */
entNo ;
stmtCacheEntry * entry ;
/* hash the statement */
/* hash the statement */
initEntNo = HashStmt ( ecpgQuery ) ;
/* search for an unused entry */
/* search for an unused entry */
entNo = initEntNo ; /* start with the initial entry # for the
* bucket */
luEntNo = initEntNo ; /* use it as the initial 'least used' entry */
* bucket */
luEntNo = initEntNo ; /* use it as the initial 'least used' entry */
for ( ix = 0 ; ix < stmtCacheEntPerBucket ; + + ix )
{
entry = & stmtCacheEntries [ entNo ] ;
if ( ! entry - > stmtID [ 0 ] ) /* unused entry - use it */
if ( ! entry - > stmtID [ 0 ] ) /* unused entry - use it */
break ;
if ( entry - > execs < stmtCacheEntries [ luEntNo ] . execs )
luEntNo = entNo ; /* save new 'least used' entry */
+ + entNo ; /* increment entry # */
luEntNo = entNo ; /* save new 'least used' entry */
+ + entNo ; /* increment entry # */
}
/* if no unused entries were found - use the 'least used' entry found in the bucket */
if ( ix > = stmtCacheEntPerBucket ) /* if no unused entries were found */
entNo = luEntNo ; /* re-use the 'least used' entry */
/*
* if no unused entries were found , re - use the ' least used ' entry found in
* the bucket
*/
if ( ix > = stmtCacheEntPerBucket )
entNo = luEntNo ;
/* 'entNo' is the entry to use - make sure its free */
/* 'entNo' is the entry to use - make sure its free */
if ( ecpg_freeStmtCacheEntry ( lineno , compat , entNo ) < 0 )
return - 1 ;
/* add the query to the entry */
/* add the query to the entry */
entry = & stmtCacheEntries [ entNo ] ;
entry - > lineno = lineno ;
entry - > ecpgQuery = ecpg_strdup ( ecpgQuery , lineno ) ;
@ -469,10 +482,10 @@ ecpg_auto_prepare(int lineno, const char *connection_name, const int compat, cha
{
int entNo ;
/* search the statement cache for this statement */
/* search the statement cache for this statement */
entNo = SearchStmtCache ( query ) ;
/* if not found - add the statement to the cache */
/* if not found - add the statement to the cache */
if ( entNo )
{
char * stmtID ;