// // mysqlpl.cpp // // 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 _NO_COMMENT #define _NO_COMMENT // no #pragma comment(lib, ...) statements in .lib files #endif #include "mysqlpl.h" #include #include #ifndef _MSC_VER #define _snprintf snprintf inline void strupr(char* s) { for(; *s; ++s) *s = toupper(*s); } #endif namespace MySqlPL { MSqlException::MSqlException(MYSQL* db, const char* file, int line) { char buffer[2048]; _sql_error_code = mysql_errno(db); const char* error_str = mysql_error(db); #if MYSQLPL_PREP_STMT const char* state_str = mysql_sqlstate(db); sprintf(buffer, "MySQL error %d - SQLSTATE %s: %s", _sql_error_code, state_str, error_str); _sqlstate = state_str; #else sprintf(buffer, "MySQL error %d: %s", _sql_error_code, error_str); #endif _msg = strdup((const char*)buffer); _file = file; _line = line; } #if MYSQLPL_PREP_STMT MSqlException::MSqlException(MYSQL_STMT* s, const char* file, int line) { char buffer[2048]; _sql_error_code = mysql_stmt_errno(s); const char* error_str = mysql_stmt_error(s); const char* state_str = mysql_stmt_sqlstate(s); sprintf(buffer, "MySQL error %d - SQLSTATE %s: %s", _sql_error_code, state_str, error_str); _sqlstate = state_str; _msg = strdup(buffer); _file = file; _line = line; } MSqlException::MSqlException(MYSQL_STMT* s, SqlStatement& stmt, const char* file, int line) { char buffer[2048]; _sql_error_code = mysql_stmt_errno(s); const char* error_str = mysql_stmt_error(s); const char* state_str = mysql_stmt_sqlstate(s); sprintf(buffer, "MySQL error %d - SQLSTATE %s: %s", _sql_error_code, state_str, error_str); _last_sql = stmt.get_last_sql(); if (!_last_sql.empty()) { const char* sql = _last_sql.c_str(); _snprintf((char*)buffer, sizeof(buffer)-1, "%s\nlast SQL statement:\n%s\n", buffer, sql); } _msg = strdup((const char*)buffer); _sqlstate = state_str; _file = file; _line = line; } #endif MSqlException::MSqlException(const char* msg, const char* file, int line) { _msg = strdup(msg); _file = file; _line = line; } void MSqlConnection::connect(const char* username, const char* password, const char* db_name, const char* host, unsigned port, unsigned long clientflag) { _connected = false; _db = mysql_real_connect(_env, host, username, password, db_name, port, NULL, clientflag); if (!_db) THROW_MYSQLPL_EXCEPTION(_env); _connected = true; #if MYSQLPL_PREP_STMT // disable auto commit mode my_bool res = mysql_autocommit(_db, 0); mysqlpl_check_error(_env, res); #else SqlStatement(*this).execute("set autocommit=0"); // "set autocommit=0" is not supported before MySQL 4.1 #endif } #if MYSQLPL_PREP_STMT unsigned MSqlConnection::get_warnings_count() const { unsigned res = mysql_warning_count(_db); if (res == -1) THROW_MYSQLPL_EXCEPTION(_db); return res; } std::string MSqlConnection::get_info() const { const char* info = mysql_info(_db); if (!info) THROW_MYSQLPL_EXCEPTION(_db); return info; } #else const char* MSqlConnection::get_info() const { return mysql_info(_db); } #endif #if MYSQLPL_PREP_STMT std::string SqlInt::str() const { if (_ind.is_null()) return ""; char buffer[16]; sprintf(buffer, "%d", _value); return buffer; } std::string SqlInteger::str() const { if (_ind.is_null()) return ""; char buffer[32]; sprintf(buffer, "%I64d", _value); return buffer; } SqlNumber::SqlNumber(const char* s) { if (sscanf(s, "%lf", &_value) == 1) // %lf -> double _ind.set(); } std::string SqlNumber::str() const { if (_ind.is_null()) return ""; char buffer[64]; sprintf(buffer, "%f", _value); // %f -> double return buffer; } SqlDate::SqlDate(const char* str, enum_mysql_timestamp_type type) { while(str && isspace(*str)) ++str; if (str && *str) { hour = 0; minute = 0; second = 0; second_part = 0; switch(type) { case MYSQL_TIMESTAMP_DATE: if (sscanf(str, "%04d-%02d-%02d", &year, &month, &day) != 3) if (sscanf(str, "%02d.%02d.%04d", &day, &month, &year) != 3) THROW_MYSQLPL_EXCEPTION("date conversion error"); break; case MYSQL_TIMESTAMP_TIME: if (sscanf(str, "%02d:%02d:%02d.%06d", &hour, &minute, &second, &second_part) < 3) THROW_MYSQLPL_EXCEPTION("time conversion error"); break; //case MYSQL_TIMESTAMP_DATETIME: default: if (sscanf(str, "%04d-%02d-%02d %02d:%02d:%02d.%06d", &year, &month, &day, &hour, &minute, &second, &second_part) < 6) { second = 0; if (sscanf(str, "%02d.%02d.%04d %02d:%02d:%02d.%06d", &day, &month, &year, &hour, &minute, &second, &second_part) < 3) THROW_MYSQLPL_EXCEPTION("datetime conversion error"); } } super::time_type = type; _ind.set(); } else { super::time_type = MYSQL_TIMESTAMP_NONE; _ind.clear(); } } SqlDate::SqlDate(const SqlDate& other, enum_mysql_timestamp_type type) : SqlValue(other) { memcpy(this, &other, sizeof(MYSQL_TIME)); if (other.time_type != type) { if (type==MYSQL_TIMESTAMP_NONE || type==MYSQL_TIMESTAMP_ERROR) super::time_type = type; else { if (other.time_type == MYSQL_TIMESTAMP_DATE) { if (type == MYSQL_TIMESTAMP_TIME) THROW_MYSQLPL_EXCEPTION("no conversion from time to date"); super::hour = 0; super::minute = 0; super::second = 0; } else if (other.time_type == MYSQL_TIMESTAMP_TIME) { if (type == MYSQL_TIMESTAMP_DATE) THROW_MYSQLPL_EXCEPTION("no conversion from date to time"); super::year = 0; super::month = 0; super::day = 0; } super::time_type = type; } } } std::string SqlDate::str() const { if (_ind.is_not_null()) { char buffer[40]; switch(time_type) { case MYSQL_TIMESTAMP_DATE: sprintf(buffer, "%04d-%02d-%02d", year, month, day); break; case MYSQL_TIMESTAMP_TIME: sprintf(buffer, "%02d:%02d:%02d.%06d", hour, minute, second, second_part); break; //case MYSQL_TIMESTAMP_DATETIME: default: sprintf(buffer, "%04d-%02d-%02d %02d:%02d:%02d.%06d", year, month, day, hour, minute, second, second_part); } return buffer; } else return std::string(); } std::string MSqlBlob::str() const { if (_ind.is_not_null()) { return std::string((char*)_ptr, _len); } else return std::string(); } #endif // MYSQLPL_PREP_STMT std::string ColumnType::get_type_str(bool show_null) const { std::ostringstream str; switch(_data_type) { case MYSQL_TYPE_STRING: str << "char(" << _width << ")"; break; case MYSQL_TYPE_VAR_STRING: str << "varchar(" << _width << ")"; break; case MYSQL_TYPE_DECIMAL: if (_width == 0) str << "decimal"; else str << "decimal(" << (_width-1) << "," << _decimals << ")"; break; #if MYSQL_VERSION_ID>=50000 case MYSQL_TYPE_NEWDECIMAL: if (_width == 0) str << "newdecimal"; else str << "newdecimal(" << (_width-1) << "," << _decimals << ")"; break; #endif case MYSQL_TYPE_TINY: str << "tinyint(" << _width << ")"; break; case MYSQL_TYPE_SHORT: str << "shortint(" << _width << ")"; break; case MYSQL_TYPE_LONG: str << "int(" << _width << ")"; break; case MYSQL_TYPE_LONGLONG: str << "bigint(" << _width << ")"; break; #ifdef FIELD_TYPE_ENUM case FIELD_TYPE_ENUM: str << "enum"; break; #endif case MYSQL_TYPE_FLOAT: if (_width == 12) str << "float"; else str << "float(" << _width << "," << _decimals << ")"; break; case MYSQL_TYPE_DOUBLE: if (_width == 22) str << "double"; else str << "double(" << _width << "," << _decimals << ")"; break; case MYSQL_TYPE_DATE: str << "date"; break; #if MYSQL_VERSION_ID>=50000 case MYSQL_TYPE_NEWDATE: str << "newdate"; break; #endif case MYSQL_TYPE_DATETIME: str << "datetime"; break; case MYSQL_TYPE_TIME: str << "time"; break; case MYSQL_TYPE_YEAR: str << "year(" << _width << ")"; break; case MYSQL_TYPE_TINY_BLOB: if (_flags & BINARY_FLAG) str << "tinyblob"; else str << "tinytext"; break; case MYSQL_TYPE_MEDIUM_BLOB: if (_flags & BINARY_FLAG) str << "mediumblob"; else str << "mediumtext"; break; case MYSQL_TYPE_LONG_BLOB: if (_flags & BINARY_FLAG) str << "longblob"; else str << "longtext"; break; case MYSQL_TYPE_BLOB: if (_flags & BINARY_FLAG) str << "blob"; else str << "text"; break; default: str << "unknown"; } if (show_null) if (IS_NOT_NULL(_flags)) str << " not null"; else str << " null"; return str.str(); } SqlStatement::SqlStatement(MSqlConnection& conn) : _db(conn), _state(UNINITIALIZED), _res(NULL), _stmt_type(-1), _result(NULL) { #if MYSQLPL_PREP_STMT _stmt = mysql_stmt_init(_db); #endif } SqlStatement::SqlStatement(MSqlConnection& conn, const std::string& sql) : _db(conn), _state(UNINITIALIZED), _res(NULL), _stmt_type(-1), _result(NULL) { #if MYSQLPL_PREP_STMT _stmt = mysql_stmt_init(_db); #endif prepare(sql); } SqlStatement::SqlStatement(MSqlConnection& conn, const SqlQuery& query) : _db(conn), _state(UNINITIALIZED), _res(NULL), _stmt_type(-1), _result(NULL) { #if MYSQLPL_PREP_STMT _stmt = mysql_stmt_init(_db); #endif execute(query); } SqlStatement::~SqlStatement() { #if MYSQLPL_PREP_STMT if (_stmt) mysql_stmt_close(_stmt); #else if (_result) mysql_free_result(_result); #endif } void SqlStatement::prepare(const std::string& sql) { delete _res; _res = NULL; _last_sql = sql; #if MYSQLPL_PREP_STMT int res = mysql_stmt_prepare(_stmt, sql.c_str(), sql.length()); mysqlpl_check_error(_stmt, res); _state = PREPARED; #else _sql = sql; if (_result) mysql_free_result(_result); #endif _stmt_type = -1; _result = NULL; // _result_bind_vector.clear(); _param_bind_vector.clear(); } my_ulonglong SqlStatement::get_row_count() const { #if MYSQLPL_PREP_STMT if (is_select()) { if (mysql_stmt_store_result(_stmt)) THROW_MYSQLPL_EXCEPTION(_stmt); } my_ulonglong res = mysql_stmt_affected_rows(_stmt); // for DML statements /* if (res == (my_ulonglong)-1) res = mysql_stmt_num_rows(_stmt); // only for SELECT statements */ if (res == (my_ulonglong)-1) THROW_MYSQLPL_EXCEPTION(_stmt); #else int res = mysql_affected_rows(_db); if (res == -1) THROW_MYSQLPL_EXCEPTION(_db); #endif return res; } #if MYSQLPL_PREP_STMT//@@ void SqlStatement::bind_result(MYSQL_BIND* bind_array) { my_bool res = mysql_stmt_bind_result(_stmt, bind_array); mysqlpl_check_error(_stmt, res); if (_state & EXECUTED) { delete _res; _res = NULL; _state = (_state|RESULT_BOUND) & ~FETCHED; } else _state |= RESULT_BOUND; } #endif void SqlStatement::execute() { #if MYSQLPL_PREP_STMT if (!(_state & RESULT_BOUND)) { // a SELECT statement without ready define variables? if (is_select()) { // a statement with result set? (=> SELECT) _result_bind_vector.resize(get_column_count()); // define resultset variables assert(!_res); _res = new SqlResult(*this); } } MSqlBindVector param_mbind_vector; // bind parameter values if (!_param_bind_vector.empty()) { // Umwandlung der Bindparameter von BindPar in MYSQL_BIND-Strukturelemente param_mbind_vector.resize(_param_bind_vector.size()); MSqlBindVector::iterator out = param_mbind_vector.begin(); for(BindVector::const_iterator in=_param_bind_vector.begin(); in!=_param_bind_vector.end(); ++in,++out) mysql_bind_param(*in, *out); my_bool res = mysql_stmt_bind_param(_stmt, ¶m_mbind_vector[0]); mysqlpl_check_error(_stmt, res); } int res = mysql_stmt_execute(_stmt); mysqlpl_check_error(_stmt, res); #else int res = mysql_query(_db, create_bound_sql().c_str()); mysqlpl_check_error(_db, res); if (_result) mysql_free_result(_result); _result = mysql_store_result(_db); if (_result) { // is_select() // define resultset variables if (_res) delete _res; _res = new SqlResult(*this); } #endif _state = (_state|EXECUTED) & ~FETCHED; } #if !MYSQLPL_PREP_STMT static const char* next_bind_variable(const char* p) { for(; *p; ++p) if (*p == '?') return p; // look for quotes and escape characters else if (*p == '\'') { while(*++p) if (*p=='\'' && *++p!='\'') break; } return NULL; } // create sql statement from prepared statement and integrate bind variables std::string SqlStatement::create_bound_sql() const { const char* p = _sql.c_str(); std::string sql; char buffer[64]; for(BindVector::const_iterator it=_param_bind_vector.begin(); it!=_param_bind_vector.end(); ++it) { const char* q = next_bind_variable(p); if (!q) THROW_MYSQLPL_EXCEPTION("too much bind values"); sql.append(p, q-p); const BindPar& value = *it; switch(value._type) { case MYSQL_TYPE_VAR_STRING: { sql.append("'"); // escape quote characters in bound string constants const char* p = (const char*)value._ptr; for(int i=0; itable; _name = field->name; // get column data type _data_type = field->type; _width = field->length; _decimals = field->decimals; // get NULL-ability, binary, ... flags _flags = field->flags; } void SqlStatement::bind_param(int idx, BindPar par) { if (_param_bind_vector.size() <= idx) _param_bind_vector.resize(idx+1); _param_bind_vector.bind(idx, par); } void SqlQuery::bind_param(BindPar par) { int idx = _param_bind_vector.size(); _param_bind_vector.resize(idx+1); _param_bind_vector.bind(idx, par); } void BindVector::bind(int idx, const BindPar& par) { at(idx) = par; } void SqlStatement::print_results(std::ostream& out, bool header) { if (!(_state & EXECUTED)) execute(); if (header) _res->print_columns(out); int row_cnt = 0; while(fetch()) { ++row_cnt; out << "row " << row_cnt << ":\n"; _res->print_values(out); out << std::endl; } } SqlRecord::SqlRecord(SqlStatement& stmt) : _stmt(stmt) { int column_cnt = stmt.get_column_count(); _columns.resize(column_cnt); // unsigned num_fields = mysql_num_fields(stmt.get_meta_res()); MYSQL_FIELD* fields = mysql_fetch_fields(stmt.get_meta_res()); for(ColumnVector::iterator it=_columns.begin(); it!=_columns.end(); ++it) { it->_type.init(fields++); #if MYSQLPL_PREP_STMT it->_column = SqlVariant(it->_type._data_type); #endif } //_name_map.clear(); } const ColumnType& SqlRecord::get_column_type(const std::string& col_name) const { NameMap::const_iterator found = find_column(col_name); if (found != _name_map.end()) { int idx = found->second; return _columns[idx]._type; } else { THROW_MYSQLPL_EXCEPTION("column not found"); return *(ColumnType*)NULL; } } #if MYSQLPL_PREP_STMT const SqlVariant& SqlRecord::get_column(const std::string& col_name) const { NameMap::const_iterator found = find_column(col_name); if (found != _name_map.end()) { int idx = found->second; return _columns[idx]._column; } else { THROW_MYSQLPL_EXCEPTION("column not found"); return *(SqlVariant*)NULL; } } #endif SqlRecord::NameMap::const_iterator SqlRecord::find_column(const std::string& col_name) const { std::string upper_name; // initialize column name map if (_name_map.empty()) { int idx = 0; for(ColumnVector::const_iterator it=_columns.begin(); it!=_columns.end(); ++it,++idx) { upper_name = it->_type._name.c_str(); strupr((char*)upper_name.data()); _name_map[upper_name] = idx; } } upper_name = col_name; strupr((char*)upper_name.data()); return _name_map.find(upper_name); } int SqlRecord::get_column_idx(const std::string& col_name) const { NameMap::const_iterator found = find_column(col_name); if (found != _name_map.end()) return found->second; else { THROW_MYSQLPL_EXCEPTION("column not found"); return -1; } } void SqlRecord::print_columns(std::ostream& out) { for(ColumnVector::const_iterator it=_columns.begin(); it!=_columns.end(); ++it) { const ColumnType& type = it->_type; if (!type._table_name.empty()) out << type._table_name << "."; out << type._name << ": " << type.get_type_str() << std::endl; } out << std::endl; } void SqlRecord::print_values(std::ostream& out) { #if MYSQLPL_PREP_STMT for(ColumnVector::const_iterator it=_columns.begin(); it!=_columns.end(); ++it) { const ColumnType& type = it->_type; // if (!type._table_name.empty()) // out << type._table_name << "."; out << type._name << "=" << it->_column.str() << std::endl; } #else for(size_t i=0; i<_columns.size(); ++i) { const ColumnType& type = _columns[i]._type; // if (!type._table_name.empty()) // out << type._table_name << "."; out << type._name << "=" << _stmt->get_string(i) << std::endl; } #endif } #if MYSQLPL_PREP_STMT SqlVariant::SqlVariant(enum_field_types data_type) { _data_type = data_type; switch(data_type) { case MYSQL_TYPE_STRING: _data_type = MYSQL_TYPE_VAR_STRING; // fall through case MYSQL_TYPE_VAR_STRING: _string = new SqlString; break; case MYSQL_TYPE_TINY: case MYSQL_TYPE_SHORT: case MYSQL_TYPE_INT24: case MYSQL_TYPE_YEAR: #ifdef FIELD_TYPE_ENUM case FIELD_TYPE_ENUM: #endif _data_type = MYSQL_TYPE_LONG; // fall through case MYSQL_TYPE_LONG: _int = new SqlInt; break; case MYSQL_TYPE_LONGLONG: _integer = new SqlInteger; break; case MYSQL_TYPE_DECIMAL: #if MYSQL_VERSION_ID>=50000 case MYSQL_TYPE_NEWDECIMAL: #endif case MYSQL_TYPE_FLOAT: _data_type = MYSQL_TYPE_DOUBLE; // fall through case MYSQL_TYPE_DOUBLE: _number = new SqlNumber; break; case MYSQL_TYPE_DATE: _date = new SqlDate(MYSQL_TIMESTAMP_DATE); break; #if MYSQL_VERSION_ID>=50000 case MYSQL_TYPE_NEWDATE: _date = new SqlDate(MYSQL_TIMESTAMP_DATE); break; #endif case MYSQL_TYPE_DATETIME: _date = new SqlDate(MYSQL_TIMESTAMP_DATETIME); break; case MYSQL_TYPE_TIMESTAMP: _date = new SqlDate(MYSQL_TIMESTAMP_TIME); break; case MYSQL_TYPE_TINY_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: _data_type = MYSQL_TYPE_BLOB; // fall through case MYSQL_TYPE_BLOB: _blob = new MSqlBlob; break; default: THROW_MYSQLPL_EXCEPTION("unsupported datatype"); } } SqlVariant::SqlVariant(const SqlVariant& other) { _data_type = (enum_field_types)-1; assign(other); } void SqlVariant::assign(const SqlVariant& other) { clear(); _data_type = other._data_type; switch(other._data_type) { case -1: break; case MYSQL_TYPE_VAR_STRING: _string = new SqlString(*other._string); break; case MYSQL_TYPE_LONG: _int = new SqlInt(*other._int); break; case MYSQL_TYPE_LONGLONG: _integer = new SqlInteger(*other._integer); break; case MYSQL_TYPE_DOUBLE: _number = new SqlNumber(*other._number); break; case MYSQL_TYPE_DATE: #if MYSQL_VERSION_ID>=50000 case MYSQL_TYPE_NEWDATE: #endif case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIME: case MYSQL_TYPE_TIMESTAMP: _date = new SqlDate(*other._date); break; case MYSQL_TYPE_BLOB: _blob = new MSqlBlob(*other._blob); break; default: assert(0); } } void SqlVariant::clear() { switch(_data_type) { case -1: break; case MYSQL_TYPE_VAR_STRING: delete _string; break; case MYSQL_TYPE_LONG: delete _int; break; case MYSQL_TYPE_LONGLONG: delete _integer; break; case MYSQL_TYPE_DOUBLE: delete _number; break; case MYSQL_TYPE_DATE: #if MYSQL_VERSION_ID>=50000 case MYSQL_TYPE_NEWDATE: #endif case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIME: case MYSQL_TYPE_TIMESTAMP: delete _date; break; case MYSQL_TYPE_BLOB: delete _blob; break; default: assert(0); } _data_type = (enum_field_types)-1; } std::string SqlVariant::str() const { switch(_data_type) { case -1: return ""; case MYSQL_TYPE_VAR_STRING: return _string->c_str(); // return *_string; case MYSQL_TYPE_LONG: return _int->str(); case MYSQL_TYPE_LONGLONG: return _integer->str(); case MYSQL_TYPE_DOUBLE: return _number->str(); case MYSQL_TYPE_DATE: #if MYSQL_VERSION_ID>=50000 case MYSQL_TYPE_NEWDATE: #endif case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIME: case MYSQL_TYPE_TIMESTAMP: return _date->str(); case MYSQL_TYPE_BLOB: return _blob->str(); break; default: assert(0); return ""; } } SqlNumber SqlVariant::number() const { switch(_data_type) { case -1: return SqlNumber(); case MYSQL_TYPE_VAR_STRING: return SqlNumber(*_string); case MYSQL_TYPE_LONG: return (int)*_int; case MYSQL_TYPE_LONGLONG: return (LONGLONG)*_integer; case MYSQL_TYPE_DOUBLE: return *_number; //case MYSQL_TYPE_DATETIME: // return ... default: THROW_MYSQLPL_EXCEPTION("no conversion to number"); } } int SqlVariant::get_int() const { switch(_data_type) { case -1: return 0; case MYSQL_TYPE_VAR_STRING: return atoi(*_string); case MYSQL_TYPE_LONG: return *_int; case MYSQL_TYPE_LONGLONG: return *_integer; case MYSQL_TYPE_DOUBLE: return _number->get_int(); //case MYSQL_TYPE_DATETIME: // return ... default: THROW_MYSQLPL_EXCEPTION("no conversion to int"); } } #ifdef _MSC_VER __int64 SqlVariant::get_int64() const { switch(_data_type) { case -1: return 0; case MYSQL_TYPE_VAR_STRING: return _atoi64(*_string); case MYSQL_TYPE_LONG: return *_int; case MYSQL_TYPE_LONGLONG: return *_integer; case MYSQL_TYPE_DOUBLE: return _number->get_int64(); //case MYSQL_TYPE_DATETIME: // return ... default: THROW_MYSQLPL_EXCEPTION("no conversion to int64"); } } #endif double SqlVariant::get_double() const { switch(_data_type) { case -1: return 0; case MYSQL_TYPE_VAR_STRING: return atof(*_string); case MYSQL_TYPE_LONG: return *_int; case MYSQL_TYPE_LONGLONG: return *_integer; case MYSQL_TYPE_DOUBLE: return _number->get_double(); //case MYSQL_TYPE_DATETIME: // return ... default: THROW_MYSQLPL_EXCEPTION("no conversion to double"); } } SqlDate SqlVariant::date(enum_mysql_timestamp_type type) const { switch(_data_type) { case -1: return SqlDate(); case MYSQL_TYPE_VAR_STRING: return SqlDate(*_string, MYSQL_TIMESTAMP_DATE); case MYSQL_TYPE_DATE: #if MYSQL_VERSION_ID>=50000 case MYSQL_TYPE_NEWDATE: #endif case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIME: case MYSQL_TYPE_TIMESTAMP: return SqlDate(*_date, type); default: THROW_MYSQLPL_EXCEPTION("no conversion to date type"); } } bool SqlVariant::is_null() const { switch(_data_type) { case -1: return true; case MYSQL_TYPE_VAR_STRING: return _string->is_null(); case MYSQL_TYPE_LONG: return _int->is_null(); case MYSQL_TYPE_LONGLONG: return _integer->is_null(); case MYSQL_TYPE_DOUBLE: return _number->is_null(); case MYSQL_TYPE_DATE: #if MYSQL_VERSION_ID>=50000 case MYSQL_TYPE_NEWDATE: #endif case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIME: case MYSQL_TYPE_TIMESTAMP: return _date->is_null(); case MYSQL_TYPE_BLOB: return _blob->is_null(); default: assert(0); return true; } } void mysql_bind_param(const BindPar& par, MYSQL_BIND& bind) { memset(&bind, 0, sizeof(bind)); bind.buffer = par._ptr; bind.buffer_type = par._type; bind.buffer_length = par._len; bind.is_null = par._pind; bind.length = par._plen; } void SqlStatement::bind_result(ColumnVector& columns) { int idx = 0; for(ColumnVector::iterator it=columns.begin(); it!=columns.end(); ++it) it->_column.bind_result_column(*this, _result_bind_vector[idx++]); bind_result(&_result_bind_vector[0]); } void SqlStatement::bind_result_column(BindResultPar par, MYSQL_BIND& bind) { memset(&bind, 0, sizeof(bind)); bind.buffer = par._ptr; bind.buffer_type = par._type; bind.buffer_length = par._len; bind.is_null = par._pind; bind.length = par._plen; } void SqlVariant::bind_result_column(SqlStatement& stmt, MYSQL_BIND& bind) { switch(_data_type) { case MYSQL_TYPE_VAR_STRING: stmt.bind_result_column(*_string, bind); break; case MYSQL_TYPE_LONG: stmt.bind_result_column(*_int, bind); break; case MYSQL_TYPE_LONGLONG: stmt.bind_result_column(*_integer, bind); break; case MYSQL_TYPE_DOUBLE: stmt.bind_result_column(*_number, bind); break; case MYSQL_TYPE_DATE: #if MYSQL_VERSION_ID>=50000 case MYSQL_TYPE_NEWDATE: #endif case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIME: case MYSQL_TYPE_TIMESTAMP: stmt.bind_result_column(*_date, bind); break; case MYSQL_TYPE_BLOB: stmt.bind_result_column(*_blob, bind); break; default: assert(0); } } #endif // MYSQLPL_PREP_STMT } // namespace MySqlPL