#include "postgres_fe.h"
#include <ctype.h>
#include "ecpgtype.h"
#include "ecpglib.h"
#include "ecpgerrno.h"
#include "extern.h"
#include "sqlca.h"
Go to the source code of this file.
Data Structures | |
struct | stmtCacheEntry |
Defines | |
#define | POSTGRES_ECPG_INTERNAL |
#define | STMTID_SIZE 32 |
Functions | |
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) |
static bool | replace_variables (char **text, int lineno) |
static bool | prepare_common (int lineno, struct connection *con, const char *name, const char *variable) |
bool | ECPGprepare (int lineno, const char *connection_name, const bool questionmarks, const char *name, const char *variable) |
struct prepared_statement * | ecpg_find_prepared_statement (const char *name, struct connection *con, struct prepared_statement **prev_) |
bool | 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) |
bool | ECPGdeallocate_all (int lineno, int compat, const char *connection_name) |
char * | ecpg_prepared (const char *name, struct connection *con) |
char * | ECPGprepared_statement (const char *connection_name, const char *name, int lineno) |
static int | HashStmt (const char *ecpgQuery) |
static int | SearchStmtCache (const char *ecpgQuery) |
static int | ecpg_freeStmtCacheEntry (int lineno, int compat, int entNo) |
static int | AddStmtToCache (int lineno, const char *stmtID, const char *connection, int compat, const char *ecpgQuery) |
bool | ecpg_auto_prepare (int lineno, const char *connection_name, const int compat, char **name, const char *query) |
Variables | |
static int | nextStmtID = 1 |
static const int | stmtCacheNBuckets = 2039 |
static const int | stmtCacheEntPerBucket = 8 |
static stmtCacheEntry | stmtCacheEntries [16384] = {{0, {0}, 0, 0, 0}} |
static int AddStmtToCache | ( | int | lineno, | |
const char * | stmtID, | |||
const char * | connection, | |||
int | compat, | |||
const char * | ecpgQuery | |||
) | [static] |
Definition at line 418 of file prepare.c.
References stmtCacheEntry::connection, ecpg_freeStmtCacheEntry(), ecpg_strdup(), stmtCacheEntry::ecpgQuery, stmtCacheEntry::execs, HashStmt(), stmtCacheEntry::lineno, stmtCacheEntPerBucket, and stmtCacheEntry::stmtID.
Referenced by ecpg_auto_prepare().
{ 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(lineno, compat, entNo) < 0) return (-1); /* add the query to the entry */ entry = &stmtCacheEntries[entNo]; entry->lineno = lineno; entry->ecpgQuery = ecpg_strdup(ecpgQuery, lineno); entry->connection = connection; entry->execs = 0; memcpy(entry->stmtID, stmtID, sizeof(entry->stmtID)); return (entNo); }
static bool deallocate_one | ( | int | lineno, | |
enum COMPAT_MODE | c, | |||
struct connection * | con, | |||
struct prepared_statement * | prev, | |||
struct prepared_statement * | this | |||
) | [static] |
Definition at line 201 of file prepare.c.
References statement::command, connection::connection, statement::connection, ecpg_alloc(), ecpg_check_PQresult(), ecpg_free(), ECPG_INVALID_STMT, ecpg_log(), ecpg_raise(), ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, INFORMIX_MODE, statement::lineno, name, prepared_statement::next, NULL, PQclear(), PQexec(), connection::prep_stmts, prepared_statement::prepared, and prepared_statement::stmt.
Referenced by ecpg_deallocate_all_conn(), ecpg_freeStmtCacheEntry(), ECPGdeallocate(), and ECPGprepare().
{ bool r = false; ecpg_log("deallocate_one on line %d: name %s\n", lineno, this->name); /* first deallocate the statement in the backend */ if (this->prepared) { char *text; PGresult *query; text = (char *) ecpg_alloc(strlen("deallocate \"\" ") + strlen(this->name), this->stmt->lineno); if (text) { 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)) { PQclear(query); r = true; } } } /* * 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); ecpg_free(this->name); if (prev != NULL) prev->next = this->next; else con->prep_stmts = this->next; ecpg_free(this); return true; }
bool ecpg_auto_prepare | ( | int | lineno, | |
const char * | connection_name, | |||
const int | compat, | |||
char ** | name, | |||
const char * | query | |||
) |
Definition at line 468 of file prepare.c.
References AddStmtToCache(), ecpg_find_prepared_statement(), ecpg_get_connection(), ecpg_log(), ecpg_strdup(), ECPGprepare(), stmtCacheEntry::execs, nextStmtID, NULL, prepare_common(), SearchStmtCache(), and stmtCacheEntry::stmtID.
Referenced by ECPGdo().
{ int entNo; /* search the statement cache for this statement */ entNo = SearchStmtCache(query); /* if not found - add the statement to the cache */ if (entNo) { char *stmtID; struct connection *con; struct prepared_statement *prep; ecpg_log("ecpg_auto_prepare on line %d: statement found in cache; entry %d\n", lineno, entNo); stmtID = stmtCacheEntries[entNo].stmtID; con = ecpg_get_connection(connection_name); prep = ecpg_find_prepared_statement(stmtID, con, NULL); /* This prepared name doesn't exist on this connection. */ if (!prep && !prepare_common(lineno, con, stmtID, query)) return (false); *name = ecpg_strdup(stmtID, lineno); } else { char stmtID[STMTID_SIZE]; ecpg_log("ecpg_auto_prepare on line %d: statement not in cache; inserting\n", lineno); /* generate a statement ID */ sprintf(stmtID, "ecpg%d", nextStmtID++); if (!ECPGprepare(lineno, connection_name, 0, stmtID, query)) return (false); if (AddStmtToCache(lineno, stmtID, connection_name, compat, query) < 0) return (false); *name = ecpg_strdup(stmtID, lineno); } /* increase usage counter */ stmtCacheEntries[entNo].execs++; return (true); }
bool ecpg_deallocate_all_conn | ( | int | lineno, | |
enum COMPAT_MODE | c, | |||
struct connection * | con | |||
) |
Definition at line 276 of file prepare.c.
References deallocate_one(), NULL, and connection::prep_stmts.
Referenced by ecpg_finish(), and ECPGdeallocate_all().
{ /* deallocate all prepared statements */ while (con->prep_stmts) { if (!deallocate_one(lineno, c, con, NULL, con->prep_stmts)) return false; } return true; }
struct prepared_statement* ecpg_find_prepared_statement | ( | const char * | name, | |
struct connection * | con, | |||
struct prepared_statement ** | prev_ | |||
) | [read] |
Definition at line 182 of file prepare.c.
References prepared_statement::next, NULL, and connection::prep_stmts.
Referenced by ecpg_auto_prepare(), ecpg_freeStmtCacheEntry(), ecpg_prepared(), ECPGdeallocate(), ECPGdescribe(), and ECPGprepare().
{ struct prepared_statement *this, *prev; for (this = con->prep_stmts, prev = NULL; this != NULL; prev = this, this = this->next) { if (strcmp(this->name, name) == 0) { if (prev_) *prev_ = prev; return this; } } return NULL; }
static int ecpg_freeStmtCacheEntry | ( | int | lineno, | |
int | compat, | |||
int | entNo | |||
) | [static] |
Definition at line 383 of file prepare.c.
References stmtCacheEntry::connection, deallocate_one(), ecpg_find_prepared_statement(), ecpg_free(), ecpg_get_connection(), stmtCacheEntry::ecpgQuery, and stmtCacheEntry::stmtID.
Referenced by AddStmtToCache().
{ stmtCacheEntry *entry; struct connection *con; struct prepared_statement *this, *prev; 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 '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 */ if (entry->ecpgQuery) { ecpg_free(entry->ecpgQuery); entry->ecpgQuery = 0; } return (entNo); }
char* ecpg_prepared | ( | const char * | name, | |
struct connection * | con | |||
) |
Definition at line 295 of file prepare.c.
References statement::command, ecpg_find_prepared_statement(), NULL, and prepared_statement::stmt.
Referenced by ECPGdo(), and ECPGprepared_statement().
{ struct prepared_statement *this; this = ecpg_find_prepared_statement(name, con, NULL); return this ? this->stmt->command : NULL; }
bool ECPGdeallocate | ( | int | lineno, | |
int | c, | |||
const char * | connection_name, | |||
const char * | name | |||
) |
Definition at line 253 of file prepare.c.
References deallocate_one(), ecpg_find_prepared_statement(), ecpg_get_connection(), ecpg_init(), ECPG_INVALID_STMT, ecpg_raise(), ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, and INFORMIX_MODE.
Referenced by main().
{ struct connection *con; struct prepared_statement *this, *prev; con = ecpg_get_connection(connection_name); if (!ecpg_init(con, connection_name, lineno)) return false; this = ecpg_find_prepared_statement(name, con, &prev); if (this) return deallocate_one(lineno, c, con, prev, this); /* prepared statement is not found */ if (INFORMIX_MODE(c)) return true; ecpg_raise(lineno, ECPG_INVALID_STMT, ECPG_SQLSTATE_INVALID_SQL_STATEMENT_NAME, name); return false; }
bool ECPGdeallocate_all | ( | int | lineno, | |
int | compat, | |||
const char * | connection_name | |||
) |
Definition at line 289 of file prepare.c.
References ecpg_deallocate_all_conn(), and ecpg_get_connection().
Referenced by main().
{ return ecpg_deallocate_all_conn(lineno, compat, ecpg_get_connection(connection_name)); }
bool ECPGprepare | ( | int | lineno, | |
const char * | connection_name, | |||
const bool | questionmarks, | |||
const char * | name, | |||
const char * | variable | |||
) |
Definition at line 161 of file prepare.c.
References deallocate_one(), ECPG_COMPAT_PGSQL, ecpg_find_prepared_statement(), ecpg_get_connection(), ecpg_init(), and prepare_common().
Referenced by ecpg_auto_prepare(), main(), and test().
{ 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)) return false; /* check if we already have prepared this statement */ this = ecpg_find_prepared_statement(name, con, &prev); if (this && !deallocate_one(lineno, ECPG_COMPAT_PGSQL, con, prev, this)) return false; return prepare_common(lineno, con, name, variable); }
char* ECPGprepared_statement | ( | const char * | connection_name, | |
const char * | name, | |||
int | lineno | |||
) |
Definition at line 306 of file prepare.c.
References ecpg_get_connection(), and ecpg_prepared().
Referenced by main(), and test().
{ (void) lineno; /* keep the compiler quiet */ return ecpg_prepared(name, ecpg_get_connection(connection_name)); }
static int HashStmt | ( | const char * | ecpgQuery | ) | [static] |
Definition at line 316 of file prepare.c.
References stmtCacheEntPerBucket, and stmtCacheNBuckets.
Referenced by AddStmtToCache(), and SearchStmtCache().
{ 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); }
static bool isvarchar | ( | unsigned char | c | ) | [static] |
static bool prepare_common | ( | int | lineno, | |
struct connection * | con, | |||
const char * | name, | |||
const char * | variable | |||
) | [static] |
Definition at line 103 of file prepare.c.
References statement::command, statement::compat, connection::connection, statement::connection, ecpg_alloc(), ecpg_check_PQresult(), ecpg_free(), ecpg_log(), ecpg_strdup(), statement::inlist, statement::lineno, next(), NULL, statement::outlist, PQclear(), PQprepare(), connection::prep_stmts, and replace_variables().
Referenced by ecpg_auto_prepare(), and ECPGprepare().
{ struct statement *stmt; struct prepared_statement *this; PGresult *query; /* allocate new statement */ this = (struct prepared_statement *) ecpg_alloc(sizeof(struct prepared_statement), lineno); if (!this) return false; stmt = (struct statement *) ecpg_alloc(sizeof(struct statement), lineno); if (!stmt) { ecpg_free(this); return false; } /* create statement */ stmt->lineno = lineno; stmt->connection = con; stmt->command = ecpg_strdup(variable, lineno); stmt->inlist = stmt->outlist = NULL; /* if we have C variables in our statement replace them with '?' */ replace_variables(&(stmt->command), lineno); /* add prepared statement to our list */ this->name = ecpg_strdup(name, lineno); this->stmt = stmt; /* and finally really prepare the statement */ query = PQprepare(stmt->connection->connection, name, stmt->command, 0, NULL); if (!ecpg_check_PQresult(query, stmt->lineno, stmt->connection->connection, stmt->compat)) { ecpg_free(stmt->command); ecpg_free(this->name); ecpg_free(this); ecpg_free(stmt); return false; } ecpg_log("prepare_common on line %d: name %s; query: \"%s\"\n", stmt->lineno, name, stmt->command); PQclear(query); this->prepared = true; if (con->prep_stmts == NULL) this->next = NULL; else this->next = con->prep_stmts; con->prep_stmts = this; return true; }
static bool replace_variables | ( | char ** | text, | |
int | lineno | |||
) | [static] |
Definition at line 49 of file prepare.c.
References ecpg_alloc(), ecpg_free(), isvarchar(), and snprintf().
Referenced by prepare_common().
{ bool string = false; int counter = 1, ptr = 0; for (; (*text)[ptr] != '\0'; ptr++) { if ((*text)[ptr] == '\'') string = string ? false : true; if (string || (((*text)[ptr] != ':') && ((*text)[ptr] != '?'))) continue; 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; 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))) { ecpg_free(buffer); return false; } strncpy(newcopy, *text, ptr); strcpy(newcopy + ptr, buffer); 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 */ } } return true; }
static int SearchStmtCache | ( | const char * | ecpgQuery | ) | [static] |
Definition at line 351 of file prepare.c.
References HashStmt(), and stmtCacheEntPerBucket.
Referenced by ecpg_auto_prepare().
{ 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) == 0) break; /* found it */ } ++entNo; /* incr entry # */ } /* if entry wasn't found - set entry # to zero */ if (entIx >= stmtCacheEntPerBucket) entNo = 0; return (entNo); }
int nextStmtID = 1 [static] |
Definition at line 25 of file prepare.c.
Referenced by ecpg_auto_prepare().
const int stmtCacheEntPerBucket = 8 [static] |
Definition at line 27 of file prepare.c.
Referenced by AddStmtToCache(), HashStmt(), and SearchStmtCache().
stmtCacheEntry stmtCacheEntries[16384] = {{0, {0}, 0, 0, 0}} [static] |
const int stmtCacheNBuckets = 2039 [static] |
Definition at line 26 of file prepare.c.
Referenced by HashStmt().