// // mysqlpl.h // // Copyright (c) 2004, 2006, 2007, 2009 Martin Fuchs // /* All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _MYSQLPL_H #ifdef _MSC_VER #pragma warning(disable: 4786) #endif #if defined(_WIN32) && !defined(_WINDOWS_) #include // for LPCTSTR #else #include #include #endif #include #include #include #include #include #include // tested with MySQL version 4.0.24 and above (needs MySQL 4.1 to use native prepared statements) #include #ifdef _MSC_VER #ifndef _NO_COMMENT #pragma comment(lib, "libmySQL") #if defined(_DEBUG) && defined(_DLL) // DEBUG version only supported with MSVCRTD #pragma comment(lib, "mysqlpld") #else #ifdef _DLL #pragma comment(lib, "mysqlpl") #elif defined(_MT) #pragma comment(lib, "mysqlplt") #else #pragma comment(lib, "mysqlpll") #endif #endif #endif // _NO_COMMENT #define LONGLONG __int64 #else // _MSC_VER #define LONGLONG long long #endif // _MSC_VER namespace MySqlPL { #ifndef MYSQLPL_PREP_STMT #if MYSQL_VERSION_ID>=41000 #define MYSQLPL_PREP_STMT 1 #else #define MYSQLPL_PREP_STMT 0 #endif #endif /// MySQL Errorhandling struct SqlStatement; struct MSqlException : public std::exception { typedef std::exception super; MSqlException(MYSQL* db, const char* file, int line); #if MYSQLPL_PREP_STMT MSqlException(MYSQL_STMT* s, const char* file, int line); MSqlException(MYSQL_STMT* s, SqlStatement& stmt, const char* file, int line); #endif MSqlException(const char* msg, const char* file, int line); ~MSqlException() throw () {} virtual const char* what() const throw () {return _msg.c_str();} unsigned _sql_error_code; std::string _msg; #if MYSQLPL_PREP_STMT std::string _sqlstate; #endif std::string _last_sql; const char* _file; int _line; }; #ifndef MYSQLPL_EXCEPTION #define MYSQLPL_EXCEPTION MySqlPL::MSqlException #endif #define THROW_MYSQLPL_EXCEPTION(par) throw MYSQLPL_EXCEPTION(par, __FILE__, __LINE__) /// error handling functions inline void mysqlpl_check_error(MYSQL* db) { unsigned int error = mysql_errno(db); if (error != 0) THROW_MYSQLPL_EXCEPTION(db); } inline void mysqlpl_check_error(MYSQL* db, int res) { if (res) { unsigned int error = mysql_errno(db); if (error != 0) THROW_MYSQLPL_EXCEPTION(db); } } inline void mysqlpl_check_error(MYSQL* db, my_bool b) { if (b) { unsigned int error = mysql_errno(db); if (error != 0) THROW_MYSQLPL_EXCEPTION(db); } } #if MYSQLPL_PREP_STMT inline void mysqlpl_check_error(MYSQL_STMT* s) { unsigned int error = mysql_stmt_errno(s); if (error != 0) THROW_MYSQLPL_EXCEPTION(s); } inline void mysqlpl_check_error(MYSQL_STMT* s, int res) { if (res) { unsigned int error = mysql_stmt_errno(s); if (error != 0) THROW_MYSQLPL_EXCEPTION(s); } } inline void mysqlpl_check_error(MYSQL_STMT* s, my_bool b) { if (b) { unsigned int error = mysql_stmt_errno(s); if (error != 0) THROW_MYSQLPL_EXCEPTION(s); } } #endif struct MSqlEnv { MSqlEnv(MYSQL* mysql=NULL) { _mysql = mysql_init(NULL); } ~MSqlEnv() { mysql_close(_mysql); } operator MYSQL*() const {return _mysql;} protected: MYSQL* _mysql; }; /// simple MySQL login to database struct MSqlConnection { MSqlConnection(MSqlEnv& env) : _env(env), _db(NULL), _connected(false) { } MSqlConnection(MSqlEnv& env, const char* username, const char* password, const char* db_name, const char* host="localhost", unsigned port=3306, unsigned long clientflag=0) : _env(env), _db(NULL), _connected(false) { connect(username, password, db_name, host, port, clientflag); } void connect(const char* username, const char* password, const char* db_name, const char* host="localhost", unsigned port=3306, unsigned long clientflag=0); ~MSqlConnection() { /*see MSqlEnv::~MSqlEnv() if (_connected) mysql_close(_mysql); */ } #if MYSQLPL_PREP_STMT // get warnings unsigned get_warnings_count() const; std::string get_info() const; void print_warnings(std::ostream& out) { while(get_warnings_count()) out << get_info() << std::endl; } #else const char* get_info() const; void print_warnings(std::ostream& out) { const char* info = get_info(); if (info) out << info << std::endl; } #endif // get last generated insert ID my_ulonglong get_insert_id() const { return mysql_insert_id(_db); } void commit() { #if MYSQLPL_PREP_STMT my_bool res = mysql_commit(_db); #else my_bool res = mysql_query(_db, "commit"); #endif mysqlpl_check_error(_env, res); } void rollback() { #if MYSQLPL_PREP_STMT //@@ my_bool res = mysql_rollback(_db); #else my_bool res = mysql_query(_db, "rollback"); #endif mysqlpl_check_error(_env, res); } operator MYSQL*() const {return _db;} protected: MSqlEnv& _env; MYSQL* _db; bool _connected; private: // disallow copy constructor usage MSqlConnection(const MSqlConnection&); }; /// column description struct ColumnType { std::string _table_name; std::string _name; enum_field_types _data_type; int _width; int _decimals; int _flags; ColumnType() { _data_type = (enum_field_types)-1; _width = 0; _decimals = 0; _flags = 0; } std::string get_type_str(bool show_null=false) const; void init(const MYSQL_FIELD*); }; /// indicator variable struct SqlInd { SqlInd(my_bool is_null=1) : _is_null(is_null) { } operator my_bool() const {return _is_null;} operator my_bool*() {return &_is_null;} bool is_null() const {return _is_null!=0;} bool is_not_null() const {return _is_null==0;} void clear() {_is_null = 1;} void set() {_is_null = 0;} protected: my_bool _is_null; }; struct SqlValue { SqlValue() {} SqlValue(const SqlValue& other) : _ind(other._ind) {} bool is_null() const {return _ind.is_null();} bool is_not_null() const {return _ind.is_not_null();} const SqlInd& ind() const {return _ind;} SqlInd& ind() {return _ind;} protected: SqlInd _ind; }; #if MYSQLPL_PREP_STMT /// int with indicator variable struct SqlInt : public SqlValue { SqlInt() // NULL constructor { } SqlInt(int value) : _value(value) { _ind.set(); } SqlInt(const SqlInt& other) : SqlValue(other), _value(other._value) { } enum {INT_NULL = -1}; operator int() const {return _ind.is_null()? INT_NULL: _value;} int& get_ref() {return _value;} std::string str() const; protected: int _value; }; /// 64 bit integer with indicator variable struct SqlInteger : public SqlValue { SqlInteger() // NULL constructor { } SqlInteger(int value) : _value(value) { _ind.set(); } SqlInteger(const SqlInteger& other) : SqlValue(other), _value(other._value) { } enum {INT_NULL = -1}; operator LONGLONG() const {return _ind.is_null()? INT_NULL: _value;} LONGLONG& get_ref() {return _value;} std::string str() const; protected: LONGLONG _value; }; struct SqlString : public SqlValue { SqlString(int blen=2000) : _blen(blen), _str((char*)malloc((blen+1)*sizeof(char))) { *_str = '\0'; } SqlString(const char* s, int blen=2000) : _blen(blen), _str((char*)malloc((blen+1)*sizeof(char))) { operator=(s); } SqlString(const SqlString& other) : SqlValue(other), _blen(other._blen), _str((char*)malloc((other._blen+1)*sizeof(char))) { strcpyn(_str, other._str, _blen+1); } ~SqlString() { free(_str); } int len() const {return is_null()? 0: strlen(_str);} int blen() const {return _blen;} int alen() const {return _blen + 1;} void resize(int l) {_blen = l; _str = (char*)realloc(_str, (l+1)*sizeof(char));} void clear() {*_str = '\0'; _ind.clear();} char* str() {return _str;} // Note: _ind is not checked by this function. char* str(int l) {resize(l); return _str;} // Note: _ind is not changed by this function. const char* c_str() const {return is_null()? "": _str;} operator const char*() const {return is_null()? "": _str;} SqlString& operator=(const char* s) { if (s) { strcpy(_str, s); _ind.set(); } else { *_str = '\0'; _ind.clear(); } return *this; } SqlString& operator=(const std::string& s) { strcpyn(_str, c_str(), blen()+1); _ind.set(); return *this; } friend std::ostream& operator<<(std::ostream& os, const SqlString& str) {if (str.is_not_null()) os << str._str; return os;} static inline char* strcpyn(char* dest, const char*source, size_t count) { char* d = dest; for(const char* s=source; count&&(*d++=*s++); ) count--; return dest; } protected: short _blen; char* _str; }; /// wrapper for MYSQL_TIME struct SqlDate : public MYSQL_TIME, public SqlValue { typedef MYSQL_TIME super; SqlDate(enum_mysql_timestamp_type type=MYSQL_TIMESTAMP_DATETIME) {super::time_type = type;} SqlDate(const char* str, enum_mysql_timestamp_type type=MYSQL_TIMESTAMP_DATETIME); SqlDate(const SqlDate& other, enum_mysql_timestamp_type type); enum_field_types get_data_type() const { switch(super::time_type) { case MYSQL_TIMESTAMP_NONE: return MYSQL_TYPE_NULL; case MYSQL_TIMESTAMP_DATE: return MYSQL_TYPE_DATE; case MYSQL_TIMESTAMP_TIME: return MYSQL_TYPE_TIME; case MYSQL_TIMESTAMP_DATETIME: return MYSQL_TYPE_DATETIME; default: return (enum_field_types)-1; } } std::string str() const; }; struct SqlNumber : public SqlValue { SqlNumber() {} SqlNumber(int i) {_value = i; _ind.set();} SqlNumber(LONGLONG l) {_value = (double)l; _ind.set();} SqlNumber(double d) {_value = d; _ind.set();} SqlNumber(const char* s); void* get_ref() {return &_value;} std::string str() const; operator double*() {return &_value;} operator const double*() const {return &_value;} int get_int() const { return _ind.is_not_null()? (int)(_value+.5): 0; } #ifdef _MSC_VER __int64 get_int64() const { return _ind.is_not_null()? (__int64)(_value+.5): 0; } #endif double get_double() const { return _ind.is_not_null()? _value: 0.; } protected: double _value; }; struct MSqlBlob : public SqlValue { MSqlBlob(int len=0x10000) : _len(len), _ptr(NULL), _own(true) { } MSqlBlob(void* ptr, int len) : _len(len), _ptr(ptr), _own(false) { } MSqlBlob(const MSqlBlob& other) : SqlValue(other), _len(other._len), _own(true) { if (other._ptr) memcpy(_ptr=malloc(other._len), other._ptr, other._len); else _ptr = NULL; } ~MSqlBlob() { if (_own) free(_ptr); } void* get_ref() { if (_own && !_ptr) // delayed buffer allocation _ptr = malloc(_len); return _ptr; } int get_len() const {return _len;} unsigned long& get_len_ref() {return _len;} std::string str() const; protected: unsigned long _len; void* _ptr; bool _own; }; #endif #if MYSQL_VERSION_ID<41000 //@@ #define MYSQL_TYPE_DECIMAL FIELD_TYPE_DECIMAL #define MYSQL_TYPE_TINY FIELD_TYPE_TINY #define MYSQL_TYPE_SHORT FIELD_TYPE_SHORT #define MYSQL_TYPE_LONG FIELD_TYPE_LONG #define MYSQL_TYPE_FLOAT FIELD_TYPE_FLOAT #define MYSQL_TYPE_DOUBLE FIELD_TYPE_DOUBLE #define MYSQL_TYPE_NULL FIELD_TYPE_NULL #define MYSQL_TYPE_TIMESTAMP FIELD_TYPE_TIMESTAMP #define MYSQL_TYPE_LONGLONG FIELD_TYPE_LONGLONG #define MYSQL_TYPE_INT24 FIELD_TYPE_INT24 #define MYSQL_TYPE_DATE FIELD_TYPE_DATE #define MYSQL_TYPE_TIME FIELD_TYPE_TIME #define MYSQL_TYPE_DATETIME FIELD_TYPE_DATETIME #define MYSQL_TYPE_YEAR FIELD_TYPE_YEAR #define MYSQL_TYPE_ENUM FIELD_TYPE_ENUM #define MYSQL_TYPE_SET FIELD_TYPE_SET #define MYSQL_TYPE_TINY_BLOB FIELD_TYPE_TINY_BLOB #define MYSQL_TYPE_MEDIUM_BLOB FIELD_TYPE_MEDIUM_BLOB #define MYSQL_TYPE_LONG_BLOB FIELD_TYPE_LONG_BLOB #define MYSQL_TYPE_BLOB FIELD_TYPE_BLOB #define MYSQL_TYPE_VAR_STRING FIELD_TYPE_VAR_STRING #define MYSQL_TYPE_STRING FIELD_TYPE_STRING #define MYSQL_TYPE_GEOMETRY FIELD_TYPE_GEOMETRY #define MYSQL_TYPE_BIT FIELD_TYPE_BIT /* only since MySQL 5.0 #define MYSQL_TYPE_NEWDECIMAL FIELD_TYPE_NEWDECIMAL #define MYSQL_TYPE_NEWDATE FIELD_TYPE_NEWDATE */ #endif struct BindPar { void* _ptr; int _len; enum_field_types _type; my_bool* _pind; unsigned long*_plen; BindPar() { _ptr = NULL; _len = 0; _type = (enum_field_types)-1; _pind = NULL; _plen = NULL; } BindPar(const char* buffer, int len=-1, enum_field_types type=MYSQL_TYPE_VAR_STRING, my_bool* pind=NULL) { _ptr = (void*) buffer; if (len == -1) // not applicable for OUT variables _len = strlen(buffer); else _len = len; _type = type; _pind = pind; _plen = NULL; } BindPar(const std::string& str) { _ptr = (void*) str.c_str(); _len = str.length(); _type = MYSQL_TYPE_VAR_STRING; _pind = NULL; _plen = NULL; } #ifdef ISSD_EXP BindPar(const String& str) { _ptr = (void*) str.c_str(); _len = str.len(); _type = MYSQL_TYPE_VAR_STRING; _pind = NULL; _plen = NULL; } #endif BindPar(const int& var, my_bool* pind=NULL) { _ptr = (void*)&var; _len = sizeof(var); _type = MYSQL_TYPE_LONG; _pind = pind; _plen = NULL; } BindPar(const double& var, my_bool* pind=NULL) { _ptr = (void*)&var; _len = sizeof(var); _type = MYSQL_TYPE_DOUBLE; _pind = pind; _plen = NULL; } #if MYSQLPL_PREP_STMT BindPar(SqlInt& var) { int& ref = var.get_ref(); _ptr = &ref; _len = sizeof(ref); _type = MYSQL_TYPE_LONG; _pind = var.ind(); _plen = NULL; } BindPar(SqlInteger& var) { LONGLONG& ref = var.get_ref(); _ptr = &ref; _len = sizeof(ref); _type = MYSQL_TYPE_LONGLONG; _pind = var.ind(); _plen = NULL; } BindPar(const SqlString& str) { _ptr = (void*) str.c_str(); _len = str.len(); _type = MYSQL_TYPE_VAR_STRING; _pind = NULL; _plen = NULL; } BindPar(SqlString& str) { _ptr = (void*) str.str(); _len = str.alen(); _type = MYSQL_TYPE_VAR_STRING; _pind = str.ind(); _plen = NULL; } BindPar(SqlDate& date) { _ptr = &date; _len = sizeof(MYSQL_TIME); _type = date.get_data_type(); _pind = date.ind(); _plen = NULL; } BindPar(SqlNumber& num) { _ptr = num.get_ref(); _len = sizeof(double); _type = MYSQL_TYPE_DOUBLE; _pind = num.ind(); _plen = NULL; } BindPar(MSqlBlob& blob) { _ptr = blob.get_ref(); _len = blob.get_len(); _type = MYSQL_TYPE_BLOB; _pind = blob.ind(); _plen = &blob.get_len_ref(); } #endif }; #if MYSQLPL_PREP_STMT /// factory for call parameters for MySQL define functions struct BindResultPar { void* _ptr; int _len; enum_field_types _type; my_bool* _pind; unsigned long*_plen; BindResultPar(SqlInt& var) { int& ref = var.get_ref(); _ptr = &ref; _len = sizeof(ref); _type = MYSQL_TYPE_LONG; _pind = var.ind(); _plen = NULL; } BindResultPar(SqlInteger& var) { LONGLONG& ref = var.get_ref(); _ptr = &ref; _len = sizeof(ref); _type = MYSQL_TYPE_LONGLONG; _pind = var.ind(); _plen = NULL; } BindResultPar(int& var, my_bool* pind=NULL) { _ptr = &var; _len = sizeof(var); _type = MYSQL_TYPE_LONG; _pind = pind; _plen = NULL; } BindResultPar(const char* buffer, int len, enum_field_types type=MYSQL_TYPE_VAR_STRING, my_bool* pind=NULL) { _ptr = (void*) buffer; _len = len; _type = type; _pind = pind; _plen = NULL; } BindResultPar(SqlString& str) { _ptr = str.str(); _len = str.alen(); _type = MYSQL_TYPE_VAR_STRING; _pind = str.ind(); _plen = NULL; } BindResultPar(SqlNumber& num) { _ptr = num.get_ref(); _len = sizeof(double); _type = MYSQL_TYPE_DOUBLE; _pind = num.ind(); _plen = NULL; } #if MYSQLPL_PREP_STMT BindResultPar(SqlDate& date) { _ptr = &date; _len = sizeof(MYSQL_TIME); _type = date.get_data_type(); _pind = date.ind(); _plen = NULL; } #endif BindResultPar(MSqlBlob& blob) { _ptr = blob.get_ref(); _len = blob.get_len(); _type = MYSQL_TYPE_BLOB; _pind = blob.ind(); _plen = &blob.get_len_ref(); } }; struct SqlVariant { SqlVariant() : _data_type((enum_field_types)-1) { } SqlVariant(enum_field_types data_type); SqlVariant(const SqlVariant& other); ~SqlVariant() {clear();} SqlVariant(const SqlString& x) { _string = new SqlString(x); _data_type = MYSQL_TYPE_VAR_STRING; } SqlVariant(const char* x) { _string = new SqlString(x); _data_type = MYSQL_TYPE_VAR_STRING; } SqlVariant(const SqlInt& x) { _int = new SqlInt(x); _data_type = MYSQL_TYPE_LONG; } SqlVariant(const SqlInteger& x) { _integer = new SqlInteger(x); _data_type = MYSQL_TYPE_LONGLONG; } SqlVariant(const SqlNumber& x) { _number = new SqlNumber(x); _data_type = MYSQL_TYPE_DOUBLE; } #if MYSQLPL_PREP_STMT SqlVariant(const SqlDate& x) { _date = new SqlDate(x); _data_type = x.get_data_type(); } #endif void clear(); void assign(const SqlVariant& other); int get_data_type() const {return _data_type;} SqlVariant& operator=(const SqlVariant& other) {assign(other); return *this;} std::string str() const; SqlNumber number() const; int get_int() const; #ifdef _MSC_VER __int64 get_int64() const; #endif double get_double() const; #if MYSQLPL_PREP_STMT SqlDate date(enum_mysql_timestamp_type type=MYSQL_TIMESTAMP_DATE) const; SqlDate datetime() const {return date(MYSQL_TIMESTAMP_DATETIME);} SqlDate time() const {return date(MYSQL_TIMESTAMP_TIME);} #endif bool is_null() const; bool is_not_null() const {return !is_null();} #if MYSQLPL_PREP_STMT void bind_result_column(SqlStatement& stmt, MYSQL_BIND& bind); #endif protected: union { SqlString* _string; SqlInt* _int; SqlInteger* _integer; SqlNumber* _number; #if MYSQLPL_PREP_STMT SqlDate* _date; #endif MSqlBlob* _blob; }; enum_field_types _data_type; }; #endif struct ColumnData { #if MYSQLPL_PREP_STMT SqlVariant _column; #endif ColumnType _type; }; typedef std::vector ColumnVector; struct BindVector : public std::vector { void bind(int idx, const BindPar& par); }; #if MYSQLPL_PREP_STMT typedef std::vector MSqlBindVector; void mysql_bind_param(const BindPar& par, MYSQL_BIND& bind); #endif /// a record to hold return columns for a given statement struct SqlRecord { SqlRecord(SqlStatement& stmt); int get_column_count() const {return _columns.size();} #if MYSQLPL_PREP_STMT const SqlVariant& get_column(int idx) const {return _columns[idx]._column;} const SqlVariant& get_column(const std::string& col_name) const; #endif const ColumnType& get_column_type(int idx) const {return _columns[idx]._type;} const ColumnType& get_column_type(const std::string& col_name) const; void print_columns(std::ostream& out); void print_values(std::ostream& out); #ifdef _XMLSTORAGE_H void dump_values(XMLStorage::XMLPos& out); #endif protected: SqlStatement& _stmt; ColumnVector _columns; typedef std::map NameMap; mutable NameMap _name_map; // column index cache NameMap::const_iterator find_column(const std::string& col_name) const; int get_column_idx(const std::string& col_name) const; }; #if !MYSQLPL_PREP_STMT struct SqlResult : public SqlRecord { MYSQL_ROW _row; SqlResult(SqlStatement& stmt) : SqlRecord(stmt), _row(NULL) { } bool is_null(int idx) const { return _row[idx] == NULL; } int is_null(const std::string& col_name) const { return is_null(get_column_idx(col_name)); } bool is_not_null(int idx) const { return _row[idx] != NULL; } int is_not_null(const std::string& col_name) const { return is_not_null(get_column_idx(col_name)); } int get_int(int idx) const { return atoi(_row[idx]); } int get_int(const std::string& col_name) const { return get_int(get_column_idx(col_name)); } #ifdef _MSC_VER __int64 get_int64(int idx) const { return _atoi64(_row[idx]); } __int64 get_int64(const std::string& col_name) const { return get_int64(get_column_idx(col_name)); } #endif double get_double(int idx) const { return atof(_row[idx]); } double get_double(const std::string& col_name) const { return get_double(get_column_idx(col_name)); } std::string get_string(int idx) const { const char* str = _row[idx]; return str? str: std::string(); } std::string get_string(const std::string& col_name) const { return get_string(get_column_idx(col_name)); } #if MYSQLPL_PREP_STMT // never used SqlDate get_date(int idx, enum_mysql_timestamp_type type=MYSQL_TIMESTAMP_DATE) const { return get_column(idx).date(type); } SqlDate get_date(const std::string& col_name, enum_mysql_timestamp_type type=MYSQL_TIMESTAMP_DATE) const { return get_date(get_column_idx(col_name)); } SqlDate get_datetime(int idx) const { return get_column(idx).date(MYSQL_TIMESTAMP_DATETIME); } SqlDate get_datetime(const std::string& col_name) const { return get_column(col_name).date(MYSQL_TIMESTAMP_DATETIME); } #endif }; #endif struct SqlQuery { explicit SqlQuery(const char* sql) : _sql(sql) { } void where(const char* cond) { if (_cond.empty()) _cond += "\nwhere "; else _cond += "\nand "; _cond += cond; } std::string get_sql() const { return _sql + _cond; } void bind_param(BindPar par); const BindVector& get_params() const { return _param_bind_vector; } protected: std::string _sql; std::string _cond; BindVector _param_bind_vector; }; /// a MySQL SQL statement struct SqlStatement { SqlStatement(MSqlConnection& conn); SqlStatement(MSqlConnection& conn, const std::string& sql); SqlStatement(MSqlConnection& conn, const SqlQuery& query); ~SqlStatement(); protected: MYSQL* _db; #if MYSQLPL_PREP_STMT MYSQL_STMT* _stmt; MSqlBindVector _result_bind_vector; #else std::string _sql; std::string create_bound_sql() const; #endif BindVector _param_bind_vector; mutable MYSQL_RES* _result; enum STATE { UNINITIALIZED=0, #if MYSQLPL_PREP_STMT PREPARED=1, RESULT_BOUND=2, #endif EXECUTED=4, FETCHED=8, //EOF_DATA=16, STMT_ERROR=32 }; int _state; std::string _last_sql; struct SqlResult* _res; int _stmt_type; public: //bool eof() const {return _state < EOF_DATA;} // Preparation of a SQL statements void prepare(const std::string& sql); const std::string& get_last_sql() const { return _last_sql; } // get number of processed rows my_ulonglong get_row_count() const; // Binding of input and output variables void bind_param(int idx, BindPar par); //TODO implement named parameter binding void bind_params(const BindVector& params) { _param_bind_vector = params; } // Definition of variables to receive query results #if MYSQLPL_PREP_STMT void bind_result_column(BindResultPar par, MYSQL_BIND& bind); void bind_result(MYSQL_BIND* bind_array); #endif // define all columns of a complete recordset #if MYSQLPL_PREP_STMT void bind_result(ColumnVector& columns); #endif void execute(); void execute(const std::string& sql) { prepare(sql); execute(); } void execute(const SqlQuery& query) { prepare(query.get_sql()); bind_params(query.get_params()); execute(); } bool execute_fetch() { execute(); return fetch(); } bool execute_fetch(const std::string& sql) { prepare(sql); return execute_fetch(); } bool fetch() { if (!(_state & EXECUTED)) execute(); #if MYSQLPL_PREP_STMT int res = mysql_stmt_fetch(_stmt); if (res == MYSQL_NO_DATA) return false; mysqlpl_check_error(_stmt, res); #else _res->_row = mysql_fetch_row(_result); if (!_res->_row) return false; #endif _state |= FETCHED; return true; } MYSQL_RES* get_meta_res() const; bool is_select() const; int get_column_count() const; void get_column_type(int idx, ColumnType& info) const; void print_results(std::ostream& out, bool header=true); void print_results(const std::string& sql, std::ostream& out, bool header=true) { execute(sql); print_results(out, header); } #ifdef _XMLSTORAGE_H void dump_results(XMLStorage::XMLPos& idx, const XMLStorage::XS_String& element_name); void dump_results(const std::string& sql, XMLStorage::XMLPos& idx, const XMLStorage::XS_String& element_name) { execute(sql); dump_results(idx, element_name); } #endif SqlResult* operator->() { if (!_res) fetch(); return _res; } }; #if MYSQLPL_PREP_STMT /// class to retrieve query result values struct SqlResult : public SqlRecord { SqlResult(SqlStatement& stmt) : SqlRecord(stmt) { #if MYSQLPL_PREP_STMT stmt.bind_result(_columns); #endif } bool is_null(int idx) const { return get_column(idx).is_null(); } int is_null(const std::string& col_name) const { return get_column(col_name).is_null(); } bool is_not_null(int idx) const { return get_column(idx).is_not_null(); } int is_not_null(const std::string& col_name) const { return get_column(col_name).is_not_null(); } int get_int(int idx) const { return get_column(idx).get_int(); } int get_int(const std::string& col_name) const { return get_column(col_name).get_int(); } #ifdef _MSC_VER __int64 get_int64(int idx) const { return get_column(idx).get_int64(); } __int64 get_int64(const std::string& col_name) const { return get_column(col_name).get_int64(); } #endif double get_double(int idx) const { return get_column(idx).get_double(); } double get_double(const std::string& col_name) const { return get_column(col_name).get_double(); } std::string get_string(int idx) const { return get_column(idx).str(); } std::string get_string(const std::string& col_name) const { return get_column(col_name).str(); } #if MYSQLPL_PREP_STMT SqlDate get_date(int idx, enum_mysql_timestamp_type type=MYSQL_TIMESTAMP_DATE) const { return get_column(idx).date(type); } SqlDate get_date(const std::string& col_name, enum_mysql_timestamp_type type=MYSQL_TIMESTAMP_DATE) const { return get_column(col_name).date(type); } SqlDate get_datetime(int idx) const { return get_column(idx).date(MYSQL_TIMESTAMP_DATETIME); } SqlDate get_datetime(const std::string& col_name) const { return get_column(col_name).date(MYSQL_TIMESTAMP_DATETIME); } #endif }; #endif // MYSQLPL_PREP_STMT } // namespace MySqlPL #define _MYSQLPL_H #endif // _MYSQLPL_H