I am very new to QT and SQLite DBMS. I am trying to open an existing database created using "sqlite3" command-line program under ubuntu Linux. The same database I am trying to access under QT using the following code :
void MainWindow::func()
{
QSqlQuery query;
accounts_db = new QSqlDatabase();
*accounts_db = QSqlDatabase::addDatabase("QSQLITE");
perror("? ");
accounts_db->setDatabaseName("/home/user/xyz.db");
QSqlError *a = new QSqlError();
*a = accounts_db->lastError();
perror(a->text().toLatin1());
if (!accounts_db->open()) {
perror("database open error :");
}
if ( !accounts_db->isOpen() ) {
perror("database is not open");
}
query.exec("select accno,branchcode,fname,lname,curbalance,accdate from accounts");
while(query.next()) {
QString str = query.value(0).toString();
std::cerr << qPrintable(str) << std::endl;
}
end:
;
}
This fails with the following errors...
No such file or directory
: Invalid argument
QSqlQuery::exec: database not open
Notice that I get "No such file or directory" after adddatabase(), have no clue whatsoever which file is it talking about. Also notice that isOpen() and open() are returning "true" (???). The "database not open" error is from db.exec() call (...I suppose...).
In desperate need of guidance...
The constructor of QSqlQuery with no parameters uses the default database for your application. Maybe it is not set yet. Use the constructor specifying the database the query is required to use:
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "connection_name");
// Open db...
QSqlQuery query(db);
if (!query.exec(...)) {
// ...
}
// ...
Pay attention to how you close the connection afterwards.
EDIT: This is a test I just wrote and is working on my system. You might want to try.
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QVariant>
int main(int argc, char *argv[])
{
// Create database.
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "Connection");
db.setDatabaseName("/tmp/test.db");
if (!db.open()) {
qDebug("Error occurred opening the database.");
qDebug("%s.", qPrintable(db.lastError().text()));
return -1;
}
// Insert table.
QSqlQuery query(db);
query.prepare("CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, text TEXT)");
if (!query.exec()) {
qDebug("Error occurred creating table.");
qDebug("%s.", qPrintable(db.lastError().text()));
return -1;
}
// Insert row.
query.prepare("INSERT INTO test VALUES (null, ?)");
query.addBindValue("Some text");
if (!query.exec()) {
qDebug("Error occurred inserting.");
qDebug("%s.", qPrintable(db.lastError().text()));
return -1;
}
// Query.
query.prepare("SELECT * FROM test");
if (!query.exec()) {
qDebug("Error occurred querying.");
qDebug("%s.", qPrintable(db.lastError().text()));
return -1;
}
while (query.next()) {
qDebug("id = %d, text = %s.", query.value(0).toInt(),
qPrintable(query.value(1).toString()));
}
return 0;
}
This is mostly guessing, since your code is wrong on quite a few things, including the error reporting.
The most likely problem is that your file path is simply not right, or the user you're running your application with does not have the appropriate permissions on the file and/or directory. (Note: files and directory are case sensitive in Linux.)
perror should only be used after calling a system function that actually failed and that sets errno when it does. Qt doesn't do that.
Please try running this, and update your question if you still cannot resolve your issue:
void MainWindow::func()
{
// Note: no pointer!
QSqlDatabase accounts_db = QSqlDatabase::addDatabase("QSQLITE");
accounts_db.setDatabaseName("/home/user/xyz.db");
if (!accounts_db.open())
{
qDebug() << "Could not open database file:";
qDebug() << accounts_db.lastError();
return;
}
// Note: don't construct queries before you have a database!
QSqlQuery query;
if (!query.exec("select accno,branchcode,fname,lname,curbalance,accdate from accounts"))
{
qDebug() << "Query failed:";
qDebug() << query.lastError();
return;
}
while(query.next()) {
QString str = query.value(0).toString();
std::cerr << qPrintable(str) << std::endl;
}
}
(I haven't even tried to compile this, so YMMV.)
Have a look at the SQL examples also, and look at how they handle all this there.
Alright, I created a brand new database file using sqlite3 command, now the same program in my question is working !!!.
I had also tried this before, but that time it did not work (...I hate it when that happens). I guess the previous file may be corrupted. But the previous database file could be accessed from cmdline sqlite3 program, so I was assuming that file was ok,...but apparently not.
Anyway, thanks a lot guys for giving me time, and very sorry if I wasted it :( .
I am marking this as an answer just for the sake of clarity that this question is answered. But its not exactly an answer (...because I still don't understand what was happening !? )
Thanks again...
EDIT :
Here is the code
QSqlError *a = new QSqlError();
accounts_db = new QSqlDatabase();
*accounts_db = QSqlDatabase::addDatabase("QSQLITE");
accounts_db->setDatabaseName("/home/user/test.db");
if ( !accounts_db->open() ) {
qDebug() << accounts_db->lastError();
qDebug() << "Could not open database file:";
}
QSqlQuery query;
if ( !(accounts_db->isOpen()) ) {
qDebug() << accounts_db->lastError();
qDebug() << ": Could not open database file:";
goto end; // quit if not successful
}
query.exec("select * from accounts");
while(query.next()) {
// loop for i columns
QString str = query.value(i).toString();
std::cerr << qPrintable(str) << std::endl ;
// loop
}
end:
;
Related
I am trying to establish communication between a laptop and an embedded board over USB. USB driver for board has been installed and it has been detected in Windows device manager. Now I am developing code in Visual Studio 2013 (Win32 Console Application) using libusb.
The libusb_init() function does not return an error however when I try to open the device with libusb_open_device_with_vid_pid(), execution breaks at function usbi_mutex_init() in the threads_windows.c file of the libusb library. This file contains the source for "libusb synchronization on Microsoft Windows".
I also tried to call function libusb_get_device_list() but get the same error. Could you please suggest a solution?
main.cpp from my application source code -->
#include <iostream>
#include "libusb.h"
using namespace std;
int main()
{
int init_status = 0;
libusb_context *context = NULL;
libusb_device_handle *device;
init_status = libusb_init(&context);
if (init_status<0)
{
cout << "could not initialize";
return -1;
}
device = libusb_open_device_with_vid_pid(NULL, 0x0483, 0x5750); //execution breaks here
if (device == NULL)
{
cout << "could not open device";
return -1;
}
else
{
cout << "Device opened successfukky";
}
return 0;
}
threads_windows.c from libusb source code -->
int usbi_mutex_lock(usbi_mutex_t *mutex) {
DWORD result;
if(!mutex) return ((errno=EINVAL));
result = WaitForSingleObject(*mutex, INFINITE); //execution breaks here
if(result == WAIT_OBJECT_0 || result == WAIT_ABANDONED)
return 0; // acquired (ToDo: check that abandoned is ok)
return ((errno=EINVAL)); // don't know how this would happen
// so don't know proper errno
}
Looks to me like you get a specific, non-default context with your libusb_init() but when you use libusb_open_device_with_vid_pid() you are pass NULL which means to use the default context rather than the context created by the libusb_init().
You may just want to use the default context if it is a single device and you only need a single session. The documentation indicates that there are "limitations" with libusb_open_device_with_vid_pid() and it is not intended for anything other than test applications. I assume this is because in real applications there may be multiple devices and this convenience function just takes the first one matching the arguments. However the issue you are seeing is probably related to the context.
For a one off type of specific project your code would look something like:
#include <iostream>
#include "libusb.h"
using namespace std;
int main()
{
int init_status = 0;
libusb_device_handle *device;
// specify NULL for the context address so that libusb_init will use default content.
// this means that any libusb function with a context argument will be called with NULL.
init_status = libusb_init (NULL);
if (init_status < 0)
{
cout << "could not initialize";
return -1;
}
// open the first device found in the device list with this vendor id and product id
// for a real application in a multi-device environment we would need to
// iterate through the various devices using libusb_get_device_list() to get
// the list of devices then using libusb_get_device_descriptor() to iterate
// through the list to find the device we want. also need libusb_free_device_list ()
// after finishing with the list. lots of work for a simple one off project
device = libusb_open_device_with_vid_pid (NULL, 0x0483, 0x5750);
if (device == NULL)
{
cout << "could not open device";
return -1;
} else {
cout << "Device opened successfully";
}
return 0;
}
I have recently started testing the OTL library with the SQL Server using the Visual Studio 2013. My tests demonstrated that the performance of simple select statements against a 10000 count table is 40% slower than the performance of a similar .NET 4.0 test application. All tests were performed with all optimizations turned on for both platforms.
Both apps perform the following tasks:
Open the db connection
Create (and reserve space) for the container object.
Execute the select statement command.
For each record fetched from db
create an entity using the db(stream/reader) object
add the object to container
close
.NET C# app requires 0.5 secs to complete this task, while OTL-C++ app takes 0.7 secs to complete and I wonder if it is possible to optimize the C++ app to perform faster?
Snippet of C++ code:
#define OTL_ODBC_MSSQL_2008 // Compile OTL 4/ODBC, MS SQL 2008
#define OTL_CPP_11_ON
#define OTL_STL // Turn on STL features
#define OTL_ANSI_CPP // Turn on ANSI C++ typecasts
#define OTL_UNICODE // Enable Unicode OTL for ODBC
#include "otlv4.h"
class Employee
{
private:
int employeeId;
wstring regno;
wstring name;
wstring surname;
public:
Employee()
{
}
Employee(otl_stream& stream)
{
unsigned short _regno[32];
unsigned short _name[32];
unsigned short _surname[32];
if (!stream.is_null())
{
stream >> employeeId;
}
if (!stream.is_null())
{
stream >> (unsigned char*)_regno;
regno = (wchar_t*)_regno;
}
if (!stream.is_null()){
stream >> (unsigned char*)_name;
name = (wchar_t*)_name;
}
if (!stream.is_null()){
stream >> (unsigned char*)_surname;
surname = (wchar_t*)_surname;
}
}
int GetEmployeeId() const
{
return employeeId;
}
};
otl_connect db;
int main()
{
otl_connect::otl_initialize();
try
{
otl_connect::otl_initialize();
try
{
// connect
db.rlogon("DSN=SQLODBC");
// start timing
clock_t begin = clock();
otl_stream i(10000, "SELECT Id, Field1, Field2, Field3 FROM Test", db);
// create container
vector<Employee> employeeList;
employeeList.reserve(10000);
// iterate and fill container
while (!i.eof())
{
Employee employee(i);
employeeList.push_back(employee);
}
i.close();
// cleanup
size_t size = employeeList.size();
clock_t end = clock();
double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
cout << "Total records:" << size << endl;
cout << "Time elapsed to read all records:" << elapsed_secs << endl;
}
catch (otl_exception& p){ // intercept OTL exceptions
cerr << p.msg << endl; // print out error message
cerr << p.stm_text << endl; // print out SQL that caused the error
cerr << p.sqlstate << endl; // print out SQLSTATE message
cerr << p.var_info << endl; // print out the variable that caused the error
}
db.logoff();
return EXIT_SUCCESS;
}
I don't think so, when you look the code source of otl, it does use ODBC api for SQL Server and is only optimized as a odbc top layer. The SQL Server .NET 4.0 will use the sql driver api instead of odbc api for performance reason.
Also if you don't preallocate your memory consumption, you will always loose to .NET and Java due to the SysAllocMem function call. It's like trying to measure 4000 call to SysAlloc vs 1 call to SysAlloc. Your performance issue is directly linked to those functions.
I'm writing in VC++ with VS2012 pro and trying to get my logger to output something like this
03/26/2013 Registry()+
03/26/2013 Registry::LoadDWORD("VersionNumber")+;
03/26/2013 Registry(3)-
with the following lines of code
RegistryHelper::RegistryHelper()
{
LogWriter::WriteStart("Registry");
}
bool RegistryHelper::LoadDWORDValue(char* entry, UINT defaultValue, UINT& returnValue)
{
LogWriter::WriteStart("Registry::LoadDWORD", entry);
//Code to get DWORD
LogWriter::WriteEnd("Registry::LoadDWORD", returnValue);
return true;
}
The code I have thus far is this
void LogWriter::WriteStart(const char* log, ...)
{
tcout << log << "(";
va_list argptr;
va_start(argptr, log);
vfprintf(stderr, log, argptr);
va_end(argptr);
std::wcout << ")+" << EOL;
}
as a test I wrote this.
LogWriter::WriteStart("Registry", "Something", "else", "Start", "STop");
char* entry = "VersionNumber";
LogWriter::WriteStart("Registry", entry);
LogWriter::WriteStart("Registry");
but i am only getting back
2013-03-26.11:41:15 Registry()+
2013-03-26.11:41:15 Registry()+
2013-03-26.11:41:15 Registry()+
but i am expecting back
2013-03-26.11:41:15 Registry(Something, else, Start, STop)+
2013-03-26.11:41:15 Registry(VersionNumber)+
2013-03-26.11:41:15 Registry()+
With some playing around with it (mainly grabbing code from online and try a few different things) I've been able to make it say Registry(Registry)+ but is about as close as I've come. (I was using a while loop and checking for NULL) I'm somewhat new to VC++ and very new to using params (sorry i'm a C# guy). This is as far as I've gotten in about 1 hour of playing around with it. What am I doing wrong?
You are attempting to use variable-number-of-arguments feature on top of *printf function, but you are not passing any format specifier (like %d, %s) when you are calling WriteStart.
A call should be like:
LogWriter::WriteStart("Registry %s", entry);
Also, you need not to hard-code the function name to indate from where the log is being generated. The statement:
LogWriter::WriteStart("Registry::LoadDWORD", entry);
Can easily be replaced with:
LogWriter::WriteStart(__FUNCTION__, entry); // I am ignoring the format-specifier here
__FUNCTION__ will be replaced by fully-qualified function name by the preprocessor.
Moreover, you can also craft a macro that will take care of all this:
#define WRITE_LOG(_smsg) \
LogWriter::WriteStart(__FUNCTION__ , _smsg);
And use it:
WRITE_LOG("Your log message"); // Again, I ignore format-specifier here and in macro.
If you are using macro, and using variable-argument function with format specifier, you can use __VA_ARGS__ along with macro itself.
Try
std::cout << log << "(";
va_list argptr;
va_start(argptr, log);
vfprintf(stdout, log, argptr); // use same stream here!
va_end(argptr);
std::cout << ")+" << EOL;
Better - just pass whatever output stream you wish to use as an argument:
void LogWriter::WriteStart(FILE *fp, const char* log, ...)
{
fprintf (fp, "(");
va_list argptr;
va_start(argptr, log);
vfprintf(fp, log, argptr);
va_end(argptr);
fprintf (fp, ")\n");
}
I have a third party component written in C/C++ (on VS 2010) which can be downloaded here.
This component accepts 3 parameters as input (a filename and two numbers) and outputs a result in the console, and then outputs a file.
I've used Process and ProcessStartInfo in a C# WinForm project to consume this component which works fine. However, now I want to consume this in a WCF C# RESTful service, in which case the solution I thought with WinForm will not work.
It was suggested that I instead convert this to a MFC DLL and then use InterOp to call the unmanaged DLL through my C# web service (other suggestions are welcome).
Unfortunately, I have no idea on how to do that and my knowledge on C/C++ is fairly average. So my question is: How do I create a DLL from that component which accepts these 3 parameters (taken from main()):
cin >> fname;
cin >> minA;
cin >> minO;
then does whatever calculations it's supposed to do and return this (again taken from main()):
cout << "\nNumber is: " << num;
(and obviously still output the file it's supposed to output) ?
Any help would be HIGHLY appreciated.
Thanks in advance!
UPDATE: As a point of reference, here is my WinForm implementation mentioned above.
ProcessStartInfo cmdStartInfo = new ProcessStartInfo();
Process cmdProcess = new Process();
BackgroundWorker BWorker = new BackgroundWorker();
//is able to report progress
BWorker.WorkerReportsProgress = true;
//is able to be cancelled
BWorker.WorkerSupportsCancellation = true;
//attach events
BWorker.DoWork += worker_DoWork;
BWorker.RunWorkerCompleted += worker_RunWorkerCompleted;
BWorker.RunWorkerAsync();
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
if (firstTimeLoaded)
{
cmdStartInfo.FileName = Path.GetFullPath("../../Resources/thirdparty.exe");
cmdStartInfo.WorkingDirectory = Path.GetFullPath("../../Resources/");
cmdStartInfo.RedirectStandardOutput = true;
cmdStartInfo.RedirectStandardError = true;
cmdStartInfo.RedirectStandardInput = true;
cmdStartInfo.UseShellExecute = false;
cmdStartInfo.CreateNoWindow = true;
cmdProcess.StartInfo = cmdStartInfo;
cmdProcess.SynchronizingObject = this;
cmdProcess.ErrorDataReceived += cmd_Error;
cmdProcess.Exited += cmd_Exited;
cmdProcess.EnableRaisingEvents = true;
cmdProcess.Start();
cmdProcess.BeginErrorReadLine();
firstTimeLoaded = false;
}
while (!cmdProcess.HasExited)
{
if (use)
{
if (BWorker.CancellationPending)
{
e.Cancel = true;
}
StringBuilder builder = new StringBuilder();
//read unbuffered output
while (cmdProcess.StandardOutput.Peek() != -1)
{
char inputChar = (char)cmdProcess.StandardOutput.Read();
if (inputChar != '\r' && inputChar != '\n')
{
builder.Append(inputChar);
}
if (inputChar == '\n')
{
break;
}
}
if (cmdProcess.StandardOutput.Peek() == -1)
{
cmdProcess.StandardOutput.DiscardBufferedData();
}
//process the output
string output = builder.ToString();
//determine appropriate action
switch (output)
{
case "Enter file name: ":
cmdProcess.StandardInput.WriteLine(textBox1.Text);
break;
case "Enter minimum size of A: ":
cmdProcess.StandardInput.WriteLine(textBox2.Text);
break;
case "Enter minimum size of O: ":
cmdProcess.StandardInput.WriteLine(textBox3.Text);
break;
}
if (output.Contains("Number: "))
{
MessageBox.Show("Number is: " + output.Substring(output.LastIndexOf(" ") + 1));
use = false;
}
}
}
}
Let's give this a try.
In VS2010, create a Win32 Project under Visual C++/Win32. For this purpose, call it MyWin32Lib.
Add the thirdparty.cpp file to the project and compile. You should get some warnings, but it's ok.
Create a new header file called thirdparty.h so we can export the function signature.
In the thirdparty.h file, do:
#pragma once
// This will be the interface for third party file
int concepts(char* szFileName, int nMinIntent, int nMinExtent);
In the thirdparty.cpp file, add #include "stdafx.h" right before #include
Change the main function signature to match the one in the header:
//int main()
// Instead of getting input from console, we're passing it the values
int concepts(char* szFileName, int nMinIntent, int nMinExtent)
Comment out all input requests, and just copy the args to the local vars:
//cout << "\n\n***** In-Close 3.0 Concept Miner *****";
//cout << "\n\nEnter cxt file name including extension: ";
//cin >> fname;
//cout << "\nEnter minimum size of intent (no. attributes): ";
//cin >> minIn;
//cout << "\nEnter minimum size of extent (no. objects): ";
//cin >> minEx;
strcpy_s(fname, _countof(fname), szFileName);
minIn = nMinIntent;
minEx = nMinExtent;
Comment out cout << "\nNumber... (this is no longer needed)
At the end of the function, do:
break;
}
//cout << "\n\nHit <enter> to finish";
//while ( !_kbhit());
return numcons;
}
I don't know why there's a while(1) since there's no way to get out of it, but assume we'll doing it only once.
Make sure you compile ok.
Create a new CPP file, call it "Concepts.cpp"
In Concepts.cpp, enter:
#include "stdafx.h"
#include "thirdparty.h"
extern "C"
{
__declspec(dllexport) int GetConcepts(char* szFileName, int nMinIntent, int nMinExtent)
{
return concepts(szFileName, nMinIntent, nMinExtent);
}
}
*You should now have a Win32 DLL that performs the work using arguments instead.
Create a C# Class Library project.
Create a C# class called "Concepts.cs"
In this class, enter:
public class Concepts
{
// Link to the Win32 library through InterOp
[DllImport("MyWin32Lib.dll")]
public static extern int GetConcepts(
[MarshalAs( UnmanagedType.LPStr )] string fileName, int minIntent, int minExtent );
}
*You have to marshal the filename input as ANSI since that's what thirdparty.cpp uses.
I think I got all of it. You can now reference your C# library from a web service.
I have a fairly simple call I'm trying to make to a database. I have everything surrounded in try/catch and if statements, but... nothing. I know I'm making the connection (the connection refcount in MySQL increments each time I try running the script), but it never seems to return. Code is:
if (!conn.connect(db, server, username, pass))
{ /* Log error to a file */}
try
{
mysqlpp::Query query = conn.query();
query << "CALL db.test('1', '2')";
std::cout << "About to call query" << std::endl;
if (mysqlpp::StoreQueryResult res = query.store())
{
std::string toReturn = "";
res[0][0].to_string(toReturn);
std::cout << "Query called. Result: " << toReturn << std::endl;
}
}
catch(Exception e)
{ /*Output caught exception*/ }
and I get:
About to call query
as my sole output.
I have more debugging in there (query is being put together correctly, connection is correct, etc).
Anyone have any idea what might be happening, or what I should check next?
Thanks!
-- Edit: If I run the call straight from MySQL, everything works as expected, so that's not causing the problem.
You should call the query inside conn.query(); Like
std::cout << "About to call query" << std::endl;
mysqlpp::Query query = conn.query("CALL db.test('1', '2')");
if (mysqlpp::StoreQueryResult res = query.store())
{
std::string toReturn = ""; //this is not necessary
res[0][0].to_string(toReturn); //this is not necessary
for (size_t i = 0; i < res.num_rows(); ++i)
{
std::cout << "Query called. Result: " << res[i][0] << std::endl;
}
}
you can refer http://tangentsoft.net/mysql++/doc/html/userman/tutorial.html for examples