Im working on an online game and I have a problem with getting the ms-sql results into a other cpp file.
cpp file1 to start the query:
databaseManager.Query( hDB, new CQuery_AuthServer(req->awchUserId, req->awchPasswd);
req->awchUserId and req->awchPasswd are data from socket (username and password)
now on cpp file2 I execute the query inside a class
class CQuery_AuthServer : public CNtlQuery
{
public:
CQuery_AuthServer(const WCHAR * lpszUserID, const WCHAR * lpszUserPW)
{
ZeroMemory( m_szUserID, MAX_SIZE_USER_ID + 1 );
ZeroMemory( m_szUserPW, MAX_SIZE_USER_PW + 1 );
memcpy(m_szUserID, lpszUserID, MAX_SIZE_USER_ID);
memcpy(m_szUserPW, lpszUserPW, MAX_SIZE_USER_PW);
}
int ExecuteQuery(CNtlDatabaseConnection * pConnection)
{
FIND_SQLUNIT( SP_AuthLogin, pConnection, pSqlUnit2 );
if( NULL == pSqlUnit2 )
{
return NTL_FAIL;
}
strncpy_s( pSqlUnit2->m_szUserID, m_szUserID, MAX_SIZE_USER_ID );
strncpy_s( pSqlUnit2->m_szUserPW, m_szUserPW, MAX_SIZE_USER_ID );
pSqlUnit2->Exec();
printf("ExecuteQuery Done: result: %i ACC ID: %i \n", pSqlUnit2->m_nResultCode, pSqlUnit2->m_dwAccountID );
return NTL_SUCCESS;
}
public:
char m_szUserID[MAX_SIZE_USER_ID + 1];
char m_szUserPW[MAX_SIZE_USER_PW + 1];
};
This is needed for the query
BEGIN_DECLARE_SQLUNIT( SP_AuthLogin, "{ ? = call AuthLogin(?,?,?) }" )
BEGIN_VARIABLE()
char m_szUserID[MAX_SIZE_USER_ID + 1];
char m_szUserPW[MAX_SIZE_USER_PW + 1];
int m_dwAccountID;
int m_nResultCode;
END_VARIABLE()
BEGIN_PARAM(3)
PARAM_ENTRY(SQL_PARAM_OUTPUT, m_nResultCode)
PARAM_ENTRY_STR(SQL_PARAM_INPUT, m_szUserID)
PARAM_ENTRY_STR(SQL_PARAM_INPUT, m_szUserPW)
PARAM_ENTRY(SQL_PARAM_OUTPUT, m_dwAccountID)
END_PARAM()
END_DECLARE_SQLUNIT()
Now I can get the result but the result only works inside int ExecuteQuery
The query results are:
pSqlUnit2->m_nResultCode
pSqlUnit2->m_dwAccountID
how can I get those 2 results in the first cpp file where I made the query?
edit: the first cpp file:
void CClientSession::SendCharLogInReq(CNtlPacket * pPacket)
{
sUA_LOGIN_REQ * req = (sUA_LOGIN_REQ *)pPacket->GetPacketData();
HDATABASE hDB = INVALID_HDATABASE;
CNtlDatabaseManager databaseManager;
databaseManager.Query( hDB, new CQuery_AuthServer(req->awchUserId, req->awchPasswd) );
//WANT RESULT HERE
}
I dont really know what to do.. Im really newbie
here is the complete source https://www.sendspace.com/file/oc5v34
at PacketAuthServer.cpp I run the query
at AuthQueryServer.h I execute the query
Disregard the previous answer. The problem with the previous answer is that it was expecting databaseManager.Query to be syncrhonous, and to execute CQuery_AuthServer::ExecuteQuery before it returns to the caller. In fact it doesn't - it just adds the query to the queue, and your database management framework doesn't give you the ability to wait for completion of that query.
You should read the NtlDatabase manual to know how to make synchronous database calls
Related
Im currently trying C++ and building a databaseconnection with mysql c api from oracle. In first place it works fine.
If i query for a col like " select username [...] where id=1" I'll get my result: testuser.
But if i try "select * from..." I'll get:
1 //correct ID
t // only first letter.
Iam looking arround quite a bit, even here but cant figuer out ho to get the complete result:
1
testuser
As always: Thanks for your time and experience.
Nasten
my Code:
#include "mysql.h"
[...]
sendToLog(_T("Abfrage Starten."));
MYSQL* m_pConn = ConnectToDatabase();
ASSERT(m_pConn != nullptr);
MYSQL_RES *m_pResultSet;
MYSQL_ROW m_mysqlRow;
//Query:
mysql_query(m_pConn, "SELECT * FROM fplaner.user WHERE ll_UserID=1");
//Result speichern
m_pResultSet = mysql_store_result(m_pConn);
//Resultset durchgehen
ASSERT(m_pResultSet != nullptr);
int m_llResCount = mysql_num_fields(m_pResultSet);
if (m_llResCount == 0)
{
sendToLog(_T("ResultSet ist NICHT null aber Leer."));
}
else
{
while ((m_mysqlRow = mysql_fetch_row(m_pResultSet)))
{
for (int i = 0; i < m_llResCount; i++)
{
if (m_mysqlRow == NULL)
{
sendToLog(_T("Ungültiges ResultSet erhalten on COunt: "+i));
}
else
{
sendToLog(_T("Gültiges ResultSet erhalten."));
CString strTest(*m_mysqlRow[i]);
//CString strTest(*m_mysqlRow);--> gives correct name when query with select name
from...
m_mysqlRow
sendToLog((strTest));
}
}
}
}
Probleme solved:
The resultset is an Char pointer on an pointer. By dereferencing it with * it will only provide the first char if the strong. So without it works fine:
Change "CString strTest(*m_mysqlRow[i]);" to "CString strTest(m_mysqlRow[i]);" . and it will work as intended.
I am trying to make a save system for my ESP32 project, and I have the following code:
void write_string_nvs(char *memorySlot, String key, String value)
{
nvs_handle my_handle;
esp_err_t err = nvs_open(memorySlot, NVS_READWRITE, &my_handle);
if (err == ESP_OK)
{
int kL = key.length();
int vL = value.length();
char keyA[kL + 1];
key.toCharArray(keyA, kL + 1);
char valueA[vL + 1];
value.toCharArray(valueA, vL + 1);
Serial.println("Storing \"" + String(keyA) + "\"(" + String(kL) + ")>\"" + String(valueA) + "\"(" + String(vL) + ") in NVS.");
esp_err_t err = nvs_set_blob(my_handle, keyA, &valueA, vL);
if (err == ESP_OK)
{
err = nvs_commit(my_handle);
if (err == ESP_OK)
Serial.println("Correctly saved \"" + key + "\" in " + String(memorySlot));
else
Serial.println("write_string_nvs::commit -> Could not save \"" + key + "\" in " + String(memorySlot) + ": " + esp_err_toString(err, true));
}
else
Serial.println("write_string_nvs::nvs_set_blob -> Could not save \"" + key + "\" in " + String(memorySlot) + ": " + esp_err_toString(err, true) + "");
nvs_close(my_handle);
}
else
Serial.println("Could not initialize " + String(memorySlot) + " NVS slot: " + esp_err_toString(err, true) + "");
}
I call it the following way, from a serial command:
...
String params[3];
split(serialRead, ' ', params);
String s = params[0];
String k = params[1];
String v = params[2];
bool error = false;
if (s.length() <= 0) {
error = true;
Serial.println("Please, specify an storage name");
}
if (k.length() <= 0) {
error = true;
Serial.println("Please, specify a key");
}
if (v.length() <= 0) {
error = true;
Serial.println("Please, specify a value");
}
if (!error) {
String slotName = "";
if (startsWithIgnoreCase(s, "main")) {
slotName = "storage";
}
if (startsWithIgnoreCase(s, "wifi")) {
slotName = "wifi";
}
if (slotName.length() > 1) {
Serial.println("Writing \"" + v + "\"" + " at \"\"" + k + "\" in " + slotName);
char slot[slotName.length()];
slotName.toCharArray(slot, slotName.length());
write_string_nvs(slot, k, v);
} else
Serial.println("Specified invalid slot");
}
By doing this I am trying to make a command parser to store values and read them afterwards, with the following commands: storage write <wifi/main> <key> <value> and storage read <wifi/main> <key>.
But the problem comes when I try to type the write command, and the code executes, the ESP32 Serial returns:
assertion "heap != NULL && "realloc() pointer is outside heap areas"" failed: file "/Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/heap/heap_caps.c", line 285, function: heap_caps_realloc
abort() was called at PC 0x40152903 on core 1
Backtrace: 0x40091ca4:0x3ffce0c0 0x40091ed5:0x3ffce0e0 0x40152903:0x3ffce100 0x400847a9:0x3ffce130 0x4008483d:0x3ffce150 0x4008b2e9:0x3ffce170 0x4000bedd:0x3ffce190 0x400dd4e2:0x3ffce1b0 0x400dd544:0x3ffce1d0 0x400dd6a6:0x3ffce1f0 0x400dd6d1:0x3ffce210 0x400d1b06:0x3ffce240 0x400d5939:0x3ffce260 0x400de489:0x3ffce7d0 0x40094135:0x3ffce7f0
Rebooting...
I don't know what to do, I have tried some different write and read codes, but I can't find any that stores the values correctly. The read command works, but obviously, it doesn't return anything, because the memory is empty. Here's the read command, in case you want to take a look at it:
String read_string_nvs(char *memorySlot, String key)
{
nvs_handle my_handle;
esp_err_t err = nvs_open(memorySlot, NVS_READWRITE, &my_handle);
String espErrStr = esp_err_toString(err, true);
char *value;
if (err == ESP_OK || startsWithIgnoreCase(espErrStr, "ESP_OK"))
{
size_t string_size;
int kL = key.length();
char wifi_slot[kL + 1];
key.toCharArray(wifi_slot, kL + 1);
esp_err_t err = nvs_get_str(my_handle, wifi_slot, NULL, &string_size);
value = (char *)malloc(string_size);
err = nvs_get_str(my_handle, wifi_slot, value, &string_size);
nvs_close(my_handle);
return String(value);
}
else
Serial.println("Could not open memory (\"" + espErrStr + "\")");
return espErrStr;
}
I've been with this issue for some weeks, and I really don't know what to do, maybe the system is not good for what I want, or I may be doing something wrong.
For developing I am using VSCode with PlatformIO.
Please, take a look and it and if you could tell me what's wrong or what to do, I'd be really pleased.
Thanks in advance.
I am busy with the same problem (I am going to use 4Mb of the flash as a nvs partition) and I have found a some clue: https://www.esp32.com/viewtopic.php?t=6815
It seems that problem is with the RAM-size - the system needs a RAM to create the nvs-pages-map and if it's not enough for this task - it calls the system abort.
P.S. I have decoded my firmware.elf into firmware.lst with the addresses and the assembler code and the backtrace is so:
app_main -> initArduino -> nvs_flash_init -> nvs_flash_init_partition -> nvs_flash_init_custom -> ZN3nvs_storage_init_Ejj ->ZN3nvs_Storage_populateBlobIndicesIntrusiveList -> _Znwj -> _cxa_allocate_exception -> terminatev -> cxabiv111_terminateEPFvvE - here the system aborts
To decode the .elf into .lst - just copy the firmware.elf into the folder with the xtensa-esp32-elf-objdump.exe (it is probably here .platformio\packages\toolchain-xtensa32\bin) and run in the command prompt - xtensa-esp32-elf-objdump.exe -S -l -d firmware.elf > [YourFileName].lst
These lines are problematic:
char slot[slotName.length()];
slotName.toCharArray(slot, slotName.length());
write_string_nvs(slot, k, v);
slotName.length() will return the number of characters in slotName. slot is a C string, which needs a null terminating character at the end (\0), so it needs to be declared with one byte more than the number of characters in the string. The declaration you have is too short.
You can side-step the problem by rewriting these lines as:
write_string_nvs(slotName.c_str(), k, v);
String already stores its contents as a C string internally, so the c_str() method just gives you a pointer to the buffer it manages. Be careful with this, that pointer won't be valid after the String object becomes invalid, so if the String is a variable in a function or code block, its c_str() will stop being valid when that you leave that function or code block.
Since this is some kind of heap or memory allocation issue it's possible the bug is outside of the code you shared. I would review all the code looking for instances of where you convert a String to a C character array and try using the c_str() idiom instead.
This is a pretty common problem that bites a lot of programmers.
It's also possible the problem is in your write_string_nvs() implementation.
After connecting to a Firebird database with C++ builder, I cannot get a result from a simple select request.
I have some confusion about a lot of members of classes:
void __fastcall TForm2::btn1Click(TObject *Sender)
{ TSQLConnection co = new TSQLConnection(this);
Base_Firebird *fb = new Base_Firebird() ;
bool bl = fb->Connecter(co);
String sqlstring = "select nom_action from T_ACTION where CLE_ACTION=6 ";
if (bl)
TSQLQuery *req = new TSQLQuery(NULL) ;
req->SQLConnection = co ;
req->SQL->Add(sqlstring);
req->Open() ;
}
My problem is here after opening the TSQLQuery, I don't know how I can get the result and execute the command.
Try changing the end of your subroutine to something like this:
if (bl)
{ /// you forgot compound operator here !!!!!
TSQLQuery *req = new TSQLQuery(this) ;
req->SQLConnection = co ;
req->SQL->Text = sqlstring;
req->Open() ;
int j = 0;
while( !req->EOF() )
{
++j;
String Value = req->Fields[0]->AsString;
ShowMessageFmt( "Row %d ==> Value: %s ", ARRAYOFCONST(( j, Value )) );
// String MSG = Format( "Row %d ==> Value: %s ", ARRAYOFCONST(( j, Value )) );
// ShowMessage( MSG );
req -> Next();
};
req->Close();
ShowMessage("Data over.");
}
req -> Free(); // maybe "delete req;" would work too, dunno
}
To check:
http://docwiki.embarcadero.com/Libraries/Seattle/en/Vcl.Dialogs.ShowMessageFmt
http://docwiki.embarcadero.com/Libraries/Seattle/en/System.SysUtils.Format
https://osdn.net/projects/cc1101driver/scm/svn/blobs/head/trunk/VC_test/Cpp_builder_2009/Cpp_Builder_test/documents/JVC_20120502/jvcl/examples/JvProgressDialog/BCB/JvProgressDialogMain.cpp
http://www.texttransformer.com/d2chelp/cbuilderarrayofconst.htm
http://docwiki.embarcadero.com/RADStudio/Seattle/en/Open_Arrays#C.2B.2B_functions_that_take_open_array_arguments
http://docwiki.embarcadero.com/RADStudio/Seattle/en/Support_for_Object_Pascal_Data_Types_and_Language_Concepts
Read Embarcadero's documentation. There are whole chapters on how to work the SQL components you are using, including:
How To Perform Database Procedures
Navigating Datasets
Using dbExpress
Using dbExpress Components Index
Using TSQLQuery
Data.SqlExpr.TSQLQuery
For example:
void __fastcall TForm2::btn1Click(TObject *Sender)
{
TSQLConnection *co = new TSQLConnection(NULL);
Base_Firebird *fb = new Base_Firebird();
if (fb->Connecter(co))
{
TSQLQuery *req = new TSQLQuery(NULL);
req->SQLConnection = co;
req->SQL->Text = "select nom_action from T_ACTION where CLE_ACTION=6";
req->Open();
while (!req->Eof)
{
// use req->Fields as needed...
req->Next();
}
delete req;
}
delete fb;
delete co;
}
I'm currently trying to make some sort of "aliaslist" for a game.
I've gotten so far where a user connects, the code check if their "aliaslist" file exist, it it doesn't it'll create one.
Once its created, their playername gets saved to that file, However, if they reconnect it will be namename
I want to achieve it to have a name on each line like:
name
name
I currently have this code, and was wondering what I am doing wrong. Note, its the q3engine.
if(!isBot) {
file = va("aliaslist/%s", onlyip);
trap_FS_FOpenFile( file, &f, FS_APPEND_TEXT );
if ( !f ) {
trap_FS_FOpenFile( file, &f, FS_WRITE_TEXT );
}
else {
int len;
len = strlen(client->pers.netname);
trap_FS_Write(va("%s \n", client->pers.netname), len, f);
trap_FS_FCloseFile( f );
}
}
You only write strlen(client->pers.netname) number of characters to the file in your trap_FS_Write.
To write the space and the newline as well:
trap_FS_Write(va("%s \n", client->pers.netname), len + 2, f);
(Notice the + 2)
I am developing an MFC application using Visual C++ 2010
I am reading data for one file but It seems seekg is not working
Here is my code
//Transaction is a class i have defined before
void displayMessage(CString message)
{
MessageBox(NULL,message,L"error",MB_OK | MB_ICONERROR);
}
///////////////////////////////
ifstream input;
input.open("test.dat" , ios::binary );
if( input.fail() )
{
CString mess;
mess = strerror( errno );
mess.Insert(0,L"Error\n");
displayMessage(mess);
}
Transaction myTr(0,myDate,L"",0,0,L""); // creating an object of transaction
unsigned long position = 0;
while(input.read( (char *) &myTr , sizeof(Transaction)))
{
if(myTr.getType() == 400 )
position = (unsigned long)input.tellg() - sizeof(Transaction);
}
CString m;
m.Format(L"Pos : %d",position);
displayMessage(m);
input.clear();//I also tried removing this line
input.seekg(position,ios::beg );
m.Format(L"get pos: %d",input.tellg());
displayMessage(m);
input.close();
The first displayMessage shows This : Pos : 6716 But second one showes : get pos: 0
Why seekg is not working ?
Thanks
The problem is that CString.Format() is a varargs function and basic_istream::tellg() returns a pos_type which isn't a type that can be passed as a vararg agument so you get undefined behavior.
If you want to pass the position you get bace from tellg() to CString::Format() you'll need to cast it or put it in a temporary, intermediate variable:
unsigned long new_pos = input.tellg();
m.Format(L"get pos: %d", new_pos);