Store OpenCV::Mat to SQLite DB as BLOB - c++

Is it possible to store image from opencv::Mat to sqlite database (as BLOB or other type)?
I can store other variable like string, but not the cv::Mat in.
Here is my function code
void SQLiteWrapper::WriteDetectInfo(std::string markName, std::string dmgClass, cv::Mat in)
{
char *zErrMsg = 0;
std::ostringstream strQuery;
strQuery << "INSERT INTO DetectedDamage(Markname, Class, Image)";
strQuery << "VALUES('" << markName;
strQuery << "','" << dmgClass;
strQuery << "'," << in;
strQuery << ");";
std::string query = strQuery.str();
int rc = sqlite3_exec(DB3, query.c_str(), SQLiteWrapper::CallBack, (void*)CB_WRITE_DETECT_INFO, &zErrMsg);
}

For storing an image as BLOB you need to convert the mat to char* first. For this purpose you can use cv::imencode(). and then you can insert the blob data as:
int rc = 0;
char* buffer = new char[size]; // Your image data from `cv::imencode()`
sqlite3_stmt *strQuery = NULL;
sqlite3_prepare_v2(db,"INSERT INTO DetectedDamage(Markname, Class, Image) VALUES (NULL, NULL, ?)", -1, &strQuery, NULL);
sqlite3_bind_blob(strQuery, 1, buffer, size, SQLITE_STATIC);
if (rc != SQLITE_OK) {
std::cerr << "bind failed!" << std::endl;
} else {
rc = sqlite3_step(strQuery);
if (rc != SQLITE_DONE)
std::cerr << "execution failed!" << sqlite3_errmsg(db) << std::endl;
}

Related

sqlite3: Table schema not copying from main database to second database

I am attempting to copy the same table schema and a select number of entries from my main database to a new secondary database. I am able to create the second database START.sql and inside it, a table called copied, however the schema between that and the main masterDatabaseTest differ and as a result I receive the error:
table START.copied has 1 columns but 5 values were supplied
The code:
void newLog(std::string tableName, std::string timeStart, std::string timeEnd)
{
char *err_msg = NULL;
int rc= -1;
std::string dbLogName = timeStart;
std::string dbLogName2 = dbLogName + ".sql";
std::string attachQuery = "ATTACH DATABASE 'START.sql' AS 'START';";
std::string copyTable = "CREATE TABLE START.copied AS SELECT sql FROM sqlite_master WHERE type='table' and name='masterDatabaseTest';";
std::string insertCopied = "INSERT INTO START.copied SELECT * from sqlite_master where type='table' and name='masterDatabaseTest';";
std::string detach = "DETACH DATABASE START;";
std::cout << dbLogName << "\n"
<< attachQuery << "\n"
<< copyTable << "\n"
<< insertCopied << "\n"
<< detach << std::endl;
sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, 0);
rc = sqlite3_open(databaseName.c_str(), &db); // CREATES DATABASE
std::cout << "OPEN: " << rc << std::endl;
rc = sqlite3_exec(db, attachQuery.c_str(), NULL, 0, &err_msg);
std::cout << "ATTACH: " << rc << std::endl;
if(rc != 0){
std::cout << err_msg << std::endl;
}
rc = sqlite3_exec(db, copyTable.c_str(), NULL, 0, &err_msg);
std::cout << "copyTable: " << rc << std::endl;
if(rc != 0){
std::cout << err_msg << std::endl;
}
rc = sqlite3_exec(db, insertCopied.c_str(), NULL, 0, &err_msg);
std::cout << "insertCopied: " << rc << std::endl;
if(rc != 0){
std::cout << err_msg << std::endl;
}
rc = sqlite3_exec(db, detach.c_str(), NULL, 0, &err_msg);
std::cout << "detach: " << rc << std::endl;
if(rc != 0){
std::cout << err_msg << std::endl;
}
sqlite3_exec(db, "END TRANSACTION;", NULL, NULL, 0);
}
inside commandline sqlite3 database.sql:
sqlite> .schema
CREATE TABLE masterDatabaseTest (ID INTEGER,RECORDTIME BIGINT,TYPE INTEGER,TIMESTAMP BIGINT,ENCODER1 INTEGER,ENCODER2 INTEGER,ENCODER3 INTEGER,ENCODER4 INTEGER,ENCODER5 INTEGER);
inside commandline sqlite3 START.sql
sqlite> .schema
CREATE TABLE copied(sql TEXT);
If you want "an exact copy of the schema of masterDatabaseTest", you do not need to use sqlite_master. The DDL query
CREATE TABLE START.copied AS SELECT * from masterDatabaseTest
will accomplish that. If you want a select number of entries, add a WHERE clause. If you do not want any rows from the source table, add a WHERE 0; it will create the schema and will not select any rows.
I have figured out my problem :)
the db instance was not pointing to the correct database, so although I was able to execute it correctly in commandline, the actual program has no initialised the database connection so the sqlite3_exec command was pointing to nothing.
Fixing that I was able to execute the commands with no problem.

sqlite3_exec returns 1 although query is right

Here's my code
std::string dbFileName = "GalleryDB.sqlite";
int doesFileExist = _access(dbFileName.c_str(), 0);
int res = sqlite3_open(dbFileName.c_str(), &db);
if (res != SQLITE_OK) {
db = nullptr;
std::cout << "Failed to open DB" << std::endl;
return -1;
}
if (doesFileExist == 0) {
char* sqlStatement = "CREATE TABLE USERS (ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , NAME TEXT NOT NULL);";
char** errMessage = nullptr;
res = sqlite3_exec(db, sqlStatement, nullptr, nullptr, errMessage);
if (res != SQLITE_OK)
{
std::cout << res;
std::cout << "ERROR! CANT CREATE USERS" << '\n';
}
}
Altough my query to create the users table is correct, and it does create the table it always returns 1. What's the reason? Did I do something wrong?

SQLite what type of value returned by sqlite3_column_text?

i try to make simple auth system. its part of server code:
void ClientHandler(int index) {
strstr << "SELECT id FROM users WHERE login='" << login1 << "'" << " AND password='" << password1 << "'";
std::string str = strstr.str();
char* db_name = "users.db";
sqlite3* db;
char* zErrMsg = 0;
int error;
sqlite3_stmt* res;
const char* tail;
error = sqlite3_open(db_name, &db);
if (error)
{
cout << "Can't open database: " << sqlite3_errmsg(db) << endl;
sqlite3_close(db);
}
error = sqlite3_prepare_v2(db, str.c_str(), 1000, &res, &tail);
if (error)
{
cout << "Can't select data: " << sqlite3_errmsg(db) << endl;
sqlite3_close(db);
}
cout << "Display result from table1" << endl;
int rec_count = 0;
while (sqlite3_step(res) == SQLITE_ROW)
{
cout << sqlite3_column_int64(res, 0) << endl;
//rec_count++;
}
if (sqlite3_column_text(res, 0) != NULL)
{ // GOOD
int msg_size = msg2.size();
send(Connections[index], (char*)& msg_size, sizeof(int), NULL);
send(Connections[index], msg2.c_str(), msg_size, NULL);
std::cout << msg2 << std::endl;
}
{ // BAD
int msg_size = msg3.size();
send(Connections[index], (char*)& msg_size, sizeof(int), NULL);
send(Connections[index], msg3.c_str(), msg_size, NULL);
std::cout << msg3 << std::endl;
}
delete[] msg;
}
In this part i whant to check is log/pass correct (by finding ID).
if (sqlite3_column_text(res, 0) != NULL)
{ // GOOD
int msg_size = msg2.size();
send(Connections[index], (char*)& msg_size, sizeof(int), NULL);
send(Connections[index], msg2.c_str(), msg_size, NULL);
std::cout << msg2 << std::endl;
}
{ // BAD
int msg_size = msg3.size();
send(Connections[index], (char*)& msg_size, sizeof(int), NULL);
send(Connections[index], msg3.c_str(), msg_size, NULL);
std::cout << msg3 << std::endl;
}
But i cant understand what type of data return sqlite3_column_text (when log/pass incorect he return nothing?)
How i can make this if/else statement correctly?
In your sql statement you select some "id" from the table users, where the login and password data should be equal.
So, it will only return an id, if such an record is found. sqlite3_step(res) will then return SQLITE_ROW. And here you need to check. Either the password is correct or not. At least if you have unique IDs and unique logins, which is a must.
Then you need to rewite your code to something like
if (sqlite3_step(res) == SQLITE_ROW)
{ // GOOD
cout << sqlite3_column_int64(res, 0) << endl;
int msg_size = msg2.size();
send(Connections[index], (char*)& msg_size, sizeof(int), NULL);
send(Connections[index], msg2.c_str(), msg_size, NULL);
std::cout << msg2 << std::endl;
}
else
{ // BAD
int msg_size = msg3.size();
send(Connections[index], (char*)& msg_size, sizeof(int), NULL);
send(Connections[index], msg3.c_str(), msg_size, NULL);
std::cout << msg3 << std::endl;
}
You should not call if (sqlite3_column_text(res, 0) != NULL). MOst probaly you iid ist an int64. No need to get it as string again.
By the way sqlite3_column_text(res, 0) would return a char* to a null terminated string. >ou just need to write something like char* idtext = sqlite3_column_text(res, 0). But only, if a record could be read!
Always check the return values!
Caveat! Too much of your code is unknown to me, so I cannot judge completely. . .

SQLite, SELECT and max function

Why does the following code gives me the different result when using max function? I thought that it should return SQLITE_DONE in this case too.
#include <boost/scope_exit.hpp>
#include <sqlite3.h>
#include <cstdlib>
#include <iostream>
int main()
{
sqlite3* db;
int rc = sqlite3_open(":memory:", &db);
BOOST_SCOPE_EXIT_ALL(&db)
{
sqlite3_close(db);
};
if (rc != SQLITE_OK)
{
std::cerr << "Can't open database."
<< " Error code: " << rc
<< " Error description: " << sqlite3_errmsg(db);
return EXIT_FAILURE;
}
char* errMsg;
rc = sqlite3_exec(db, "CREATE TABLE foo (bar INTEGER)", NULL, NULL, &errMsg);
if (rc != SQLITE_OK)
{
std::cerr << "Can't create \"foo\" table."
<< " Error code: " << rc
<< " Error description: " << errMsg;
sqlite3_free(errMsg);
return EXIT_FAILURE;
}
{
sqlite3_stmt* stmt;
rc = sqlite3_prepare_v2(db, "SELECT bar FROM foo WHERE bar = 1", -1, &stmt, NULL);
if (rc != SQLITE_OK)
{
std::cerr << "Can't prepare SELECT statement."
<< " Error code: " << rc
<< " Error description: " << sqlite3_errmsg(db);
return EXIT_FAILURE;
}
BOOST_SCOPE_EXIT_ALL(&stmt)
{
sqlite3_finalize(stmt);
};
rc = sqlite3_step(stmt);
std::cout << rc << std::endl; // 101 -- SQLITE_DONE
}
{
sqlite3_stmt* stmt;
rc = sqlite3_prepare_v2(db, "SELECT max(bar) FROM foo WHERE bar = 1", -1, &stmt, NULL);
if (rc != SQLITE_OK)
{
std::cerr << "Can't prepare SELECT statement."
<< " Error code: " << rc
<< " Error description: " << sqlite3_errmsg(db);
return EXIT_FAILURE;
}
BOOST_SCOPE_EXIT_ALL(&stmt)
{
sqlite3_finalize(stmt);
};
rc = sqlite3_step(stmt);
std::cout << rc << std::endl; // 100 -- SQLITE_ROW
}
}
Thanks in advance.
When you are using GROUP BY, you get one group for each unique value of the grouped column(s).
If there does not exist any row to be grouped, there are no groups, and the query does not return any rows.
When you are using an aggregate function like max() without GROUP BY, the entire table becomes a single group.
This happens even if the table is empty, i.e., you then get a single group that aggregates over the empty set.
If you don't want to get a result when there are not bar = 1 rows, add GROUP BY bar.

SQLite Blob insertion c++

After visiting dozens of websites containing info about SQLite I still cannot find a solution to fix an error while binding a blob. Here is the table decleration:
CREATE TABLE ONE (
ID INTEGER PRIMARY KEY AUTOINCREMENT
NOT NULL,
NAME CHAR( 50 ) NOT NULL,
LABEL CHAR( 50 ),
GRP CHAR( 50 ),
FILE BLOB
);
And here is the code for insertion:
int InsertFile(string name)
{
const char* dbname = name.c_str();
sqlite3 *database;
int rc = sqlite3_open(dbname, &database);
char *zErrMsg = 0;
unsigned char *buffer = (unsigned char*) malloc(sizeof(char)*MAX);
ifstream file;
file.open("Sql.pdf", ios::in|ios::binary);
if ( ! file )
{
cout << "An error occurred opening the file" << endl;
}
int count = 0;
const void* fileptr = NULL;
fileptr = buffer;
while(file.good())
{
char c=file.get();
buffer[count]=c;
count++;
}
file.close();
sqlite3_stmt *stmt = NULL;
char* statement = "INSERT INTO ONE( ID, NAME, LABEL, GRP, FILE ) VALUES ( NULL, 'fedfsdfss', NULL, NULL, ?);";
rc = sqlite3_prepare_v2(database, statement, 0, &stmt, NULL);
rc = sqlite3_bind_blob(stmt, 1, fileptr, sizeof(char)*count, SQLITE_TRANSIENT);
const char* result = sqlite3_errmsg(database);
rc = sqlite3_step(stmt);
result = sqlite3_errmsg(database);
sqlite3_close(database);
free(buffer);
fileptr=NULL;
return 0;
}
EDIT: Pasted full function, the amount of characters im trying to insert is about 350K.
The result from binb_blob is always 21, error code contains nothing. buffer contains binary file data, which most probably isn't too big hence the error code. Any hints would be apprieciated.
Your code has too many errors to count.
Try something like this:
int InsertFile(const string& db_name)
{
ifstream file("Sql.pdf", ios::in | ios::binary);
if (!file) {
cerr << "An error occurred opening the file\n";
return 12345;
}
file.seekg(0, ifstream::end);
streampos size = file.tellg();
file.seekg(0);
char* buffer = new char[size];
file.read(buffer, size);
sqlite3 *db = NULL;
int rc = sqlite3_open_v2(db_name.c_str(), &db, SQLITE_OPEN_READWRITE, NULL);
if (rc != SQLITE_OK) {
cerr << "db open failed: " << sqlite3_errmsg(db) << endl;
} else {
sqlite3_stmt *stmt = NULL;
rc = sqlite3_prepare_v2(db,
"INSERT INTO ONE(ID, NAME, LABEL, GRP, FILE)"
" VALUES(NULL, 'fedfsdfss', NULL, NULL, ?)",
-1, &stmt, NULL);
if (rc != SQLITE_OK) {
cerr << "prepare failed: " << sqlite3_errmsg(db) << endl;
} else {
// SQLITE_STATIC because the statement is finalized
// before the buffer is freed:
rc = sqlite3_bind_blob(stmt, 1, buffer, size, SQLITE_STATIC);
if (rc != SQLITE_OK) {
cerr << "bind failed: " << sqlite3_errmsg(db) << endl;
} else {
rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE)
cerr << "execution failed: " << sqlite3_errmsg(db) << endl;
}
}
sqlite3_finalize(stmt);
}
sqlite3_close(db);
delete[] buffer;
}