summaryrefslogtreecommitdiff
path: root/src/interfaces/ecpg/ecpglib/prepare.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces/ecpg/ecpglib/prepare.c')
-rw-r--r--src/interfaces/ecpg/ecpglib/prepare.c363
1 files changed, 189 insertions, 174 deletions
diff --git a/src/interfaces/ecpg/ecpglib/prepare.c b/src/interfaces/ecpg/ecpglib/prepare.c
index 2433478a05b..930bb4f64e6 100644
--- a/src/interfaces/ecpg/ecpglib/prepare.c
+++ b/src/interfaces/ecpg/ecpglib/prepare.c
@@ -1,4 +1,4 @@
-/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/prepare.c,v 1.23 2007/11/05 20:57:24 tgl Exp $ */
+/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/prepare.c,v 1.24 2007/11/15 21:14:45 momjian Exp $ */
#define POSTGRES_ECPG_INTERNAL
#include "postgres_fe.h"
@@ -13,32 +13,32 @@
struct prepared_statement
{
- char *name;
- bool prepared;
- struct statement *stmt;
- struct prepared_statement *next;
+ char *name;
+ bool prepared;
+ struct statement *stmt;
+ struct prepared_statement *next;
};
#define STMTID_SIZE 32
-typedef struct
+typedef struct
{
- int lineno;
- char stmtID[STMTID_SIZE];
- char *ecpgQuery;
- long execs; /* # of executions */
- 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 stmtCacheEntry stmtCacheEntries[16384] = {{0,{0},0,0,0}};
+ int lineno;
+ char stmtID[STMTID_SIZE];
+ char *ecpgQuery;
+ long execs; /* # of executions */
+ 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 stmtCacheEntry stmtCacheEntries[16384] = {{0, {0}, 0, 0, 0}};
static struct prepared_statement *find_prepared_statement(const char *name,
- struct connection *con, struct prepared_statement **prev);
-static bool deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con,
- struct prepared_statement *prev, struct prepared_statement *this);
+ struct connection * con, struct prepared_statement ** prev);
+static bool deallocate_one(int lineno, enum COMPAT_MODE c, struct connection * con,
+ struct prepared_statement * prev, struct prepared_statement * this);
static bool
isvarchar(unsigned char c)
@@ -58,8 +58,9 @@ isvarchar(unsigned char c)
static bool
replace_variables(char **text, int lineno, bool questionmarks)
{
- bool string = false;
- int counter = 1, ptr = 0;
+ bool string = false;
+ int counter = 1,
+ ptr = 0;
for (; (*text)[ptr] != '\0'; ptr++)
{
@@ -69,21 +70,23 @@ replace_variables(char **text, int lineno, bool questionmarks)
if (string || (((*text)[ptr] != ':') && ((*text)[ptr] != '?')))
continue;
- if (((*text)[ptr] == ':') && ((*text)[ptr+1] == ':'))
- ptr += 2; /* skip '::' */
+ if (((*text)[ptr] == ':') && ((*text)[ptr + 1] == ':'))
+ ptr += 2; /* skip '::' */
else
{
- int len;
- int buffersize = sizeof(int) * CHAR_BIT * 10 / 3; /* a rough guess of the size we need */
- char *buffer, *newcopy;
+ int len;
+ int buffersize = sizeof(int) * CHAR_BIT * 10 / 3; /* a rough guess of the
+ * size we need */
+ char *buffer,
+ *newcopy;
if (!(buffer = (char *) ecpg_alloc(buffersize, lineno)))
return false;
snprintf(buffer, buffersize, "$%d", counter++);
- for (len=1; (*text)[ptr+len] && isvarchar((*text)[ptr+len]); len++);
- if (!(newcopy = (char *) ecpg_alloc(strlen(*text) - len + strlen(buffer) + 1, lineno)))
+ for (len = 1; (*text)[ptr + len] && isvarchar((*text)[ptr + len]); len++);
+ if (!(newcopy = (char *) ecpg_alloc(strlen(*text) -len + strlen(buffer) + 1, lineno)))
{
ecpg_free(buffer);
return false;
@@ -91,16 +94,16 @@ replace_variables(char **text, int lineno, bool questionmarks)
strncpy(newcopy, *text, ptr);
strcpy(newcopy + ptr, buffer);
- strcat(newcopy, (*text) + ptr + len);
+ strcat(newcopy, (*text) +ptr + len);
ecpg_free(*text);
ecpg_free(buffer);
*text = newcopy;
- if ((*text)[ptr] == '\0') /* we reached the end */
- ptr--; /* since we will (*text)[ptr]++ in the top level for
- * loop */
+ if ((*text)[ptr] == '\0') /* we reached the end */
+ ptr--; /* since we will (*text)[ptr]++ in the top
+ * level for loop */
}
}
return true;
@@ -110,10 +113,10 @@ replace_variables(char **text, int lineno, bool questionmarks)
bool
ECPGprepare(int lineno, const char *connection_name, const int questionmarks, const char *name, const char *variable)
{
- struct connection *con;
- struct statement *stmt;
- struct prepared_statement *this,
- *prev;
+ struct connection *con;
+ struct statement *stmt;
+ struct prepared_statement *this,
+ *prev;
struct sqlca_t *sqlca = ECPGget_sqlca();
PGresult *query;
@@ -174,11 +177,12 @@ ECPGprepare(int lineno, const char *connection_name, const int questionmarks, co
return true;
}
-static struct prepared_statement *find_prepared_statement(const char *name,
- struct connection *con, struct prepared_statement **prev_)
+static struct prepared_statement *
+find_prepared_statement(const char *name,
+ struct connection * con, struct prepared_statement ** prev_)
{
- struct prepared_statement *this,
- *prev;
+ struct prepared_statement *this,
+ *prev;
for (this = con->prep_stmts, prev = NULL; this != NULL; prev = this, this = this->next)
{
@@ -193,19 +197,20 @@ static struct prepared_statement *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;
+ bool r = false;
ecpg_log("ECPGdeallocate line %d: NAME: %s\n", lineno, this->name);
/* first deallocate the statement in the backend */
if (this->prepared)
{
- char *text;
- PGresult *query;
-
+ char *text;
+ PGresult *query;
+
text = (char *) ecpg_alloc(strlen("deallocate \"\" ") + strlen(this->name), this->stmt->lineno);
+
if (text)
{
sprintf(text, "deallocate \"%s\"", this->name);
@@ -220,15 +225,15 @@ deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con, struct pr
}
/*
- * Just ignore all errors since we do not know the list of cursors we
- * are allowed to free. We have to trust the software.
+ * Just ignore all errors since we do not know the list of cursors we are
+ * allowed to free. We have to trust the software.
*/
if (!r && !INFORMIX_MODE(c))
{
ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, this->name);
return false;
}
-
+
/* okay, free all the resources */
ecpg_free(this->stmt->command);
ecpg_free(this->stmt);
@@ -245,9 +250,9 @@ deallocate_one(int lineno, enum COMPAT_MODE c, struct connection *con, struct pr
bool
ECPGdeallocate(int lineno, int c, const char *connection_name, const char *name)
{
- struct connection *con;
- struct prepared_statement *this,
- *prev;
+ struct connection *con;
+ struct prepared_statement *this,
+ *prev;
con = ecpg_get_connection(connection_name);
@@ -263,7 +268,7 @@ ECPGdeallocate(int lineno, int c, const char *connection_name, const char *name)
}
bool
-ecpg_deallocate_all_conn(int lineno, enum COMPAT_MODE c, struct connection *con)
+ecpg_deallocate_all_conn(int lineno, enum COMPAT_MODE c, struct connection * con)
{
/* deallocate all prepared statements */
while (con->prep_stmts)
@@ -282,9 +287,10 @@ ECPGdeallocate_all(int lineno, int compat, const char *connection_name)
}
char *
-ecpg_prepared(const char *name, struct connection *con, int lineno)
+ecpg_prepared(const char *name, struct connection * con, int lineno)
{
- struct prepared_statement *this;
+ struct prepared_statement *this;
+
this = find_prepared_statement(name, con, NULL);
return this ? this->stmt->command : NULL;
}
@@ -302,97 +308,102 @@ ECPGprepared_statement(const char *connection_name, const char *name, int lineno
static int
HashStmt(const char *ecpgQuery)
{
- int stmtIx, bucketNo, hashLeng, stmtLeng;
- long long hashVal, 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 */
-
- hashVal = 0;
- for(stmtIx = 0; stmtIx < hashLeng; ++stmtIx)
- {
- hashVal = hashVal + (int) ecpgQuery[stmtIx];
- hashVal = hashVal << 13;
- rotVal = (hashVal & 0x1fff00000000LL) >> 32;
- hashVal = (hashVal & 0xffffffffLL) | rotVal;
- }
-
- bucketNo = hashVal % stmtCacheNBuckets;
- bucketNo += 1; /* don't use bucket # 0 */
-
- return (bucketNo * stmtCacheEntPerBucket);
+ int stmtIx,
+ bucketNo,
+ hashLeng,
+ stmtLeng;
+ long long hashVal,
+ 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 */
+
+ hashVal = 0;
+ for (stmtIx = 0; stmtIx < hashLeng; ++stmtIx)
+ {
+ hashVal = hashVal + (int) ecpgQuery[stmtIx];
+ hashVal = hashVal << 13;
+ rotVal = (hashVal & 0x1fff00000000LL) >> 32;
+ hashVal = (hashVal & 0xffffffffLL) | rotVal;
+ }
+
+ bucketNo = hashVal % stmtCacheNBuckets;
+ bucketNo += 1; /* don't use bucket # 0 */
+
+ return (bucketNo * stmtCacheEntPerBucket);
}
/*
* search the statement cache - search for entry with matching ECPG-format query
* Returns entry # in cache if found
- * OR zero if not present (zero'th entry isn't used)
+ * OR zero if not present (zero'th entry isn't used)
*/
static int
SearchStmtCache(const char *ecpgQuery)
{
- int entNo, entIx;
-
-/* hash the statement */
- entNo = HashStmt(ecpgQuery);
-
-/* search the cache */
- for(entIx = 0; entIx < stmtCacheEntPerBucket; ++entIx)
- {
- if(stmtCacheEntries[entNo].stmtID[0]) /* check if entry is in use */
- {
- if(!strcmp(ecpgQuery, stmtCacheEntries[entNo].ecpgQuery))
- break; /* found it */
- }
- ++entNo; /* incr entry # */
- }
+ int entNo,
+ entIx;
+
+/* hash the statement */
+ entNo = HashStmt(ecpgQuery);
+
+/* search the cache */
+ for (entIx = 0; entIx < stmtCacheEntPerBucket; ++entIx)
+ {
+ if (stmtCacheEntries[entNo].stmtID[0]) /* check if entry is in use */
+ {
+ if (!strcmp(ecpgQuery, stmtCacheEntries[entNo].ecpgQuery))
+ break; /* found it */
+ }
+ ++entNo; /* incr entry # */
+ }
/* if entry wasn't found - set entry # to zero */
- if(entIx >= stmtCacheEntPerBucket)
- entNo = 0;
+ if (entIx >= stmtCacheEntPerBucket)
+ entNo = 0;
- return(entNo);
+ return (entNo);
}
/*
* free an entry in the statement cache
* Returns entry # in cache used
- * OR negative error code
+ * OR negative error code
*/
static int
-ecpg_freeStmtCacheEntry(int entNo) /* entry # to free */
+ecpg_freeStmtCacheEntry(int entNo) /* entry # to free */
{
- stmtCacheEntry *entry;
- PGresult *results;
- char deallocText[100];
- struct connection *con;
-
- entry = &stmtCacheEntries[entNo];
- if(!entry->stmtID[0]) /* return if the entry isn't in use */
- return(0);
-
- con = ecpg_get_connection(entry->connection);
-/* free the server resources for the statement */
- ecpg_log("ecpg_freeStmtCacheEntry line %d: deallocate %s, cache entry #%d\n", entry->lineno, entry->stmtID, entNo);
- sprintf(deallocText, "DEALLOCATE PREPARE %s", entry->stmtID);
- results = PQexec(con->connection, deallocText);
-
- if (!ecpg_check_PQresult(results, entry->lineno, con->connection, ECPG_COMPAT_PGSQL))
- return(-1);
- PQclear(results);
-
- entry->stmtID[0] = '\0';
-
-/* free the memory used by the cache entry */
- if(entry->ecpgQuery)
- {
- ecpg_free(entry->ecpgQuery);
- entry->ecpgQuery = 0;
- }
-
- return(entNo);
+ stmtCacheEntry *entry;
+ PGresult *results;
+ char deallocText[100];
+ struct connection *con;
+
+ entry = &stmtCacheEntries[entNo];
+ if (!entry->stmtID[0]) /* return if the entry isn't in use */
+ return (0);
+
+ con = ecpg_get_connection(entry->connection);
+/* free the server resources for the statement */
+ ecpg_log("ecpg_freeStmtCacheEntry line %d: deallocate %s, cache entry #%d\n", entry->lineno, entry->stmtID, entNo);
+ sprintf(deallocText, "DEALLOCATE PREPARE %s", entry->stmtID);
+ results = PQexec(con->connection, deallocText);
+
+ if (!ecpg_check_PQresult(results, entry->lineno, con->connection, ECPG_COMPAT_PGSQL))
+ return (-1);
+ PQclear(results);
+
+ entry->stmtID[0] = '\0';
+
+/* free the memory used by the cache entry */
+ if (entry->ecpgQuery)
+ {
+ ecpg_free(entry->ecpgQuery);
+ entry->ecpgQuery = 0;
+ }
+
+ return (entNo);
}
/*
@@ -400,63 +411,67 @@ ecpg_freeStmtCacheEntry(int entNo) /* entry # to free */
* returns entry # in cache used OR negative error code
*/
static int
-AddStmtToCache(int lineno, /* line # of statement */
- char *stmtID, /* statement ID */
- const char *connection, /* connection */
- const char *ecpgQuery) /* query */
+AddStmtToCache(int lineno, /* line # of statement */
+ char *stmtID, /* statement ID */
+ const char *connection, /* connection */
+ const char *ecpgQuery) /* query */
{
- int ix, initEntNo, luEntNo, entNo;
- stmtCacheEntry *entry;
-
-/* hash the statement */
- initEntNo = HashStmt(ecpgQuery);
-
-/* 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 */
- for(ix = 0; ix < stmtCacheEntPerBucket; ++ix)
- {
- entry = &stmtCacheEntries[entNo];
- 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 # */
- }
-
-/* 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 */
-
-/* 'entNo' is the entry to use - make sure its free */
- if (ecpg_freeStmtCacheEntry(entNo) < 0)
- return (-1);
-
-/* add the query to the entry */
- entry = &stmtCacheEntries[entNo];
- entry->lineno = lineno;
- entry->ecpgQuery = ecpg_strdup(ecpgQuery, lineno);
- entry->connection = (char *)connection;
- entry->execs = 0;
- memcpy(entry->stmtID, stmtID, sizeof(entry->stmtID));
-
- return(entNo);
+ int ix,
+ initEntNo,
+ luEntNo,
+ entNo;
+ stmtCacheEntry *entry;
+
+/* hash the statement */
+ initEntNo = HashStmt(ecpgQuery);
+
+/* 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 */
+ for (ix = 0; ix < stmtCacheEntPerBucket; ++ix)
+ {
+ entry = &stmtCacheEntries[entNo];
+ 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 # */
+ }
+
+/* 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 */
+
+/* 'entNo' is the entry to use - make sure its free */
+ if (ecpg_freeStmtCacheEntry(entNo) < 0)
+ return (-1);
+
+/* add the query to the entry */
+ entry = &stmtCacheEntries[entNo];
+ entry->lineno = lineno;
+ entry->ecpgQuery = ecpg_strdup(ecpgQuery, lineno);
+ entry->connection = (char *) connection;
+ entry->execs = 0;
+ memcpy(entry->stmtID, stmtID, sizeof(entry->stmtID));
+
+ return (entNo);
}
/* handle cache and preparation of statments in auto-prepare mode */
bool
ecpg_auto_prepare(int lineno, const char *connection_name, const int questionmarks, char **name, const char *query)
{
- int entNo;
+ 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(entNo)
+ /* if not found - add the statement to the cache */
+ if (entNo)
{
ecpg_log("ecpg_auto_prepare line %d: stmt found in cache, entry %d\n", lineno, entNo);
- *name = ecpg_strdup(stmtCacheEntries[entNo].stmtID, lineno);
+ *name = ecpg_strdup(stmtCacheEntries[entNo].stmtID, lineno);
}
else
{
@@ -467,13 +482,13 @@ ecpg_auto_prepare(int lineno, const char *connection_name, const int questionmar
sprintf(*name, "ecpg%d", nextStmtID++);
if (!ECPGprepare(lineno, connection_name, questionmarks, ecpg_strdup(*name, lineno), query))
- return(false);
+ return (false);
if (AddStmtToCache(lineno, *name, connection_name, query) < 0)
- return(false);
+ return (false);
}
/* increase usage counter */
stmtCacheEntries[entNo].execs++;
- return(true);
+ return (true);
}