added: TextStream a class similar to std::ostringstream
but with a Clear() method the dynamic allocated buffer can be easily reused added: DbTextStream a special version of a stream used to create a database string query everything is escaped by default added: DbBase a base class with some basic methods for communicating with the database added: DbConn a class for managing connection to the database changed: some refactoring in Db class git-svn-id: svn://ttmath.org/publicrep/winix/trunk@655 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
301
db/dbbase.cpp
Executable file
301
db/dbbase.cpp
Executable file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* This file is a part of Winix
|
||||
* and is not publicly distributed
|
||||
*
|
||||
* Copyright (c) 2010, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dbbase.h"
|
||||
#include "core/log.h"
|
||||
#include "core/error.h"
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <limits>
|
||||
|
||||
|
||||
|
||||
DbBase::DbBase()
|
||||
{
|
||||
db_conn = 0;
|
||||
log_queries = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DbBase::SetConn(DbConn * conn)
|
||||
{
|
||||
db_conn = conn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DbBase::SetConn(DbConn & conn)
|
||||
{
|
||||
db_conn = &conn;
|
||||
}
|
||||
|
||||
|
||||
DbConn * DbBase::GetConn()
|
||||
{
|
||||
return db_conn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DbBase::LogQueries(bool log_q)
|
||||
{
|
||||
log_queries = log_q;
|
||||
}
|
||||
|
||||
|
||||
|
||||
PGresult * DbBase::AssertQuery(const char * q)
|
||||
{
|
||||
if( log_queries )
|
||||
log << log1 << "Db: executing query: " << q << logend;
|
||||
|
||||
bool bad_query = false;
|
||||
PGresult * r = PQexec(db_conn->GetPgConn(), q);
|
||||
|
||||
if( !r )
|
||||
{
|
||||
bad_query = true;
|
||||
|
||||
if( PQstatus(db_conn->GetPgConn()) != CONNECTION_OK )
|
||||
{
|
||||
db_conn->AssertConnection();
|
||||
r = PQexec(db_conn->GetPgConn(), q);
|
||||
|
||||
if( r )
|
||||
bad_query = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( bad_query )
|
||||
{
|
||||
log << log1 << "Db: Problem with this query: \"" << q << '\"' << logend;
|
||||
log << log1 << "Db: " << PQerrorMessage(db_conn->GetPgConn()) << logend;
|
||||
|
||||
throw Error(WINIX_ERR_DB_INCORRECT_QUERY);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
PGresult * DbBase::AssertQuery(const std::string & q)
|
||||
{
|
||||
return AssertQuery(q.c_str());
|
||||
}
|
||||
|
||||
|
||||
PGresult * DbBase::AssertQuery(const DbTextStream & query)
|
||||
{
|
||||
return AssertQuery(query.CStr());
|
||||
}
|
||||
|
||||
|
||||
void DbBase::AssertResult(PGresult * r, ExecStatusType t)
|
||||
{
|
||||
if( PQresultStatus(r) != t )
|
||||
{
|
||||
log << "Db: Incorrect result status: " << PQerrorMessage(db_conn->GetPgConn()) << logend;
|
||||
|
||||
throw Error(WINIX_ERR_DB_INCORRENT_RESULT_STATUS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int DbBase::AssertColumn(PGresult * r, const char * column_name)
|
||||
{
|
||||
int c = PQfnumber(r, column_name);
|
||||
|
||||
if( c == -1 )
|
||||
{
|
||||
log << log1 << "Db: there is no column: " << column_name << logend;
|
||||
|
||||
throw Error(WINIX_ERR_DB_NO_COLUMN);
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
const char * DbBase::AssertValue(PGresult * r, int row, int col)
|
||||
{
|
||||
const char * res = PQgetvalue(r, row, col);
|
||||
|
||||
if( !res )
|
||||
{
|
||||
log << log1 << "Db: there is no such an item in the result, row:" << row << ", col:" << col << logend;
|
||||
|
||||
throw Error(WINIX_ERR_NO_ITEM);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
long DbBase::AssertValueLong(PGresult * r, int row, int col)
|
||||
{
|
||||
return strtol( AssertValue(r, row, col), 0, 10 );
|
||||
}
|
||||
|
||||
|
||||
int DbBase::AssertValueInt(PGresult * r, int row, int col)
|
||||
{
|
||||
return (int)strtol( AssertValue(r, row, col), 0, 10 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned long DbBase::AssertValueULong(PGresult * r, int row, int col)
|
||||
{
|
||||
return strtoul( AssertValue(r, row, col), 0, 10 );
|
||||
}
|
||||
|
||||
|
||||
unsigned int DbBase::AssertValueUInt(PGresult * r, int row, int col)
|
||||
{
|
||||
return (unsigned int)strtoul( AssertValue(r, row, col), 0, 10 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DbBase::ClearResult(PGresult * r)
|
||||
{
|
||||
if( r )
|
||||
PQclear(r);
|
||||
}
|
||||
|
||||
|
||||
bool DbBase::IsNull(PGresult * r, int row, int col)
|
||||
{
|
||||
return PQgetisnull(r, row, col) == 1;
|
||||
}
|
||||
|
||||
|
||||
int DbBase::Rows(PGresult * r)
|
||||
{
|
||||
// PQntuples - Returns the number of rows (tuples) in the query result. Because it returns
|
||||
// an integer result, large result sets might overflow the return value on 32-bit operating systems.
|
||||
return PQntuples(r);
|
||||
}
|
||||
|
||||
|
||||
int DbBase::Cols(PGresult * r)
|
||||
{
|
||||
// PQnfields - Returns the number of columns (fields) in each row of the query result.
|
||||
return PQnfields(r);
|
||||
}
|
||||
|
||||
|
||||
long DbBase::AffectedRows(PGresult * r)
|
||||
{
|
||||
// PQcmdTuples - This function returns a string containing the number of rows affected by the SQL
|
||||
// statement that generated the PGresult. This function can only be used following the execution
|
||||
// of an INSERT, UPDATE, DELETE, MOVE, FETCH, or COPY statement, or [...]
|
||||
char * rows_str = PQcmdTuples(r); // can be an empty string
|
||||
long rows = 0;
|
||||
|
||||
if( rows_str )
|
||||
{
|
||||
rows = strtol(rows_str, 0, 10);
|
||||
// strtol - If an overflow or underflow occurs, errno is set to ERANGE
|
||||
// and the function return value is clamped according to the following table:
|
||||
// Function underflow overflow
|
||||
// strtol() LONG_MIN LONG_MAX
|
||||
|
||||
if( rows < 0 )
|
||||
rows = 0;
|
||||
}
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
|
||||
long DbBase::AssertCurrval(const char * table)
|
||||
{
|
||||
PGresult * r;
|
||||
|
||||
bquery.Clear();
|
||||
bquery << R("select currval(")
|
||||
<< table
|
||||
<< R(");");
|
||||
|
||||
r = AssertQuery(bquery);
|
||||
AssertResult(r, PGRES_TUPLES_OK);
|
||||
|
||||
if( Rows(r) != 1 )
|
||||
{
|
||||
log << log1 << "Db: error (currval) for table: " << table << ", " << PQerrorMessage(db_conn->GetPgConn()) << logend;
|
||||
throw Error(WINIX_ERR_DB_ERR_CURRVAL);
|
||||
}
|
||||
|
||||
return AssertValueLong(r, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
tm DbBase::ConvertTime(const char * str)
|
||||
{
|
||||
tm t;
|
||||
|
||||
memset(&t, 0, sizeof(t));
|
||||
|
||||
if( !str )
|
||||
return t;
|
||||
|
||||
size_t len = strlen(str);
|
||||
|
||||
if( len != 19 )
|
||||
{
|
||||
// the format must be like this: 2008-12-31 22:30:00
|
||||
log << log1 << "DbBase: ConvertTime: unknown time format: \"" << str << "\"";
|
||||
return t;
|
||||
}
|
||||
|
||||
t.tm_year = atoi(str + 0) - 1900; /* year - 1900 */
|
||||
t.tm_mon = atoi(str + 5) - 1; /* month of year (0 - 11) */
|
||||
t.tm_mday = atoi(str + 8); /* day of month (1 - 31) */
|
||||
t.tm_hour = atoi(str + 11); /* hours (0 - 23) */
|
||||
t.tm_min = atoi(str + 14); /* minutes (0 - 59) */
|
||||
t.tm_sec = atoi(str + 17); /* seconds (0 - 60) */
|
||||
|
||||
// t.tm_wday = 0; /* day of week (Sunday = 0) */
|
||||
// t.tm_yday = 0; /* day of year (0 - 365) */
|
||||
// t.tm_isdst = 0; /* is summer time in effect? */
|
||||
// t.tm_zone = 0; // const_cast<char*>(""); /* abbreviation of timezone name */
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
const char * DbBase::ConvertTime(const tm & t)
|
||||
{
|
||||
// not thread safe
|
||||
static char buffer[100];
|
||||
|
||||
sprintf(buffer, "%04d-%02d-%02d %02d:%02d:%02d",
|
||||
t.tm_year + 1900,
|
||||
t.tm_mon + 1,
|
||||
t.tm_mday,
|
||||
t.tm_hour,
|
||||
t.tm_min,
|
||||
t.tm_sec);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user