Source file: src/database.h
/* Copyright (C) 2004-2012 Daniel Verite
This file is part of Manitou-Mail (see http://www.manitou-mail.org)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
#ifndef INC_DATABASE_H
#define INC_DATABASE_H
#include <QString>
#include <QThread>
#include <QMutex>
#include <QList>
#include <list>
// PostgreSQL implementation
#include <libpq-fe.h>
#include <libpq/libpq-fs.h>
class db_cnx;
class db_excpt;
class db_listener;
class QSocketNotifier;
/*
Top-level database class.
Implementations for different RDBMS inherit from this class and
override the appropriate functions depending on the database
capabilities and API
*/
class database
{
public:
database();
virtual ~database();
virtual void begin_transaction();
virtual void commit_transaction();
virtual void rollback_transaction();
virtual int logon(const char* conninfo)=0;
virtual void logoff()=0;
virtual bool reconnect()=0;
virtual QString escape_string_literal(const QString)=0;
void end_transaction();
int open_transactions_count() const;
const QString& encoding() const {
return m_encoding;
}
virtual void add_listener(db_listener*)=0;
virtual void remove_listener(db_listener*)=0;
protected:
int set_encoding(const QString encoding) {
m_encoding=encoding;
return 0;
}
private:
/* Number of open transactions.
This is used to allow for nested beginTransaction/endTransactions
pairs in a RDBMS where commit blocks are not nested (i.e. commit
or rollback is applied to all changes that occurred after the
last commit or rollback, without savepoints like in Oracle).
commit or rollback issued in non-top level transactions blocks
will be ignored; only the top level transaction commit or
rollback will be sent to the db backend, thus commiting or
rolling back all the changes made in the nested transactions as
well as in the top level block. */
int m_open_trans_count;
// currently SQL_ASCII or UNICODE
QString m_encoding;
};
/// Connection class
class db_cnx_elt
{
public:
db_cnx_elt() {
m_available=true;
m_connected=false;
}
database* m_db;
bool m_available;
bool m_connected;
};
class pgConnection;
class pg_notifier: public QObject
{
Q_OBJECT
public:
pg_notifier(pgConnection* cnx);
~pg_notifier();
private slots:
void process_notification();
private:
QSocketNotifier* m_socket_notifier;
pgConnection* m_pgcnx;
};
class pgConnection : public database
{
public:
pgConnection(): m_pgConn(NULL), m_notifier(NULL) {}
virtual ~pgConnection() {
logoff();
}
int logon(const char* conninfo);
void logoff();
bool reconnect();
bool ping();
QString escape_string_literal(const QString);
PGconn* connection() {
return m_pgConn;
}
QList<db_listener*> m_listeners;
void add_listener(db_listener*);
void remove_listener(db_listener*);
private:
PGconn* m_pgConn;
pg_notifier* m_notifier;
};
/*
db_cnx is instantiated when there is a need to query the database
and destroyed when it's finished. It does not reconnect each time
but rather reuse connections previously that are maintained opened.
*/
class db_cnx
{
public:
db_cnx(bool other_thread=false);
virtual ~db_cnx();
PGconn* connection() {
return m_cnx->connection();
}
database* datab() {
return m_cnx;
}
const database* cdatab() const {
return m_cnx;
}
bool next_seq_val(const char*, int*);
bool next_seq_val(const char*, unsigned int*);
// overrides database's methods
void begin_transaction();
void commit_transaction();
void rollback_transaction();
void end_transaction() {
m_cnx->end_transaction();
}
static void set_connect_string(const char* cnx);
static void set_dbname(const QString dbname);
static void disconnect_all();
static bool idle();
void enable_user_alerts(bool); // return previous state
bool ping();
void handle_exception(db_excpt& e);
static const QString& dbname();
QString escape_string_literal(const QString);
private:
pgConnection* m_cnx;
bool m_alerts_enabled;
static std::list<db_cnx_elt*> m_cnx_list;
static QMutex m_mutex;
static bool m_initialized;
static QString m_connect_string;
static QString m_dbname;
};
// Transaction object. The destructor issues a rollback if commit has
// not been called and we're a top level transaction within our
// connection
class db_transaction
{
public:
// db_transaction(database& db);
db_transaction(db_cnx& d);
virtual ~db_transaction();
void commit();
void rollback();
private:
db_cnx* m_pDb;
bool m_commit_done;
};
//#define db_cnx pgConnect
/// sql Exception class
class db_excpt
{
public:
db_excpt() {}
db_excpt(const QString query, db_cnx& d);
// defined in db.cpp
db_excpt(const QString query, const QString msg, QString code=QString::null);
virtual ~db_excpt() {}
QString query() const { return m_query; }
QString errmsg() const { return m_err_msg; }
QString errcode() const { return m_err_code; }
bool unique_constraint_violation() const {
return m_err_code=="23505";
}
private:
QString m_query;
QString m_err_msg;
QString m_err_code;
};
void DBEXCPT(db_excpt& p); // db.cpp
#endif // INC_DATABASE_H
HTML source code generated by GNU Source-Highlight plus some custom post-processing
List of all available source files