C++ Qt sql lite database connection issue - c++

The following code is used by me to connect to a database using Qt IDE. And if it successfully connects to the database Connected to db is printed on a label. But the issue is if I even given a wrong database path it returns Connected to db on the label how can i correct this issue?
QSqlDatabase mydb= QSqlDatabase::addDatabase("QSQLITE");
mydb.setDatabaseName("x");
if(!mydb.open()){
ui->label->setText("Failed to open the db");
}
else{
ui->label->setText("Connected to db");
}
Even though in the above code i put "x" which is not a valid database path I get "Connected to db' in the label when I run the program!
How can i correct this issue?

Qt uses as SQLite backend uses the sqlite library, so you will use one of the functions to open the database:
int sqlite3_open(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
int sqlite3_open16(
const void *filename, /* Database filename (UTF-16) */
sqlite3 **ppDb /* OUT: SQLite db handle */
);
int sqlite3_open_v2(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
const char *zVfs /* Name of VFS module to use */
);
According to the docs:
These routines open an SQLite database file as specified by the
filename argument. The filename argument is interpreted as UTF-8 for
sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte
order for sqlite3_open16(). A database connection handle is usually
returned in *ppDb, even if an error occurs. The only exception is that
if SQLite is unable to allocate memory to hold the sqlite3 object, a
NULL will be written into *ppDb instead of a pointer to the sqlite3
object. If the database is opened (and/or created) successfully, then
SQLITE_OK is returned. Otherwise an error code is returned. The
sqlite3_errmsg() or sqlite3_errmsg16() routines can be used to obtain
an English language description of the error following a failure of
any of the sqlite3_open() routines.
From which we conclude that if the database does not exist this will create it, it will only generate the error in creating it if there are problems to allocate memory.

Related

SQLITE_CANTOPEN - windows c++

I am trying to create an Sqlite database in the selected folder but can`t do this.
Operating System - Windows, editor - Visual studio, progect encoding is unicode. Encoding of input string with database connection unknown. Language - C++
The problem:
I can't create database when I use following connection string: file:C:/Users/Public/Desktop/testDb.sqlite
I am always getting error 14 (SQLITE_CANTOPEN).
I use following function to create database:
CSqliteManager::CSqliteManager(const char* dbName)
{
db = nullptr;
int rc = sqlite3_open(dbName, &db);
if (rc != SQLITE_OK)
{
db = nullptr;
}
}
How should me change connection string to create database fo the sollowing pass:
C://Users/Public/Desctop/MyBD.sqlite
You can't use URI style filenames with sqlite3_open() as they're disabled by default (I'm assuming you didn't enable them globally). Instead you need to use sqlite3_open_v2() with the appropriate option (SQLITE_OPEN_URI). Details and more details.
(Or just not use a URI, of course)

Qt 5.x, ODBC (dBase, dbf), Windows, encodings

The database is a set of dbf files in Windows-1251 codepage (1C 7.7, if you need to know). How do I get a UTF-8 string as a result? Somehow manages to see the desired text in console only, only with a locale: IBM 866
Code example:
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
db.setDatabaseName("Driver={Microsoft dBASE Driver (*.dbf)};DriverID=277;Dbq=/path/to/database");
db.open(); // Ok
QSqlQuery query = QSqlQuery("select descr from SC84", db);
query.next(); // Ok
// "╩єчютэюх цхыхчю"
qDebug(query.value(0).toByteArray().data());
// if setup locale ...
QTextCodec::setCodecForLocale(QTextCodec::codecForName("IBM 866"));
// "Кузовное железо" (i was looking for this russian words!)
qDebug(query.value(0).toByteArray().data());
// "╩єчютэюх цхыхчю"
QMessageBox::information(this, "test as is", query.value(0).toString());
// "тХй╤Ф╤З╤О╤В╤Н╤О╤Е ╤Ж╤Е╤Л╤Е╤З╤О" — what was wrong?
QMessageBox::information(this, "test from DOS-866",
QTextCodec::codecForName("IBM 866")->toUnicode(query.value(0).toByteArray().data()));
I understand that there is somewhere an implicit conversion. But cannot find a solution!
PS The question is closed. It was hard to guess that the reason recoding "cp1251 as cp866". The problem is that ignored the connection settings in the ODBC DSN string. Attempts to solve with the option "DataCodePage=ANSI" had failed, the option was discarded. But setting this value in the registry under\SOFTWARE\Microsoft\Jet\4.0\Engines\xBase solved the problem immediately...
In the query results cp1251 encoded as cp866, mangling text. Setup DataCodePage=ANSI" DSN ODBC is ignored. So you need to set the value of the ANSI in registry \SOFTWARE\Microsoft\Jet\4.0\Engines\xBase.

Is it possible to back a readonly SQLite database with a memory buffer (or PE resource)?

I would like to embed a reasonably large chunk of data stored in a SQLite database into my binary using Windows' "custom resources" feature. (This is a whitelist for a logging tool) SQLite does come with support for in memory databases, but it looks like that may be limited to creating completely new databases; and does not seem to support reading from a memory buffer; but I'm not positive.
Does the database support anything like this? (I have to embed SQLite for other reasons, so it'd be awesome to use it for whitelists too...)
The online backup section of sqlite documentation http://www.sqlite.org/backup.html has some code that might do what you want (i.e. dump in memory db to file, or reload a file into an in memory db). That should allow you do save you pre-indexed db into a file that you can add to your resources and load in memory at run-time.
This is the code in question (copied straight from the page linked above)
/*
** This function is used to load the contents of a database file on disk
** into the "main" database of open database connection pInMemory, or
** to save the current contents of the database opened by pInMemory into
** a database file on disk. pInMemory is probably an in-memory database,
** but this function will also work fine if it is not.
**
** Parameter zFilename points to a nul-terminated string containing the
** name of the database file on disk to load from or save to. If parameter
** isSave is non-zero, then the contents of the file zFilename are
** overwritten with the contents of the database opened by pInMemory. If
** parameter isSave is zero, then the contents of the database opened by
** pInMemory are replaced by data loaded from the file zFilename.
**
** If the operation is successful, SQLITE_OK is returned. Otherwise, if
** an error occurs, an SQLite error code is returned.
*/
int loadOrSaveDb(sqlite3 *pInMemory, const char *zFilename, int isSave){
int rc; /* Function return code */
sqlite3 *pFile; /* Database connection opened on zFilename */
sqlite3_backup *pBackup; /* Backup object used to copy data */
sqlite3 *pTo; /* Database to copy to (pFile or pInMemory) */
sqlite3 *pFrom; /* Database to copy from (pFile or pInMemory) */
/* Open the database file identified by zFilename. Exit early if this fails
** for any reason. */
rc = sqlite3_open(zFilename, &pFile);
if( rc==SQLITE_OK ){
/* If this is a 'load' operation (isSave==0), then data is copied
** from the database file just opened to database pInMemory.
** Otherwise, if this is a 'save' operation (isSave==1), then data
** is copied from pInMemory to pFile. Set the variables pFrom and
** pTo accordingly. */
pFrom = (isSave ? pInMemory : pFile);
pTo = (isSave ? pFile : pInMemory);
/* Set up the backup procedure to copy from the "main" database of
** connection pFile to the main database of connection pInMemory.
** If something goes wrong, pBackup will be set to NULL and an error
** code and message left in connection pTo.
**
** If the backup object is successfully created, call backup_step()
** to copy data from pFile to pInMemory. Then call backup_finish()
** to release resources associated with the pBackup object. If an
** error occurred, then an error code and message will be left in
** connection pTo. If no error occurred, then the error code belonging
** to pTo is set to SQLITE_OK.
*/
pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main");
if( pBackup ){
(void)sqlite3_backup_step(pBackup, -1);
(void)sqlite3_backup_finish(pBackup);
}
rc = sqlite3_errcode(pTo);
}
/* Close the database connection opened on database file zFilename
** and return the result of this function. */
(void)sqlite3_close(pFile);
return rc;
}

How can I create a local database inside a Microsoft Visual C++ 2010 Express project?

How can I create a local database inside a Microsoft Visual C++ 2010 Express project?
I can't find this simple answer in the web. The only answer I've found is for Visual Studio: using project > add new item > local database. But this option isn't available in Visual c++ 2010 Express edition.
I tried installing "Microsoft SQL Server Compact 4" and "Microsoft SQL Server Denali", and updating "Microsoft Visual C++ 2010 Express" from "Windows Update".
Ok, I got a solution at last. Regrettably I must answer my own question...
I used SQLite library (http://www.sqlite.org/). It was a little complicated because the sqlite documentation is a bit vague, but I did as follows:
Download sqlitedll*.zip - extract .def and .dll files somewhere.
Generate the lib file with a command like "c:\program
files\micros~1\vc98\bin\lib" /def:sqlite3.def". Do that from a command
prompt, in the directory with the .def file in, with the appropriate
path to your lib.exe. You may need to run vcvars32.bat first, which is
also in the bin directory. Copy the resulting .lib to an appropriate
place, and set that as a library directory in VC++. (Or do it on a
per-project basis.)
Download the sqlite-source*.zip file, and extract the sqlite3.h file
from within to a suitable directory. Set that as an include directory
in VC++. (Again, you could do it on a per-project basis.)
In your project, #include as required, add sqlite3.lib
to your project, copy the sqlite3.dll to your executable's directory
or working directory, and you should be ready to go.
Then, is easy to use no-out queries, but if you want to use a SQL "SELECT" for example, you could use this code:
std::string queries;
// A prepered statement for fetching tables
sqlite3_stmt *stmt;
// Create a handle for database connection, create a pointer to sqlite3
sqlite3 *handle;
// try to create the database. If it doesnt exist, it would be created
// pass a pointer to the pointer to sqlite3, in short sqlite3**
int retval = sqlite3_open("local.db",&handle);
// If connection failed, handle returns NULL
if(retval){
System::Windows::Forms::MessageBox::Show("Database connection failed");
return;
}
// Create the SQL query for creating a table
char create_table[100] = "CREATE TABLE IF NOT EXISTS users (uname TEXT PRIMARY KEY,pass TEXT NOT NULL,activated INTEGER)";
// Execute the query for creating the table
retval = sqlite3_exec(handle,create_table,0,0,0);
// Insert first row and second row
queries = "INSERT INTO users VALUES('manish','manish',1)";
retval = sqlite3_exec(handle,queries.c_str(),0,0,0);
queries = "INSERT INTO users VALUES('mehul','pulsar',0)";
retval = sqlite3_exec(handle,queries.c_str(),0,0,0);
// select those rows from the table
queries = "SELECT * from users";
retval = sqlite3_prepare_v2(handle,queries.c_str(),-1,&stmt,0);
if(retval){
System::Windows::Forms::MessageBox::Show("Selecting data from DB Failed");
return ;
}
// Read the number of rows fetched
int cols = sqlite3_column_count(stmt);
while(1){
// fetch a row’s status
retval = sqlite3_step(stmt);
if(retval == SQLITE_ROW){
// SQLITE_ROW means fetched a row
// sqlite3_column_text returns a const void* , typecast it to const char*
for(int col=0 ; col<cols;col++){
const char *val = (const char*)sqlite3_column_text(stmt,col);
System::Windows::Forms::MessageBox::Show(stdstr2systemstr(sqlite3_column_name(stmt,col))+" = "+stdstr2systemstr(val));
}
}
else
if(retval == SQLITE_DONE){
// All rows finished
System::Windows::Forms::MessageBox::Show("All rows fetched");
break;
}
else{
// Some error encountered
System::Windows::Forms::MessageBox::Show("Some error encountered");
return ;
}
}
// Close the handle to free memory
sqlite3_close(handle);
I expect this info be useful!
Sources:
http://www.gamedev.net/topic/332251-sqlite3-and-visual-c/page_p_3157685#entry3157685
http://milky.manishsinha.net/2009/03/30/sqlite-with-c/

SQLite open performance-issue

I am writing a desktop application under windows,
I am using sqlite to store information,
I created a db with index on string column, insert a lot of informations, the db size about 16M,
If I restart Windows, and open my application.
It takes about 9-10 secodes to open the sqlite db.
The code is as follow:
int nRet;
nRet = sqlite3_open16(szFile, &mpDB);
if (nRet != SQLITE_OK)
{
LPCTSTR szError = (LPCTSTR) _sqlite3_errmsg(mpDB);
throw CppSQLite3Exception(nRet, (LPCTSTR)szError, DONT_DELETE_MSG);
}
setBusyTimeout(mnBusyTimeoutMs);
Is it possible to accelerate it ?
Many Thanks!
YOu can use sqlite3 command line utility to check your database.
Or you can recreate your tables with data (dump/restore).