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;
}
Related
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?
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. . .
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;
}
I want to read binary file to OpenCL Memory Object using Zero Copy method. But, when my code execute readFile, my program has stopped working.
I have read other Q&A,
segmentation fault(core dumped) in opencl
How to avoid constant memory copying in OpenCL
But, I haven't solved my problem yet.
This is my code
//OPENCL Include
#include <CL/cl.h>
typedef float2 cplx;
int readFile(char *filen, cplx* data);
int main(int argc, char* argv[])
{
char *filename = (char*)malloc(100);
sprintf(filename,"%s",argv[1]);
//OpenCL Structures
cl_device_id device;
cl_context context;
cl_command_queue commandQueue;
int err;
int filesize = 1024;
device = create_device();
context = clCreateContext(NULL, 1, &device, NULL, NULL, &err);
if(err < 0)
{
perror("Couldn't create a context");
exit(1);
}
commandQueue = clCreateCommandQueue(context, device, 0, &err);
if(err < 0)
{
perror("Couldn't create Command Queue");
exit(1);
}
cl_mem memObj_data[1] = {0};
size_t buffer_size = 1024 * sizeof(cplx);
printf("Create Buffer\n");
memObj_data[0] = clCreateBuffer(context, CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR, buffer_size, NULL, &err);
if(err != CL_SUCCESS)
{
cerr << getErrorString(err) << endl;
exit(1);
}
// cplx *data = (cplx*)malloc(sizeof(cplx)*sizeFile);
// data = (cplx*)clEnqueueMapBuffer(commandQueue, memObj_data[0], CL_TRUE, CL_MAP_WRITE, 0, buffer_size, 0, NULL, NULL, &err);
printf("Enqueue Map Buffer\n");
cplx* data = (cplx*)clEnqueueMapBuffer(commandQueue, memObj_data[0], CL_TRUE, CL_MAP_WRITE, 0, buffer_size, 0, NULL, NULL, &err);
if(err != CL_SUCCESS)
{
cerr << getErrorString(err) << endl;
exit(1);
}
int ret = readFile(filename, data);
if(ret == 1)
{
cout << "Error on Reading File" << endl;
return 1;
printf("Enequeue Unmap Memory Object\n");
err = clEnqueueUnmapMemObject(commandQueue, memObj_data[0], data, 0, NULL, NULL);
if(err != CL_SUCCESS)
{
cerr << getErrorString(err) << endl;
exit(1);
}
//Deallocate resource
clReleaseMemObject(memObj_data[0]);
clReleaseCommandQueue(commandQueue);
clReleaseContext(context);
clReleaseDevice(device);
//FREE MEMORY
delete[] filename;
return 0;
}
int readFile(char *filen, cplx* data)
{
cout << "Read File" << endl;
//Get size contains of file
// ifstream file("../testfile", ios::in | ios::binary | ios::ate);
streampos size;
char path[20];
sprintf(path,"%s",filen);
ifstream file(path, ios::in | ios::binary | ios::ate);
if(file.is_open())
{
size = file.tellg();
// *data = (cplx*)realloc(*data, sizeof(cplx)*size);
if(size)
{
// data = data;
cout << "Read CFL file Success" << endl;
}
else
{
cout << "Error Allocating Memory" << endl;
return 1;
}
cout << "Contains Size : "<< std::to_string(size) << endl;
}
else
{
cout << "Unable to open file";
return 1;
}
if(file.is_open())
{
file.seekg(0, ios::beg);
file.read((char*)data, size);
file.close();
}
// int start = 230;
// int finish = 250;
// cout << "ON Functions" << endl;
// for(int i = start; i < finish; i++)
// {
// cout << i << " "<< std::to_string((*data)[i].x) << " + " << std::to_string((*data)[i].y) << endl;
// }
// data = memblock;
// free(memblock);
return 0;
}
Then, while read binary file, my program has stopped working.
Two tables (Teachers and Students) are created while the Id in Students is referenced to the TeacherId in Teachers using FOREIGN KEY. If we use two different methods to insert the values into Students:
1. sqlite3_exec();
2. sqlite3_bind();
The return message from sqlite3_errmsg() is not the same using these two methods:
1. sqlite3_exec(): return "foreign key constraints failed";
2. sqlite3_bind(): return "SQL logic error or missing database";
The message from sqlite3_errmsg() for sqlite3_exec() is more clearer than that for sqlite3_bind();
However, sqlite3_bind() is more convenient and efficient to insert values compared to sqlite3_exec();
My question: How to get a clearer returned error message for sqlite3_bind()?
The following is the full codes:
#include <string.h>
#include <stdio.h>
#include <iostream>
#include "sqlite3.h"
using namespace std;
sqlite3* db;
int first_row;
// callback function;
int select_callback(void *p_data, int num_fields, char **p_fields, char **p_col_names)
{
int i;
int* nof_records = (int*) p_data;
(*nof_records)++;
// first_row was defined in <select_stmt> function;
// if first_row == 1, print the first row
// and then set first_row = 0 to avoid the subsequent execution for the following rows.
if (first_row == 1)
{
first_row = 0;
for (i=0; i < num_fields; i++)
{ printf("%20s", p_col_names[i]);
}
printf("\n");
for (i=0; i< num_fields*20; i++)
{ printf("=");
}
printf("\n");
}
for(i=0; i < num_fields; i++)
{ if (p_fields[i])
{ printf("%20s", p_fields[i]);
}
else
{ printf("%20s", " ");
}
}
printf("\n");
return 0;
}
// With callback function;
void select_stmt(const char* stmt)
{ char *errmsg;
int ret;
int nrecs = 0;
first_row = 1;
ret = sqlite3_exec(db, stmt, select_callback, &nrecs, &errmsg);
if(ret!=SQLITE_OK)
{ printf("Error in select statement %s [%s].\n", stmt, errmsg);
}
else
{ printf("\n %d records returned.\n", nrecs);
}
}
// Without callback function;
void sql_stmt(const char* stmt)
{ char *errmsg;
int ret;
ret = sqlite3_exec(db, stmt, 0, 0, &errmsg);
if(ret != SQLITE_OK)
{ printf("Error in statement: %s [%s].\n", stmt, errmsg);
}
}
//////////////////////////////////////// Main /////////////////////////////////
int main()
{ cout << "sqlite3_open("", &db): " << sqlite3_open("./shcool.db", &db) << endl;
if(db == 0)
{ printf("\nCould not open database.");
return 1;
}
char *errmsg;
int result;
result = sqlite3_exec ( db,
"Drop TABLE IF EXISTS Teachers", // stmt
0,
0,
&errmsg
);
if ( result != SQLITE_OK )
{ cout << "\nCould not prepare statement: Drop TABLE: " << result << endl;
cout << "errmsg: " << errmsg << endl;
return 1;
}
result = sqlite3_exec ( db,
"Drop TABLE IF EXISTS Students", // stmt
0,
0,
&errmsg
);
if ( result != SQLITE_OK )
{ cout << "\nCould not prepare statement: Drop TABLE: " << result << endl;
cout << "errmsg: " << errmsg << endl;
return 1;
}
// CREATE TABLE Teachers;
sql_stmt("CREATE TABLE Teachers(Id integer PRIMARY KEY,Name text,Age integer NOT NULL)");
//////////////////////////// insert values into Teachers; /////////////////////////////////
sqlite3_stmt *stmt;
sqlite3_prepare(db, "PRAGMA foreign_keys = ON;", -1, &stmt, 0);
if ( sqlite3_prepare
( db,
"insert into Teachers values (:Id,:Name,:Age)", // stmt
-1, // If than zero, then stmt is read up to the first nul terminator
&stmt,
0 // Pointer to unused portion of stmt
)
!= SQLITE_OK )
{ printf("\nCould not prepare statement.");
return 1;
}
int index1, index2, index3;
index1 = sqlite3_bind_parameter_index(stmt, ":Id");
index2 = sqlite3_bind_parameter_index(stmt, ":Name");
index3 = sqlite3_bind_parameter_index(stmt, ":Age");
cout << index1 << endl;
cout << index2 << endl;
cout << index3 << endl;
printf("\nThe statement has %d wildcards\n", sqlite3_bind_parameter_count(stmt));
int id[] = {1, 2, 3};
string name[] = {"Zhang", "Hou", "Liu"};
int age[] = {28, 29, 31};
for ( int i = 0; i != 3; i++ )
{ if (sqlite3_bind_int
(stmt,
index1, // Index of wildcard
id[i]
)
!= SQLITE_OK)
{ printf("\nCould not bind sqlite3_bind_int.\n");
return 1;
}
if (sqlite3_bind_text
( stmt,
index2, // Index of wildcard
name[i].c_str(),
strlen(name[i].c_str()),
SQLITE_STATIC
)
!= SQLITE_OK)
{ printf("\nCould not bind sqlite3_bind_text.\n");
return 1;
}
if (sqlite3_bind_int
( stmt,
index3, // Index of wildcard
age[i]
)
!= SQLITE_OK)
{ printf("\nCould not bind sqlite3_bind_int.\n");
return 1;
}
// execute sqlite3_step(), and check the state of the statement
if (sqlite3_step(stmt) != SQLITE_DONE)
{ printf("\nCould not step (execute) stmt.\n");
return 1;
}
// reset the statement if you want to continue the sqlite3_bind().
cout << "sqlite3_reset(stmt): " << sqlite3_reset(stmt) << endl;
}
//////////////////////////// insert values into Students; /////////////////////////////////
// CREATE TABLE Students;
sql_stmt("CREATE TABLE Students (Id integer PRIMARY KEY, TeacherId integer, FOREIGN KEY(TeacherId) REFERENCES Teachers(id) )" );
//////// Method 1: use sqlite3_exec to insert values; ////////////
sql_stmt("INSERT INTO Students Values (0, 1)" );
sql_stmt("INSERT INTO Students Values (1, 2)" );
sql_stmt("INSERT INTO Students Values (2, 9)" );
cout << "sqlite3_errmsg: " << sqlite3_errmsg(db) << endl;
//////// Method 2: use sqlite3_bind to insert values; ////////////
result = sqlite3_exec ( db,
"Drop TABLE IF EXISTS Students", // stmt
0,
0,
&errmsg
);
if ( result != SQLITE_OK )
{ cout << "\nCould not prepare statement: Drop TABLE: " << result << endl;
cout << "errmsg: " << errmsg << endl;
return 1;
}
// CREATE TABLE Students;
sql_stmt("CREATE TABLE Students (Id integer PRIMARY KEY, TeacherId integer, FOREIGN KEY(TeacherId) REFERENCES Teachers(id) )" );
if ( sqlite3_prepare
( db,
"insert into Students values ( :Id,:TeacherId )", // stmt
-1, // If than zero, then stmt is read up to the first nul terminator
&stmt,
0 // Pointer to unused portion of stmt
)
!= SQLITE_OK )
{ printf("\nCould not prepare statement.");
return 1;
}
index1 = sqlite3_bind_parameter_index(stmt, ":Id");
index2 = sqlite3_bind_parameter_index(stmt, ":TeacherId");
cout << index1 << endl;
cout << index2 << endl;
printf("\nThe statement has %d wildcards\n", sqlite3_bind_parameter_count(stmt));
int studentId[] = {0, 1, 2};
/// if the FOREIGN KEY works, the teacherId should not be 9;
int teacherId[] = {1, 2, 9};
for ( int i = 0; i != 3; i++ )
{ if (sqlite3_bind_int
(stmt,
index1, // Index of wildcard
studentId[i]
)
!= SQLITE_OK)
{ printf("\nCould not bind sqlite3_bind_int.\n");
return 1;
}
if (sqlite3_bind_int
( stmt,
index2, // Index of wildcard
teacherId[i]
)
!= SQLITE_OK)
{ printf("\nCould not bind sqlite3_bind_int.\n");
cout << "sqlite3_errmsg: " << sqlite3_errmsg(db) << endl;
return 1;
}
// execute sqlite3_step(), and check the state of the statement
// cout << "sqlite3_errmsg: " << sqlite3_errmsg(db) << endl;
if ( result = sqlite3_step(stmt) != SQLITE_DONE )
{ printf("\nCould not step (execute) stmt.\n");
cout << "sqlite3_errmsg: " << sqlite3_errmsg(db) << endl;
cout << "result: " << result << endl;
return 1;
}
cout << "result: " << result << endl;
// reset the statement if you want to continue the sqlite3_bind().
cout << "sqlite3_reset(stmt): " << sqlite3_reset(stmt) << endl;
}
printf("\n");
// Print all;
select_stmt("select * from Teachers");
select_stmt("select * from Students");
sqlite3_close(db);
return 0;
}
It's recommended to use sqlite3_prepare_v2 instead of sqlite3_prepare. Excerpt:
The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are recommended for all new programs. The two older interfaces are retained for backwards compatibility, but their use is discouraged. In the "v2" interfaces, the prepared statement that is returned (the sqlite3_stmt object) contains a copy of the original SQL text. This causes the sqlite3_step() interface to behave differently in three ways:
[Point 1 omitted]
2. When an error occurs, sqlite3_step() will return one of the detailed error codes or extended error codes. The legacy behavior was that sqlite3_step() would only return a generic SQLITE_ERROR result code and the application would have to make a second call to sqlite3_reset() in order to find the underlying cause of the problem. With the "v2" prepare interfaces, the underlying reason for the error is returned immediately.
[Point 3 omitted]