How to use parameters using MySQL and a TADOQuery instance? - c++

I have a TADOConnection pointing to a MySQL 8.0 instance. The connection is tested and it works. Following this example on how to use prepared statement, I'm having an error and I have no idea why.
The following code works fine, it will return true from the very last statement. No errors, no warnings.
AnsiString sqlQuery = "SELECT e.name FROM employee e WHERE e.id = 1;";
if (!_query->Connection->Connected) {
try {
_query->Connection->Connected = true;
} catch (EADOError& e) {
return false;
}
}
_query->SQL->Clear();
_query->SQL->Add(sqlQuery);
_query->Prepared = true;
try {
_query->Active = true;
if (_query->RecordCount == 0) {
return false;
}
} catch (EADOError& e) {
return false;
}
return true;
However, the following code fails executing _query->SQL->Add(sqlQuery); with this error:
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.
AnsiString sqlQuery = "SELECT e.name FROM employee e WHERE e.id = :id;";
if (!_query->Connection->Connected) {
try {
_query->Connection->Connected = true;
} catch (EADOError& e) {
return false;
}
}
_query->SQL->Clear();
_query->SQL->Add(sqlQuery); // <---- EOleException here
_query->Parameters->ParamByName("id")->Value = id;
_query->Prepared = true;
try {
_query->Active = true;
if (_query->RecordCount == 0) {
return false;
}
} catch (EADOError& e) {
return false;
}
return true;
Everywhere I find examples, all of them use :paramName to specify parameters. What am I missing?
Update 1
I have tried changing the code like this :
_query->SQL->Clear();
TParameter * param = _query->Parameters->AddParameter();
param->Name = "id";
param->Value = 1;
_query->SQL->Add(sqlQuery); // <---- EOleException still here
Some forum post suggests to switch the Advanced Compiler option "Register Variables" to "None", but this is already the setting of my project, and the exception is still thrown.
Update 2
I can ignore the error, and everything gets executed just fine, however it fails whenever I perform a step-by-step execution. Of course, I can still put a breakpoint after, and jump right over the faulty line, but it's still annoying and does not explain why there is this error there in the first place.

The exception is on setting the SQL string - which tells you that it's wrong. As per #RogerCigol's comment, you should NOT have the ; at the end of your SQL string.
Kudos to Roger for that.
If you want to access parameters, you MUST set the SQL string first, it will be parsed to identify the parameters. The parameters will not exist until the string is parsed, or you manually create them (which is pointless as they would be recreated on parsing the string).
You can also access the parameters as an ordered index, and I have always been able to use ? as an anonymous parameter with MySQL.

Related

Getting Unchecked return value from library?

Calling remove(file.txt) without checking return value. This library function may fail and return an error code
I am getting above warning in below code-
bool chkfile() {
std::remove(file.txt);
return true;
}
How should I remove this warning?
You can refer to this link to see the issue. You have to check if there is no issue during remove operation.
Your code should be something like this,
bool chkfile() {
if (std::remove("file.txt") != 0) {
// error handling
} else {
// success
return true;
}
}

rapidjson's assert IsObject() fails randomly while it shouldn't

we are facing an issue where the RAPIDJSON_ASSERT(IsObject()) called by MemberEnd() which is called by HasMember() fails. However, that rapidjson::Value is guaranteed to be an object by other logic.
Here is the code snippet:
const std::string str = "{\"outer_key\":{\"inner_key\":\"value\", \"foo\":\"bar\"}}";
rapidjson::Document doc;
if (doc.Parse(str.c_str()).HasParseError()) {
return -1;
}
rapidjson::Value::MemberIterator it = doc.FindMember("outer_key");
// make sure the member is of Object type
if (it == doc.MemberEnd() || !it->value.IsObject()) {
return -1;
}
rapidjson::Value* p_json;
p_json = &(it->value);
rapidjson::Document new_doc;
rapidjson::Document::AllocatorType& new_doc_allocator = new_doc.GetAllocator();
// if SOME_FLAG is set and "outer_key" exists in the input JSON string,
// use "outer_key"'s value so that `new_doc` will have other properties such as `foo` for free.
if (SOME_FLAG && p_json != NULL) {
new_doc.CopyFrom(*p_json, new_doc_allocator);
// The value of "inner_key" will be re-added later, so remove it for now.
// assert(IsObject()) fails here and core is dumped.
if (new_doc.HasMember("inner_key")) {
new_doc.RemoveMember("inner_key");
}
} else {
// Otherwise, start from an empty object.
new_doc.SetObject();
}
// Add "inner_key" for both cases above.
const std::string new_value_str = "new_value";
new_doc.AddMember("inner_key", rapidjson::StringRef(new_value_str.c_str()), new_doc_allocator);
We suspect that the new_doc.CopyFrom(*p_json, new_doc_allocator); line is the culprit, but are kind of new to rapidjson and not sure whether it is the correct way to use new_doc_allocator to copy *p_json to new_doc.
The weird part is that this issue only happened online for a small number of requests. We extracted the input JSON string, checked that it is valid, but couldn't reproduce the failure offline.
It would be good if someone could point out where we did wrong. Thanks in advance.

Swift return error that goes against what the Apple developer site says

func evaluateDate(nDate: Int!, rDate: Int!) -> Int{
if(nDate < rDate) {
return 1
}
if(nDate == rDate) {
return 2
}
if(nDate > rDate) {
return 3
}
}
Every time I get an error that says: "Missing return in a function expected to return 'Int'"
However on the apple developer website they give an example of this doing
func sayHello(personName: String, alreadyGreeted: Bool) -> String {
if alreadyGreeted {
return sayHelloAgain(personName)
} else {
return sayHello(personName)
}
}
print(sayHello("Tim", alreadyGreeted: true))
// prints "Hello again, Tim!"
I don't understand what's going on because also in another place I try to change the value of a variable and it doesn't recognize the variable has changed outside the if-else block, however I don't ever remember this being an issue.
Your if statement structure is incorrect. The compiler is complaining because the if's have no else to fall into, subsequently the func is failing to return in all situations.
func evaluateDate(nDate: Int!, rDate: Int!) -> Int {
if (nDate < rDate) {
return 1
} else if (nDate == rDate) {
return 2
} else {
return 3
}
}
In Apple's example, your code will either execute the if-branch and return, or execute the else-branch and return.
In your code, there is an if and your code may return. If it doesn't return then there is another if where it may return. And another if where it may return. So what happens after the third if?
It may be obvious to you that the third if-branch will be entered and return. It isn't obvious to the compiler. It's not that obvious to you either, because otherwise you wouldn't have written the if at all, but just "return 3".

Create a function to get a username using a try and catch method in C++

I'm trying to create a function to get a username using a try and catch method in C++. Unfortunately this code doesn't work, and my application closes when it tries to run.
QString UserInfo::getFullUserName()
{
DBG_ENTERFUNC(getFullUserName);
QString result;
qDebug("trying to get the username");
try
{
struct passwd fullUserData=*getpwnam(getUserName().toLatin1());
result = fullUserData.pw_gecos;
// it is the first of the comma seperated records that contain the user name
result = result.split(",").first();
if (result.isEmpty())
{
result = getUserName();
}
}
catch (...)
{
qDebug("exception caught");
}
qDebug() << result;
#endif
DBG_EXITFUNC;
return result;
}
The problem occurs in this line of code as I have placed prints after it that are never reached.
struct passwd fullUserData=*getpwnam(getUserName().toLatin1());
Does anyone know what is the issue here?
*Edit--------
Here is my function getUserName()
QString UserInfo::GetUserName()
{
DBG_ENTERFUNC(GetUserName);
QString result;
foreach (QString environmentEntry, QProcess::systemEnvironment())
{
QString varName = environmentEntry.section('=',0,0);
QString varValue = environmentEntry.section('=',1,1);
if (varName == "USER" || varName == "USERNAME")
{
result = varValue;
}
}
DBG_EXITFUNC;
return result;
}
getpwnam() returns NULL when the username was not found. You are potentially dereferencing a NULL pointer.
*getpwnam(getUserName().toLatin1());
// ^ potential NULL pointer deref
Always check before deferencing a potentially invalid pointer:
struct passwd *fullUserData = getpwnam(getUserName().toLatin1());
// ^ note pointer
if (fullUserData != NULL) {
result = fullUserData->pw_gecos;
// ^^ fullUserData is a struct pointer
} else {
// throw Exception
}
If this is confusing to you, you might want to read up on C++ and pointers.

Check user input for errors elegantly

My program waits for user input, and when appropriate, will process it. I need to check the user input to make sure it fulfils certain criteria, and if it doesn't fulfil all of those criteria it will be rejected.
Pseudo-code is something like:
if (fulfills_condition_1)
{
if (fulfills_condition_2)
{
if (fulfills_condition_3)
{
/*process message*/
}
else
cout << error_message_3; //where error_message_1 is a string detailing error
}
else
cout << error_message_2; //where error_message_2 is a string detailing error
}
else
cout << error_message_1; //where error_message_3 is a string detailing error
There is the possibility that the number of these conditions could increase, and I was wondering if there was a neater way to represent this using a switch or something like that instead of lots of cascading if statements.
I know there is the possibility of using
if (fulfills_condition_1 && fulfills_condition_2 && fulfills_condition_3)
/*process message*/
else
error_message; //"this message is not formatted properly"
but this is less useful than the first, and does not say where the issue is.
The conditions can roughly be arranged in increasing importance i.e. checking for condition_1 is more important than checking for condition_3, so the if statements do work - but is there a better way in general for doing this?
How about
if (!fulfills_condition_1) throw BadInput(error_message_1);
if (!fulfills_condition_2) throw BadInput(error_message_2);
if (!fulfills_condition_3) throw BadInput(error_message_3);
/* process message */
Then your exception handler can report the error message, and retry or abort as appropriate.
If what bothers you are the cascading ifs, you could go for one of the following:
Using a boolean:
bool is_valid = true;
string error = "";
if (!condition_one) {
error = "my error";
is_valid = false;
}
if (is_valid && !condition_two) {
...
}
...
if (!is_valid) {
cout << error;
} else {
// Do something with valid input
}
Using exceptions:
try {
if (!condition_one) {
throw runtime_error("my error");
}
if (!condition_two) {
...
}
...
} catch (...) {
// Handle your exception here
}
I suggest you can use "early return" technique:
if (!fulfills_condition_1)
// error msg here.
return;
// fulfills_condition1 holds here.
if (!fulfills_condition_2)
// error msg here.
return;
// Both conditon1 and condition2 hold here.
if (!fulfills_condition_3)
// error msg here.
return.
If this was going to be reused in a few places, I would make a DSL:
Validator inputType1Validator =
Validator.should(fulfill_condition_1, error_message_1)
.and(fulfill_condition_2, error_message_2)
.and(fulfill_condition_3, error_message_3)
inputType1Validator.check(input);