24 #define MAKE_SQLSTATE(ch1,ch2,ch3,ch4,ch5) {ch1,ch2,ch3,ch4,ch5}
26 #define PGSQL_STATECODE_LEN 5
27 #include <utils/errcodes.h>
41 const char PgSqlConnection::DUPLICATE_KEY[] = ERRCODE_UNIQUE_VIOLATION;
42 const char PgSqlConnection::NULL_KEY[] = ERRCODE_NOT_NULL_VIOLATION;
44 bool PgSqlConnection::warned_about_tls =
false;
46 PgSqlResult::PgSqlResult(PGresult *result)
47 : result_(result), rows_(0), cols_(0) {
56 rows_ = PQntuples(result);
57 cols_ = PQnfields(result);
63 if (row < 0 || row >= rows_) {
65 <<
", out of range: 0.." << rows_);
77 if (col < 0 || col >= cols_) {
79 <<
", out of range: 0.." << cols_);
91 const char* label = NULL;
94 label = PQfname(result_, col);
96 std::ostringstream os;
97 os <<
"Unknown column:" << col;
105 : conn_(conn), committed_(false) {
125 if (PQstatus(
conn_) == CONNECTION_OK) {
127 if (PQresultStatus(r) != PGRES_COMMAND_OK) {
136 std::pair<uint32_t, uint32_t>
142 conn.openDatabaseInternal(
false);
144 const char* version_sql =
"SELECT version, minor FROM schema_version;";
146 if (PQresultStatus(r) != PGRES_TUPLES_OK) {
148 << version_sql <<
", reason: " << PQerrorMessage(conn.
conn_));
157 return (make_pair(
version, minor));
165 if (PQresultStatus(r) != PGRES_COMMAND_OK) {
167 <<
" name: " << statement.
name
168 <<
", reason: " << PQerrorMessage(
conn_)
169 <<
", text: " << statement.
text);
178 tagged_statement != end_statement; ++tagged_statement) {
185 return (getConnParametersInternal(
false));
189 PgSqlConnection::getConnParametersInternal(
bool logging) {
190 string dbconnparameters;
191 string shost =
"localhost";
198 dbconnparameters +=
"host = '" + shost +
"'" ;
200 unsigned int port = 0;
202 setIntParameterValue(
"port", 0, numeric_limits<uint16_t>::max(), port);
204 }
catch (
const std::exception& ex) {
210 std::ostringstream oss;
212 dbconnparameters +=
" port = " + oss.str();
218 dbconnparameters +=
" user = '" + suser +
"'";
226 dbconnparameters +=
" password = '" + spassword +
"'";
234 dbconnparameters +=
" dbname = '" + sname +
"'";
237 isc_throw(NoDatabaseName,
"must specify a name for the database");
241 unsigned int tcp_user_timeout = 0;
246 setIntParameterValue(
"connect-timeout", 1, numeric_limits<int>::max(), connect_timeout);
251 setIntParameterValue(
"tcp-user-timeout", 0, numeric_limits<int>::max(), tcp_user_timeout);
253 }
catch (
const std::exception& ex) {
258 std::ostringstream oss;
259 oss <<
" connect_timeout = " << connect_timeout;
261 if (tcp_user_timeout > 0) {
263 #ifdef HAVE_PGSQL_TCP_USER_TIMEOUT
264 oss <<
" tcp_user_timeout = " << tcp_user_timeout * 1000;
265 static_cast<void>(logging);
272 dbconnparameters += oss.str();
274 return (dbconnparameters);
279 openDatabaseInternal(
true);
283 PgSqlConnection::openDatabaseInternal(
bool logging) {
284 std::string dbconnparameters = getConnParametersInternal(logging);
287 PGconn* new_conn = PQconnectdb(dbconnparameters.c_str());
292 if (PQstatus(new_conn) != CONNECTION_OK) {
295 std::string error_message = PQerrorMessage(new_conn);
306 const char* sqlstate = PQresultErrorField(r, PG_DIAG_SQLSTATE);
308 return ((sqlstate != NULL) &&
315 int s = PQresultStatus(r);
316 if (s != PGRES_COMMAND_OK && s != PGRES_TUPLES_OK) {
321 const char* sqlstate = PQresultErrorField(r, PG_DIAG_SQLSTATE);
322 if ((sqlstate == NULL) ||
323 ((memcmp(sqlstate,
"08", 2) == 0) ||
324 (memcmp(sqlstate,
"53", 2) == 0) ||
325 (memcmp(sqlstate,
"54", 2) == 0) ||
326 (memcmp(sqlstate,
"57", 2) == 0) ||
327 (memcmp(sqlstate,
"58", 2) == 0))) {
331 .
arg(sqlstate ? sqlstate :
"<sqlstate null>");
342 "fatal database error or connectivity lost");
348 <<
", reason: " << PQerrorMessage(
conn_));
354 <<
", reason: " << PQerrorMessage(
conn_));
358 const char* error_message = PQerrorMessage(
conn_);
360 << statement.
name <<
", status: " << s
361 <<
"sqlstate:[ " << (sqlstate ? sqlstate :
"<null>")
362 <<
" ], reason: " << error_message);
376 if (PQresultStatus(r) != PGRES_COMMAND_OK) {
377 const char* error_message = PQerrorMessage(
conn_);
402 if (PQresultStatus(r) != PGRES_COMMAND_OK) {
403 const char* error_message = PQerrorMessage(
conn_);
422 if (PQresultStatus(r) != PGRES_COMMAND_OK) {
423 const char* error_message = PQerrorMessage(
conn_);
435 std::string sql(
"SAVEPOINT " + name);
445 std::string sql(
"ROLLBACK TO SAVEPOINT " + name);
466 <<
" expected: " << statement.
nbparams
467 <<
" parameters, given: " << in_bindings.
size()
468 <<
", statement: " << statement.
name
469 <<
", SQL: " << statement.
text);
472 const char*
const* values = 0;
473 const int* lengths = 0;
474 const int* formats = 0;
476 values =
static_cast<const char* const*
>(&in_bindings.
values_[0]);
477 lengths =
static_cast<const int *
>(&in_bindings.
lengths_[0]);
478 formats =
static_cast<const int *
>(&in_bindings.
formats_[0]);
483 values, lengths, formats, 0)));
498 int rows = result_set->getRows();
499 for (
int row = 0; row < rows; ++row) {
501 process_result_row(*result_set, row);
502 }
catch (
const std::exception& ex) {
505 statement.
text <<
">");
523 return (boost::lexical_cast<int>(PQcmdTuples(*result_set)));
528 PgSqlConnection::setIntParameterValue(
const std::string& name, int64_t min, int64_t max, T& value) {
535 if (svalue.empty()) {
540 auto parsed_value = boost::lexical_cast<T>(svalue);
542 if ((parsed_value < min) || (parsed_value > max)) {
543 isc_throw(BadValue,
"bad " << svalue <<
" value");
546 value = parsed_value;
552 isc_throw(BadValue, name <<
" parameter (" <<
553 svalue <<
") must be an integer between "
554 << min <<
" and " << max);
int version()
returns Kea hooks version.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown if a function is called in a prohibited way.
A generic exception that is thrown when an unexpected error condition occurs.
std::string getParameter(const std::string &name) const
Returns value of a connection parameter.
void markUnusable()
Sets the unusable flag to true.
void checkUnusable()
Throws an exception if the connection is not usable.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
Exception thrown when a specific connection has been rendered unusable either through loss of connect...
Exception thrown on failure to open database.
Exception thrown on failure to execute a database function.
Database duplicate entry error.
Key is NULL but was specified NOT NULL.
Common PgSql Connector Pool.
void startTransaction()
Starts new transaction.
void rollback()
Rollbacks current transaction.
void createSavepoint(const std::string &name)
Creates a savepoint within the current transaction.
uint64_t updateDeleteQuery(PgSqlTaggedStatement &statement, const PsqlBindArray &in_bindings)
Executes UPDATE or DELETE prepared statement and returns the number of affected rows.
int transaction_ref_count_
Reference counter for transactions.
void selectQuery(PgSqlTaggedStatement &statement, const PsqlBindArray &in_bindings, ConsumeResultRowFun process_result_row)
Executes SELECT query using prepared statement.
bool compareError(const PgSqlResult &r, const char *error_state)
Checks a result set's SQL state against an error state.
std::string getConnParameters()
Creates connection string from specified parameters.
static const char NULL_KEY[]
Define the PgSql error state for a null foreign key error.
std::function< void(PgSqlResult &, int)> ConsumeResultRowFun
Function invoked to process fetched row.
void prepareStatement(const PgSqlTaggedStatement &statement)
Prepare Single Statement.
static const char DUPLICATE_KEY[]
Define the PgSql error state for a duplicate key error.
PgSqlResultPtr executePreparedStatement(PgSqlTaggedStatement &statement, const PsqlBindArray &in_bindings=PsqlBindArray())
Executes a prepared SQL statement.
bool isTransactionStarted() const
Checks if there is a transaction in progress.
static std::pair< uint32_t, uint32_t > getVersion(const ParameterMap ¶meters)
Get the schema version.
PgSqlHolder conn_
PgSql connection handle.
void rollbackToSavepoint(const std::string &name)
Rollbacks to the given savepoint.
void startRecoverDbConnection()
The recover connection.
void insertQuery(PgSqlTaggedStatement &statement, const PsqlBindArray &in_bindings)
Executes INSERT prepared statement.
void commit()
Commits current transaction.
void executeSQL(const std::string &sql)
Executes the an SQL statement.
virtual ~PgSqlConnection()
Destructor.
void checkStatementError(const PgSqlResult &r, PgSqlTaggedStatement &statement)
Checks result of the r object.
void prepareStatements(const PgSqlTaggedStatement *start_statement, const PgSqlTaggedStatement *end_statement)
Prepare statements.
void openDatabase()
Open database with logging.
static void getColumnValue(const PgSqlResult &r, const int row, const size_t col, std::string &value)
Fetches text column value as a string.
void setConnection(PGconn *connection)
Sets the connection to the value given.
RAII wrapper for PostgreSQL Result sets.
void colCheck(int col) const
Determines if a column index is valid.
void rowCheck(int row) const
Determines if a row index is valid.
void rowColCheck(int row, int col) const
Determines if both a row and column index are valid.
~PgSqlResult()
Destructor.
std::string getColumnLabel(const int col) const
Fetches the name of the column in a result set.
PgSqlTransaction(PgSqlConnection &conn)
Constructor.
void commit()
Commits transaction.
~PgSqlTransaction()
Destructor.
We want to reuse the database backend connection and exchange code for other uses,...
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
const int DB_DBG_TRACE_DETAIL
Database logging levels.
const int PGSQL_DEFAULT_CONNECTION_TIMEOUT
@ PGSQL_TCP_USER_TIMEOUT_UNSUPPORTED
@ PGSQL_START_TRANSACTION
boost::shared_ptr< PgSqlResult > PgSqlResultPtr
const size_t OID_NONE
Constants for PostgreSQL data types These are defined by PostgreSQL in <catalog/pg_type....
Defines the logger used by the top-level component of kea-lfc.
#define PGSQL_STATECODE_LEN
DB_LOG & arg(T first, Args... args)
Pass parameters to replace logger placeholders.
Define a PostgreSQL statement.
int nbparams
Number of parameters for a given query.
const char * text
Text representation of the actual query.
const char * name
Short name of the query.
const Oid types[PGSQL_MAX_PARAMETERS_IN_QUERY]
OID types.
std::vector< const char * > values_
Vector of pointers to the data values.
std::vector< int > formats_
Vector of "format" for each value.
size_t size() const
Fetches the number of entries in the array.
std::vector< int > lengths_
Vector of data lengths for each value.