How to write a prepared update query? - c++

I've been trying to write an update function that takes the user to be updated(usr), the flag which then translates to the field to be updated and the new value. Here's the function,
bool DBManager::updateDB(User* usr, int flag, QVariant& value)
{
QSqlQuery query;
bool status = false;
QString temp_value = "";
QList<QString> fieldlist = {"First_Name", "Last_Name", "Email", "Username", "Password"};
QString field = fieldlist.at(flag);
if (field == "First_Name") {
usr->setFirstName(value.toString());
temp_value = usr->getFirstName();
} else if (field == "Last_Name") {
usr->setLastName(value.toString());
temp_value = usr->getLastName();
} else {
qDebug() << "invalid option";
}
query.prepare("UPADATE Users SET :field = :newValue WHERE Username = :Username");
query.bindValue(":field",field);
query.bindValue(":newValue",temp_value);
query.bindValue(":Username",usr->getUserName());
qDebug() << query.boundValues();
if (m_db.isOpen()){
if (query.exec()){
status = true;
qDebug() << "DATABASE:: Record update successful";
} else {
qDebug() << "DATABASE:: Record update unsuccessful - " << query.lastError();
}
} else {
qDebug() << "DATABASE:: not open ";
}
return status;
}
When I run the code I get an error. Here is the output:
QMap((":Username", QVariant(QString, "zielinkin1"))(":field", QVariant(QString, "Last_Name"))(":newValue", QVariant(QString, "Thibos")))
DATABASE:: Record update unsuccessful - QSqlError("", "Parameter count mismatch", "") User not updated DATABASE:: database closed
How to fix this?

Cause
First problem
It is not hard to guess, that value binding works only for values, not for field names.
For more info, please read about Inserting, Updating, and Deleting Records.
Second problem
Found by #JimCastro:
You have a typo in your query. UPADATE should be UPDATE.
Solution
Use a string concatenation to form your prepared query.
Example
Instead of
query.prepare("UPDATE Users SET :field = :newValue WHERE Username = :Username");
write
query.prepare("UPDATE Users SET " + field + " = :newValue WHERE Username = :Username");
Delete or comment this line
query.bindValue(":field",field);

Related

Error while executing query for Postgresql from Qt C++

I want to enter enter data from vector of objects into Postgresql table but it's not working. I establish connection to the database successfully, but the output returns an error -
QSqlError("42601", "QPSQL: Unable to create query", "ERROR: syntax error at end of input\nLINE 1: EXECUTE \n
My Code -
void MainWindow::WriteToDatabase()
{
// Establishing a connection to MySQL
database = QSqlDatabase::addDatabase("QPSQL");
database.setHostName("localhost");
database.setUserName("postgres");
database.setPassword("1234");
database.setDatabaseName("nz5_flightdatar");
bool test = QSqlDatabase::isDriverAvailable("QPSQL");
qDebug() << test << Qt::endl;
if(database.open())
{
sort(FlightList.begin(), FlightList.end());
vector<FlightData>::iterator itr;
ui->plainTextEdit->clear();
for (itr = FlightList.begin(); itr != FlightList.end(); itr++)
{
static int i = 0;
QString Time = QString::fromStdString(FlightList[i].getTime());
double Latitude = FlightList[i].getLatitude();
double Longitude = FlightList[i].getLongitude();
int Course = FlightList[i].getCourse();
int KTS = FlightList[i].getKTS();
int MPH = FlightList[i].getMPH();
int AltitudeFeet = FlightList[i].getAltitudeFeet();
QString ReportingFacility = QString::fromStdString(FlightList[i].getReportingFacility());
i++;
QSqlQuery query;
query.prepare("INSERT INTO 'public.flight_data' (Time, Latitude, Longitude, Course, KTS, MPH, AltitudeFeet, ReportingFacility)"
"VALUES (':time', ':latitude', ':longitude', ':course', ':kts', ':mph', ':altitudefeet', ':reportingfacility')");
query.bindValue(":time", Time);
query.bindValue(":latitude", Latitude);
query.bindValue(":longitude", Longitude);
query.bindValue(":course", Course);
query.bindValue(":kts", KTS);
query.bindValue(":mph", MPH);
query.bindValue(":altitudefeet", AltitudeFeet);
query.bindValue(":reportingfacility", ReportingFacility);
if(query.exec())
qDebug() << "success";
else
{
QMessageBox::information(this, "error", "No success");
qDebug() << query.lastError();
exit(0);
}
}
ui->statusbar->showMessage("Writing data to Database successful", 4000);
}
else
{
QMessageBox::warning(this, "Not connected", "Unable to connect to Database");
}
}
and the output -
qt.core.plugin.loader: In C:/Qt_Framework/6.4.1/mingw_64/plugins/sqldrivers/qsqlmysqld.dll:
Plugin uses incompatible Qt library (5.13.0) [debug]
true
QSqlError("42601", "QPSQL: Unable to create query", "ERROR: syntax error at end of input\nLINE 1: EXECUTE \n ^\n(42601)")
I am familiar with MySQL but I went crazy today trying to install drivers but failed miserably (read document and also a lot of StackOverflow threads), so I switched to Postgresql as Qt supports QPSQL.
Kindly help if you can.

How to insert a record into Microsoft Access using MFC?

How can I insert record in Microsoft Access?
CString SqlString;
CString name="I want to add this variable in Table3";
SqlString = "INSERT INTO Table3 (Name,Numbers) VALUES (name,099)";
When I do it that way gives the following error:
Database error:Too few parameters.Expected 1.
This is a snippet from my own application:
BOOL CCommunityTalksApp::SetRecordForTalkNumber(int iTalkNumber, UINT uID, CString &rStrError)
{
CDatabase *pDatabase;
CString strSQL, strField;
BOOL bOK;
pDatabase = theApp.GetDatabase();
if(pDatabase != nullptr)
{
if (iTalkNumber == 9999)
strField = _T(" ");
else
strField.LoadString(uID);
strSQL.Format(_T("INSERT INTO [Public Talk Titles] ([Theme], [Category], [Talk Number]) VALUES ('%s', 'NS', %d)"), strField, iTalkNumber);
TRY
{
pDatabase->ExecuteSQL((LPCTSTR)strSQL);
bOK = TRUE;
}
CATCH(CDBException, Except)
{
rStrError = Except->m_strError;
bOK = FALSE;
}
END_CATCH
}
return bOK;
}
As you can see:
Use [ and ] to wrap the table and field names to address any issues with spaces.
Qualify the field names first — particularly if you are only populating certain field values.
Wrap the string values with single quotes.
So:
SqlString = "INSERT INTO Table3 (Name,Numbers) VALUES (name,099)";
Would be something like:
SqlString = "INSERT INTO [Table3] ([Name],[Numbers]) VALUES ('name',099)";
I appreciate that the square brackets are not needed for your table / field names though.

Rollback not working coldfusion transaction

I'm using cfscript with a transaction, but it keep the record in the database even though I call the rollback. I'm calling the rollback inside the try not the catch because I need to validate it there.
Here is my code:
transaction action="begin"{
try{
rollbackAction = false;
// Insert into CustomerBilling
insertCustomerBilling = new query();
insertCustomerBilling.setDatasource("rent");
insertCustomerBilling.setName("insertCustomerBilling");
insertCustomerBilling.addParam(name="CustomerID", value="#CompanyID#", cfsqltype="cf_sql_integer");
insertCustomerBilling.addParam(name="Cost", value="#Cost#", cfsqltype="cf_sql_decimal");
insertCustomerBilling.addParam(name="BillDate", value="#DateFormat(Now(), 'yyyy/mm/dd')#", cfsqltype="cf_sql_datetime");
insertCustomerBilling.addParam(name="PaidDate", value="#DateFormat(Now(), 'yyyy/mm/dd')#", cfsqltype="cf_sql_datetime");
result = insertCustomerBilling.execute(sql="INSERT INTO CustomerBilling " &
" (CustomerID, Cost, BillDate, Paid, PaidDate, PropertyID, BillTypeID) " &
" VALUES(:CustomerID, :Cost, :BillDate, 0, :PaidDate, 0, 1 )");
GetCCExemption = new query();
GetCCExemption.setDatasource("rent");
GetCCExemption.setName("GetCCExemption");
GetCCExemption.addParam(name="CompanyID", value="#CompanyID#", cfsqltype="cf_sql_integer");
result = GetCCExemption.execute(sql="Select * From Billing_CCExemptions Where CompanyID = :CompanyID");
rs = result.getResult();
if(rs.recordCount <= 0){
// Check if we inserted customer into Stripe_Customer
GetStripeCustomer = new query();
GetStripeCustomer.setDatasource("rent");
GetStripeCustomer.setName("GetStripeCustomer");
GetStripeCustomer.addParam(name="CompanyID", value="#CompanyID#", cfsqltype="cf_sql_integer");
resultSC = GetStripeCustomer.execute(sql="Select * From Stripe_Customer Where CompanyID = :CompanyID");
rsSC = resultSC.getResult();
if(rsSC.recordCount > 0){
// Charge
charge = oStripe.chargeCustomer();
} else{
// Notify us we haven't inserted into Stripe_Customer
mailerService = new mail();
mailerService.setTo('test#test.com');
mailerService.setFrom("support#test.com");
mailerService.setSubject("Error");
mailerService.setType("html");
mailBody = "ERROR";
mailerService.send(body=mailBody);
transaction action="rollback";
rollbackAction = true;
}
}
if(!rollbackAction){
transaction action="commit";
}
} catch(any e){
transaction action="rollback";
}
}
Does anyone know why the rollback isn't working?
Thanks
Change this:
if(!rollbackAction){
transaction action="commit";
}
} catch(any e){
transaction action="rollback";
to this
if(!rollbackAction){
transaction action="commit";
}
else
transaction action="rollback";
Your catch block only executes if the try block experiences a runtime error. Runtime errors mean, "did not execute". They have nothing to do with unwanted results.

Create sqlite table is not work

I have a method that make a connection to SQLITE and work with database by conditions (insert data or create table in my database.)
When I call it in my code, at first open database correctly but can not create tables. Mean that query does not show error but not execute.
this is my method :
void SQL(string cmnd)
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");//not dbConnection
QString path = "DBAbsent";
db.setDatabaseName(path);
QSqlQuery q(db);
if(!db.open())
{
printf("Error to open database");
}
else
{
if (cmnd=="createTable")
{
q.prepare("create table IF NOT EXISTS Personel (P_id int primary key, "
"CardID varchar(50), "
"name varchar(50));");
if(!q.exec())
{
qDebug()<<strerror(errno);
qDebug()<<q.lastError(); // show this error : QSqlError("", "Unable to fetch row", "No query")
}
q.prepare("create table IF NOT EXISTS Absent "
"(P_id int , "
"DateTime varchar(50), "
"key1 int,key2 int,key3 int,key4 int);");
if(!q.exec())
qDebug()<<strerror(errno);
db.close();
return;
}
else if (cmnd=="Register")
{
string card=ReadFromCard();
printf("\nCard Accepted : %s\nEnter Your name: ",card.c_str());
string name;
int id;
//string dt=QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
cin>>name;
printf("\n Name Accepted.\nEnter Your Personel ID: ");
cin>>id;
q.prepare( "SELECT count(P_id) FROM Personel WHERE P_id =?;" );
q.bindValue(0,id);
if( !q.exec() )
{
printf("\nThe error occured from P_ID database");
qDebug()<<strerror(errno);
//ShowMainMenu();
//return;
}
// Note: if you don't return in case of an error, put this into the else{} part
while( q.next() )
{
if (q.value(0).toInt()>0)
{
printf("\nThis personel ID was repeated\n");
break;
}
else
{
q.prepare("SELECT CardID FROM Personel WHERE CardID =?;");
q.bindValue(0,card.c_str());
q.exec();
while(q.next())
{
printf("\nThis card is not valid : it was repeated\n");
break;
}
}
}
q.prepare("insert into Personel value(?,?,?);");
q.bindValue(0,id);
q.bindValue(1,card.c_str());
q.bindValue(2,name.c_str());
q.exec();
printf("\nInsert Personel complete\n");
db.close();
return;
}
else
{
string card;
card=cmnd;
QString dt=QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
q.prepare("SELECT P_id FROM Personel WHERE CardID =?;");
q.bindValue(0,card.c_str());
if( !q.exec() )
{
printf("\nThe error occured from database418\n");
ShowMainMenu();
}
string result=("\n CARD NOT VALID =>repeated %s\n");
// Note: if you don't return in case of an error, put this into the else{} part
while( q.next() )
{
int P_id = q.value(0).toInt();
q.prepare("insert into Absent(P_id,DateTime,key1,key2,key3,key4) value(?,?,1,0,0,0);");
q.bindValue(0,P_id);
q.bindValue(1,dt);
q.exec();
result=("\n********WELL COME **********%s\n");
}
printf("%s",result);
db.close();
return;
}
}
}
And this is my output :
0 - Press 0 to Back
1 - Press 1 to Register the card
1
//the below lines when I want to select something from both tables , occurred
No such file or directory
QSqlError("", "Unable to fetch row", "No query")
No such file or directory
//the below line is when the if(cmnd="Register") {..} block is running , occurred.
QSqlDatabasePrivate::addDatabase: duplicate connection name 'qt_sql_default_connection', old connection removed.
You don't need to close and open db connection every time SQL() function is running. Better approach is to open db once, when your app starts and close it at the end. Then, in SQL(..) you just create query like
QSqlQuery q;
and work with it.
Cause of QSqlError("", "Unable to fetch row", "No query") is that you create QSqlQuery(db); before db is opened. And you need to check q.prepare() for errors too.
It solved. Just do these :
1 - As #Tony said: QSqlQuery should defined after opening database.
2 - q.prepare just uses for SQL query contains bindvalue(), like select() or insert() .

QMYSQL query failing

I'm currently working on my project within C++ using Qt. I have MySQL as database storage and the idea is to make a small messenger like MSN and Skype.
However, my MySQL queries are failing. It simply gets no results or gives me an error. There's loads of code coming up, I'm sorry for that.
This is my mysql.cpp which creates and opens the database connection:
#include "mysql.h"
mysql::mysql()
{
this->db = QSqlDatabase::addDatabase("QMYSQL", "QMYSQL");
this->db.setHostName("localhost");
this->db.setUserName("root");
this->db.setPassword("Eequi4");
this->db.setDatabaseName("test");
this->db.open();
}
mysql::~mysql()
{
}
mysql_result mysql::create_result(QString query)
{
return mysql_result(this->db.exec(query));
}
QSqlError mysql::error()
{
return this->db.lastError();
}
The connection is opened. That works correctly.
This is my mysql_result.cpp, the file I use to add parameters, insert, get results etc:
#include "mysql_result.h"
mysql_result::mysql_result(QSqlQuery query)
{
this->query = query;
}
void mysql_result::add_parameter(QVariant value)
{
this->query.addBindValue(value);
}
void mysql_result::add_parameter(QString key, QVariant value)
{
this->query.bindValue(key, value);
}
int mysql_result::get_last_id()
{
return this->query.lastInsertId().toInt();
}
void mysql_result::execute()
{
this->query.execBatch();
}
QSqlQuery mysql_result::get_query()
{
return this->query;
}
mysql_result::~mysql_result()
{
}
Okay, this should work. If I have the following code, it correctly returns all member first_name's from the database:
mysql_result res = _mysql->create_result("SELECT * FROM members");
QSqlQuery qry = res.get_query();
while (qry.next())
{
qDebug() << qry.value("first_name");
}
In member_controller.cpp (the class I use to retrieve members by name/id), I got this:
member* member_controller::get_member(int id)
{
mysql_result result = engine::get_mysql().create_result("SELECT * FROM members WHERE member_id = :ID");
result.add_parameter(":ID", id);
QSqlQuery query = result.get_query();
if (query.exec() && query.next())
{
return new member(id, query.value("first_name").toString(), query.value("second_name").toString(), query.value("screen_name").toString(), query.value("email").toString(), query.value("status").toString());
}
else
{
qDebug() << engine::get_mysql().error() << "\n";
qDebug() << query.lastError() << "\n";
}
return new member(0, "", "", "", "", "");
}
What it does it will go to the else, and I get the error invalid syntax near :ID. If I replace :ID with #ID (just like in C#), it will go to the else without error code.. I don't know what the problem is.
Two things. The code needs to be optimized a bit and made easier, I'm gonna work on that. Also, is it possible/allowed to put code in a pastebin and paste the URL rather than put the code here?
Try changing your query to this:
"SELECT * FROM members WHERE member_id = ?"
and add your param like this:
result.add_parameter(0, id);
I'd also suspect, if (query.exec() && query.next()) is incorrect, and the check for .next() should be removed as I'd imagine that requires another record to exist in the result set.