|
/**
* @(#)dsqlxprez_2.cpp 1.0.0
*
* Copyright 2004 Vijay Mathew Pandyalakal. All rights reserved.
*
* Change history:
* Created on July 26, 2004
* Last Modified on January 11, 2007
*
*/
#include <algorithm>
#include <iterator>
#include <sstream>
#include "dsqlxprez_2.h"
/**
* This file defines C++ abtractions to provide a JDBC style interface to SQLite.
* @author Vijay Mathew Pandyalakal
* @since 1.0.0
*/
// class SqlException
/**
* Creates an exception with the given code
* @param code error code
* @since 1.0.0
*/
dsqlxprez::SQLException::SQLException(int code)
: m_nCode(code)
{
setMessageFromCode();
}
/**
* Creates an exception with the given message
* @param msg Error message
* @since 1.0.0
*/
dsqlxprez::SQLException::SQLException(std::string msg)
: m_nCode(0), m_strMsg(msg)
{
}
dsqlxprez::SQLException::~SQLException() throw () { }
const char*
dsqlxprez::SQLException::what() const throw()
{
std::ostringstream oss;
oss << m_nCode << ": " << m_strMsg;
return oss.str().c_str();
}
/**
* Returns the error code
* @return int
* @since 1.0.0
*/
int
dsqlxprez::SQLException::getCode()
{
return m_nCode;
}
/**
* Returns the error message
* @return string
* @since 1.0.0
*/
std::string
dsqlxprez::SQLException::getMessage()
{
return m_strMsg;
}
/**
* Creates a message from the current error code
* @since 1.0.0
*/
void
dsqlxprez::SQLException::setMessageFromCode()
{
if (m_nCode == SQLITE_ERROR) m_strMsg = "SQL error or missing database";
else if(m_nCode == SQLITE_INTERNAL) m_strMsg = "An internal logic error in the database";
else if(m_nCode == SQLITE_PERM) m_strMsg = "Access permission denied";
else if(m_nCode == SQLITE_ABORT) m_strMsg = "Callback routine requested an abort";
else if(m_nCode == SQLITE_BUSY) m_strMsg = "The database file is locked";
else if(m_nCode == SQLITE_LOCKED) m_strMsg = "A table in the database is locked";
else if(m_nCode == SQLITE_NOMEM) m_strMsg = "A memory allocation failed in the database";
else if(m_nCode == SQLITE_READONLY) m_strMsg = "Attempt to write a readonly database";
else if(m_nCode == SQLITE_INTERRUPT) m_strMsg = "Operation terminated by a database interrupt";
else if(m_nCode == SQLITE_IOERR) m_strMsg = "Some kind of disk I/O error occurred";
else if(m_nCode == SQLITE_CORRUPT) m_strMsg = "The database disk image is malformed";
else if(m_nCode == SQLITE_NOTFOUND) m_strMsg = "Table or record not found";
else if(m_nCode == SQLITE_FULL) m_strMsg = "Insertion failed because database is full";
else if(m_nCode == SQLITE_CANTOPEN) m_strMsg = "Unable to open the database file";
else if(m_nCode == SQLITE_PROTOCOL) m_strMsg = "Database lock protocol error";
else if(m_nCode == SQLITE_EMPTY) m_strMsg = "Database table is empty";
else if(m_nCode == SQLITE_SCHEMA) m_strMsg = "The database schema changed";
else if(m_nCode == SQLITE_TOOBIG) m_strMsg = "Too much data for one row of a table";
else if(m_nCode == SQLITE_CONSTRAINT) m_strMsg = "Abort due to contraint violation";
else if(m_nCode == SQLITE_MISMATCH) m_strMsg = "Data type mismatch";
else if(m_nCode == SQLITE_MISUSE) m_strMsg = "Library used incorrectly";
else if(m_nCode == SQLITE_NOLFS) m_strMsg = "Uses OS features not supported on host";
else if(m_nCode == SQLITE_AUTH) m_strMsg = "Authorization denied";
else m_strMsg = "Unknown database error";
}
// class Connection
/**
* Constructor
* @since 1.0.0
*/
dsqlxprez::Connection::Connection()
: m_sqlite(0), m_stmt(0), m_dbMtdt(0)
{
}
/**
* Destructor
* @since 1.0.0
*/
dsqlxprez::Connection::~Connection()
{
close();
}
/**
* Opens a database. The database is created, if not found.
* @param db_name database name
* @since 1.0.0
*/
void
dsqlxprez::Connection::open(const char* db_name)
throw (dsqlxprez::SQLException)
{
close();
int ret = sqlite3_open(db_name,&m_sqlite);
if (ret != SQLITE_OK)
{
close();
throw dsqlxprez::SQLException(ret);
}
m_dbMtdt = NULL;
// fills in the DatabaseMetaData
refreshMetaData();
}
/**
* Creates and returns a statement object
* @return Statement*
* @since 1.0.0
*/
dsqlxprez::Statement*
dsqlxprez::Connection::createStatement()
{
delete m_stmt;
m_stmt = new Statement(m_sqlite);
return m_stmt;
}
/**
* Returns meta data of the entire database
* @return DatabaseMetaData*
* @since 1.0.0
*/
dsqlxprez::DatabaseMetaData*
dsqlxprez::Connection::getDatabaseMetaData()
{
return m_dbMtdt;
}
/**
* Refreshes the meta data
* @since 1.0.0
*/
void
dsqlxprez::Connection::refreshMetaData() throw (SQLException)
{
sqlite3_stmt *stmt;
std::string sql = "select type,name,sql from sqlite_master";
int ret = sqlite3_prepare(m_sqlite,sql.c_str(),sql.length(),&stmt,NULL);
if (ret != SQLITE_OK)
throw dsqlxprez::SQLException(ret);
int res = sqlite3_step(stmt);
std::vector<dsqlxprez::DatabaseObject> vct;
while (true)
{
if (res != SQLITE_ROW && res != SQLITE_OK && res != SQLITE_DONE)
throw dsqlxprez::SQLException(res);
if (res != SQLITE_ROW) break;
dsqlxprez::DatabaseObject dobj;
dobj.type_ = (const char*)sqlite3_column_text(stmt,0);
dobj.name_ = (const char*)sqlite3_column_text(stmt,1);
dobj.sql_ = (const char*)sqlite3_column_text(stmt,2);
vct.push_back(dobj);
res = sqlite3_step(stmt);
}
sqlite3_finalize(stmt);
delete m_dbMtdt;
m_dbMtdt = new dsqlxprez::DatabaseMetaData(vct);
}
/**
* Closes the database and releases all resources
* @since 1.0.0
*/
void
dsqlxprez::Connection::close()
{
delete m_stmt;
m_stmt = NULL;
delete m_dbMtdt;
m_dbMtdt = NULL;
if (m_sqlite != NULL)
{
sqlite3_close(m_sqlite);
m_sqlite = NULL;
}
}
// class Statement
/**
* Constructor
* @param pS Handle to the core database
* @since 1.0.0
*/
dsqlxprez::Statement::Statement(sqlite3* pS)
: m_sqlite(pS), m_rslt(0)
{
}
/**
* Destructor
* @since 1.0.0
*/
dsqlxprez::Statement::~Statement()
{
delete m_rslt;
}
/**
* Executes an sql and returns the number of rows affected
* @param sql SQL to execute
* @since 1.0.0
*/
int
dsqlxprez::Statement::execute(const char* sql) throw (dsqlxprez::SQLException)
{
int ret = sqlite3_exec(m_sqlite,sql,0,0,0);
if (ret != SQLITE_OK)
throw dsqlxprez::SQLException(ret);
return sqlite3_changes(m_sqlite);
}
/**
* Executes an sql and returns a pointer to the resultset
* @param sql SQL query
* @since 1.0.0
*/
dsqlxprez::ResultSet*
dsqlxprez::Statement::executeQuery(const char* sql)
throw (dsqlxprez::SQLException)
{
sqlite3_stmt *stmt;
int ret = sqlite3_prepare(m_sqlite,sql,strlen(sql),&stmt,NULL);
if (ret != SQLITE_OK) throw dsqlxprez::SQLException(ret);
delete m_rslt;
m_rslt = new ResultSet(stmt);
return m_rslt;
}
// class ResultSet
/**
* Constructor
* @param ps Pointer to sqlite statement object
* since 1.0.0
*/
dsqlxprez::ResultSet::ResultSet(sqlite3_stmt* ps)
throw (dsqlxprez::SQLException)
{
if (ps == NULL) throw dsqlxprez::SQLException("NULL statement object");
m_stmt = ps;
m_nRes = sqlite3_step(m_stmt);
if (m_nRes != SQLITE_OK && m_nRes != SQLITE_ROW && m_nRes != SQLITE_DONE)
throw dsqlxprez::SQLException(m_nRes);
m_bSecondStep = true;
std::vector<Column> vct;
int col_count = sqlite3_column_count(m_stmt);
for (int i=0;i<col_count;i++)
{
Column col;
col.name_ = sqlite3_column_name(m_stmt,i);
try
{
const char* type = sqlite3_column_decltype(m_stmt,i);
if (type)
col.type_ = type;
else
col.type_ = "VARIANT"; // is this selection good?
}
catch(...)
{
col.type_ = "VARIANT";
}
vct.push_back(col);
}
m_rsltMtdt = new ResultSetMetaData(vct);
}
/**
* Destructor
* @since 1.0.0
*/
dsqlxprez::ResultSet::~ResultSet()
{
if (m_stmt != NULL)
{
sqlite3_finalize(m_stmt);
m_stmt = NULL;
}
delete m_rsltMtdt;
}
/**
* Moves to the next row of the resultset
* @return bool
* @since 1.0.0
*/
bool
dsqlxprez::ResultSet::next() throw (dsqlxprez::SQLException)
{
if (m_nRes != SQLITE_ROW) return false;
if (m_bSecondStep)
{
m_bSecondStep = false;
return true;
}
m_nRes = sqlite3_step(m_stmt);
if (m_nRes != SQLITE_OK && m_nRes != SQLITE_ROW && m_nRes != SQLITE_DONE)
throw dsqlxprez::SQLException(m_nRes);
if (m_nRes == SQLITE_DONE) return false;
return true;
}
/**
* Returns true if the given column has a null value
* @return bool
* @since 1.0.0
*/
bool
dsqlxprez::ResultSet::isNull(int colNum) throw (dsqlxprez::SQLException)
{
// as of now we don't support null
return false;
}
/**
* Returns data of column as a string
* @param colNum Column number, starting at 1
* @return const char*
* @since 1.0.0
*/
std::string
dsqlxprez::ResultSet::getString(int colNum) throw (dsqlxprez::SQLException)
{
int i = colNum-1;
if (i < 0) throw dsqlxprez::SQLException("Invalid column number");
std::string ret = (const char*)sqlite3_column_text(m_stmt,(i));
return ret;
}
/**
* Returns data of column as an int
* @param colNum Column number, starting at 1
* @return int
* @since 1.0.0
*/
int
dsqlxprez::ResultSet::getInt(int colNum) throw (dsqlxprez::SQLException)
{
return atoi(getString(colNum).c_str());
}
/**
* Returns data of column as a Long
* @param colNum Column number, starting at 1
* @return long
* @since 1.0.0
*/
long
dsqlxprez::ResultSet::getLong(int colNum) throw (dsqlxprez::SQLException)
{
return atol(getString(colNum).c_str());
}
/**
* Returns data of column as an unsiged int
* @param colNum Column number, starting at 1
* @return unsigned int
* @since 1.0.0
*/
unsigned int
dsqlxprez::ResultSet::getUInt(int colNum) throw (dsqlxprez::SQLException)
{
return (unsigned int)atoi(getString(colNum).c_str());
}
/**
* Returns data of column as a unsigned long
* @param colNum Column number, starting at 1
* @return unsigned long
* @since 1.0.0
*/
unsigned long
dsqlxprez::ResultSet::getULong(int colNum) throw (dsqlxprez::SQLException)
{
return (unsigned long)atol(getString(colNum).c_str());
}
/**
* Returns data of column as a float
* @param colNum Column number, starting at 1
* @return float
* @since 1.0.0
*/
float
dsqlxprez::ResultSet::getFloat(int colNum) throw (dsqlxprez::SQLException)
{
return atof(getString(colNum).c_str());
}
/**
* Returns data of column as a double
* @param colNum Column number, starting at 1
* @return double
* @since 1.0.0
*/
double
dsqlxprez::ResultSet::getDouble(int colNum) throw (dsqlxprez::SQLException)
{
return (double)atof(getString(colNum).c_str());
}
namespace
{
const std::string to_lower(const std::string& s)
{
std::string res;
std::transform(s.begin(), s.end(), std::back_inserter(res), tolower);
return res;
}
}
/**
* Returns data of column as a bool
* @param colNum Column number, starting at 1
* @return double
* @since 1.0.0
*/
bool
dsqlxprez::ResultSet::getBoolean(int colNum) throw (dsqlxprez::SQLException)
{
std::string str = to_lower(getString(colNum));
return (str == "true" || str == "1");
}
/**
* Returns meta data of the resultset
* @return ResultSetMetaData*
* @since 1.0.0
*/
dsqlxprez::ResultSetMetaData*
dsqlxprez::ResultSet::getMetaData() throw (dsqlxprez::SQLException)
{
return m_rsltMtdt;
}
// class ResultSetMetaData
/**
* Constructor
* @param vct Vector of columns
* @since 1.0.0
*/
dsqlxprez::ResultSetMetaData::ResultSetMetaData(std::vector<Column> vct)
: m_vctColumns(vct)
{
}
/**
* Returns number of columns in the resultset
* @return int
* @since 1.0.0
*/
int
dsqlxprez::ResultSetMetaData::getColumnCount()
{
return m_vctColumns.size();
}
/**
* Returns the name of the column
* @param colNum Number of column, starting at 1
* @return string
* @since 1.0.0
*/
std::string
dsqlxprez::ResultSetMetaData::getColumnName(int colNum)
throw (dsqlxprez::SQLException)
{
int i = colNum-1;
if (i < 0 || i >= m_vctColumns.size())
throw dsqlxprez::SQLException("Invalid column number");
return m_vctColumns[i].name_;
}
/**
* Returns the datatype of the column
* @param colNum Number of column, starting at 1
* @return string
* @since 1.0.0
*/
std::string
dsqlxprez::ResultSetMetaData::getColumnType(int colNum)
throw (dsqlxprez::SQLException)
{
int i = colNum-1;
if (i < 0 || i >= m_vctColumns.size())
throw dsqlxprez::SQLException("Invalid column number");
return m_vctColumns[i].type_;
}
// class DatabaseMetaData
/**
* Constructor
* @param Vector of database objects
* @since 1.0.0
*/
dsqlxprez::DatabaseMetaData::DatabaseMetaData(std::vector<dsqlxprez::DatabaseObject> vct)
: m_vctObjects(vct)
{
}
/**
* Returns the number of objects in the database
* @return int
* @since 1.0.0
*/
int
dsqlxprez::DatabaseMetaData::getNumObjects()
{
return m_vctObjects.size();
}
/**
* Returns the name of the object at the given position
* @param colNum Column number,starts at 1
* @return string
* @since 1.0.0
*/
std::string
dsqlxprez::DatabaseMetaData::getName(int colNum) throw (dsqlxprez::SQLException)
{
int i = colNum - 1;
if (i < 0 || i >= m_vctObjects.size())
throw dsqlxprez::SQLException("Invalid column number");
return m_vctObjects[i].name_;
}
/**
* Returns the type of the object at the given position
* @param colNum Column number,starts at 1
* @return string
* @since 1.0.0
*/
std::string
dsqlxprez::DatabaseMetaData::getType(int colNum) throw (dsqlxprez::SQLException)
{
int i = colNum - 1;
if (i < 0 || i >= m_vctObjects.size())
throw dsqlxprez::SQLException("Invalid column number");
return m_vctObjects[i].type_;
}
/**
* Returns the sql that created the object at the given position
* @param colNum Column number,starts at 1
* @return string
* @since 1.0.0
*/
std::string
dsqlxprez::DatabaseMetaData::getSql(int colNum) throw (dsqlxprez::SQLException)
{
int i = colNum - 1;
if (i < 0 || i >= m_vctObjects.size())
throw dsqlxprez::SQLException("Invalid column number");
return m_vctObjects[i].sql_;
}
/**
* Checks if the given object exists in the database
* @param name_ Name of the object
* @param type_ Type of the object (table,index)
* @return bool
* @since 1.0.0
*/
bool
dsqlxprez::DatabaseMetaData::doesObjectExist(const char* name_,
const char* type_)
{
int sz = m_vctObjects.size();
for (int i=0;i<sz;i++)
{
if ((to_lower(m_vctObjects[i].name_) == to_lower(name_))
&& (to_lower(m_vctObjects[i].type_) == to_lower(type_)))
return true;
}
return false;
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.