mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-26 14:37:44 +00:00
Implemented prepared statmements
This commit is contained in:
parent
98899756fb
commit
4e25fa0ed7
14 changed files with 2237 additions and 39 deletions
|
@ -1,6 +1,7 @@
|
|||
#include "Connection.h"
|
||||
#include "MySqlBase.h"
|
||||
#include "Statement.h"
|
||||
#include "PreparedStatement.h"
|
||||
|
||||
#include <vector>
|
||||
#include <boost/scoped_array.hpp>
|
||||
|
@ -228,3 +229,16 @@ std::string Core::Db::Connection::getError()
|
|||
return "";
|
||||
}
|
||||
|
||||
Core::Db::PreparedStatement* Core::Db::Connection::prepareStatement( const std::string &sql )
|
||||
{
|
||||
MYSQL_STMT* stmt = mysql_stmt_init( getRawCon() );
|
||||
|
||||
if( !stmt )
|
||||
throw std::runtime_error( "Could not init prepared statement: " + this->getError() );
|
||||
|
||||
if( mysql_stmt_prepare( stmt, sql.c_str(), sql.size() ) )
|
||||
throw std::runtime_error( "Could not prepare statement: " + this->getError() );
|
||||
|
||||
return new PreparedStatement( stmt, this );
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ namespace Db
|
|||
typedef std::map< enum mysql_option, std::string > optionMap;
|
||||
class MySqlBase;
|
||||
class Statement;
|
||||
class PreparedStatement;
|
||||
|
||||
class Connection
|
||||
{
|
||||
|
@ -69,7 +70,7 @@ namespace Db
|
|||
|
||||
bool reconnect();
|
||||
|
||||
//sql::PreparedStatement * prepareStatement(const sql::SQLString& sql);
|
||||
PreparedStatement* prepareStatement( const std::string& sql );
|
||||
|
||||
//sql::PreparedStatement * prepareStatement(const sql::SQLString& sql, int autoGeneratedKeys);
|
||||
|
||||
|
|
44
src/servers/Server_Common/Database/DataType.h
Normal file
44
src/servers/Server_Common/Database/DataType.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
#ifndef SAPPHIRE_DATATYPE_H
|
||||
#define SAPPHIRE_DATATYPE_H
|
||||
namespace Core
|
||||
{
|
||||
namespace Db
|
||||
{
|
||||
class DataType
|
||||
{
|
||||
DataType();
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
UNKNOWN = 0,
|
||||
BIT,
|
||||
TINYINT,
|
||||
SMALLINT,
|
||||
MEDIUMINT,
|
||||
INTEGER,
|
||||
BIGINT,
|
||||
REAL,
|
||||
DOUBLE,
|
||||
DECIMAL,
|
||||
NUMERIC,
|
||||
CHAR,
|
||||
BINARY,
|
||||
VARCHAR,
|
||||
VARBINARY,
|
||||
LONGVARCHAR,
|
||||
LONGVARBINARY,
|
||||
TIMESTAMP,
|
||||
DATE,
|
||||
TIME,
|
||||
YEAR,
|
||||
GEOMETRY,
|
||||
ENUM,
|
||||
SET,
|
||||
SQLNULL,
|
||||
JSON
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif //SAPPHIRE_DATATYPE_H
|
623
src/servers/Server_Common/Database/PreparedResultSet.cpp
Normal file
623
src/servers/Server_Common/Database/PreparedResultSet.cpp
Normal file
|
@ -0,0 +1,623 @@
|
|||
#include "PreparedResultSet.h"
|
||||
#include "ResultBind.h"
|
||||
#include "DataType.h"
|
||||
#include <string>
|
||||
#include <cctype>
|
||||
#include <clocale>
|
||||
|
||||
namespace
|
||||
{
|
||||
static inline char * my_l_to_a(char * buf, size_t buf_size, int64_t a)
|
||||
{
|
||||
snprintf(buf, buf_size, "%lld", (long long) a);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static inline char * my_ul_to_a(char * buf, size_t buf_size, uint64_t a)
|
||||
{
|
||||
snprintf(buf, buf_size, "%llu", (unsigned long long) a);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static inline char * my_f_to_a(char * buf, size_t buf_size, double a)
|
||||
{
|
||||
snprintf(buf, buf_size, "%f", a);
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Core::Db::PreparedResultSet::findColumn( const std::string &columnLabel ) const
|
||||
{
|
||||
std::string searchColumn = columnLabel;
|
||||
|
||||
std::transform( searchColumn.begin(), searchColumn.end(), searchColumn.begin(),
|
||||
[](unsigned char c){ return std::toupper( c ); } );
|
||||
|
||||
auto iter = m_fieldNameToIndex.find( searchColumn );
|
||||
if( iter == m_fieldNameToIndex.end() )
|
||||
return 0;
|
||||
|
||||
return iter->second + 1;
|
||||
}
|
||||
|
||||
Core::Db::PreparedResultSet::PreparedResultSet( boost::shared_ptr< ResultBind >& pBind,
|
||||
Core::Db::PreparedStatement* par ) :
|
||||
ResultSet( nullptr, par ),
|
||||
m_pResultBind( pBind )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool Core::Db::PreparedResultSet::isBeforeFirstOrAfterLast() const
|
||||
{
|
||||
return ( m_rowPosition == 0 );
|
||||
}
|
||||
|
||||
Core::Db::PreparedResultSet::~PreparedResultSet()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint32_t Core::Db::PreparedResultSet::getUInt( const uint32_t columnIndex ) const
|
||||
{
|
||||
|
||||
if( isBeforeFirstOrAfterLast() )
|
||||
throw std::runtime_error( "PreparedResultSet::getUInt: can't fetch because not on result set" );
|
||||
|
||||
if( columnIndex == 0 || columnIndex > m_numFields )
|
||||
throw std::runtime_error( "PreparedResultSet::getUInt: invalid value of 'columnIndex'" );
|
||||
|
||||
m_lastQueriedColumn = columnIndex;
|
||||
|
||||
if (*m_pResultBind->m_pBind[columnIndex - 1].is_null) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast< uint32_t >( getUInt64_intern( columnIndex, true ) );
|
||||
}
|
||||
|
||||
uint32_t Core::Db::PreparedResultSet::getUInt( const std::string& columnLabel ) const
|
||||
{
|
||||
return getUInt( findColumn( columnLabel ) );
|
||||
}
|
||||
|
||||
int64_t Core::Db::PreparedResultSet::getInt64( const uint32_t columnIndex ) const
|
||||
{
|
||||
|
||||
if( isBeforeFirstOrAfterLast() )
|
||||
throw std::runtime_error( "PreparedResultSet::getInt64: can't fetch because not on result set" );
|
||||
|
||||
if( columnIndex == 0 || columnIndex > m_numFields )
|
||||
throw std::runtime_error( "PreparedResultSet::getInt64: invalid value of 'columnIndex'" );
|
||||
|
||||
m_lastQueriedColumn = columnIndex;
|
||||
|
||||
if( *m_pResultBind->m_pBind[columnIndex - 1].is_null )
|
||||
return 0;
|
||||
|
||||
return getInt64_intern( columnIndex, true );
|
||||
}
|
||||
|
||||
int64_t Core::Db::PreparedResultSet::getInt64( const std::string& columnLabel ) const
|
||||
{
|
||||
return getInt64( findColumn( columnLabel ) );
|
||||
}
|
||||
|
||||
uint64_t Core::Db::PreparedResultSet::getUInt64_intern( const uint32_t columnIndex, bool ) const
|
||||
{
|
||||
|
||||
MYSQL_RES* res = mysql_stmt_result_metadata( m_pStmt->getRawStmt() );
|
||||
MYSQL_FIELD* field = mysql_fetch_field_direct( res, columnIndex );
|
||||
|
||||
switch( Util::mysql_type_to_datatype( field ) )
|
||||
{
|
||||
case DataType::REAL:
|
||||
case DataType::DOUBLE:
|
||||
return static_cast< uint64_t >( getDouble( columnIndex ) );
|
||||
case DataType::NUMERIC:
|
||||
case DataType::DECIMAL:
|
||||
case DataType::TIMESTAMP:
|
||||
case DataType::DATE:
|
||||
case DataType::TIME:
|
||||
case DataType::CHAR:
|
||||
case DataType::BINARY:
|
||||
case DataType::VARCHAR:
|
||||
case DataType::VARBINARY:
|
||||
case DataType::LONGVARCHAR:
|
||||
case DataType::LONGVARBINARY:
|
||||
case DataType::SET:
|
||||
case DataType::ENUM:
|
||||
case DataType::JSON:
|
||||
return strtoull( getString(columnIndex).c_str(), nullptr, 10 );
|
||||
case DataType::BIT:
|
||||
{
|
||||
uint64_t uval = 0;
|
||||
/* This length is in bytes, on the contrary to what can be seen in mysql_resultset.cpp where the Meta is used */
|
||||
switch( *m_pResultBind->m_pBind[columnIndex - 1].length )
|
||||
{
|
||||
case 8:uval = (uint64_t) bit_uint8korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
case 7:uval = (uint64_t) bit_uint7korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
case 6:uval = (uint64_t) bit_uint6korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
case 5:uval = (uint64_t) bit_uint5korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
case 4:uval = (uint64_t) bit_uint4korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
case 3:uval = (uint64_t) bit_uint3korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
case 2:uval = (uint64_t) bit_uint2korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
case 1:uval = (uint64_t) bit_uint1korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
}
|
||||
return uval;
|
||||
}
|
||||
case DataType::YEAR:
|
||||
case DataType::TINYINT:
|
||||
case DataType::SMALLINT:
|
||||
case DataType::MEDIUMINT:
|
||||
case DataType::INTEGER:
|
||||
case DataType::BIGINT:
|
||||
{
|
||||
|
||||
uint64_t ret;
|
||||
bool is_it_null = *m_pResultBind->m_pBind[columnIndex - 1].is_null != 0;
|
||||
bool is_it_unsigned = m_pResultBind->m_pBind[columnIndex - 1].is_unsigned != 0;
|
||||
|
||||
switch( m_pResultBind->m_pBind[columnIndex - 1].buffer_length )
|
||||
{
|
||||
case 1:
|
||||
if( is_it_unsigned )
|
||||
ret = !is_it_null ? *reinterpret_cast< uint8_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0;
|
||||
else
|
||||
ret = !is_it_null ? *reinterpret_cast< int8_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0;
|
||||
break;
|
||||
case 2:
|
||||
if(is_it_unsigned)
|
||||
ret = !is_it_null ? *reinterpret_cast< uint16_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0;
|
||||
else
|
||||
ret = !is_it_null ? *reinterpret_cast< int16_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0;
|
||||
break;
|
||||
case 4:
|
||||
if( is_it_unsigned )
|
||||
ret = !is_it_null ? *reinterpret_cast< uint32_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0;
|
||||
else
|
||||
ret = !is_it_null ? *reinterpret_cast< int32_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0;
|
||||
break;
|
||||
case 8:
|
||||
if( is_it_unsigned )
|
||||
ret = !is_it_null ? *reinterpret_cast< uint64_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0;
|
||||
else
|
||||
ret = !is_it_null ? *reinterpret_cast< int64_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error( "PreparedResultSet::getInt64_intern: invalid type" );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw std::runtime_error( "MySQL_Prepared_ResultSet::getUInt64_intern: unhandled type. Please, report" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int64_t Core::Db::PreparedResultSet::getInt64_intern( const uint32_t columnIndex, bool ) const
|
||||
{
|
||||
|
||||
MYSQL_RES* res = mysql_stmt_result_metadata( m_pStmt->getRawStmt() );
|
||||
MYSQL_FIELD* field = mysql_fetch_field_direct( res, columnIndex );
|
||||
|
||||
switch( Util::mysql_type_to_datatype( field ) )
|
||||
{
|
||||
case DataType::REAL:
|
||||
case DataType::DOUBLE:
|
||||
return static_cast< int64_t >( getDouble( columnIndex ) );
|
||||
case DataType::NUMERIC:
|
||||
case DataType::DECIMAL:
|
||||
case DataType::TIMESTAMP:
|
||||
case DataType::DATE:
|
||||
case DataType::TIME:
|
||||
case DataType::CHAR:
|
||||
case DataType::BINARY:
|
||||
case DataType::VARCHAR:
|
||||
case DataType::VARBINARY:
|
||||
case DataType::LONGVARCHAR:
|
||||
case DataType::LONGVARBINARY:
|
||||
case DataType::SET:
|
||||
case DataType::ENUM:
|
||||
case DataType::JSON:
|
||||
return strtoll( getString( columnIndex ).c_str(), nullptr, 10 );
|
||||
case DataType::BIT:
|
||||
{
|
||||
int64_t uval = 0;
|
||||
switch( *m_pResultBind->m_pBind[columnIndex - 1].length )
|
||||
{
|
||||
case 8:uval = ( int64_t ) bit_uint8korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
case 7:uval = ( int64_t ) bit_uint7korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
case 6:uval = ( int64_t ) bit_uint6korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
case 5:uval = ( int64_t ) bit_uint5korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
case 4:uval = ( int64_t ) bit_uint4korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
case 3:uval = ( int64_t ) bit_uint3korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
case 2:uval = ( int64_t ) bit_uint2korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
case 1:uval = ( int64_t ) bit_uint1korr( m_pResultBind->m_pBind[columnIndex - 1].buffer );break;
|
||||
}
|
||||
return uval;
|
||||
}
|
||||
case DataType::YEAR:
|
||||
case DataType::TINYINT:
|
||||
case DataType::SMALLINT:
|
||||
case DataType::MEDIUMINT:
|
||||
case DataType::INTEGER:
|
||||
case DataType::BIGINT:
|
||||
{
|
||||
int64_t ret;
|
||||
bool is_it_null = *m_pResultBind->m_pBind[columnIndex - 1].is_null != 0;
|
||||
bool is_it_unsigned = m_pResultBind->m_pBind[columnIndex - 1].is_unsigned != 0;
|
||||
|
||||
switch( m_pResultBind->m_pBind[columnIndex - 1].buffer_length )
|
||||
{
|
||||
case 1:
|
||||
if( is_it_unsigned )
|
||||
ret = !is_it_null ? *reinterpret_cast< uint8_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0;
|
||||
else
|
||||
ret = !is_it_null ? *reinterpret_cast< int8_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0;
|
||||
break;
|
||||
case 2:
|
||||
if( is_it_unsigned )
|
||||
ret = !is_it_null ? *reinterpret_cast< uint16_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0;
|
||||
else
|
||||
ret = !is_it_null ? *reinterpret_cast< int16_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0;
|
||||
break;
|
||||
case 4:
|
||||
if( is_it_unsigned )
|
||||
ret = !is_it_null ? *reinterpret_cast< uint32_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer) : 0;
|
||||
else
|
||||
ret = !is_it_null ? *reinterpret_cast< int32_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer) : 0;
|
||||
break;
|
||||
case 8:
|
||||
if( is_it_unsigned )
|
||||
ret = !is_it_null ? *reinterpret_cast< uint64_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0;
|
||||
else
|
||||
ret = !is_it_null ? *reinterpret_cast< int64_t* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error( "PreparedResultSet::getInt64_intern: invalid type" );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
throw std::runtime_error( "PreparedResultSet::getInt64_intern: unhandled type. Please, report" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t Core::Db::PreparedResultSet::getUInt64( const uint32_t columnIndex ) const
|
||||
{
|
||||
|
||||
if( isBeforeFirstOrAfterLast() )
|
||||
throw std::runtime_error( "PreparedResultSet::getUInt64: can't fetch because not on result set" );
|
||||
|
||||
if( columnIndex == 0 || columnIndex > m_numFields )
|
||||
throw std::runtime_error( "PreparedResultSet::getUInt64: invalid value of 'columnIndex'" );
|
||||
|
||||
m_lastQueriedColumn = columnIndex;
|
||||
|
||||
if( *m_pResultBind->m_pBind[columnIndex - 1].is_null )
|
||||
return 0;
|
||||
return getUInt64_intern( columnIndex, true );
|
||||
}
|
||||
|
||||
uint64_t Core::Db::PreparedResultSet::getUInt64( const std::string& columnLabel ) const
|
||||
{
|
||||
return getUInt64( findColumn( columnLabel ) );
|
||||
}
|
||||
|
||||
std::string Core::Db::PreparedResultSet::getString( const uint32_t columnIndex ) const
|
||||
{
|
||||
if( isBeforeFirstOrAfterLast() )
|
||||
throw std::runtime_error( "PreparedResultSet::getString: can't fetch because not on result set" );
|
||||
|
||||
if( columnIndex == 0 || columnIndex > m_numFields )
|
||||
throw std::runtime_error( "PreparedResultSet::getString: invalid 'columnIndex'" );
|
||||
|
||||
m_lastQueriedColumn = columnIndex;
|
||||
if( *m_pResultBind->m_pBind[columnIndex - 1].is_null )
|
||||
return std::string("");
|
||||
|
||||
MYSQL_RES* res = mysql_stmt_result_metadata( m_pStmt->getRawStmt() );
|
||||
MYSQL_FIELD* field = mysql_fetch_field_direct( res, columnIndex );
|
||||
|
||||
switch( Util::mysql_type_to_datatype( field ) )
|
||||
{
|
||||
case DataType::TIMESTAMP:
|
||||
{
|
||||
char buf[28];
|
||||
MYSQL_TIME * t = static_cast< MYSQL_TIME* >( m_pResultBind->m_pBind[columnIndex - 1].buffer );
|
||||
if( t->second_part )
|
||||
snprintf( buf, sizeof(buf) - 1, "%04d-%02d-%02d %02d:%02d:%02d.%06lu",
|
||||
t->year, t->month, t->day, t->hour, t->minute, t->second, t->second_part );
|
||||
else
|
||||
snprintf( buf, sizeof(buf) - 1, "%04d-%02d-%02d %02d:%02d:%02d",
|
||||
t->year, t->month, t->day, t->hour, t->minute, t->second );
|
||||
|
||||
return std::string( buf );
|
||||
}
|
||||
case DataType::DATE:
|
||||
{
|
||||
char buf[12];
|
||||
MYSQL_TIME* t = static_cast< MYSQL_TIME* >( m_pResultBind->m_pBind[columnIndex - 1].buffer );
|
||||
snprintf( buf, sizeof( buf ) - 1, "%02d-%02d-%02d", t->year, t->month, t->day );
|
||||
|
||||
return std::string( buf );
|
||||
}
|
||||
case DataType::TIME:
|
||||
{
|
||||
char buf[18];
|
||||
MYSQL_TIME* t = static_cast<MYSQL_TIME*>( m_pResultBind->m_pBind[columnIndex - 1].buffer );
|
||||
if( t->second_part )
|
||||
snprintf( buf, sizeof( buf ), "%s%02d:%02d:%02d.%06lu", t->neg ? "-" : "", t->hour, t->minute, t->second, t->second_part );
|
||||
else
|
||||
snprintf( buf, sizeof( buf ), "%s%02d:%02d:%02d", t->neg ? "-" : "", t->hour, t->minute, t->second );
|
||||
|
||||
return std::string( buf );
|
||||
}
|
||||
case DataType::BIT:
|
||||
case DataType::YEAR: // fetched as a SMALLINT
|
||||
case DataType::TINYINT:
|
||||
case DataType::SMALLINT:
|
||||
case DataType::MEDIUMINT:
|
||||
case DataType::INTEGER:
|
||||
case DataType::BIGINT:
|
||||
{
|
||||
char buf[30];
|
||||
|
||||
if( m_pResultBind->m_pBind[columnIndex - 1].is_unsigned )
|
||||
my_ul_to_a( buf, sizeof( buf ) - 1, getUInt64_intern( columnIndex, false ) );
|
||||
else
|
||||
my_l_to_a( buf, sizeof( buf ) - 1, getInt64_intern( columnIndex, false ) );
|
||||
|
||||
return std::string( buf );
|
||||
}
|
||||
case DataType::REAL:
|
||||
case DataType::DOUBLE:
|
||||
{
|
||||
char buf[50];
|
||||
my_f_to_a( buf, sizeof( buf ) - 1, getDouble( columnIndex ) );
|
||||
return std::string( buf );
|
||||
}
|
||||
case DataType::NUMERIC:
|
||||
case DataType::DECIMAL:
|
||||
case DataType::CHAR:
|
||||
case DataType::BINARY:
|
||||
case DataType::VARCHAR:
|
||||
case DataType::VARBINARY:
|
||||
case DataType::LONGVARCHAR:
|
||||
case DataType::LONGVARBINARY:
|
||||
case DataType::SET:
|
||||
case DataType::ENUM:
|
||||
case DataType::JSON:
|
||||
return std::string( static_cast< char* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ),
|
||||
*m_pResultBind->m_pBind[columnIndex - 1].length );
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
throw std::runtime_error( " PreparedResultSet::getString: unhandled type. Please, report" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string Core::Db::PreparedResultSet::getString( const std::string& columnLabel) const
|
||||
{
|
||||
return getString( findColumn( columnLabel ) );
|
||||
}
|
||||
|
||||
int32_t Core::Db::PreparedResultSet::getInt( uint32_t columnIndex ) const
|
||||
{
|
||||
if( isBeforeFirstOrAfterLast() )
|
||||
throw std::runtime_error( "PreparedResultSet::getInt: can't fetch because not on result set" );
|
||||
|
||||
if( columnIndex == 0 || columnIndex > m_numFields )
|
||||
throw std::runtime_error( "PreparedResultSet::getInt: invalid value of 'columnIndex'" );
|
||||
|
||||
m_lastQueriedColumn = columnIndex;
|
||||
|
||||
if( *m_pResultBind->m_pBind[columnIndex - 1].is_null )
|
||||
return 0;
|
||||
|
||||
return static_cast< int32_t >( getInt64_intern( columnIndex, true ) );
|
||||
}
|
||||
|
||||
int32_t Core::Db::PreparedResultSet::getInt( const std::string& columnLabel ) const
|
||||
{
|
||||
return getInt( findColumn( columnLabel ) );
|
||||
}
|
||||
|
||||
long double Core::Db::PreparedResultSet::getDouble(const uint32_t columnIndex) const
|
||||
{
|
||||
if( isBeforeFirstOrAfterLast() )
|
||||
throw std::runtime_error( "PreparedResultSet::getDouble: can't fetch because not on result set" );
|
||||
|
||||
if( columnIndex == 0 || columnIndex > m_numFields )
|
||||
throw std::runtime_error( "PreparedResultSet::getDouble: invalid 'columnIndex'" );
|
||||
|
||||
|
||||
m_lastQueriedColumn = columnIndex;
|
||||
|
||||
if( *m_pResultBind->m_pBind[columnIndex - 1].is_null)
|
||||
return 0.0;
|
||||
|
||||
MYSQL_RES* res = mysql_stmt_result_metadata( m_pStmt->getRawStmt() );
|
||||
MYSQL_FIELD* field = mysql_fetch_field_direct( res, columnIndex );
|
||||
|
||||
switch( Util::mysql_type_to_datatype( field ) )
|
||||
{
|
||||
case DataType::BIT:
|
||||
case DataType::YEAR:
|
||||
case DataType::TINYINT:
|
||||
case DataType::SMALLINT:
|
||||
case DataType::MEDIUMINT:
|
||||
case DataType::INTEGER:
|
||||
case DataType::BIGINT:
|
||||
{
|
||||
long double ret;
|
||||
bool is_it_unsigned = m_pResultBind->m_pBind[columnIndex - 1].is_unsigned != 0;
|
||||
|
||||
if( is_it_unsigned )
|
||||
{
|
||||
uint64_t ival = getUInt64_intern( columnIndex, false );
|
||||
ret = static_cast< long double >( ival );
|
||||
}
|
||||
else
|
||||
{
|
||||
int64_t ival = getInt64_intern( columnIndex, false );
|
||||
ret = static_cast< long double >( ival );
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
case DataType::NUMERIC:
|
||||
case DataType::DECIMAL:
|
||||
case DataType::TIMESTAMP:
|
||||
case DataType::DATE:
|
||||
case DataType::TIME:
|
||||
case DataType::CHAR:
|
||||
case DataType::BINARY:
|
||||
case DataType::VARCHAR:
|
||||
case DataType::VARBINARY:
|
||||
case DataType::LONGVARCHAR:
|
||||
case DataType::LONGVARBINARY:
|
||||
case DataType::SET:
|
||||
case DataType::ENUM:
|
||||
case DataType::JSON:
|
||||
{
|
||||
long double ret = Util::strtonum( getString( columnIndex ).c_str() );
|
||||
return ret;
|
||||
}
|
||||
case DataType::REAL:
|
||||
{
|
||||
long double ret = !*m_pResultBind->m_pBind[columnIndex - 1].is_null ?
|
||||
*reinterpret_cast< float* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0.;
|
||||
return ret;
|
||||
}
|
||||
case DataType::DOUBLE:
|
||||
{
|
||||
long double ret = !*m_pResultBind->m_pBind[columnIndex - 1].is_null ?
|
||||
*reinterpret_cast< double* >( m_pResultBind->m_pBind[columnIndex - 1].buffer ) : 0.;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error("PreparedResultSet::getDouble: unhandled type. Please, report");
|
||||
return .0;
|
||||
}
|
||||
|
||||
long double Core::Db::PreparedResultSet::getDouble( const std::string& columnLabel ) const
|
||||
{
|
||||
return getDouble( findColumn( columnLabel ) );
|
||||
}
|
||||
|
||||
size_t Core::Db::PreparedResultSet::getRow() const
|
||||
{
|
||||
return static_cast< size_t >( m_rowPosition );
|
||||
}
|
||||
|
||||
size_t Core::Db::PreparedResultSet::rowsCount() const
|
||||
{
|
||||
return static_cast< uint32_t >( m_numRows );
|
||||
}
|
||||
|
||||
const Core::Db::Statement* Core::Db::PreparedResultSet::getStatement() const
|
||||
{
|
||||
return m_pStmt;
|
||||
}
|
||||
|
||||
std::istream* Core::Db::PreparedResultSet::getBlob( const uint32_t columnIndex ) const
|
||||
{
|
||||
if( isBeforeFirstOrAfterLast() )
|
||||
throw std::runtime_error( "PreparedResultSet::getBlob: can't fetch because not on result set" );
|
||||
|
||||
return new std::istringstream( getString( columnIndex ) );
|
||||
}
|
||||
|
||||
std::istream* Core::Db::PreparedResultSet::getBlob( const std::string& columnLabel ) const
|
||||
{
|
||||
return new std::istringstream( getString( columnLabel ) );
|
||||
}
|
||||
|
||||
std::vector< char > Core::Db::PreparedResultSet::getBlobVector( uint32_t columnIndex ) const
|
||||
{
|
||||
if( columnIndex == 0 || columnIndex > m_numFields )
|
||||
throw std::runtime_error( "PreparedResultSet::getBlobVector: invalid value of 'columnIndex'" );
|
||||
|
||||
boost::scoped_ptr< std::istream > inStr( getBlob( columnIndex ) );
|
||||
char buff[4196];
|
||||
std::vector< char > data;
|
||||
inStr->read( buff, sizeof( buff ) );
|
||||
if( inStr->gcount() )
|
||||
{
|
||||
data.resize( static_cast< uint32_t >( inStr->gcount() ) );
|
||||
memcpy( data.data(), buff, static_cast< size_t >( inStr->gcount() ) );
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector< char > Core::Db::PreparedResultSet::getBlobVector( const std::string& columnLabel ) const
|
||||
{
|
||||
return getBlobVector( findColumn( columnLabel ) );
|
||||
}
|
||||
|
||||
bool Core::Db::PreparedResultSet::getBoolean( const uint32_t columnIndex ) const
|
||||
{
|
||||
if( isBeforeFirstOrAfterLast() )
|
||||
throw std::runtime_error( "PreparedResultSet::getBoolean: can't fetch because not on result set" );
|
||||
return getInt(columnIndex ) != 0;
|
||||
}
|
||||
|
||||
bool Core::Db::PreparedResultSet::getBoolean( const std::string& columnLabel ) const
|
||||
{
|
||||
if( isBeforeFirstOrAfterLast() )
|
||||
throw std::runtime_error("PreparedResultSet::getBoolean: can't fetch because not on result set");
|
||||
return getInt(columnLabel ) != 0;
|
||||
}
|
||||
|
||||
bool Core::Db::PreparedResultSet::isLast() const
|
||||
{
|
||||
return ( m_rowPosition == m_numRows );
|
||||
}
|
||||
|
||||
bool Core::Db::PreparedResultSet::isFirst() const
|
||||
{
|
||||
return ( m_rowPosition == 1 );
|
||||
}
|
||||
|
||||
bool Core::Db::PreparedResultSet::isNull( const uint32_t columnIndex ) const
|
||||
{
|
||||
if( columnIndex == 0 || columnIndex > m_numFields )
|
||||
throw std::runtime_error( "PreparedResultSet::isNull: invalid value of 'columnIndex'" );
|
||||
|
||||
if( isBeforeFirstOrAfterLast() )
|
||||
throw std::runtime_error( "PreparedResultSet::isNull: can't fetch because not on result set" );
|
||||
return *m_pResultBind->m_pBind[columnIndex - 1].is_null != 0;
|
||||
}
|
||||
|
||||
bool Core::Db::PreparedResultSet::isNull( const std::string& columnLabel ) const
|
||||
{
|
||||
uint32_t index = findColumn( columnLabel );
|
||||
if( index == 0 )
|
||||
throw std::runtime_error( "PreparedResultSet::isNull: invalid value of 'columnLabel'" );
|
||||
return isNull( index );
|
||||
}
|
||||
|
||||
bool Core::Db::PreparedResultSet::next()
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
// reset last_queried_column
|
||||
// m_lastQueriedColumn = std::numeric_limits< uint32_t >::max();
|
||||
|
||||
int result = mysql_stmt_fetch( m_pStmt->getRawStmt() );
|
||||
if( !result || result == MYSQL_DATA_TRUNCATED )
|
||||
ret = true;
|
||||
if( result == MYSQL_NO_DATA )
|
||||
ret = false;
|
||||
if( result == 1 )
|
||||
throw std::runtime_error( "PreparedResultSet:next: error getting next result" );
|
||||
++m_rowPosition;
|
||||
|
||||
return ret;
|
||||
}
|
115
src/servers/Server_Common/Database/PreparedResultSet.h
Normal file
115
src/servers/Server_Common/Database/PreparedResultSet.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
#ifndef SAPPHIRE_PREPAREDRESULTSET_H
|
||||
#define SAPPHIRE_PREPAREDRESULTSET_H
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include "ResultSet.h"
|
||||
|
||||
namespace Core
|
||||
{
|
||||
namespace Db
|
||||
{
|
||||
class PreparedStatement;
|
||||
// class PreparedResultSetMetaData;
|
||||
class ResultBind;
|
||||
|
||||
class PreparedResultSet : public ResultSet
|
||||
{
|
||||
private:
|
||||
mutable uint32_t m_lastQueriedColumn; // this is updated by calls to getInt(int), getString(int), etc...
|
||||
|
||||
uint32_t m_numFields;
|
||||
uint64_t m_numRows;
|
||||
uint64_t m_rowPosition;
|
||||
|
||||
typedef std::map< std::string, uint32_t > FieldNameIndexMap;
|
||||
|
||||
FieldNameIndexMap m_fieldNameToIndex;
|
||||
|
||||
PreparedStatement * m_pStmt;
|
||||
|
||||
bool is_valid;
|
||||
|
||||
// boost::scoped_ptr< MySQL_PreparedResultSetMetaData > rs_meta;
|
||||
|
||||
boost::shared_ptr< ResultBind > m_pResultBind;
|
||||
|
||||
protected:
|
||||
void checkValid() const;
|
||||
void closeIntern();
|
||||
bool isBeforeFirstOrAfterLast() const;
|
||||
void seek();
|
||||
|
||||
int64_t getInt64_intern(const uint32_t columnIndex, bool cutTooBig) const;
|
||||
uint64_t getUInt64_intern(const uint32_t columnIndex, bool cutTooBig) const;
|
||||
|
||||
public:
|
||||
PreparedResultSet( boost::shared_ptr< ResultBind >& pBind, PreparedStatement* par );
|
||||
|
||||
virtual ~PreparedResultSet();
|
||||
|
||||
void clearWarnings();
|
||||
|
||||
void close();
|
||||
|
||||
uint32_t findColumn( const std::string& columnLabel ) const;
|
||||
|
||||
std::istream * getBlob(uint32_t columnIndex) const;
|
||||
std::istream * getBlob(const std::string& columnLabel) const;
|
||||
|
||||
std::vector< char > getBlobVector( uint32_t columnIndex ) const;
|
||||
std::vector< char > getBlobVector( const std::string& columnLabel ) const;
|
||||
|
||||
bool getBoolean(uint32_t columnIndex) const;
|
||||
bool getBoolean(const std::string& columnLabel) const;
|
||||
|
||||
long double getDouble(uint32_t columnIndex) const;
|
||||
long double getDouble(const std::string& columnLabel) const;
|
||||
|
||||
int32_t getInt(uint32_t columnIndex) const;
|
||||
int32_t getInt(const std::string& columnLabel) const;
|
||||
|
||||
uint32_t getUInt(uint32_t columnIndex) const;
|
||||
uint32_t getUInt(const std::string& columnLabel) const;
|
||||
|
||||
int64_t getInt64(uint32_t columnIndex) const;
|
||||
int64_t getInt64(const std::string& columnLabel) const;
|
||||
|
||||
uint64_t getUInt64(uint32_t columnIndex) const;
|
||||
uint64_t getUInt64(const std::string& columnLabel) const;
|
||||
|
||||
//sql::ResultSetMetaData * getMetaData() const;
|
||||
|
||||
size_t getRow() const;
|
||||
|
||||
const Statement * getStatement() const;
|
||||
|
||||
std::string getString(uint32_t columnIndex) const;
|
||||
std::string getString(const std::string& columnLabel) const;
|
||||
|
||||
void getWarnings();
|
||||
|
||||
bool isClosed() const;
|
||||
|
||||
void insertRow();
|
||||
|
||||
bool isFirst() const;
|
||||
|
||||
bool isLast() const;
|
||||
|
||||
bool isNull(uint32_t columnIndex) const;
|
||||
|
||||
bool isNull(const std::string& columnLabel) const;
|
||||
|
||||
bool next();
|
||||
|
||||
size_t rowsCount() const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //SAPPHIRE_PREPAREDRESULTSET_H
|
696
src/servers/Server_Common/Database/PreparedStatement.cpp
Normal file
696
src/servers/Server_Common/Database/PreparedStatement.cpp
Normal file
|
@ -0,0 +1,696 @@
|
|||
#include "PreparedStatement.h"
|
||||
#include "PreparedResultSet.h"
|
||||
#include "Connection.h"
|
||||
#include "ResultBind.h"
|
||||
#include <boost/variant.hpp>
|
||||
#include <boost/scoped_array.hpp>
|
||||
#include <errmsg.h>
|
||||
|
||||
static const unsigned int MAX_SEND_LONGDATA_BUFFER = 1 << 18; //1<<18=256k (for istream)
|
||||
static const unsigned int MAX_SEND_LONGDATA_CHUNK = 1 << 18; //1<<19=512k (for string)
|
||||
|
||||
namespace Core
|
||||
{
|
||||
namespace Db
|
||||
{
|
||||
|
||||
// Visitor class to send long data contained in blob_bind
|
||||
class LongDataSender : public boost::static_visitor< bool >
|
||||
{
|
||||
unsigned position;
|
||||
MYSQL_STMT* m_pStmt;
|
||||
LongDataSender()
|
||||
{}
|
||||
|
||||
public:
|
||||
|
||||
LongDataSender(MYSQL_STMT* pStmt, unsigned int i)
|
||||
: position( i )
|
||||
, m_pStmt( pStmt )
|
||||
{
|
||||
}
|
||||
|
||||
bool operator()(std::istream * my_blob) const
|
||||
{
|
||||
if (my_blob == NULL)
|
||||
return false;
|
||||
|
||||
//char buf[MAX_SEND_LONGDATA_BUFFER];
|
||||
boost::scoped_array< char > buf( new char[MAX_SEND_LONGDATA_BUFFER] );
|
||||
|
||||
do
|
||||
{
|
||||
if( my_blob->eof() )
|
||||
break;
|
||||
my_blob->read( buf.get(), MAX_SEND_LONGDATA_BUFFER );
|
||||
|
||||
if( my_blob->bad() )
|
||||
throw std::runtime_error( "Error while reading from blob (bad)" );
|
||||
else if( my_blob->fail() )
|
||||
{
|
||||
if( !my_blob->eof() )
|
||||
throw std::runtime_error( "Error while reading from blob (fail)" );
|
||||
}
|
||||
if( mysql_stmt_send_long_data( m_pStmt, position, buf.get(), static_cast< unsigned long >( my_blob->gcount() ) ) )
|
||||
{
|
||||
switch( mysql_stmt_errno( m_pStmt ) )
|
||||
{
|
||||
case CR_OUT_OF_MEMORY:
|
||||
throw std::bad_alloc();
|
||||
case CR_INVALID_BUFFER_USE:
|
||||
throw std::runtime_error("PreparedStatement::setBlob: can't set blob value on that column");
|
||||
case CR_SERVER_GONE_ERROR:
|
||||
case CR_COMMANDS_OUT_OF_SYNC:
|
||||
default:
|
||||
throw std::runtime_error("PreparedStatement:: Default error");
|
||||
}
|
||||
}
|
||||
} while( true );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator()( std::string* str ) const
|
||||
{
|
||||
if ( str == nullptr )
|
||||
return false;
|
||||
|
||||
uint32_t sent = 0, chunkSize;
|
||||
|
||||
while( sent < str->length() )
|
||||
{
|
||||
chunkSize = ( sent + MAX_SEND_LONGDATA_CHUNK > str->length()
|
||||
? str->length() - sent
|
||||
: MAX_SEND_LONGDATA_CHUNK );
|
||||
|
||||
if( mysql_stmt_send_long_data( m_pStmt, position, str->c_str() + sent, chunkSize ) )
|
||||
{
|
||||
|
||||
switch( mysql_stmt_errno( m_pStmt ) )
|
||||
{
|
||||
case CR_OUT_OF_MEMORY:
|
||||
throw std::bad_alloc();
|
||||
case CR_INVALID_BUFFER_USE:
|
||||
throw std::runtime_error( "PreparedStatement::setBlob: can't set blob value on that column" );
|
||||
case CR_SERVER_GONE_ERROR:
|
||||
case CR_COMMANDS_OUT_OF_SYNC:
|
||||
default:
|
||||
throw std::runtime_error( "PreparedStatement:: Default error" );
|
||||
}
|
||||
}
|
||||
|
||||
sent+= chunkSize;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class BlobBindDeleter : public boost::static_visitor<>
|
||||
{
|
||||
public:
|
||||
|
||||
void operator()( std::string*& str ) const
|
||||
{
|
||||
if( str != nullptr )
|
||||
{
|
||||
delete str;
|
||||
str= nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void operator()( std::istream*& my_blob ) const
|
||||
{
|
||||
if( my_blob!= nullptr )
|
||||
{
|
||||
delete my_blob;
|
||||
my_blob= nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class BlobIsNull : public boost::static_visitor< bool >
|
||||
{
|
||||
public:
|
||||
|
||||
bool operator()( std::string*& str ) const
|
||||
{
|
||||
return str == nullptr;
|
||||
}
|
||||
|
||||
bool operator()( std::istream*& my_blob ) const
|
||||
{
|
||||
return my_blob == nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void resetBlobBind(MYSQL_BIND & param)
|
||||
{
|
||||
delete [] static_cast<char *>(param.buffer);
|
||||
|
||||
param.buffer_type = MYSQL_TYPE_LONG_BLOB;
|
||||
param.buffer = nullptr;
|
||||
param.buffer_length = 0;
|
||||
param.is_null_value = 0;
|
||||
|
||||
delete param.length;
|
||||
param.length = new unsigned long(0);
|
||||
}
|
||||
|
||||
|
||||
class ParamBind
|
||||
{
|
||||
public:
|
||||
|
||||
typedef boost::variant< std::istream*, std::string* > Blob_t;
|
||||
|
||||
private:
|
||||
|
||||
unsigned int m_paramCount;
|
||||
boost::scoped_array< MYSQL_BIND > bind;
|
||||
boost::scoped_array< bool > value_set;
|
||||
boost::scoped_array< bool > delete_blob_after_execute;
|
||||
|
||||
typedef std::map<unsigned int, Blob_t > Blobs;
|
||||
|
||||
Blobs blob_bind;
|
||||
|
||||
public:
|
||||
|
||||
ParamBind(unsigned int paramCount)
|
||||
: m_paramCount( paramCount ),
|
||||
bind( nullptr ),
|
||||
value_set( nullptr ),
|
||||
delete_blob_after_execute( nullptr )
|
||||
{
|
||||
if (m_paramCount)
|
||||
{
|
||||
bind.reset(new MYSQL_BIND[paramCount]);
|
||||
memset(bind.get(), 0, sizeof(MYSQL_BIND) * paramCount);
|
||||
|
||||
value_set.reset(new bool[paramCount]);
|
||||
delete_blob_after_execute.reset(new bool[paramCount]);
|
||||
for (unsigned int i = 0; i < paramCount; ++i)
|
||||
{
|
||||
bind[i].is_null_value = 1;
|
||||
value_set[i] = false;
|
||||
delete_blob_after_execute[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~ParamBind()
|
||||
{
|
||||
clearParameters();
|
||||
|
||||
for( Blobs::iterator it = blob_bind.begin(); it != blob_bind.end(); ++it )
|
||||
{
|
||||
if (delete_blob_after_execute[it->first])
|
||||
{
|
||||
delete_blob_after_execute[it->first] = false;
|
||||
boost::apply_visitor( BlobBindDeleter(), it->second );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set( unsigned int position )
|
||||
{
|
||||
value_set[position] = true;
|
||||
}
|
||||
|
||||
void unset( unsigned int position )
|
||||
{
|
||||
value_set[position] = false;
|
||||
if( delete_blob_after_execute[position] )
|
||||
{
|
||||
delete_blob_after_execute[position] = false;
|
||||
boost::apply_visitor( BlobBindDeleter(),blob_bind[position] );
|
||||
blob_bind.erase( position );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setBlob( unsigned int position, Blob_t & blob, bool delete_after_execute )
|
||||
{
|
||||
set( position );
|
||||
|
||||
resetBlobBind( bind[position] );
|
||||
|
||||
Blobs::iterator it = blob_bind.find( position );
|
||||
if( it != blob_bind.end() && delete_blob_after_execute[position] )
|
||||
boost::apply_visitor( BlobBindDeleter(), it->second );
|
||||
|
||||
if( boost::apply_visitor( BlobIsNull(), blob ) )
|
||||
{
|
||||
if( it != blob_bind.end() )
|
||||
blob_bind.erase(it);
|
||||
|
||||
delete_blob_after_execute[position] = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
blob_bind[position] = blob;
|
||||
delete_blob_after_execute[position] = delete_after_execute;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool isAllSet()
|
||||
{
|
||||
for( uint32_t i = 0; i < m_paramCount; ++i )
|
||||
{
|
||||
if (!value_set[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void clearParameters()
|
||||
{
|
||||
for( uint32_t i = 0; i < m_paramCount; ++i )
|
||||
{
|
||||
delete ( char* ) bind[i].length;
|
||||
bind[i].length = nullptr;
|
||||
delete[] ( char* ) bind[i].buffer;
|
||||
bind[i].buffer = nullptr;
|
||||
if (value_set[i])
|
||||
{
|
||||
Blobs::iterator it = blob_bind.find( i );
|
||||
if( it != blob_bind.end() && delete_blob_after_execute[i] )
|
||||
{
|
||||
boost::apply_visitor( BlobBindDeleter(), it->second );
|
||||
blob_bind.erase( it );
|
||||
}
|
||||
blob_bind[i] = Blob_t();
|
||||
value_set[i] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MYSQL_BIND * getBindObject()
|
||||
{
|
||||
return bind.get();
|
||||
}
|
||||
|
||||
|
||||
boost::variant< std::istream*, std::string* > getBlobObject( uint32_t position )
|
||||
{
|
||||
Blobs::iterator it= blob_bind.find( position );
|
||||
|
||||
if( it != blob_bind.end() )
|
||||
return it->second;
|
||||
|
||||
return Blob_t();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Core::Db::PreparedStatement::PreparedStatement( MYSQL_STMT* pStmt, Core::Db::Connection* pConn )
|
||||
: Statement( pConn )
|
||||
{
|
||||
m_pStmt = pStmt;
|
||||
m_pConnection = pConn;
|
||||
m_paramCount = mysql_stmt_param_count( m_pStmt );
|
||||
m_pParamBind.reset( new ParamBind( m_paramCount ) );
|
||||
m_pResultBind.reset( new ResultBind( pStmt ) );
|
||||
}
|
||||
|
||||
uint32_t Core::Db::PreparedStatement::errNo()
|
||||
{
|
||||
return mysql_stmt_errno( m_pStmt );
|
||||
}
|
||||
|
||||
Core::Db::Connection *Core::Db::PreparedStatement::getConnection()
|
||||
{
|
||||
return m_pConnection;
|
||||
}
|
||||
|
||||
Core::Db::PreparedStatement::~PreparedStatement()
|
||||
{
|
||||
if( m_pStmt )
|
||||
closeIntern();
|
||||
}
|
||||
|
||||
uint32_t Core::Db::PreparedStatement::getWarningCount()
|
||||
{
|
||||
return mysql_warning_count( m_pConnection->getRawCon() );
|
||||
}
|
||||
|
||||
uint64_t Core::Db::PreparedStatement::getUpdateCount()
|
||||
{
|
||||
throw std::runtime_error("PreparedStatement::getUpdateCount() Not implemented");
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Core::Db::PreparedStatement::sendLongDataBeforeParamBind()
|
||||
{
|
||||
MYSQL_BIND* bind = m_pParamBind->getBindObject();
|
||||
|
||||
for( unsigned int i = 0; i < m_paramCount; ++i )
|
||||
{
|
||||
if( bind[i].buffer_type == MYSQL_TYPE_LONG_BLOB )
|
||||
{
|
||||
LongDataSender lv( m_pStmt, i );
|
||||
ParamBind::Blob_t dummy( m_pParamBind->getBlobObject( i ) );
|
||||
boost::apply_visitor( lv, dummy );
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Core::Db::PreparedStatement::doQuery()
|
||||
{
|
||||
if( m_paramCount && !m_pParamBind->isAllSet() )
|
||||
throw std::runtime_error( "Value not set for all parameters" );
|
||||
|
||||
if( mysql_stmt_bind_param( m_pStmt, m_pParamBind->getBindObject() ) )
|
||||
throw std::runtime_error("Couldn't bind : " + std::to_string( errNo() ) );
|
||||
|
||||
if( !sendLongDataBeforeParamBind() || mysql_stmt_execute( m_pStmt ) )
|
||||
throw std::runtime_error( "Couldn't execute : " + std::to_string( errNo() ) + ": " + m_pConnection->getError() );
|
||||
|
||||
warningsCount = getWarningCount();
|
||||
}
|
||||
|
||||
void Core::Db::PreparedStatement::closeIntern()
|
||||
{
|
||||
if( m_pStmt )
|
||||
mysql_stmt_close( m_pStmt );
|
||||
clearParameters();
|
||||
}
|
||||
|
||||
void Core::Db::PreparedStatement::clearParameters()
|
||||
{
|
||||
m_pParamBind->clearParameters();
|
||||
}
|
||||
|
||||
bool Core::Db::PreparedStatement::execute()
|
||||
{
|
||||
doQuery();
|
||||
return mysql_stmt_field_count( m_pStmt ) > 0;
|
||||
}
|
||||
|
||||
bool Core::Db::PreparedStatement::execute( const std::string &sql )
|
||||
{
|
||||
throw std::runtime_error("PreparedStatement::execute( const std::string &sql ) Not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
Core::Db::ResultSet* Core::Db::PreparedStatement::executeQuery( const std::string &sql )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Core::Db::ResultSet* Core::Db::PreparedStatement::executeQuery()
|
||||
{
|
||||
doQuery();
|
||||
|
||||
my_bool bool_tmp = 1;
|
||||
mysql_stmt_attr_set( m_pStmt, STMT_ATTR_UPDATE_MAX_LENGTH, &bool_tmp );
|
||||
|
||||
ResultSet* tmp = new PreparedResultSet( m_pResultBind, this );
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
Core::Db::ResultSet* Core::Db::PreparedStatement::getResultSet()
|
||||
{
|
||||
my_bool bool_tmp = 1;
|
||||
mysql_stmt_attr_set( m_pStmt, STMT_ATTR_UPDATE_MAX_LENGTH, &bool_tmp );
|
||||
|
||||
ResultSet* tmp = new PreparedResultSet( m_pResultBind, this );
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
MYSQL_STMT* Core::Db::PreparedStatement::getRawStmt()
|
||||
{
|
||||
return m_pStmt;
|
||||
}
|
||||
|
||||
typedef std::pair< char*, size_t > BufferSizePair;
|
||||
|
||||
static BufferSizePair allocate_buffer_for_type(enum_field_types t)
|
||||
{
|
||||
switch( t )
|
||||
{
|
||||
case MYSQL_TYPE_LONG:
|
||||
return BufferSizePair( new char[4], 4 );
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
return BufferSizePair( new char[8], 8 );
|
||||
case MYSQL_TYPE_STRING:
|
||||
return BufferSizePair( NULLCSTR, 0 );
|
||||
case MYSQL_TYPE_NULL:
|
||||
return BufferSizePair( NULLCSTR, 0 );
|
||||
default:
|
||||
throw std::runtime_error( "allocate_buffer_for_type: invalid result_bind data type" );
|
||||
}
|
||||
}
|
||||
|
||||
void Core::Db::PreparedStatement::setInt( uint32_t parameterIndex, int32_t value )
|
||||
{
|
||||
|
||||
if( parameterIndex == 0 || parameterIndex > m_paramCount )
|
||||
throw std::runtime_error( "PreparedStatement::setInt: invalid 'parameterIndex'" );
|
||||
--parameterIndex;
|
||||
|
||||
{
|
||||
ParamBind::Blob_t dummy;
|
||||
m_pParamBind->setBlob( parameterIndex, dummy, false );
|
||||
m_pParamBind->unset( parameterIndex );
|
||||
}
|
||||
|
||||
enum_field_types t = MYSQL_TYPE_LONG;
|
||||
|
||||
BufferSizePair p = allocate_buffer_for_type(t);
|
||||
|
||||
m_pParamBind->set(parameterIndex);
|
||||
MYSQL_BIND* param = &m_pParamBind->getBindObject()[parameterIndex];
|
||||
|
||||
param->buffer_type = t;
|
||||
delete [] static_cast< char* >( param->buffer );
|
||||
param->buffer = p.first;
|
||||
param->buffer_length = 0;
|
||||
param->is_null_value = 0;
|
||||
delete param->length;
|
||||
param->length = nullptr;
|
||||
|
||||
memcpy( param->buffer, &value, p.second );
|
||||
|
||||
}
|
||||
|
||||
void Core::Db::PreparedStatement::setUInt( uint32_t parameterIndex, uint32_t value )
|
||||
{
|
||||
if( parameterIndex == 0 || parameterIndex > m_paramCount )
|
||||
throw std::runtime_error( "PreparedStatement::setInt: invalid 'parameterIndex'" );
|
||||
--parameterIndex;
|
||||
|
||||
{
|
||||
ParamBind::Blob_t dummy;
|
||||
m_pParamBind->setBlob( parameterIndex, dummy, false );
|
||||
m_pParamBind->unset( parameterIndex );
|
||||
}
|
||||
|
||||
enum_field_types t = MYSQL_TYPE_LONG;
|
||||
|
||||
BufferSizePair p = allocate_buffer_for_type(t);
|
||||
|
||||
m_pParamBind->set( parameterIndex );
|
||||
MYSQL_BIND* param = &m_pParamBind->getBindObject()[parameterIndex];
|
||||
|
||||
param->buffer_type = t;
|
||||
delete [] static_cast< char* >( param->buffer );
|
||||
param->buffer = p.first;
|
||||
param->buffer_length = 0;
|
||||
param->is_null_value = 0;
|
||||
param->is_unsigned = 1;
|
||||
delete param->length;
|
||||
param->length = nullptr;
|
||||
|
||||
memcpy( param->buffer, &value, p.second );
|
||||
}
|
||||
|
||||
void Core::Db::PreparedStatement::setInt64( uint32_t parameterIndex, int64_t value )
|
||||
{
|
||||
if( parameterIndex == 0 || parameterIndex > m_paramCount )
|
||||
throw std::runtime_error( "PreparedStatement::setInt64: invalid 'parameterIndex'" );
|
||||
--parameterIndex;
|
||||
|
||||
{
|
||||
ParamBind::Blob_t dummy;
|
||||
m_pParamBind->setBlob( parameterIndex, dummy, false );
|
||||
m_pParamBind->unset( parameterIndex );
|
||||
}
|
||||
|
||||
enum_field_types t = MYSQL_TYPE_LONGLONG;
|
||||
|
||||
BufferSizePair p = allocate_buffer_for_type(t);
|
||||
|
||||
m_pParamBind->set( parameterIndex );
|
||||
MYSQL_BIND* param = &m_pParamBind->getBindObject()[parameterIndex];
|
||||
|
||||
param->buffer_type = t;
|
||||
delete [] static_cast< char* >( param->buffer );
|
||||
param->buffer = p.first;
|
||||
param->buffer_length = 0;
|
||||
param->is_null_value = 0;
|
||||
delete param->length;
|
||||
param->length = nullptr;
|
||||
|
||||
memcpy( param->buffer, &value, p.second );
|
||||
}
|
||||
|
||||
void Core::Db::PreparedStatement::setUInt64( uint32_t parameterIndex, uint64_t value )
|
||||
{
|
||||
if( parameterIndex == 0 || parameterIndex > m_paramCount )
|
||||
throw std::runtime_error( "PreparedStatement::setInt64: invalid 'parameterIndex'" );
|
||||
--parameterIndex;
|
||||
|
||||
{
|
||||
ParamBind::Blob_t dummy;
|
||||
m_pParamBind->setBlob( parameterIndex, dummy, false );
|
||||
m_pParamBind->unset( parameterIndex );
|
||||
}
|
||||
|
||||
enum_field_types t = MYSQL_TYPE_LONGLONG;
|
||||
|
||||
BufferSizePair p = allocate_buffer_for_type(t);
|
||||
|
||||
m_pParamBind->set( parameterIndex );
|
||||
MYSQL_BIND* param = &m_pParamBind->getBindObject()[parameterIndex];
|
||||
|
||||
param->buffer_type = t;
|
||||
delete [] static_cast< char* >( param->buffer );
|
||||
param->buffer = p.first;
|
||||
param->buffer_length = 0;
|
||||
param->is_null_value = 0;
|
||||
param->is_unsigned = 1;
|
||||
delete param->length;
|
||||
param->length = nullptr;
|
||||
|
||||
memcpy( param->buffer, &value, p.second );
|
||||
}
|
||||
|
||||
void Core::Db::PreparedStatement::setNull( uint32_t parameterIndex, int )
|
||||
{
|
||||
if( parameterIndex == 0 || parameterIndex > m_paramCount )
|
||||
throw std::runtime_error( "PreparedStatement::setNull: invalid 'parameterIndex'" );
|
||||
--parameterIndex;
|
||||
|
||||
{
|
||||
ParamBind::Blob_t dummy;
|
||||
m_pParamBind->setBlob( parameterIndex, dummy, false );
|
||||
m_pParamBind->unset( parameterIndex );
|
||||
}
|
||||
|
||||
enum_field_types t = MYSQL_TYPE_NULL;
|
||||
|
||||
m_pParamBind->set( parameterIndex );
|
||||
MYSQL_BIND* param = &m_pParamBind->getBindObject()[parameterIndex];
|
||||
|
||||
param->buffer_type = t;
|
||||
delete [] static_cast< char* >( param->buffer );
|
||||
param->buffer = nullptr;
|
||||
delete param->length;
|
||||
param->length = nullptr;
|
||||
}
|
||||
|
||||
void Core::Db::PreparedStatement::setString( uint32_t parameterIndex, const std::string& value )
|
||||
{
|
||||
if( parameterIndex == 0 || parameterIndex > m_paramCount )
|
||||
{
|
||||
throw std::runtime_error( "PreparedStatement::setString: invalid 'parameterIndex'" );
|
||||
}
|
||||
if( value.length() > 256*1024 )
|
||||
{
|
||||
std::string* pvalue = new std::string( value );
|
||||
ParamBind::Blob_t dummy( pvalue );
|
||||
return m_pParamBind->setBlob( --parameterIndex, dummy, true );
|
||||
}
|
||||
|
||||
--parameterIndex;
|
||||
|
||||
{
|
||||
ParamBind::Blob_t dummy;
|
||||
m_pParamBind->setBlob( parameterIndex, dummy, false );
|
||||
m_pParamBind->unset( parameterIndex );
|
||||
}
|
||||
|
||||
enum_field_types t = MYSQL_TYPE_STRING;
|
||||
|
||||
m_pParamBind->set( parameterIndex );
|
||||
MYSQL_BIND* param = &m_pParamBind->getBindObject()[parameterIndex];
|
||||
|
||||
delete [] static_cast< char* >( param->buffer );
|
||||
|
||||
param->buffer_type = t;
|
||||
param->buffer = memcpy( new char[value.length() + 1], value.c_str(), value.length() + 1 );
|
||||
param->buffer_length = static_cast< unsigned long >( value.length() ) + 1;
|
||||
param->is_null_value = 0;
|
||||
|
||||
delete param->length;
|
||||
param->length = new unsigned long( static_cast< unsigned long >( value.length() ) );
|
||||
}
|
||||
|
||||
void Core::Db::PreparedStatement::setDouble( uint32_t parameterIndex, double value )
|
||||
{
|
||||
if( parameterIndex == 0 || parameterIndex > m_paramCount )
|
||||
{
|
||||
throw std::runtime_error( "PreparedStatement::setDouble: invalid 'parameterIndex'" );
|
||||
}
|
||||
--parameterIndex;
|
||||
|
||||
{
|
||||
ParamBind::Blob_t dummy;
|
||||
m_pParamBind->setBlob( parameterIndex, dummy, false );
|
||||
m_pParamBind->unset( parameterIndex );
|
||||
}
|
||||
|
||||
enum_field_types t = MYSQL_TYPE_DOUBLE;
|
||||
|
||||
BufferSizePair p = allocate_buffer_for_type(t);
|
||||
|
||||
m_pParamBind->set( parameterIndex );
|
||||
MYSQL_BIND* param = &m_pParamBind->getBindObject()[parameterIndex];
|
||||
|
||||
param->buffer_type = t;
|
||||
delete [] static_cast< char* >( param->buffer );
|
||||
param->buffer = p.first;
|
||||
param->buffer_length = 0;
|
||||
param->is_null_value = 0;
|
||||
delete param->length;
|
||||
param->length = nullptr;
|
||||
|
||||
memcpy( param->buffer, &value, p.second );
|
||||
}
|
||||
|
||||
void Core::Db::PreparedStatement::setDateTime( uint32_t parameterIndex, const std::string& value )
|
||||
{
|
||||
setString( parameterIndex, value );
|
||||
}
|
||||
|
||||
void Core::Db::PreparedStatement::setBoolean( uint32_t parameterIndex, bool value )
|
||||
{
|
||||
setInt( parameterIndex, value );
|
||||
}
|
||||
|
||||
void Core::Db::PreparedStatement::setBigInt( uint32_t parameterIndex, const std::string& value )
|
||||
{
|
||||
setString( parameterIndex, value );
|
||||
}
|
||||
|
||||
void Core::Db::PreparedStatement::setBlob( uint32_t parameterIndex, std::istream* blob )
|
||||
{
|
||||
if( parameterIndex == 0 || parameterIndex > m_paramCount )
|
||||
throw std::runtime_error( "PreparedStatement::setBlob: invalid 'parameterIndex'" );
|
||||
|
||||
ParamBind::Blob_t dummy(blob);
|
||||
m_pParamBind->setBlob( --parameterIndex, dummy, false );
|
||||
}
|
95
src/servers/Server_Common/Database/PreparedStatement.h
Normal file
95
src/servers/Server_Common/Database/PreparedStatement.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
#ifndef SAPPHIRE_PREPAREDSTATEMENT_H
|
||||
#define SAPPHIRE_PREPAREDSTATEMENT_H
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include "Statement.h"
|
||||
#include <mysql.h>
|
||||
|
||||
namespace Core
|
||||
{
|
||||
namespace Db
|
||||
{
|
||||
|
||||
class ParamBind;
|
||||
class ResultBind;
|
||||
|
||||
class PreparedStatement : public Statement
|
||||
{
|
||||
protected:
|
||||
MYSQL_STMT * m_pStmt;
|
||||
Connection * m_pConnection;
|
||||
boost::scoped_ptr< ParamBind > m_pParamBind;
|
||||
uint32_t m_paramCount;
|
||||
|
||||
int32_t resultSetConcurrency;
|
||||
int32_t resultSetType;
|
||||
|
||||
//boost::scoped_ptr< MySQL_PreparedResultSetMetaData > res_meta;
|
||||
//boost::scoped_ptr< MySQL_ParameterMetaData > param_meta;
|
||||
|
||||
boost::shared_ptr< ResultBind > m_pResultBind;
|
||||
|
||||
unsigned int warningsCount;
|
||||
|
||||
virtual void doQuery();
|
||||
virtual void closeIntern();
|
||||
|
||||
bool sendLongDataBeforeParamBind();
|
||||
|
||||
public:
|
||||
PreparedStatement( MYSQL_STMT* pStmt, Connection* pConn );
|
||||
virtual ~PreparedStatement();
|
||||
|
||||
Connection* getConnection() override;
|
||||
MYSQL_STMT* getRawStmt();
|
||||
|
||||
uint32_t errNo() override;
|
||||
|
||||
uint32_t getWarningCount() override;
|
||||
|
||||
uint64_t getUpdateCount() override;
|
||||
|
||||
void clearParameters();
|
||||
|
||||
bool execute();
|
||||
bool execute( const std::string& sql );
|
||||
|
||||
ResultSet* executeQuery();
|
||||
ResultSet* executeQuery( const std::string& sql );
|
||||
|
||||
bool getMoreResults();
|
||||
|
||||
ResultSet* getResultSet();
|
||||
|
||||
void setBlob( uint32_t parameterIndex, std::istream * blob );
|
||||
|
||||
void setBoolean( uint32_t parameterIndex, bool value );
|
||||
|
||||
void setBigInt( uint32_t parameterIndex, const std::string& value );
|
||||
|
||||
void setDateTime( uint32_t parameterIndex, const std::string& value );
|
||||
|
||||
void setDouble( uint32_t parameterIndex, double value );
|
||||
|
||||
void setInt( uint32_t parameterIndex, int32_t value );
|
||||
|
||||
void setUInt( uint32_t parameterIndex, uint32_t value );
|
||||
|
||||
void setInt64( uint32_t parameterIndex, int64_t value );
|
||||
|
||||
void setUInt64( uint32_t parameterIndex, uint64_t value );
|
||||
|
||||
void setNull( uint32_t parameterIndex, int sqlType );
|
||||
|
||||
void setString( uint32_t parameterIndex, const std::string& value );
|
||||
|
||||
private:
|
||||
PreparedStatement( const PreparedStatement& );
|
||||
void operator=( PreparedStatement& );
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif //SAPPHIRE_PREPAREDSTATEMENT_H
|
157
src/servers/Server_Common/Database/ResultBind.cpp
Normal file
157
src/servers/Server_Common/Database/ResultBind.cpp
Normal file
|
@ -0,0 +1,157 @@
|
|||
#include "ResultBind.h"
|
||||
|
||||
#include "mysql_util.h"
|
||||
#include "ResultBind.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
namespace Core
|
||||
{
|
||||
namespace Db
|
||||
{
|
||||
|
||||
struct st_buffer_size_type
|
||||
{
|
||||
char * buffer;
|
||||
size_t size;
|
||||
enum_field_types type;
|
||||
st_buffer_size_type( char * b, size_t s, enum_field_types t )
|
||||
: buffer( b ),
|
||||
size( s ),
|
||||
type( t )
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::pair< char*, size_t > BufferSizePair;
|
||||
static struct st_buffer_size_type
|
||||
allocate_buffer_for_field( const MYSQL_FIELD * const field )
|
||||
{
|
||||
switch( field->type )
|
||||
{
|
||||
case MYSQL_TYPE_NULL:
|
||||
return st_buffer_size_type( nullptr, 0, field->type );
|
||||
case MYSQL_TYPE_TINY:
|
||||
return st_buffer_size_type( new char[1], 1, field->type );
|
||||
case MYSQL_TYPE_SHORT:
|
||||
return st_buffer_size_type( new char[2], 2, field->type );
|
||||
case MYSQL_TYPE_INT24:
|
||||
case MYSQL_TYPE_LONG:
|
||||
case MYSQL_TYPE_FLOAT:
|
||||
return st_buffer_size_type( new char[4], 4, field->type );
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
return st_buffer_size_type( new char[8], 8, field->type );
|
||||
case MYSQL_TYPE_YEAR:
|
||||
return st_buffer_size_type( new char[2], 2, MYSQL_TYPE_SHORT );
|
||||
case MYSQL_TYPE_TIMESTAMP:
|
||||
case MYSQL_TYPE_DATE:
|
||||
case MYSQL_TYPE_TIME:
|
||||
case MYSQL_TYPE_DATETIME:
|
||||
return st_buffer_size_type( new char[sizeof( MYSQL_TIME )], sizeof( MYSQL_TIME ), field->type );
|
||||
|
||||
|
||||
case MYSQL_TYPE_TINY_BLOB:
|
||||
case MYSQL_TYPE_MEDIUM_BLOB:
|
||||
case MYSQL_TYPE_LONG_BLOB:
|
||||
case MYSQL_TYPE_BLOB:
|
||||
case MYSQL_TYPE_STRING:
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
#if LIBMYSQL_VERSION_ID > 50700
|
||||
case MYSQL_TYPE_JSON:
|
||||
return st_buffer_size_type(new char[field->max_length + 1], field->max_length + 1, field->type);
|
||||
#endif //LIBMYSQL_VERSION_ID > 50700
|
||||
|
||||
case MYSQL_TYPE_DECIMAL:
|
||||
case MYSQL_TYPE_NEWDECIMAL:
|
||||
return st_buffer_size_type( new char[64], 64, field->type );
|
||||
#if A1
|
||||
case MYSQL_TYPE_TIMESTAMP:
|
||||
case MYSQL_TYPE_YEAR:
|
||||
return st_buffer_size_type(new char[10], 10, field->type);
|
||||
#endif
|
||||
#if A0
|
||||
// There two are not sent over the wire
|
||||
case MYSQL_TYPE_ENUM:
|
||||
case MYSQL_TYPE_SET:
|
||||
#endif
|
||||
case MYSQL_TYPE_BIT:
|
||||
return st_buffer_size_type( new char[8], 8, MYSQL_TYPE_BIT );
|
||||
case MYSQL_TYPE_GEOMETRY:
|
||||
default:
|
||||
throw std::runtime_error( "allocate_buffer_for_field: invalid rbind data type" );
|
||||
}
|
||||
}
|
||||
|
||||
ResultBind::ResultBind( MYSQL_STMT* pStmt )
|
||||
: m_pStmt( pStmt ),
|
||||
m_numFields( 0 ),
|
||||
m_isNull( nullptr ),
|
||||
m_err( nullptr ),
|
||||
m_len( nullptr ),
|
||||
m_pBind( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
ResultBind::~ResultBind()
|
||||
{
|
||||
if( m_pBind.get() )
|
||||
{
|
||||
for( uint32_t i = 0; i < m_numFields; ++i )
|
||||
delete[] ( char* ) m_pBind[i].buffer;
|
||||
}
|
||||
}
|
||||
|
||||
void ResultBind::bindResult()
|
||||
{
|
||||
for( uint32_t i = 0; i < m_numFields; ++i )
|
||||
delete[] ( char* ) m_pBind[i].buffer;
|
||||
|
||||
m_pBind.reset( nullptr );
|
||||
m_isNull.reset( nullptr );
|
||||
m_err.reset( nullptr );
|
||||
m_len.reset( nullptr );
|
||||
|
||||
m_numFields = mysql_stmt_field_count( m_pStmt );
|
||||
if( !m_numFields )
|
||||
return;
|
||||
|
||||
m_pBind.reset( new MYSQL_BIND[m_numFields] );
|
||||
memset( m_pBind.get(), 0, sizeof( MYSQL_BIND ) * m_numFields );
|
||||
|
||||
m_isNull.reset( new my_bool[m_numFields] );
|
||||
memset( m_isNull.get(), 0, sizeof( my_bool ) * m_numFields );
|
||||
|
||||
m_err.reset( new my_bool[m_numFields] );
|
||||
memset( m_err.get(), 0, sizeof( my_bool ) * m_numFields );
|
||||
|
||||
m_len.reset( new unsigned long[m_numFields] );
|
||||
memset( m_len.get(), 0, sizeof( unsigned long ) * m_numFields );
|
||||
|
||||
//boost::scoped_ptr< NativeAPI::NativeResultsetWrapper > resultMeta(proxy->result_metadata());
|
||||
|
||||
MYSQL_RES* info = mysql_stmt_result_metadata( m_pStmt );
|
||||
for( uint32_t i = 0; i < m_numFields; ++i )
|
||||
{
|
||||
// MYSQL_FIELD * field = resultMeta->fetch_field();
|
||||
|
||||
MYSQL_FIELD * field = mysql_fetch_field( info );
|
||||
struct st_buffer_size_type p = allocate_buffer_for_field(field);
|
||||
m_pBind[i].buffer_type = p.type;
|
||||
m_pBind[i].buffer = p.buffer;
|
||||
m_pBind[i].buffer_length = static_cast< unsigned long >( p.size );
|
||||
m_pBind[i].length = &m_len[i];
|
||||
m_pBind[i].is_null = &m_isNull[i];
|
||||
m_pBind[i].error = &m_err[i];
|
||||
m_pBind[i].is_unsigned = field->flags & UNSIGNED_FLAG;
|
||||
}
|
||||
if( mysql_stmt_bind_result( m_pStmt, m_pBind.get() ) )
|
||||
throw std::runtime_error( "Couldn't bind : " + std::to_string( mysql_stmt_errno( m_pStmt ) ) );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
37
src/servers/Server_Common/Database/ResultBind.h
Normal file
37
src/servers/Server_Common/Database/ResultBind.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef SAPPHIRE_RESULTBIND_H
|
||||
#define SAPPHIRE_RESULTBIND_H
|
||||
|
||||
#include <boost/scoped_array.hpp>
|
||||
|
||||
#include "mysql_util.h"
|
||||
#include "mysql.h"
|
||||
#include "PreparedStatement.h"
|
||||
|
||||
namespace Core
|
||||
{
|
||||
namespace Db
|
||||
{
|
||||
|
||||
class ResultBind
|
||||
{
|
||||
uint32_t m_numFields;
|
||||
boost::scoped_array< char > m_isNull;
|
||||
boost::scoped_array< char > m_err;
|
||||
boost::scoped_array< unsigned long > m_len;
|
||||
MYSQL_STMT* m_pStmt;
|
||||
|
||||
public:
|
||||
boost::scoped_array< MYSQL_BIND > m_pBind;
|
||||
|
||||
ResultBind( MYSQL_STMT* pStmt );
|
||||
|
||||
~ResultBind();
|
||||
|
||||
void bindResult();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif //SAPPHIRE_RESULTBIND_H
|
|
@ -18,7 +18,7 @@ namespace Core
|
|||
//class ResultSetMetaData;
|
||||
|
||||
|
||||
class ResultSet : public ResultSetBase
|
||||
class ResultSet
|
||||
{
|
||||
MYSQL_ROW m_row;
|
||||
|
||||
|
@ -48,50 +48,50 @@ namespace Core
|
|||
|
||||
virtual ~ResultSet();
|
||||
|
||||
uint32_t findColumn( const std::string& columnLabel ) const;
|
||||
virtual uint32_t findColumn( const std::string& columnLabel ) const;
|
||||
|
||||
std::istream * getBlob( uint32_t columnIndex ) const;
|
||||
std::istream * getBlob( const std::string& columnLabel ) const;
|
||||
virtual std::istream * getBlob( uint32_t columnIndex ) const;
|
||||
virtual std::istream * getBlob( const std::string& columnLabel ) const;
|
||||
|
||||
std::vector< char > getBlobVector( uint32_t columnIndex ) const;
|
||||
std::vector< char > getBlobVector( const std::string& columnLabel ) const;
|
||||
virtual std::vector< char > getBlobVector( uint32_t columnIndex ) const;
|
||||
virtual std::vector< char > getBlobVector( const std::string& columnLabel ) const;
|
||||
|
||||
bool getBoolean( uint32_t columnIndex ) const;
|
||||
bool getBoolean( const std::string& columnLabel ) const;
|
||||
virtual bool getBoolean( uint32_t columnIndex ) const;
|
||||
virtual bool getBoolean( const std::string& columnLabel ) const;
|
||||
|
||||
long double getDouble( uint32_t columnIndex ) const;
|
||||
long double getDouble( const std::string& columnLabel ) const;
|
||||
virtual long double getDouble( uint32_t columnIndex ) const;
|
||||
virtual long double getDouble( const std::string& columnLabel ) const;
|
||||
|
||||
int32_t getInt( uint32_t columnIndex ) const;
|
||||
int32_t getInt( const std::string& columnLabel ) const;
|
||||
virtual int32_t getInt( uint32_t columnIndex ) const;
|
||||
virtual int32_t getInt( const std::string& columnLabel ) const;
|
||||
|
||||
uint32_t getUInt( uint32_t columnIndex ) const;
|
||||
uint32_t getUInt( const std::string& columnLabel ) const;
|
||||
virtual uint32_t getUInt( uint32_t columnIndex ) const;
|
||||
virtual uint32_t getUInt( const std::string& columnLabel ) const;
|
||||
|
||||
int64_t getInt64( uint32_t columnIndex ) const;
|
||||
int64_t getInt64( const std::string& columnLabel ) const;
|
||||
virtual int64_t getInt64( uint32_t columnIndex ) const;
|
||||
virtual int64_t getInt64( const std::string& columnLabel ) const;
|
||||
|
||||
uint64_t getUInt64( uint32_t columnIndex ) const;
|
||||
uint64_t getUInt64( const std::string& columnLabel ) const;
|
||||
virtual uint64_t getUInt64( uint32_t columnIndex ) const;
|
||||
virtual uint64_t getUInt64( const std::string& columnLabel ) const;
|
||||
|
||||
//sql::ResultSetMetaData * getMetaData() const;
|
||||
|
||||
size_t getRow() const;
|
||||
virtual size_t getRow() const;
|
||||
|
||||
const Statement * getStatement() const;
|
||||
virtual const Statement * getStatement() const;
|
||||
|
||||
std::string getString( uint32_t columnIndex ) const;
|
||||
std::string getString( const std::string& columnLabel ) const;
|
||||
virtual std::string getString( uint32_t columnIndex ) const;
|
||||
virtual std::string getString( const std::string& columnLabel ) const;
|
||||
|
||||
bool isFirst() const;
|
||||
virtual bool isFirst() const;
|
||||
|
||||
bool isLast() const;
|
||||
virtual bool isLast() const;
|
||||
|
||||
bool isNull( uint32_t columnIndex ) const;
|
||||
virtual bool isNull( uint32_t columnIndex ) const;
|
||||
|
||||
bool isNull( const std::string& columnLabel ) const;
|
||||
virtual bool isNull( const std::string& columnLabel ) const;
|
||||
|
||||
bool next();
|
||||
virtual bool next();
|
||||
|
||||
size_t rowsCount() const;
|
||||
private:
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include "StatementBase.h"
|
||||
|
||||
namespace Core
|
||||
{
|
||||
|
@ -12,7 +11,7 @@ namespace Db
|
|||
class Connection;
|
||||
class ResultSet;
|
||||
|
||||
class Statement : public StatementBase
|
||||
class Statement
|
||||
{
|
||||
protected:
|
||||
Connection * m_pConnection;
|
||||
|
@ -28,19 +27,19 @@ namespace Db
|
|||
|
||||
virtual ~Statement() {};
|
||||
|
||||
Connection * getConnection() override;
|
||||
virtual Connection * getConnection();
|
||||
|
||||
bool execute( const std::string& sql ) override;
|
||||
virtual bool execute( const std::string& sql );
|
||||
|
||||
ResultSet * executeQuery( const std::string& sql ) override;
|
||||
virtual ResultSet * executeQuery( const std::string& sql );
|
||||
|
||||
ResultSet * getResultSet() override;
|
||||
virtual ResultSet * getResultSet();
|
||||
|
||||
uint64_t getUpdateCount() override;
|
||||
virtual uint64_t getUpdateCount();
|
||||
|
||||
uint32_t getWarningCount() override;
|
||||
virtual uint32_t getWarningCount();
|
||||
|
||||
uint32_t errNo() override;
|
||||
virtual uint32_t errNo();
|
||||
|
||||
private:
|
||||
/* Prevent use of these */
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include "mysql_util.h"
|
||||
#include "DataType.h"
|
||||
#include <mysql.h>
|
||||
|
||||
long double Util::strtold(const char *nptr, char **endptr)
|
||||
{
|
||||
|
@ -57,3 +59,374 @@ long double Util::strtonum( const std::string &str, int radix )
|
|||
|
||||
return val;
|
||||
}
|
||||
|
||||
#define cppconn_mbcharlen_big5 NULL
|
||||
#define check_mb_big5 NULL
|
||||
#define cppconn_mbcharlen_ujis NULL
|
||||
#define check_mb_ujis NULL
|
||||
#define cppconn_mbcharlen_sjis NULL
|
||||
#define check_mb_sjis NULL
|
||||
#define cppconn_mbcharlen_euckr NULL
|
||||
#define check_mb_euckr NULL
|
||||
#define cppconn_mbcharlen_gb2312 NULL
|
||||
#define check_mb_gb2312 NULL
|
||||
#define cppconn_mbcharlen_gbk NULL
|
||||
#define check_mb_gbk NULL
|
||||
#define cppconn_mbcharlen_utf8 NULL
|
||||
#define check_mb_utf8_valid NULL
|
||||
#define cppconn_mbcharlen_ucs2 NULL
|
||||
#define check_mb_ucs2 NULL
|
||||
#define cppconn_mbcharlen_cp932 NULL
|
||||
#define check_mb_cp932 NULL
|
||||
#define cppconn_mbcharlen_eucjpms NULL
|
||||
#define check_mb_eucjpms NULL
|
||||
#define cppconn_mbcharlen_utf8 NULL
|
||||
#define check_mb_utf8_valid NULL
|
||||
#define cppconn_mbcharlen_utf8mb4 cppconn_mbcharlen_utf8
|
||||
#define check_mb_utf8mb4_valid check_mb_utf8_valid
|
||||
#define cppconn_mbcharlen_utf16 NULL
|
||||
#define check_mb_utf16_valid NULL
|
||||
#define cppconn_mbcharlen_utf32 NULL
|
||||
#define check_mb_utf32_valid NULL
|
||||
|
||||
/* {{{ our_charsets60 */
|
||||
const Util::OUR_CHARSET our_charsets60[] =
|
||||
{
|
||||
{ 1, "big5","big5_chinese_ci", 1, 2, "", cppconn_mbcharlen_big5, check_mb_big5},
|
||||
{ 3, "dec8", "dec8_swedisch_ci", 1, 1, "", NULL, NULL},
|
||||
{ 4, "cp850", "cp850_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 6, "hp8", "hp8_english_ci", 1, 1, "", NULL, NULL},
|
||||
{ 7, "koi8r", "koi8r_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 8, "latin1", "latin1_swedish_ci", 1, 1, "", NULL, NULL},
|
||||
{ 9, "latin2", "latin2_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 10, "swe7", "swe7_swedish_ci", 1, 1, "", NULL, NULL},
|
||||
{ 11, "ascii", "ascii_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 12, "ujis", "ujis_japanese_ci", 1, 3, "", cppconn_mbcharlen_ujis, check_mb_ujis},
|
||||
{ 13, "sjis", "sjis_japanese_ci", 1, 2, "", cppconn_mbcharlen_sjis, check_mb_sjis},
|
||||
{ 16, "hebrew", "hebrew_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 18, "tis620", "tis620_thai_ci", 1, 1, "", NULL, NULL},
|
||||
{ 19, "euckr", "euckr_korean_ci", 1, 2, "", cppconn_mbcharlen_euckr, check_mb_euckr},
|
||||
{ 22, "koi8u", "koi8u_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 24, "gb2312", "gb2312_chinese_ci", 1, 2, "", cppconn_mbcharlen_gb2312, check_mb_gb2312},
|
||||
{ 25, "greek", "greek_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 26, "cp1250", "cp1250_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 28, "gbk", "gbk_chinese_ci", 1, 2, "", cppconn_mbcharlen_gbk, check_mb_gbk},
|
||||
{ 30, "latin5", "latin5_turkish_ci", 1, 1, "", NULL, NULL},
|
||||
{ 32, "armscii8", "armscii8_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 33, "utf8", "utf8_general_ci", 1, 3, "UTF-8 Unicode", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 35, "ucs2", "ucs2_general_ci", 2, 2, "UCS-2 Unicode", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 36, "cp866", "cp866_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 37, "keybcs2", "keybcs2_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 38, "macce", "macce_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 39, "macroman", "macroman_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 40, "cp852", "cp852_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 41, "latin7", "latin7_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 51, "cp1251", "cp1251_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 57, "cp1256", "cp1256_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 59, "cp1257", "cp1257_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 63, "binary", "binary", 1, 1, "", NULL, NULL},
|
||||
{ 92, "geostd8", "geostd8_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 95, "cp932", "cp932_japanese_ci", 1, 2, "", cppconn_mbcharlen_cp932, check_mb_cp932},
|
||||
{ 97, "eucjpms", "eucjpms_japanese_ci", 1, 3, "", cppconn_mbcharlen_eucjpms, check_mb_eucjpms},
|
||||
{ 2, "latin2", "latin2_czech_cs", 1, 1, "", NULL, NULL},
|
||||
{ 5, "latin1", "latin1_german_ci", 1, 1, "", NULL, NULL},
|
||||
{ 14, "cp1251", "cp1251_bulgarian_ci", 1, 1, "", NULL, NULL},
|
||||
{ 15, "latin1", "latin1_danish_ci", 1, 1, "", NULL, NULL},
|
||||
{ 17, "filename", "filename", 1, 5, "", NULL, NULL},
|
||||
{ 20, "latin7", "latin7_estonian_cs", 1, 1, "", NULL, NULL},
|
||||
{ 21, "latin2", "latin2_hungarian_ci", 1, 1, "", NULL, NULL},
|
||||
{ 23, "cp1251", "cp1251_ukrainian_ci", 1, 1, "", NULL, NULL},
|
||||
{ 27, "latin2", "latin2_croatian_ci", 1, 1, "", NULL, NULL},
|
||||
{ 29, "cp1257", "cp1257_lithunian_ci", 1, 1, "", NULL, NULL},
|
||||
{ 31, "latin1", "latin1_german2_ci", 1, 1, "", NULL, NULL},
|
||||
{ 34, "cp1250", "cp1250_czech_cs", 1, 1, "", NULL, NULL},
|
||||
{ 42, "latin7", "latin7_general_cs", 1, 1, "", NULL, NULL},
|
||||
{ 43, "macce", "macce_bin", 1, 1, "", NULL, NULL},
|
||||
{ 44, "cp1250", "cp1250_croatian_ci", 1, 1, "", NULL, NULL},
|
||||
{ 47, "latin1", "latin1_bin", 1, 1, "", NULL, NULL},
|
||||
{ 48, "latin1", "latin1_general_ci", 1, 1, "", NULL, NULL},
|
||||
{ 49, "latin1", "latin1_general_cs", 1, 1, "", NULL, NULL},
|
||||
{ 50, "cp1251", "cp1251_bin", 1, 1, "", NULL, NULL},
|
||||
{ 52, "cp1251", "cp1251_general_cs", 1, 1, "", NULL, NULL},
|
||||
{ 53, "macroman", "macroman_bin", 1, 1, "", NULL, NULL},
|
||||
{ 58, "cp1257", "cp1257_bin", 1, 1, "", NULL, NULL},
|
||||
{ 60, "armascii8", "armascii8_bin", 1, 1, "", NULL, NULL},
|
||||
{ 65, "ascii", "ascii_bin", 1, 1, "", NULL, NULL},
|
||||
{ 66, "cp1250", "cp1250_bin", 1, 1, "", NULL, NULL},
|
||||
{ 67, "cp1256", "cp1256_bin", 1, 1, "", NULL, NULL},
|
||||
{ 68, "cp866", "cp866_bin", 1, 1, "", NULL, NULL},
|
||||
{ 69, "dec8", "dec8_bin", 1, 1, "", NULL, NULL},
|
||||
{ 70, "greek", "greek_bin", 1, 1, "", NULL, NULL},
|
||||
{ 71, "hebrew", "hebrew_bin", 1, 1, "", NULL, NULL},
|
||||
{ 72, "hp8", "hp8_bin", 1, 1, "", NULL, NULL},
|
||||
{ 73, "keybcs2", "keybcs2_bin", 1, 1, "", NULL, NULL},
|
||||
{ 74, "koi8r", "koi8r_bin", 1, 1, "", NULL, NULL},
|
||||
{ 75, "koi8u", "koi8u_bin", 1, 1, "", NULL, NULL},
|
||||
{ 77, "latin2", "latin2_bin", 1, 1, "", NULL, NULL},
|
||||
{ 78, "latin5", "latin5_bin", 1, 1, "", NULL, NULL},
|
||||
{ 79, "latin7", "latin7_bin", 1, 1, "", NULL, NULL},
|
||||
{ 80, "cp850", "cp850_bin", 1, 1, "", NULL, NULL},
|
||||
{ 81, "cp852", "cp852_bin", 1, 1, "", NULL, NULL},
|
||||
{ 82, "swe7", "swe7_bin", 1, 1, "", NULL, NULL},
|
||||
{ 93, "geostd8", "geostd8_bin", 1, 1, "", NULL, NULL},
|
||||
{ 83, "utf8", "utf8_bin", 1, 3, "UTF-8 Unicode", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 84, "big5", "big5_bin", 1, 2, "", cppconn_mbcharlen_big5, check_mb_big5},
|
||||
{ 85, "euckr", "euckr_bin", 1, 2, "", cppconn_mbcharlen_euckr, check_mb_euckr},
|
||||
{ 86, "gb2312", "gb2312_bin", 1, 2, "", cppconn_mbcharlen_gb2312, check_mb_gb2312},
|
||||
{ 87, "gbk", "gbk_bin", 1, 2, "", cppconn_mbcharlen_gbk, check_mb_gbk},
|
||||
{ 88, "sjis", "sjis_bin", 1, 2, "", cppconn_mbcharlen_sjis, check_mb_sjis},
|
||||
{ 89, "tis620", "tis620_bin", 1, 1, "", NULL, NULL},
|
||||
{ 90, "ucs2", "ucs2_bin", 2, 2, "UCS-2 Unicode", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 91, "ujis", "ujis_bin", 1, 3, "", cppconn_mbcharlen_ujis, check_mb_ujis},
|
||||
{ 94, "latin1", "latin1_spanish_ci", 1, 1, "", NULL, NULL},
|
||||
{ 96, "cp932", "cp932_bin", 1, 2, "", cppconn_mbcharlen_cp932, check_mb_cp932},
|
||||
{ 99, "cp1250", "cp1250_polish_ci", 1, 1, "", NULL, NULL},
|
||||
{ 98, "eucjpms", "eucjpms_bin", 1, 3, "", cppconn_mbcharlen_eucjpms, check_mb_eucjpms},
|
||||
{ 128, "ucs2", "ucs2_unicode_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 129, "ucs2", "ucs2_icelandic_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 130, "ucs2", "ucs2_latvian_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 131, "ucs2", "ucs2_romanian_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 132, "ucs2", "ucs2_slovenian_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 133, "ucs2", "ucs2_polish_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 134, "ucs2", "ucs2_estonian_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 135, "ucs2", "ucs2_spanish_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 136, "ucs2", "ucs2_swedish_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 137, "ucs2", "ucs2_turkish_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 138, "ucs2", "ucs2_czech_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 139, "ucs2", "ucs2_danish_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 140, "ucs2", "ucs2_lithunian_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 141, "ucs2", "ucs2_slovak_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 142, "ucs2", "ucs2_spanish2_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 143, "ucs2", "ucs2_roman_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 144, "ucs2", "ucs2_persian_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 145, "ucs2", "ucs2_esperanto_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 146, "ucs2", "ucs2_hungarian_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 147, "ucs2", "ucs2_sinhala_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 148, "ucs2", "ucs2_german2_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 149, "ucs2", "ucs2_croatian_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 150, "ucs2", "ucs2_unicode_520_ci", 2, 2, "", cppconn_mbcharlen_ucs2, check_mb_ucs2},
|
||||
{ 192, "utf8", "utf8_unicode_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 193, "utf8", "utf8_icelandic_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 194, "utf8", "utf8_latvian_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 195, "utf8", "utf8_romanian_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 196, "utf8", "utf8_slovenian_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 197, "utf8", "utf8_polish_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 198, "utf8", "utf8_estonian_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 199, "utf8", "utf8_spanish_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 200, "utf8", "utf8_swedish_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 201, "utf8", "utf8_turkish_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 202, "utf8", "utf8_czech_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 203, "utf8", "utf8_danish_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid },
|
||||
{ 204, "utf8", "utf8_lithunian_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid },
|
||||
{ 205, "utf8", "utf8_slovak_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 206, "utf8", "utf8_spanish2_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 207, "utf8", "utf8_roman_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 208, "utf8", "utf8_persian_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 209, "utf8", "utf8_esperanto_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 210, "utf8", "utf8_hungarian_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 211, "utf8", "utf8_sinhala_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 212, "utf8", "utf8_german2_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 213, "utf8", "utf8_croatian_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 214, "utf8", "utf8_unicode_520_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 215, "utf8", "utf8_vietnamese_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 223, "utf8", "utf8_general_mysql500_ci", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
{ 45, "utf8mb4", "utf8mb4_general_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 46, "utf8mb4", "utf8mb4_bin", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 224, "utf8mb4", "utf8mb4_unicode_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 225, "utf8mb4", "utf8mb4_icelandic_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 226, "utf8mb4", "utf8mb4_latvian_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 227, "utf8mb4", "utf8mb4_romanian_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 228, "utf8mb4", "utf8mb4_slovenian_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 229, "utf8mb4", "utf8mb4_polish_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 230, "utf8mb4", "utf8mb4_estonian_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 231, "utf8mb4", "utf8mb4_spanish_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 232, "utf8mb4", "utf8mb4_swedish_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 233, "utf8mb4", "utf8mb4_turkish_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 234, "utf8mb4", "utf8mb4_czech_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 235, "utf8mb4", "utf8mb4_danish_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 236, "utf8mb4", "utf8mb4_lithuanian_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 237, "utf8mb4", "utf8mb4_slovak_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 238, "utf8mb4", "utf8mb4_spanish2_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 239, "utf8mb4", "utf8mb4_roman_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 240, "utf8mb4", "utf8mb4_persian_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 241, "utf8mb4", "utf8mb4_esperanto_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 242, "utf8mb4", "utf8mb4_hungarian_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 243, "utf8mb4", "utf8mb4_sinhala_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 244, "utf8mb4", "utf8mb4_german2_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 245, "utf8mb4", "utf8mb4_croatian_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 246, "utf8mb4", "utf8mb4_unicode_520_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
{ 247, "utf8mb4", "utf8mb4_vietnamese_ci", 1, 4, "", cppconn_mbcharlen_utf8mb4, check_mb_utf8mb4_valid},
|
||||
|
||||
/*Should not really happen, but adding them */
|
||||
{ 254, "utf8", "utf8_general_cs", 1, 3, "", cppconn_mbcharlen_utf8, check_mb_utf8_valid},
|
||||
|
||||
{ 101, "utf16", "utf16_unicode_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 102, "utf16", "utf16_icelandic_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 103, "utf16", "utf16_latvian_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 104, "utf16", "utf16_romanian_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 105, "utf16", "utf16_slovenian_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 106, "utf16", "utf16_polish_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 107, "utf16", "utf16_estonian_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 108, "utf16", "utf16_spanish_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 109, "utf16", "utf16_swedish_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 110, "utf16", "utf16_turkish_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 111, "utf16", "utf16_czech_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 112, "utf16", "utf16_danish_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 113, "utf16", "utf16_lithuanian_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 114, "utf16", "utf16_slovak_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 115, "utf16", "utf16_spanish2_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 116, "utf16", "utf16_roman_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 117, "utf16", "utf16_persian_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 118, "utf16", "utf16_esperanto_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 119, "utf16", "utf16_hungarian_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 120, "utf16", "utf16_sinhala_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 121, "utf16", "utf16_german2_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 122, "utf16", "utf16_croatian_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 123, "utf16", "utf16_unicode_520_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
{ 124, "utf16", "utf16_vietnamese_ci", 2, 4, "", cppconn_mbcharlen_utf16, check_mb_utf16_valid},
|
||||
|
||||
{ 160, "utf32", "utf32_unicode_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 161, "utf32", "utf32_icelandic_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 162, "utf32", "utf32_latvian_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 163, "utf32", "utf32_romanian_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 164, "utf32", "utf32_slovenian_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 165, "utf32", "utf32_polish_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 166, "utf32", "utf32_estonian_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 167, "utf32", "utf32_spanish_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 168, "utf32", "utf32_swedish_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 169, "utf32", "utf32_turkish_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 170, "utf32", "utf32_czech_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 171, "utf32", "utf32_danish_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 172, "utf32", "utf32_lithuanian_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 173, "utf32", "utf32_slovak_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 174, "utf32", "utf32_spanish2_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 175, "utf32", "utf32_roman_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 176, "utf32", "utf32_persian_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 177, "utf32", "utf32_esperanto_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 178, "utf32", "utf32_hungarian_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 179, "utf32", "utf32_sinhala_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 180, "utf32", "utf32_german2_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 181, "utf32", "utf32_croatian_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 182, "utf32", "utf32_unicode_520_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
{ 183, "utf32", "utf32_vietnamese_ci", 4, 4, "", cppconn_mbcharlen_utf32, check_mb_utf32_valid},
|
||||
|
||||
{ 0, NULL, NULL, 0, 0, NULL, NULL, NULL}
|
||||
};
|
||||
#define MAGIC_BINARY_CHARSET_NR 63
|
||||
|
||||
const Util::OUR_CHARSET * Util::find_charset(unsigned int charsetnr)
|
||||
{
|
||||
const OUR_CHARSET * c = our_charsets60;
|
||||
|
||||
do {
|
||||
if (c->nr == charsetnr) {
|
||||
return c;
|
||||
}
|
||||
++c;
|
||||
} while (c[0].nr != 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int Util::mysql_type_to_datatype( const MYSQL_FIELD * const field )
|
||||
{
|
||||
switch (field->type) {
|
||||
case MYSQL_TYPE_BIT:
|
||||
if (field->flags !=(BINARY_FLAG|UNSIGNED_FLAG))
|
||||
return Core::Db::DataType::BIT;
|
||||
return Core::Db::DataType::BINARY;
|
||||
case MYSQL_TYPE_DECIMAL:
|
||||
case MYSQL_TYPE_NEWDECIMAL:
|
||||
return Core::Db::DataType::DECIMAL;
|
||||
case MYSQL_TYPE_TINY:
|
||||
return Core::Db::DataType::TINYINT;
|
||||
case MYSQL_TYPE_SHORT:
|
||||
return Core::Db::DataType::SMALLINT;
|
||||
case MYSQL_TYPE_INT24:
|
||||
return Core::Db::DataType::MEDIUMINT;
|
||||
case MYSQL_TYPE_LONG:
|
||||
return Core::Db::DataType::INTEGER;
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
return Core::Db::DataType::BIGINT;
|
||||
case MYSQL_TYPE_FLOAT:
|
||||
return Core::Db::DataType::REAL;
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
return Core::Db::DataType::DOUBLE;
|
||||
case MYSQL_TYPE_NULL:
|
||||
return Core::Db::DataType::SQLNULL;
|
||||
case MYSQL_TYPE_TIMESTAMP:
|
||||
return Core::Db::DataType::TIMESTAMP;
|
||||
case MYSQL_TYPE_DATE:
|
||||
return Core::Db::DataType::DATE;
|
||||
case MYSQL_TYPE_TIME:
|
||||
return Core::Db::DataType::TIME;
|
||||
case MYSQL_TYPE_YEAR:
|
||||
return Core::Db::DataType::YEAR;
|
||||
case MYSQL_TYPE_DATETIME:
|
||||
return Core::Db::DataType::TIMESTAMP;
|
||||
case MYSQL_TYPE_TINY_BLOB:// should no appear over the wire
|
||||
{
|
||||
bool isBinary = (field->flags & BINARY_FLAG) &&
|
||||
field->charsetnr == MAGIC_BINARY_CHARSET_NR;
|
||||
const Util::OUR_CHARSET * const cs =
|
||||
Util::find_charset(field->charsetnr);
|
||||
if (!cs) {
|
||||
std::ostringstream msg("Server sent unknown charsetnr (");
|
||||
msg << field->charsetnr << ") . Please report";
|
||||
throw std::runtime_error( msg.str() );
|
||||
}
|
||||
return isBinary ? Core::Db::DataType::VARBINARY : Core::Db::DataType::VARCHAR;
|
||||
}
|
||||
case MYSQL_TYPE_MEDIUM_BLOB:// should no appear over the wire
|
||||
case MYSQL_TYPE_LONG_BLOB:// should no appear over the wire
|
||||
case MYSQL_TYPE_BLOB:
|
||||
{
|
||||
bool isBinary = (field->flags & BINARY_FLAG) &&
|
||||
field->charsetnr == MAGIC_BINARY_CHARSET_NR;
|
||||
const Util::OUR_CHARSET * const cs =
|
||||
Util::find_charset(field->charsetnr);
|
||||
if (!cs) {
|
||||
std::ostringstream msg("Server sent unknown charsetnr (");
|
||||
msg << field->charsetnr << ") . Please report";
|
||||
throw std::runtime_error( msg.str() );
|
||||
}
|
||||
return isBinary ? Core::Db::DataType::LONGVARBINARY : Core::Db::DataType::LONGVARCHAR;
|
||||
}
|
||||
case MYSQL_TYPE_VARCHAR:
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
if (field->flags & SET_FLAG) {
|
||||
return Core::Db::DataType::SET;
|
||||
}
|
||||
if (field->flags & ENUM_FLAG) {
|
||||
return Core::Db::DataType::ENUM;
|
||||
}
|
||||
if ((field->flags & BINARY_FLAG) && field->charsetnr == MAGIC_BINARY_CHARSET_NR) {
|
||||
return Core::Db::DataType::VARBINARY;
|
||||
}
|
||||
return Core::Db::DataType::VARCHAR;
|
||||
case MYSQL_TYPE_STRING:
|
||||
if (field->flags & SET_FLAG) {
|
||||
return Core::Db::DataType::SET;
|
||||
}
|
||||
if (field->flags & ENUM_FLAG) {
|
||||
return Core::Db::DataType::ENUM;
|
||||
}
|
||||
if ((field->flags & BINARY_FLAG) && field->charsetnr == MAGIC_BINARY_CHARSET_NR) {
|
||||
return Core::Db::DataType::BINARY;
|
||||
}
|
||||
return Core::Db::DataType::CHAR;
|
||||
case MYSQL_TYPE_ENUM:
|
||||
/* This hould never happen - MYSQL_TYPE_ENUM is not sent over the wire, just used in the server */
|
||||
return Core::Db::DataType::ENUM;
|
||||
case MYSQL_TYPE_SET:
|
||||
/* This hould never happen - MYSQL_TYPE_SET is not sent over the wire, just used in the server */
|
||||
return Core::Db::DataType::SET;
|
||||
case MYSQL_TYPE_GEOMETRY:
|
||||
return Core::Db::DataType::GEOMETRY;
|
||||
#if LIBMYSQL_VERSION_ID > 50700
|
||||
case MYSQL_TYPE_JSON:
|
||||
return Core::Db::DataType::JSON;
|
||||
#endif //LIBMYSQL_VERSION_ID > 50700
|
||||
default:
|
||||
return Core::Db::DataType::UNKNOWN;
|
||||
}
|
||||
}
|
|
@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <mysql.h>
|
||||
|
||||
#ifndef UL64
|
||||
#ifdef _WIN32
|
||||
|
@ -109,5 +110,21 @@ namespace Util
|
|||
{
|
||||
long double strtold( const char *nptr, char **endptr );
|
||||
long double strtonum( const std::string &str, int radix = 10 );
|
||||
int32_t mysql_type_to_datatype( const MYSQL_FIELD * const field );
|
||||
|
||||
typedef struct st_our_charset
|
||||
{
|
||||
unsigned int nr;
|
||||
const char *name;
|
||||
const char *collation;
|
||||
unsigned int char_minlen;
|
||||
unsigned int char_maxlen;
|
||||
const char *comment;
|
||||
unsigned int (*mb_charlen)(unsigned int c);
|
||||
unsigned int (*mb_valid)(const char *start, const char *end);
|
||||
} OUR_CHARSET;
|
||||
|
||||
const OUR_CHARSET * find_charset(unsigned int charsetnr);
|
||||
|
||||
}
|
||||
#endif //SAPPHIRE_MYSQL_UTIL_H
|
||||
|
|
|
@ -12,6 +12,8 @@
|
|||
#include <src/servers/Server_Common/Database/Connection.h>
|
||||
#include <src/servers/Server_Common/Database/Statement.h>
|
||||
#include <src/servers/Server_Common/Database/ResultSet.h>
|
||||
#include <src/servers/Server_Common/Database/PreparedStatement.h>
|
||||
#include <src/servers/Server_Common/Database/PreparedResultSet.h>
|
||||
|
||||
#include <src/servers/Server_Common/Network/Connection.h>
|
||||
#include <src/servers/Server_Common/Network/Hive.h>
|
||||
|
@ -213,6 +215,7 @@ bool Core::ServerZone::loadSettings( int32_t argc, char* argv[] )
|
|||
|
||||
}
|
||||
|
||||
// binary data test
|
||||
boost::scoped_ptr< Core::Db::Statement > stmt3( con->createStatement() );
|
||||
boost::scoped_ptr< Core::Db::ResultSet > res1( stmt3->executeQuery( "SELECT * FROM charabase" ) );
|
||||
|
||||
|
@ -221,6 +224,30 @@ bool Core::ServerZone::loadSettings( int32_t argc, char* argv[] )
|
|||
auto blob = res1->getBlobVector( "Customize" );
|
||||
}
|
||||
|
||||
boost::scoped_ptr< Core::Db::PreparedStatement > pstmt2( con->prepareStatement( "DELETE FROM zoneservers WHERE id = ?" ) );
|
||||
pstmt2->setInt( 1, 1021 );
|
||||
pstmt2->execute();
|
||||
|
||||
pstmt2->setInt( 1, 1001 );
|
||||
pstmt2->execute();
|
||||
|
||||
boost::scoped_ptr< Core::Db::PreparedStatement > pstmt( con->prepareStatement( "INSERT INTO zoneservers ( id, ip, port ) VALUES ( ?, ?, ?);" ) );
|
||||
pstmt->setInt( 1, 1001 );
|
||||
pstmt->setString( 2, "123.123.123.123" );
|
||||
pstmt->setInt( 3, 5454 );
|
||||
pstmt->execute();
|
||||
|
||||
pstmt->setInt( 1, 1021 );
|
||||
pstmt->setString( 2, "173.173.173.173" );
|
||||
pstmt->setInt( 3, 5151 );
|
||||
pstmt->execute();
|
||||
|
||||
boost::scoped_ptr< Core::Db::PreparedStatement > pstmt1( con->prepareStatement( "DELETE FROM zoneservers WHERE id = ?" ) );
|
||||
pstmt->setInt( 1, 1021 );
|
||||
pstmt->execute();
|
||||
|
||||
pstmt->setInt( 1, 1001 );
|
||||
pstmt->execute();
|
||||
|
||||
}
|
||||
catch( std::runtime_error e )
|
||||
|
|
Loading…
Add table
Reference in a new issue