I'm attempting to write a piece of code that would get selected item from QTableView and delete it from database.
QModelIndex index = ui->tableView->selectionModel()->currentIndex();
QString value= ui->tableView->model()->data(index).toString();
qDebug() << "Value : " << value;
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("TestDatabase.db");
if(!db.open())
{
qDebug() << db.lastError();
qFatal("Failed to connect");
}
QSqlQuery qry;
qry.prepare("DELETE * FROM movies WHERE Title='"+value+"'");
if(!qry.exec())
{
QMessageBox::critical(this, tr("error::") , qry.lastError().text());
}
db.close();
However, I'm getting 'No query Unable to fetch row' error. I would really appreciate it if you could help me out with that.
Update : The issue was that I placed '*' after DELETE.
Your code suffers form SQL injection since you are using prepare() not correctly. This is also the reason why you get the error. To use prepare() the right way it must be followed by at least one bindValue(). In your case something like:
QSqlQuery qry;
qry.prepare("DELETE * FROM movies WHERE Title = :title");
qry.bindValue(":title", value);
if(!qry.exec()) //...
bindValue() takes care that value is escaped properly and doesn't do any harm.
...if you think that SQL injections aren't a problem, have a chat with Bobby Tables :)
Related
My Objective: To download a sqlite file from google drive using google drive v3 rest api
I am working on project that involves downloading a sqlite file which is stored in google drive. So far I have been in successfull in authorizing and getting the access token. I also had luck getting all the file names (sqlite files) stored in the google drive with their respective file id. Now I want to download the file using the file id. I followed the documentation, and send the request with file id. But all i am getting is
{
"kind": "drive#file",
"id": "1AmaXWbtmkvihy1g9yoYSSCssgL4fVh6t",
"name": "_db.sqlite",
"mimeType": "application/octet-stream"
}
This is my code:
bool File_Control::Download_File(const QString &FileName)
{
// Get FileID
QString FileID = m_Map.value(FileName, QString());
if(FileID.isEmpty()){
emit setMessage("Fatal Error: FileID is missing for FileName");
return false;
}
qDebug()<<"File ID "<<FileID;
// Now Prepare the request
QUrl url(tr("https://www.googleapis.com/drive/v3/files/%1").arg(FileID));
QUrlQuery query;
query.addQueryItem("alt","media");
url.setQuery(query.query());
QNetworkRequest request(url);
QString headerData = "Bearer " + m_Settings->get_Google_Drive_Settings
(Google_Drive::AccessTokenEnum);
request.setRawHeader("Authorization", headerData.toLocal8Bit());
QNetworkReply *reply = m_Account->get_Request(request);
// Now wait for the response
QTime t1 = QTime::currentTime().addMSecs(TIMEOUT);
while((t1>QTime::currentTime()) && (!reply->isFinished())){
QCoreApplication::processEvents();
}
if(reply->isFinished())
{
if(reply->error() != QNetworkReply::NoError){
emit setMessage("Error: "+reply->errorString());
delete reply;
return false;
}
else{
QByteArray array = reply->readAll();
qDebug()<<array<<reply->error();
delete reply;
return true;
}
}
else{
emit setMessage("Error: Timeout");
delete reply;
return false;
}
}
Am I missing something?
Edit 1:
m_Map -> QMap that stores file names (of files from drive) as key and file id as value.
m_Settings -> A helper object that helps in getting access_token which is stored in Windows Registry
Google_Drive -> A helper enum type.
m_Account -> Object that helps in authorising google account. This object contains my QNetworkManager so i made a function called get_Request to get my "get request"
Initially I din't set the alt to media, so that explains the reponse I have got in the first place. Then I have set the value as shown in the code.
The issue was, that I was trying to see the contents of QByteArray in the debugging console. Since the array contains binary data, Qt did not show any characters and I thought that Google has sent an empty packet.
To make the matter worse, I have read this guide and tried to reproduce it in my browser. So I have got the error code 400.
Eventually, I have thought about checking the size of the array and to my surprise it was the same as the size of the original file on the drive. Then I have saved the contents of the array to a local file and checked the SQLite file and everything was OK.
I'm looking for a way to enable logging changes for certain tables.
I have tried and tested adding tables to database log programatically, but with various success so far - sometimes it works sometimes it doesn't (mostly it does not) - it seems simply inserting rows into DatabaseLog table doesn't quite do the trick.
What I have tried:
Adding row with proper tableId, fieldId, logType and . Domain had been assigned as 'Admin', main company, empty field and subcompanies with the same result.
I have created class that handles inserts, main two functions are:
public static void InsertBase(STR tableName, domainId _domain='Admin')
{
//base logging for insert, delete, uptade on fieldid=0
DatabaseLog DBDict;
TableId _tableId;
DatabaseLogType _logType;
fieldId _fieldId =0;
List logTypes;
int i;
ListEnumerator enumerator;
;
_tableId= tableName2id(tableName);
logTypes = new List(Types::Enum);
logTypes.addEnd(DatabaseLogType::Insert);
logTypes.addEnd(DatabaseLogType::Update);
logTypes.addEnd(DatabaseLogType::Delete);
logTypes.addEnd(DatabaseLogType::EventInsert);
logTypes.addEnd(DatabaseLogType::EventUpdate);
logTypes.addEnd(DatabaseLogType::EventDelete);
enumerator = logTypes.getEnumerator();
while(enumerator.moveNext())
{
_logType = enumerator.current();
select * from dbdict where
dbdict.logTable==_tableId && dbdict.logField==_fieldId
&& dbdict.logType==_logType;
if(!dbDict) //that means it doesnt exist
{
dbdict.logTable=_tableId;
dbdict.logField=_fieldId;
dbdict.logType=_logType;
dbdict.domainId=_domain;
dbdict.insert();
}
}
info("Success");
}
and the method that lists every single field and adds as logType::Update
public static void init(str TableName, DomainId domain='Admin')
{
DatabaseLogType logtype;
int i;
container kk, ll;
DatabaseLog dblog;
tableid _tableId;
fieldid _fieldid;
;
logtype = DatabaseLogType::Update;
//holds a container of not yet added table fields to databaselog
kk = BLX_AddTableToDatabaseLog::buildFieldList(logtype,TableName);
for(i=1; i <= conlen(kk);i++)
{
ll = conpeek(kk,i);
_tableid = tableName2id(tableName);
_fieldid = conpeek(ll,1);
info(strfmt("%1 %2", conpeek(ll,1),conpeek(ll,2)));
dblog.logType=logType;
dblog.logTable = _tableId;
dblog.domainId = domain;
dblog.logField =_fieldid;
dblog.insert();
}
}
result:
What am I missing ?
#EDIT with some additional info
Does not work for SalesTable and SalesLine, WMSBillOfLading.
I couldn't add log for SalesTable and SalesLine by using wizard in administration panel, but my colleague somehow did (she has done exactly the same things as me). We also tried to add log to various other tables and we often found out that she could while I could not and vice versa (and sometimes none managed to do it like in case of WMSBillOfLading table).
The inconsistency of this mechanism is what drove me to write this code, which I hoped would solve all the problems.
After doing your setup changes you probably have to call
SysFlushDatabaseLogSetup::main();
in order to flush any caches.
This method is also called in the standard AX code in the form method SysDatabaseLogTableSetup\Methods\close and in the class method SysDatabaseLogWizard\doRun.
I am using a QCompleter on line edit to get some text. The completer functionality is as such working fine.
The QCompleter is fetching data from Sql Table.
completer = new QCompleter(this);
model = new QSqlRelationalTableModel(this, db);
model->setTable("product");
model->select();
completer->setModel(model);
completer->setCompletionColumn(1); // points to "name" in product table
ui->line_edit->setCompleter(completer);
now on line_edit_returnPressed(), I am able to get the selected text. Is it further possible to get the primary key / row index in Sql Table for the currect selection made from "QCompleter" ?
I see that ui->line_edit->completer()->currentRow(); always return 0.
I am just trying to save one SQL query thats all.
I have to acknowledge #Pavel Strakhov comments, thanks. Had it been put up as answer, I would have accepted it.
The whole time I was using QCompleter::currentIndex with the sql table model I had set with QCompleter::setModel(). I dont know how QCompleter works but I believe it internally derives a list model from the input table model.
From documentation -
QAbstractItemModel* QCompleter::completionModel()
Returns the completion model. The completion model is a read-only list model that contains all the possible matches for the current completion prefix. The completion model is auto-updated to reflect the current completions.
So now my SLOT looks like this -
void MainWindow::on_line_edit_returnPressed()
{
QModelIndex index = ui->le_filter->completer()->currentIndex();
if (index.isValid()) {
int row = index.row();
int key = completer->completionModel()->index(row, 0).data().toInt();
qDebug() << key;
}
}
I implemented drag and drop in my software. Basically I've got a QTableView which contains file paths. The user must be able to just drag and drop files in the QTableView in order to add them.
I've already done the big of the job but I'm stuck in iterating all the paths contained in the QDropEvent object. I have to implement the dropEvent method.
void Generous::dropEvent(QDropEvent *dropEvent) {
QStringList filePathList;
// Way to iterate dropEvent and append each file path to filePathList.
addFilesToListView(filePathList);
}
How can I do that?
I would guess that a drag and drop using filepaths use the MIME type text/uri-list.
If this is true, you should probably be able to retrieve the data like this:
if (dropEvent->mimeData()->hasUrls())
{
foreach (QUrl url, dropEvent->mimeData()->urls())
{
filePathList << url.toLocalFile();
}
}
Anyway, since I am not sure, the best would be first to check what kind of info is stored inside the drop event, and see where and how you can extract the filepaths:
QStringList availableMimeTypes = dropEvent->mimeData()->formats();
qDebug() << "available MIME types:" << dropEvent->mimeData()->formats() << "\n";
foreach(QString mimeType, availableMimeTypes)
{
qDebug() << "data for MIME type" << mimeType << " :";
qDebug() << dropEvent->mimeData()->data(mimeType) << "\n";
}
You can also create a global list that will keep appending the filePaths on each dropevent. So at the end you will be having a complete list of paths.
I am currently working on a code editor written in Qt,
I have managed to implement most of the features which I desire, i.e. auto completion and syntax highlighting but there is one problem which I can't figure out.
I have created a model for which the QCompleter uses, which is fine for things like html tags and c++ keywords such as if else etc.
But I would like to add variables to the completer as they are entered by the user.
So I created an event on the QTextEdit which will get the word (I know I need to check to make sure that it is a variable etc but I just want to get it working for now).
void TextEdit::checkWord()
{
//going to get the previous word and try to do something with it
QTextCursor tc = textCursor();
tc.movePosition(QTextCursor::PreviousWord);
tc.select(QTextCursor::WordUnderCursor);
QString word = tc.selectedText();
//check to see it is in the model
}
But now I want to work out how to check to see if that word is already in the QCompleters model and if it isn't how do I add it?
I have tried the following:
QAbstractItemModel *m = completer->model();
//dont know what to do with it now :(
You can check if word is in your QCompleter really by using
QAbstractItemModel *m = completer->model();
as you can see, method model() returns const pointer.
That is good for checking procedure, you can check like this:
bool matched = false;
QString etalon("second");
QStringListModel *strModel = qobject_cast<QStringListModel*>(completer.model());
if (strModel!=NULL)
foreach (QString str, strModel->stringList()) {
if (str == etalon)
{
matched = true;
break;
}
}
qDebug()<<matched;
But for your purposes, I recommend you to declare QStringListModel, and connect it to your completer, and then, all of operations you'll must do thru your model, according to Qt's principles of MVC programming (http://doc.qt.digia.com/qt/model-view-programming.html).
Your code can be like this:
// declaration
QCompleter completer;
QStringListModel completerModel;
// initialization
completer.setModel(&completerModel);
QStringList stringListForCompleter;
stringListForCompleter << "first" << "second" << "third";
completerModel.setStringList(stringListForCompleter);
// adding new word to your completer list
completerModel.setStringList(completerModel.stringList() << "New Word");
Good luck!