Weird error on mysql_stmt_execute - c++

I have a weird error when trying to execute mysql_stmt_execute.
The flow goes:
I get the list of the tables in my database I am connecting. (catalog, schema and name)
For every table I'm getting the list of foreign keys, fields and indexes.
Everything goes good until I hit the table named performance_schema.events_stages_summary_by_account_by_event_name.
I get the error: Identifier name "events_stages_summary_by_account_by_event_name" is too long. The weird thing is that the name is not an identifier - it is a parameter to the query and it is less than 64 characters which is the identifier limit.
Below is the relevant code:
std::wstring query3 = L"SELECT kcu.column_name, kcu.ordinal_position, kcu.referenced_table_schema, kcu.referenced_table_name, kcu.referenced_column_name, rc.update_rule, rc.delete_rule FROM information_schema.key_column_usage kcu, information_schema.referential_constraints rc WHERE kcu.constraint_name = rc.constraint_name AND kcu.table_catalog = ? AND kcu.table_schema = ? AND kcu.table_name = ?;";
char *catalog_name = row[0] ? row[0] : NULL;
char *schema_name = row[1] ? row[1] : NULL;
char *table_name = row[2] ? row[2] : NULL;
MYSQL_BIND params[3];
unsigned long str_length1, str_length2, str_length3;
str_length1 = strlen( catalog_name ) * 2;
str_length2 = strlen( schema_name ) * 2;
str_length3 = strlen( table_name ) * 2;
str_data1 = new char[str_length1], str_data2 = new char[str_length2], str_data3 = new char[str_length3];
memset( str_data1, '\0', str_length1 );
memset( str_data2, '\0', str_length2 );
memset( str_data3, '\0', str_length3 );
memset( params, 0, sizeof( params ) );
strncpy( str_data1, catalog_name, str_length1 );
strncpy( str_data2, schema_name, str_length2 );
strncpy( str_data3, table_name, str_length3 );
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char *) str_data1;
params[0].buffer_length = strlen( str_data1 );
params[0].is_null = 0;
params[0].length = &str_length1;
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char *) str_data2;
params[1].buffer_length = strlen( str_data2 );
params[1].is_null = 0;
params[1].length = &str_length2;
params[2].buffer_type = MYSQL_TYPE_STRING;
params[2].buffer = (char *) str_data3;
params[2].buffer_length = strlen( str_data3 );
params[2].is_null = 0;
params[2].length = &str_length3;
if( mysql_stmt_bind_param( res1, params ) )
{
std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
errorMsg.push_back( err );
result = 1;
break;
}
else
{
prepare_meta_result = mysql_stmt_result_metadata( res1 );
if( !prepare_meta_result )
{
std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
errorMsg.push_back( err );
result = 1;
break;
}
else
{
if( mysql_stmt_execute( res1 ) )
{
std::wstring err = m_pimpl->m_myconv.from_bytes( mysql_stmt_error( res1 ) );
errorMsg.push_back( err );
result = 1;
break;
}
Could someone please shed some light on the error? I can probably try to skip this table but I'd prefer not to.
[EDIT]
mysql --version
mysql ver 14.14 Distrib 5.6.35, for Linux (x86+64) using Editine wrapper
[/EDIT]

Edit:
Seems that the code is indeed OK and the strncpy is OK. I mistakenly read that the allocation was twice the length of the string but the length was still only one length of the string.
The reason why you see that error is because you are using a string which is not null terminated. This is caused by the fact that strncpy does not null-terminate the string if it exceeds the given limit and the limit you use is the actual length of the string:
memset( str_data1, '\0', str_length1 );
strncpy( str_data1, catalog_name, str_length1 );
params[0].buffer_length = strlen( str_data1 );
A better way to do this would be to use either snprintf(3) that does null terminate the string or by using the std::string constructor that takes a const char* and a length as parameters.

Related

Using .c_str' with pointers (and also pointers to pointers)

so, I encountered a little problem and I am kinda stuck.
Basically I am trying to pass the value of a string** in C-type form to a char* string
The code is as follows:
static int BuildDBListSql( std::string **SqlBuf,
const char* ColumnNames,
const char* TableNames,
const char* CmdText,
sUINT Mode)
{
int rtnval = sSUCCESS;
const char * testSql = ( Mode & 02 ) ? ColumnNames : CmdText;
if ( SU_DbControl::DbCreateTradeTempTables(testSql) != sSUCCESS )
{
sLogMessage("Problem with temporary table results", sLOG_ERROR, 0);
return( sERROR );
}
if ( Mode & 02 )
{
*SqlBuf = new std::string[strlen(ColumnNames) + SQL_MAX_SELECT*40];
*SqlBuf = &std::string(ColumnNames);
if ( !( Mode & 010 ) )
{
// Attach State/Retrieval SQL.
char* SqlBufcopy = (*SqlBuf)->c_str();
sSQLInsertStateAndRetrieval( sDbConvertMode( Mode ), SqlBufcopy);
}
}
// SQL fragments are being passed:
else
{
size_t sqlBufLength = 0;
if ( Mode & 010 )
{
sqlBufLength = strlen(ColumnNames) + strlen(TableNames) + strlen(CmdText) + SQL_MAX_SELECT;
*SqlBuf = new std::string[ sqlBufLength ];
//sprintf( *SqlBuf, "SELECT %s FROM %s %s ",
*SqlBuf = fmt::format("SELECT {} FROM {} {} ", ColumnNames, TableNames, CmdText); // ColumnNames, TableNames, CmdText );
}
else
{
std::string *sqlPtr = new char[strlen(CmdText) + 2*SQL_MAX_SELECT];
strcpy( sqlPtr, CmdText );
sSQLSpecializeWhereClause( TableNames, sqlPtr );
sqlBufLength = strlen(ColumnNames) + strlen(TableNames) + SQL_MAX_SELECT;
sqlBufLength += strchr(TableNames, ',') ? strlen(CmdText) : strlen(sqlPtr);
*SqlBuf = new char[ sqlBufLength ];
sprintf( *SqlBuf, "SELECT %s From %s %s",
ColumnNames,
TableNames,
strchr( TableNames, ',' ) ? CmdText : sqlPtr );
delete [] sqlPtr;
// Attach State/Retrieval SQL
rtnval = sSQLInsertStateAndRetrieval( sDbConvertMode( Mode ),
*SqlBuf );
}
}
if (Mode & 0100)
{
char * tempBuf = sEntitySQLToDbSQL(*SqlBuf);
if( tempBuf )
{
delete [] *SqlBuf;
*SqlBuf = new char[ strlen(tempBuf) + 1];
strcpy(*SqlBuf, tempBuf);
}
else
{
sLogMessage("Error in sEntitySQLToDbSQL", sLOG_ERROR, 0);
return( sERROR );
}
}
return rtnval;
}
i get this error when running the solution: related to this line of code char* SqlBufcopy = (*SqlBuf)->c_str();
left of '.c_str' must have class/struct/union, type is std::string**
I kinda understand that the error is there due to me trying to get a c-type string out of a pointer, but I dont know the correct syntax to do what i want to do.
I tried with
char *SqlBufcopy = *SqlBuf.c_str()
also with
char *SqlBufcopy = *SqlBuf->c_str()
and it didnt work, help pls
To fix the error you ask about, change char *SqlBufcopy = *SqlBuf.c_str(); to
char *SqlBufcopy = (*SqlBuf)->c_str();
Reason: SqlBuf is pointer to pointer (which makes no sense at all), so to get to the actual object, you need to dereference it twice.

The DLL was successfully built but it is not working

I use the example Plugin.cpp from amibroker ADK. I make a directory 'ASCII' under the folder 'amibroker' and put all the data inside named *.AQI. But no data found in amibroker. Is there something I changed in function GetQuotesEx cause the problem?
PLUGINAPI int GetQuotesEx( LPCTSTR pszTicker, int nPeriodicity, int nLastValid, int nSize, struct Quotation *pQuotes, GQEContext *pContext )
{
char filename[256];
FILE* fh;
int iLines = 0;
// format path to the file (we are using relative path)
sprintf_s(filename, "ASCII\\%s.AQI", pszTicker);
// open file for reading
fopen_s(&fh, filename, "r");
// if file is successfully opened read it and fill quotation array
if (fh)
{
char line[ 256 ];
// read the line of text until the end of text
// but not more than array size provided by AmiBroker
while( fgets( line, sizeof( line ), fh ) && iLines < nSize )
{
// get array entry
struct Quotation *qt = &pQuotes[ iLines ];
char* pTmp = NULL;
// parse line contents: divide tokens separated by comma (strtok) and interpret values
// date and time first
int datenum = atoi( strtok_s( line, ",", &pTmp) ); // YYMMDD
int timenum = atoi( strtok_s( NULL, ",", &pTmp) ); // HHMM
// unpack datenum and timenum and store date/time
qt->DateTime.Date = 0; // make sure that date structure is intialized with zero
qt->DateTime.PackDate.Minute = timenum % 100;
qt->DateTime.PackDate.Hour = timenum / 100;
qt->DateTime.PackDate.Year = 2000 + datenum / 10000;
qt->DateTime.PackDate.Month = ( datenum / 100 ) % 100;
qt->DateTime.PackDate.Day = datenum % 100;
// now OHLC price fields
qt->Open = (float) atof( strtok_s( NULL, ",", &pTmp) );
qt->High = (float) atof( strtok_s( NULL, ",", &pTmp) );
qt->Low = (float) atof( strtok_s( NULL, ",", &pTmp) );
qt->Price = (float) atof( strtok_s( NULL, ",", &pTmp) ); // close price
// ... and Volume
qt->Volume = (float) atof( strtok_s( NULL, ",\n", &pTmp) );
iLines++;
}
// close the file once we are done
fclose( fh );
}
// return number of lines read which is equal to
// number of quotes
return iLines;
}

What wrong I have done? The function of GetDiskFreeSpaceExA didn't work at all

I tried to use GetDiskFreeSpaceExA function, but it doesn't work:
int drvNbr = PathGetDriveNumber(db7zfolderw);
if (drvNbr == -1) // fn returns -1 on error
{
const char * errmsg = "error occured during get drive number";
strcpy_s(retmsg, strlen(errmsg) + 1, errmsg);
return -3;
}
char driverletter = (char)(65 + drvNbr);
string driverstr(1, driverletter);
driverstr = driverstr + ":";
PULARGE_INTEGER freespace = 0;
PULARGE_INTEGER totalnumbtype = 0;
PULARGE_INTEGER totalnumberfreebyte = 0;
fileSize = SzArEx_GetFileSize(&db, i);
BOOL myresult=GetDiskFreeSpaceExA(
driverstr.c_str(),
freespace,
totalnumbtype,
totalnumberfreebyte
);
The value of variable freespace is 0. I have no idea why it didn't work if the value of variable which is driverstr.c_str() was D:?
Thanks for your help.
You need to supply pointers to variables that will hold the value returned. Right now you a re supplying null pointers so nothing is retured:
::ULARGE_INTEGER freespace{};
::ULARGE_INTEGER totalnumbtype{};
::ULARGE_INTEGER totalnumberfreebyte{};
::BOOL myresult
{
::GetDiskFreeSpaceExA
(
driverstr.c_str()
, &freespace
, &totalnumbtype
, &totalnumberfreebyte
)
};
It would also be a good idea to use wide char versions of these functions.

Difficulty implementing code 128 C rule

Code related to text encoding:
const char* toCode128C( const char* texto ) {
int tamanhoTexto = strlen( texto );
int tamanhoComando = strlen( "{C" ) + tamanhoTexto;
char* printerCodBarras = new char[ tamanhoComando ];
memcpy( printerCodBarras, "{C", tamanhoComando );
for ( int i = 0; i < tamanhoTexto; i += 2 ) {
int num = QString( texto ).mid( i, 2 ).toInt();
QString vl = QString( static_cast<char>( num ) );
strncat( printerCodBarras, vl.toStdString().c_str(), 1 );
}
return printerCodBarras;
}
Encoding occurs successfully, except when it contains a "00" for example code 59900001, the transformation occurs from two characters to two characters, or error occurs when encoding the value "00", thus making the (00) is not printed.

Strange Return Value

My code,
LPSTR Internal::Gz_GetSystemKey( BOOL SHOW_ERROR, BOOL SHOW_KEY ) {
HW_PROFILE_INFO HwProfInfo;
if (!GetCurrentHwProfile(&HwProfInfo))
{
if(SHOW_ERROR)
Message::Error( "An Internal Error Has Occurred", "Gizmo Message", TRUE );
return NULL;
}
std::string __clean( (char*)HwProfInfo.szHwProfileGuid );
__clean.append( std::string( (char*)HwProfInfo.szHwProfileName ) );
LPSTR neet_key = Crypt::CRC32( Crypt::MD5( (char*)__clean.c_str() ) );
if (SHOW_KEY)
Message::Info( neet_key ); // shows expected result
return neet_key; // returns strange ascii result
};
Gz BOOL Gz_CreateContext( BOOL SHOW_ERROR, BOOL SHOW_KEY ) {
HKEY CHECK; // key result container
BOOL RESULT;
std::wstring neet_key_uni; // must use unicode string in RegSetValueExW
if ( RegOpenKey(HKEY_CURRENT_USER, TEXT("Software\\NEET\\Gizmo\\"), &CHECK) != ERROR_SUCCESS )
goto CREATE_REG_CONTEXT;
else
goto STORE_NEET_KEY;
CREATE_REG_CONTEXT:
if ( RegCreateKeyA( HKEY_CURRENT_USER, "Software\\NEET\\Gizmo\\", &CHECK ) != ERROR_SUCCESS ) {
if( SHOW_ERROR )
Message::Error( "Context Could Not Be Created" );
RESULT = FALSE;
goto END_MACRO;
}
STORE_NEET_KEY:
LPSTR neet_key = Internal::Gz_GetSystemKey( SHOW_ERROR, SHOW_KEY ); // GetSystemKey generates good key, returns weird ascii
Message::Notify( neet_key );
neet_key_uni = std::wstring(neet_key, neet_key+strlen(neet_key));
if ( RegSetValueEx( CHECK, TEXT("Key"), 0, REG_SZ, (const BYTE*)neet_key_uni.c_str(), ( neet_key_uni.size() + 1 ) * sizeof( wchar_t ) ) != ERROR_SUCCESS ) {
if( SHOW_ERROR )
Message::Error( "Context Could Not Be Reached" );
RESULT = FALSE;
goto END_MACRO;
}
RESULT = TRUE;
END_MACRO:
RegCloseKey(CHECK); // safely close registry key
return RESULT;
};
I'm creating a simple PC identification lib for practice, not for commercial use.
Message::Info( neet_key );
Shows
but the actual return value is
Any ideas why? The 'Message' namespace/functions are just message boxes. As for the 'Crypt' namespace/functions, they aren't the issue at hand.
From the comments: Who owns the memory for the 'neet_key'? My guess would be that the 'Message::Info' shows a valid value because whatever memory structure its from is still in memory but when you return its no longer in memory. Therefore the returned value prints rubbish.
This is a common issue for the C++ language. I would highly recommend that you avoid using raw pointers where possible (especially when returning from functions/methods). For strings you could obviously use 'std::string'.