Concatenating TFields values - c++

I have a calculated fields in a client dataset named full address of type Memo.
I want to concatenate address fields, something like this:
TField* f = customersCDS->FieldByName("full_address");
if(f)
{
f->Value = customersCDS->FieldByName("address_line1")->Value;
f->Value += "\n";
f->Value += customersCDS->FieldByName("address_line2")->Value;
..
}
However, the above don't work. I get compiler error:
E2015 Ambiguity between '_fastcall operator Variant::float() const' and '_fastcall operator Variant::double() const'
In the end, I want to bind the calculated field with a TMemo, showing the full address on multiple lines.

TField::Value is a property. You cannot use compound assignment operators, like +=, with properties. You have to use + and = separately, eg:
TField* f = customersCDS->FieldByName("full_address");
if (f)
{
f->Value = customersCDS->FieldByName("address_line1")->Value;
f->Value = f->Value + String("\n");
f->Value = f->Value + customersCDS->FieldByName("address_line2")->Value;
..
}
In which case, you are better off using a variable instead:
TField* f = customersCDS->FieldByName("full_address");
if (f)
{
String s = customersCDS->FieldByName("address_line1")->Value;
s += "\n";
s += customersCDS->FieldByName("address_line2")->Value;
//...
f->Value = s;
}

Related

QSqlQuery, wrong number of parameters for prepared statement error

I am relative new to Qt/QSqlQuery, and in my current project I need to incorporate pgcrypto module, or pgp_sym_encrypt/decrypt function to be exact, into the regular SELECT/INSERT queries.
Here's the code that has been giving me problems:
bool BaseDAO::insertIntoDb(const DataObject &data)
{
QVariantMap dataMap = data.toQVariantMap();
QString rows = getFieldsStringForSql(dataMap);
QString placeholders = getPlaceholderStringForSql(dataMap);
QSqlQuery query = DatabaseDriver::getInstance().prepareQuery(
"INSERT INTO " + getTableName() + " " + rows + " VALUES " + placeholders +
R"( RETURNING ")" + getPKString() + R"(")" );
bindValuesToQuery(query, dataMap);
query.setForwardOnly(true);
query.exec(); // <-- where error occurs
...
...
}
QString BaseDAO::getPlaceholderStringForSql(const QVariantMap& data) const
{
QString fields = "(";
int valueCount = data.count();
const QList<QString> keys = data.keys();
if(valueCount > 0)
fields += ":" + keys[0];
for(int i = 1; i < valueCount; ++i)
{
if(!QString::compare(getTableName(), "patient") && !QString::compare(keys[i], "name"))
fields += ", pgp_sym_encrypt(:name, '" + m_pw + "')"; // need to encrypt name
else
fields += ", :" + keys[i];
}
fields += ")";
return fields;
}
void BaseDAO::bindValuesToQuery(QSqlQuery& query, const QVariantMap& data) const
{
const QVariantList valueList = data.values();
const QList<QString> keys = data.keys();
int valueCount = valueList.count();
for (int i = 0; i < valueCount; i++)
{
const QVariant &val = valueList[i];
switch(val.type()) {
case QVariant::Date:
query.bindValue(":" + keys[i], val.toDate().toString("yyyy-MM-dd"));
break;
case QVariant::Time:
query.bindValue(":" + keys[i], val.toTime().toString("hh:mm:ss.zzz"));
break;
case QVariant::DateTime:
query.bindValue(":" + keys[i], val.toDateTime().toString("yyyy-MM-ddThh:mm:ss.zzz"));
break;
default:
query.bindValue(":" + keys[i], val);
break;
}
}
}
I printed out the INSERT query before it got executed with query.lastQuery() and it looks like this:
INSERT INTO patient ("birthDate", "isMarked", "isProtected", "isTemporary", "modificationDate", "modificationTime", "name", "patientID", "permissionGroup", "sex")
VALUES
(:birthDate, :isMarked, :isProtected, :isTemporary, :modificationDate, :modificationTime, pgp_sym_encrypt(:name, 'password'), :patientID, :permissionGroup, :sex)
RETURNING "idx"
and this is the error message I got:
Fatal Error: wrong number of parameters for prepared statement "qpsqlpstmt_4"
DETAIL: Expected 11 parameters but got 1.
QPSQL: Unable to create query, Query: <<***>>.
The error totally got me confused. There are 10 parameters, but it somehow expects 11 and only gets 1? Any help is greatly appreciated!
I would recommend to rewrite getPlaceholderStringForSql
void BaseDAO::bindValuesToQuery(QSqlQuery& query, const QVariantMap& data) const
{
for(const QString & key : data.keys())
{
const QVariant &val = data.value(key);
// According to Qt doc: Note that the placeholder mark (e.g :) must be included
// when specifying the placeholder name.
const QString placeholder = QString(":%1").arg(key);
switch (val.type()) {
case QVariant::Date:
query.bindValue(placeholder,val.toDate().toString( "yyyy-MM-dd"));
break;
case QVariant::Time:
query.bindValue(placeholder,val.toTime().toString("hh:mm:ss.zzz"));
break;
case QVariant::DateTime:
query.bindValue(placeholder,val.toDateTime().toString("yyyy-MM-ddThh:mm:ss.zzz"));
break;
default:
query.bindValue(placeholder,val);
break;
}
}
Use raw litteral string for pgp_sym_encrypt(:name, '" + m_pw + "')"
R"(pgp_sym_encrypt(:name, ')" + m_pw + R("'))"
The main problem of this code is that you suddenly add a database dependency in an API (QSqlDatabase and your base code using QSqlDatabase) which shall remain database independant. A much better solution would be to use c++ directly to encrypt ans decrypt the name. Or if you absolutely want to use SQL, you should probably create two stored procedure (encrypt_field and decrypt_field) encapsulating pgp_sym_encrypt and pgp_sym_decrypt. Then you should be able to make a query via a QSqlQuery calling this stored procedures. The result of encrypt_field can be add in the insert/update SQL query while the result of decrypt_field wil be used after a SELECT query.

Qt setFilter searching? [duplicate]

I have a problem with printing in Qt.
I have HTML code in QString variables. In this code I want to insert data from a database.
I get an error:
E:\apprendreQt\gestionstock6\vente.cpp:117: error: invalid operands of types
'const char*' and 'const char [27]' to binary 'operator+'
How can I fix this?
Here is my code:
int num_bl = ui->numeroBLlineEdit->text().toInt() ;
QString html;
QString requette = "select num_facture,date,nom,prenom,code_fiscale,designation,qte_out, prix,(qte_out * prix ) as Montant, sum(qte_out * prix) as Total from ventes join produits_en_ventes join clients join produits on ventes.vente_id = produits_en_ventes.vente_id and ventes.client_id = clients.client_id and produits_en_ventes.produit_id = produits.produit_id where ventes.client_id = :client_id ";
if(!m_db->isOpen())
QMessageBox::critical(this,tr("Inventoria Solution"),m_db->lastError().text()) ;
else{
m_query->clear();
m_query->prepare(requette);
m_query->bindValue(":client_id ", num_bl);
if(!m_query->exec())
QMessageBox::critical(this,tr("Inventoria Solution"),m_query->lastError().text()) ;
else{
html += " <table>"
"<thead>"
"<tr>"
"<th>N°</th>"
"<th>DĂ©signation</th>"
"<th>Qte</th>"
"<th>Prix Unitaire</th>"
"<th>Montant</th>"
" </tr>"
"</thead>";
while(m_query->next())
{
int num_article = 1;
html += "<tr> <td>" + num_article + "</td> <td>"+m_query->value(5).toString()+"</td> <td>"+m_query->value(6).toInt() + "</td> <td>"+m_query->value(7).toInt() + "</td> <td>" + m_query->value(8).toInt() + "</td></tr>";
num_article++;
}
html += "<tfoot>"
"<tr>"
"<td>Total:"+ m_query->value(9).toInt()+"</td>"
"</tr>"
"</tfoot>"
"</table>";
}
print_Html(html);
}
I'm not sure about your error. However, AFAIK a Qstring cannot be concatenated with an int as such.
int myInt = 0;
QString text = "someString" + myInt; // WRONG
int myInt = 0;
QString text = "someString" + QString::number( myInt ); // CORRECT
or
int myInt = 0;
QString text = "someString" % QString::number( myInt ); // CORRECT
If you use operator+, you need to provide QString as an argument, but you use integer values instead: html += "<tr> <td>" + num_article, where num_article is declared as integer. You can replace it with, for example: QString::number(num_article). The same in this line:
"<td>Total:"+ m_query->value(9).toInt()+"</td>"
should be replaced with
"<td>Total:"+ m_query->value(9).toString()+"</td>"
in Qt5 you can use the QStringLiteral macro for each string that doesn't need to be localized to transform all the string literals from const char* (the C++ default) into QString, this will also make creation of those QStrings cheaper (on compilers that support it)
for Qt4 you can use the QString(const char*) constructor or QString::fromAscii(const char*) static function

Parameterized Query Returns no Results using C++ .Net MySQL Connector

I cannot seem to find any resolution to this issue on my own. I use this generic function to retrieve data from a database like so:
int id = 29
ArrayList^ classes = getClassesGeneric("dep_id", "=", id.ToString());
However, this returns no results. If I query the database through MySQL Workbench or without parameters it works fine. What am I missing?
ArrayList^ Accessor::getClassesGeneric(String^ col, String^ op, String^ value)
{
ArrayList^ result = gcnew ArrayList();
this->cmd = gcnew MySqlCommand("SELECT * FROM rpos_db.classes WHERE #col #op #value;", this->con);
try
{
this->cmd->Parameters->AddWithValue("#col", col);
this->cmd->Parameters->AddWithValue("#op", op);
this->cmd->Parameters->AddWithValue("#value", value);
this->cmd->Prepare();
MySqlDataReader^ r = this->cmd->ExecuteReader();
while (r->Read())
{
Class^ c = gcnew Class();
c->id = r->GetInt32(0);
c->dep_id = r->GetInt32(1);
c->name = r->GetString(2);
c->code = r->GetString(3);
result->Add(c);
}
r->Close();
}
catch (Exception^ ex)
{
MessageBox::Show(ex->StackTrace, ex->Message);
}
return result;
}
Using the function like this produces the indented result:
classes = getClassesGeneric("1", "=", "1");
Parameters can only be used to replace literals, not object names or syntactic elements, such as the = operator. You'd either have to hardcode it. If you want to pass them dynamically, you'd have to use string manipulation:
ArrayList^ Accessor::getClassesGeneric(String^ col, String^ op, String^ value)
{
ArrayList^ result = gcnew ArrayList();
this->cmd = gcnew MySqlCommand
("SELECT * FROM rpos_db.classes WHERE " +
col + " " + op + " #value;", this->con);
try
{
this->cmd->Parameters->AddWithValue("#value", value);
this->cmd->Prepare();
MySqlDataReader^ r = this->cmd->ExecuteReader();

What sort of design pattern should I be using here to make full use of modern C++?

I have the following piece of code for a Calculus program I'm making. All you need to know is that it's part of a recursive procedure that uses the rules of differentiation (f'(g*h)=f*g'+g*f', (g+f)'=g'+f', etc.) to find the derivative of a function represented as a string.
std::string _deriveFromNode ( node * nd )
{
std::string dfdx;
switch (nd->op)
{
case NONE: dfdx = (nd->eq == "x" ? "1" : "0");
case ADD: dfdx = _deriveFromNode(nd->LHS) + "+" + _deriveFromNode(nd->RHS);
case SUB: dfdx = _deriveFromNode(nd->LHS) + "-" + _deriveFromNode(nd->RHS);
case MULT: dfdx = nd->LHS->eq + "*" + _deriveFromNode(nd->RHS) + "+" + nd->RHS->eq + "*" +_deriveFromNode(nd->LHS);
case DIV: dfdx = "(" + nd->LHS->eq + "*" + _deriveFromNode(nd->RHS) + "-" + nd->LHS->eq + "*" + _deriveFromNode(nd->LHS);
case EXP: /* ???? */;
default: ;
}
return dfdx;
}
However, I feel like there should be some better design pattern than using a switch statement. Essentially this is mapping a node object
struct node
{
std::string eq;
oper op;
node * LHS;
node * RHS;
};
to functions, so I feel like I should be using function pointers or something. Can someone give me advice on how to convert the above to something that looks more readable, maintainable and modern?
You can create functions that deal with the logic of dealing with the various operators. This makes the code look cleaner but it still uses the switch statement.
// Declare function template.
template <oper op> std::string deriveFromNode(node* nd);
// Define specializations of function template for the
// known operators.
template <> std::string deriveFromNode<NONE>(node* nd)
{
return (nd->eq == "x" ? "1" : "0");
}
template <> std::string deriveFromNode<ADD>(node* nd)
{
return (_deriveFromNode(nd->LHS) + "+" + _deriveFromNode(nd->RHS));
}
template <> std::string deriveFromNode<SUB>(node* nd)
{
return (_deriveFromNode(nd->LHS) + "-" + _deriveFromNode(nd->RHS));
}
template <> std::string deriveFromNode<MULT>(node* nd)
{
return (nd->LHS->eq + "*" + _deriveFromNode(nd->RHS) + "+" + nd->RHS->eq + "*" +_deriveFromNode(nd->LHS));
}
template <> std::string deriveFromNode<DIV>(node* nd)
{
return ("(" + nd->LHS->eq + "*" + _deriveFromNode(nd->RHS) + "-" + nd->LHS->eq + "*" + _deriveFromNode(nd->LHS));
}
template <> std::string deriveFromNode<EXP>(node* nd)
{
// Fix the logic for this.
return "";
}
std::string _deriveFromNode ( node * nd )
{
switch (nd->op)
{
case NONE:
return deriveFromNode<NONE>(nd);
case ADD:
return deriveFromNode<ADD>(nd);
case SUB:
return deriveFromNode<SUB>(nd);
case MULT:
return deriveFromNode<MULT>(nd);
case DIV:
return deriveFromNode<DIV>(nd);
case EXP:
return deriveFromNode<EXP>(nd);
default: ;
}
return dfdx;
}
You can replace the switch the switch statement by code that uses a map to look up the function to call for various operators. I don't think that is any more elegant or efficient than using a switch.
std::string _deriveFromNode ( node * nd )
{
typedef std::string (*function_t)(node* nd);
std::map<oper, function_t> functions;
if ( functions.empty())
{
// Register the functions corresponding to the operators.
functions[NONE] = deriveFromNode<NONE>;
functions[ADD] = deriveFromNode<ADD>;
functions[SUB] = deriveFromNode<SUB>;
functions[MULT] = deriveFromNode<MULT>;
functions[DIV] = deriveFromNode<DIV>;
functions[EXP] = deriveFromNode<EXP>;
}
std::map<oper, function_t>::iterator iter = functions.find(nd->op);
if ( iter != functions.end() )
{
return iter->second(nd);
}
else
{
// Deal with unknown operator.
}
}
I feel the way you're doing it now is just fine.
You could of course define some function for those operations instead of stuffing everything in the same function, and return them right away, maybe something like this:
switch (nd->op)
{
case NONE: return std::string(nd->eq == "x" ? "1" : "0");
case ADD: return _addNode(nd);
case SUB: return _subNode(nd);
case MULT: return _mulNode(nd);
case DIV: return _divNode(nd);
case EXP: /* ???? */;
default: return "";
}
Also don't forget to add the break statements to avoid falling to the below cases, if you're not returning right away in each case.

error C2663: overloads have no legal conversion for 'this' pointer

please help me for this errors
code:
u16 ip_defragment(){
u16 result;
fragip_set::iterator i;
IP_FRAGMENTED new_defrag;
IP* pcurpack = (IP*) malloc(cur.len);
memcpy(pcurpack, cur.data, cur.len);
new_defrag.saddr = cur.saddr;
new_defrag.daddr = cur.daddr;
new_defrag.protocol = cur.ip.ppack->protocol;
new_defrag.id = i2i(cur.ip.ppack->id);
i = ip_frags.find(new_defrag);
if(i != ip_frags.end()){
i->packets.insert(pcurpack);
const_cast<u16&>(i->cur_len) += cur.ip.len - cur.ip.hlen;
const_cast<u32&>(i->last_time) = time();
if(!(cur.ip.bmore_fr) && (i->tot_len == 0)){
const_cast<u16&>(i->tot_len) = cur.ip.fr_offs + cur.ip.len;
}
if(i->cur_len == i->tot_len){
for(set<IP*>::iterator k = i->packets.begin(); k != i->packets.end(); k++){
// must copy to another buffer
if(i2i((*k)->frag_off) & IP_OFFMASK){
memcpy(ip_defrag_buffer, *k, (*k)->ihl<<2);
} else {
memcpy(ip_defrag_buffer + (i2i((*k)->frag_off) & IP_OFFMASK) * 8,
*k + ((*k)->ihl<<2), (i2i((*k)->tot_len))-((*k)->ihl<<2));
}
}
IP* defr_ip = (IP*) &ip_defrag_buffer;
defr_ip->tot_len = i2i(i->tot_len);
defr_ip->frag_off = 0;
result = i->tot_len;
ip_frags.erase(i);
return result;
}
return 0;
}
if(!(cur.ip.bmore_fr)){
new_defrag.tot_len = cur.ip.fr_offs + cur.len;
} else {
new_defrag.tot_len = 0;
}
new_defrag.cur_len = cur.ip.len; // with header size
new_defrag.last_time = time();
i = ip_frags.insert(new_defrag).first;
if(i != ip_frags.end())
i->packets.insert(pcurpack);
return 0;
}
compiled project and view only 2 errors similar
line 15 : i->packets.insert(pcurpack);
end line : i->packets.insert(pcurpack);
error with 2 lines : error C2663: 'std::_Tree<_Traits>::insert' : 4 overloads have no legal conversion for 'this' pointer
IntelliSense: no instance of overloaded function "std::set<_Kty, _Pr, _Alloc>::insert [with _Kty=IP *, _Pr=std::less<IP *>, _Alloc=std::allocator<IP *>]" matches the argument list and object (the object has type qualifiers that prevent a match)
please help me?
I had exact same error with std::set, while passing it to a lambda expression:
C2663 'std::_Tree<std::_Tset_traits<_Kty,_Pr,_Alloc,false>>::insert': 5 overloads have no legal conversion for 'this' pointer
lambda expression prototype was:
[se1, ele1](auto val) {
/* here I was editing se1 set, but above se1 is passed value type */
}
I have changed to:
[&se1, ele1](auto val) {
/* now since se1 set is sent as reference type above, it is good to edit
changes stays as I expect it to be
*/
}
Now compilation succeeds.
I used with count_if function, which calls the lamda expression for eac element, so the compiler knows that modifications should persist in set se1, which is perfectly logical.
If you desire to have the original set unchanged, then send a copy of it.