mirror of
https://github.com/SapphireServer/Sapphire.git
synced 2025-04-23 13:17:45 +00:00
706 lines
24 KiB
C++
706 lines
24 KiB
C++
#include "PreparedResultSet.h"
|
|
#include "ResultBind.h"
|
|
#include "DataType.h"
|
|
#include <string>
|
|
#include <cctype>
|
|
#include <clocale>
|
|
#include <string.h>
|
|
#include <mysql.h>
|
|
#include <algorithm>
|
|
|
|
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 Mysql::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;
|
|
}
|
|
|
|
Mysql::PreparedResultSet::PreparedResultSet( std::shared_ptr< ResultBind >& pBind,
|
|
std::shared_ptr< Mysql::PreparedStatement > par ) :
|
|
ResultSet( nullptr, par ),
|
|
m_pResultBind( pBind ),
|
|
m_pStmt( par )
|
|
{
|
|
pBind->bindResult();
|
|
|
|
m_numRows = mysql_stmt_num_rows( par->getRawStmt() );
|
|
m_numFields = mysql_stmt_field_count( par->getRawStmt() );
|
|
auto resMeta = mysql_stmt_result_metadata( m_pStmt->getRawStmt() );
|
|
|
|
for( uint32_t i = 0; i < m_numFields; ++i )
|
|
{
|
|
|
|
auto field = resMeta->fields[i];
|
|
std::string fieldName( field.name );
|
|
|
|
std::transform( fieldName.begin(), fieldName.end(), fieldName.begin(),
|
|
[]( unsigned char c ){ return std::toupper(c); } );
|
|
|
|
m_fieldNameToIndex[fieldName] = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bool Mysql::PreparedResultSet::isBeforeFirstOrAfterLast() const
|
|
{
|
|
return ( m_rowPosition == 0 );
|
|
}
|
|
|
|
Mysql::PreparedResultSet::~PreparedResultSet()
|
|
{
|
|
free();
|
|
}
|
|
|
|
uint32_t Mysql::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 ) );
|
|
}
|
|
|
|
uint16_t Mysql::PreparedResultSet::getUInt16( const uint32_t columnIndex ) const
|
|
{
|
|
return static_cast< uint16_t >( getUInt( columnIndex) );
|
|
}
|
|
|
|
uint16_t Mysql::PreparedResultSet::getUInt16( const std::string& columnLabel ) const
|
|
{
|
|
return static_cast< uint16_t >( getUInt( columnLabel) );
|
|
}
|
|
|
|
uint8_t Mysql::PreparedResultSet::getUInt8( const uint32_t columnIndex ) const
|
|
{
|
|
return static_cast< uint8_t >( getUInt( columnIndex) );
|
|
}
|
|
|
|
uint8_t Mysql::PreparedResultSet::getUInt8( const std::string& columnLabel ) const
|
|
{
|
|
return static_cast< uint8_t >( getUInt( columnLabel) );
|
|
}
|
|
|
|
int16_t Mysql::PreparedResultSet::getInt16( const uint32_t columnIndex ) const
|
|
{
|
|
return static_cast< int16_t >( getInt( columnIndex) );
|
|
}
|
|
|
|
int16_t Mysql::PreparedResultSet::getInt16( const std::string& columnLabel ) const
|
|
{
|
|
return static_cast< int16_t >( getInt( columnLabel) );
|
|
}
|
|
|
|
int8_t Mysql::PreparedResultSet::getInt8( const uint32_t columnIndex ) const
|
|
{
|
|
return static_cast< int8_t >( getInt( columnIndex) );
|
|
}
|
|
|
|
int8_t Mysql::PreparedResultSet::getInt8( const std::string& columnLabel ) const
|
|
{
|
|
return static_cast< int8_t >( getInt( columnLabel) );
|
|
}
|
|
|
|
uint32_t Mysql::PreparedResultSet::getUInt( const std::string& columnLabel ) const
|
|
{
|
|
return getUInt( findColumn( columnLabel ) );
|
|
}
|
|
|
|
int64_t Mysql::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 Mysql::PreparedResultSet::getInt64( const std::string& columnLabel ) const
|
|
{
|
|
return getInt64( findColumn( columnLabel ) );
|
|
}
|
|
|
|
uint64_t Mysql::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 - 1 );
|
|
|
|
switch( Mysql::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 Mysql::Util::strtoull( getString( columnIndex ).c_str(), nullptr );
|
|
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( "PreparedResultSet::getUInt64_intern: unhandled type. Please, report" );
|
|
return 0;
|
|
}
|
|
|
|
int64_t Mysql::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 - 1 );
|
|
|
|
switch( Mysql::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 Mysql::Util::strtoll( getString( columnIndex ).c_str(), nullptr );
|
|
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 Mysql::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 Mysql::PreparedResultSet::getUInt64( const std::string& columnLabel ) const
|
|
{
|
|
return getUInt64( findColumn( columnLabel ) );
|
|
}
|
|
|
|
std::string Mysql::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 - 1 );
|
|
|
|
switch( Mysql::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 Mysql::PreparedResultSet::getString( const std::string& columnLabel) const
|
|
{
|
|
return getString( findColumn( columnLabel ) );
|
|
}
|
|
|
|
int32_t Mysql::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 Mysql::PreparedResultSet::getInt( const std::string& columnLabel ) const
|
|
{
|
|
return getInt( findColumn( columnLabel ) );
|
|
}
|
|
|
|
long double Mysql::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 - 1);
|
|
|
|
switch( Mysql::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 = Mysql::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 Mysql::PreparedResultSet::getDouble( const std::string& columnLabel ) const
|
|
{
|
|
return getDouble( findColumn( columnLabel ) );
|
|
}
|
|
|
|
float Mysql::PreparedResultSet::getFloat( const uint32_t columnIndex ) const
|
|
{
|
|
return static_cast< float >( getDouble( columnIndex ) );
|
|
}
|
|
|
|
float Mysql::PreparedResultSet::getFloat( const std::string& columnLabel ) const
|
|
{
|
|
return static_cast< float >( getDouble( findColumn( columnLabel ) ) );
|
|
}
|
|
|
|
size_t Mysql::PreparedResultSet::getRow() const
|
|
{
|
|
return static_cast< size_t >( m_rowPosition );
|
|
}
|
|
|
|
size_t Mysql::PreparedResultSet::rowsCount() const
|
|
{
|
|
return static_cast< uint32_t >( m_numRows );
|
|
}
|
|
|
|
const std::shared_ptr< Mysql::Statement > Mysql::PreparedResultSet::getStatement() const
|
|
{
|
|
return m_pStmt;
|
|
}
|
|
|
|
std::istream* Mysql::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* Mysql::PreparedResultSet::getBlob( const std::string& columnLabel ) const
|
|
{
|
|
return new std::istringstream( getString( columnLabel ) );
|
|
}
|
|
|
|
std::vector< char > Mysql::PreparedResultSet::getBlobVector( uint32_t columnIndex ) const
|
|
{
|
|
if( columnIndex == 0 || columnIndex > m_numFields )
|
|
throw std::runtime_error( "PreparedResultSet::getBlobVector: invalid value of 'columnIndex'" );
|
|
|
|
std::unique_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 > Mysql::PreparedResultSet::getBlobVector( const std::string& columnLabel ) const
|
|
{
|
|
return getBlobVector( findColumn( columnLabel ) );
|
|
}
|
|
|
|
bool Mysql::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 Mysql::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 Mysql::PreparedResultSet::isLast() const
|
|
{
|
|
return ( m_rowPosition == m_numRows );
|
|
}
|
|
|
|
bool Mysql::PreparedResultSet::isFirst() const
|
|
{
|
|
return ( m_rowPosition == 1 );
|
|
}
|
|
|
|
bool Mysql::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 Mysql::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 Mysql::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;
|
|
}
|
|
|
|
void Mysql::PreparedResultSet::clearWarnings()
|
|
{
|
|
|
|
}
|
|
|
|
void Mysql::PreparedResultSet::free()
|
|
{
|
|
if( m_pStmt->getRawStmt() )
|
|
mysql_stmt_free_result( m_pStmt->getRawStmt() );
|
|
}
|