I got this code snippet to copy a file database to a memory database. it works but it destroys the original file database. (By destroys I mean sets the file size to zero)
/**
* Exec an sql statement in values[0] against
* the database in pData.
*/
int process_ddl_row(void * pData, int nColumns, char **values, char **columns)
{
if (nColumns != 1) {
return 1; // Error
}
sqlite3 * db = (sqlite3*)pData;
if( SQLITE_OK != sqlite3_exec(db, values[0], NULL, NULL, NULL) ) {
return 1;
}
return 0;
}
/**
* Insert from a table named by backup.{values[0]}
* into main.{values[0]} in database pData.
*/
int process_dml_row(void *pData, int nColumns, char **values, char **columns)
{
if (nColumns != 1) {
return 1; // Error
}
sqlite3* db = (sqlite3*)pData;
char *stmt = sqlite3_mprintf("insert into main.%q " "select * from backup.%q", values[0], values[0]);
if( SQLITE_OK != sqlite3_exec(db, stmt, NULL, NULL, NULL) ) {
return 1;
}
sqlite3_free(stmt);
return 0;
}
bool CDatabase::LoadFromFile( const char * databaseFile )
{
if( databaseFile == NULL || this->m_db == NULL ) {
return false;
}
sqlite3 * memorydb = this->m_db->GetDb() ; // Gets the open memory database.
sqlite3 * backupdb = NULL ;
if( SQLITE_OK != sqlite3_open_v2(databaseFile, &backupdb, SQLITE_OPEN_READONLY, NETBURNER_VFS_NAME ) ) {
return false;
}
// Schema
// ---------------------------------------------------------------------------
// Create the in-memory schema from the backup
if( SQLITE_OK != sqlite3_exec(backupdb, "BEGIN", NULL, NULL, NULL) ) {
return false;
}
if( SQLITE_OK != sqlite3_exec(backupdb, "SELECT sql FROM sqlite_master WHERE sql NOT NULL", &process_ddl_row, memorydb, NULL) ) {
return false;
}
if( SQLITE_OK != sqlite3_exec(backupdb, "COMMIT", NULL, NULL, NULL) ) {
return false;
}
sqlite3_close(backupdb);
// DATA
// ---------------------------------------------------------------------------
// Attach the backup to the in memory
char sql[255];
sprintf( sql, "ATTACH DATABASE '%s' as backup", databaseFile );
// This after this line the file database is set to zero bytes.
if( SQLITE_OK != sqlite3_exec(memorydb, sql, NULL, NULL, NULL) ) {
return false;
}
// Copy the data from the backup to the in memory
if( SQLITE_OK != sqlite3_exec(memorydb, "BEGIN", NULL, NULL, NULL) ) {
return false;
}
if( SQLITE_OK != sqlite3_exec(memorydb, "SELECT name FROM backup.sqlite_master WHERE type='table'", &process_dml_row, memorydb, NULL) ) {
return false;
}
if( SQLITE_OK != sqlite3_exec(memorydb, "COMMIT", NULL, NULL, NULL) ) {
return false;
}
if( SQLITE_OK != sqlite3_exec(memorydb, "DETACH DATABASE backup", NULL, NULL, NULL) ) {
return false;
}
return true;
}
I have been looking at it for awhile now and I can seem to figure out why this is happening. Suggestions?
Your code worked fine for me (checked on WinXP).
I think you should try running it without specifying VFS object (if possible) - just replace NETBURNER_VFS_NAME with 0 in sqlite3_open_v2 call.
This will show whether the problem is in VFS customization or not.
Related
I have this function which if you connect to a system with ssh, you can call it to execute your given command on that system.
std::string sshconnection::exec_ssh_command(ssh_session session, char *command) {
string receive = "";
int rc, nbytes;
char buffer[256];
ssh_channel channel = ssh_channel_new(session);
if( channel == NULL )
return NULL;
rc = ssh_channel_open_session(channel);
if( rc != SSH_OK ) {
ssh_channel_free(channel);
return NULL;
}
rc = ssh_channel_request_exec(channel, command);
if( rc != SSH_OK ) {
ssh_channel_close(channel);
ssh_channel_free(channel);
cout << "Error";
return NULL;
}
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
while (nbytes > 0)
{
if (write(1, buffer, nbytes) != (unsigned int) nbytes)
{
ssh_channel_close(channel);
ssh_channel_free(channel);
return NULL;
}
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
}
if( nbytes < 0 )
return NULL;
ssh_channel_send_eof(channel);
ssh_channel_close(channel);
ssh_channel_free(channel);
return receive;
}
this function works great. I just don't understand that part which is about to write from buffer into a file descriptor=1 . we haven't filled receive anywhere but it is the return value. if we call this function like below:
s = exec_ssh_command(my_ssh_session, "cat /proc/stat" );
the s won't have any value, but if we do this:
std::cout<<s;
this will print s value. and of course we can't save s in a file. can someone explain to me how is this happening?
EDIT:function to connect to ssh:
int sshconnection::sshConnection()
{
if( my_ssh_session == NULL ) {
cout << "Error creating ssh session" << endl;
return 1;
}
ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "yourip");
ssh_options_set(my_ssh_session, SSH_OPTIONS_USER, "username");
int rc = ssh_connect(my_ssh_session);
if( rc != SSH_OK ) {
cout << "Error with connecting" << endl;
ssh_free(my_ssh_session);
return -1;
}
rc = ssh_userauth_password(my_ssh_session, NULL, "yourpassword");
if( rc != SSH_AUTH_SUCCESS) {
cout << "Error with authorization " << ssh_get_error(my_ssh_session) << endl;
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
return -1;
}
// ssh_disconnect(my_ssh_session);
// ssh_free(my_ssh_session);
}
I know this is old, but I had the same issue. I came up with the following solution.
Use std::string::append like so receive.append(buffer, nbytes).
std::string sshconnection::exec_ssh_command(ssh_session session, char *command) {
string receive = "";
int rc, nbytes;
char buffer[256];
ssh_channel channel = ssh_channel_new(session);
if( channel == NULL )
return NULL;
rc = ssh_channel_open_session(channel);
if( rc != SSH_OK ) {
ssh_channel_free(channel);
return NULL;
}
rc = ssh_channel_request_exec(channel, command);
if( rc != SSH_OK ) {
ssh_channel_close(channel);
ssh_channel_free(channel);
cout << "Error";
return NULL;
}
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
while (nbytes > 0)
{
receive.append(buffer, nbytes);
nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
}
if( nbytes < 0 )
return NULL;
ssh_channel_send_eof(channel);
ssh_channel_close(channel);
ssh_channel_free(channel);
return receive;
}
Considering:
int user_id = 0x01; //dummy
int size_id = 0x01; //dummy
sqlite3_stmt *stmt;
sqlite3 *db;
int rc = sqlite3_open("path_to_database.db", &db);
if( rc != SQLITE_OK )
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
return -1;
}
rc = sqlite3_prepare_v2(db, "SELECT id, type, time_registered"
" from myTestTable"
" where user = ? and size = ?", -1, &stmt, NULL);
if (rc != SQLITE_OK)
{
throw std::string(sqlite3_errmsg(db));
sqlite3_finalize(stmt);
return -1;
}
rc = sqlite3_bind_int(stmt, 1, user_id);
if (rc != SQLITE_OK)
{
std::string errmsg(sqlite3_errmsg(db));
sqlite3_finalize(stmt);
throw errmsg;
return -1;
}
rc = sqlite3_bind_int(stmt, 2, size_id);
if (rc != SQLITE_OK)
{
std::string errmsg(sqlite3_errmsg(db));
sqlite3_finalize(stmt);
throw errmsg;
return -1;
}
[...]
This does work, but it seems not user friendly. I could use snprintf to prepare the statement instead of bind, but I'ld loose safety (even if I shouldn't be facing injection attacks on my local db).
Is there a better way to use sqlite3_bind_TYPES to bind more than one value in statement, with same types (or not if possible) ?
You could use a c++ wrapper like SQLiteCpp. If you don't like that one, there's a list at the bottom of the github page.
If you prefer to use the c interface you could invert the logic of the bind statements. This would at least unclutter the code a bit.
int rc = sqlite3_open("path_to_database.db", &db);
if( rc != SQLITE_OK )
{
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
return -1;
}
rc = sqlite3_prepare_v2(db, "SELECT id, type, time_registered"
" from myTestTable"
" where user = ? and size = ?", -1, &stmt, NULL);
if (rc == SQLITE_OK)
rc = sqlite3_bind_int(stmt, 1, user_id);
if (rc == SQLITE_OK)
rc = sqlite3_bind_int(stmt, 2, size_id);
if (rc != SQLITE_OK)
{
throw std::string(sqlite3_errmsg(db));
sqlite3_finalize(stmt);
return -1;
}
[...]
Mike
There is a database named "rfidacs" and there is a table in that database named "Alarm". Now I want to copy all the records of Alarm table to a table of same name "Alarm" of another database named DbDemo. I have written this code. Kindly correct it .I am programming on eclipse IDE on linux.
int DBDEMO :: demoTest()
{
MYSQL_ROW row;
MYSQL *conn, *conn1;
conn = mysql_init(NULL);
conn1 = mysql_init(NULL);
if(conn == NULL)
{
fprintf(stderr,"mysql_init() failed");
exit(1);
}
if(conn1 == NULL)
{
fprintf(stderr,"mysql_init() failed");
exit(1);
}
if( mysql_real_connect(conn1, "localhost", "root", "rgb123", "DbDemo", 0, NULL, 0)==NULL)
{
finish_with_error(conn1);
}
if( mysql_real_connect(conn, "localhost", "root", "rgb123", "rfidacs", 0, NULL, 0)==NULL)
{
finish_with_error(conn);
}
if(mysql_query(conn,"select * from Alarm"))
{
finish_with_error(conn);
}
MYSQL_RES *result = mysql_store_result(conn);
if(result == NULL)
{
finish_with_error(conn);
}
int num_fields = mysql_num_fields(result);
while((row=mysql_fetch_row(result)))
{
char *temp;
for(int i=0;i<num_fields;i++)
{
temp="Insert into Alarm values (row[i])";
mysql_query(conn1, temp);
if(mysql_query(conn1, "Insert into Alarm values row"))
{
finish_with_error(conn1);
}
}
}
mysql_free_result(result);
mysql_close(conn);
mysql_close(conn1);
}
return SUCCESS;
}
Thanks in advance
I think prepared statement is what you are looking for.
You create the "prepared statement" template and pass the row entry as value in each iteration.
where is the problem with the following code? It's can not DROP my table. When I make this drop from sql browser (on the same databade) - all works fine.
int rcc = sqlite3_open_v2(str_sessions_file.c_str(), &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL );
if ( SQLITE_OK != rcc)
{
fprintf (stderr, "Can't open database: %s\n", sqlite3_errmsg (db));
sqlite3_close (db);
return;
}
// Drop
std::string sql_dropatable = "DROP TABLE IF EXISTS sessions";
if( sqlite3_exec(db, sql_dropatable.c_str(), 0, 0, 0) != SQLITE_OK ) { // or == -- same effect
std::cout << "SQLite can't drop sessions table" << std::endl;
sqlite3_close (db);
//exit (1);
return;
}
I have created a MySQL table where one of the columns stores a BLOB type. (The Internet told me BLOB is the correct data type for images.)
I am pretty much a beginner with both C++ and MySQL. What I would like to do is to write a small program with a main() that puts a jpeg into that table. For the sake of this exercise, I do not want to store a reference to a directory that contains an image.
Am I wrong to think that it is as simple as filling out the part in BLOCK 2 below?
#include <iostream>
#include <string>
#include <mysql.h>
using namespace std;
int main(int argc, char **argv)
{
//BLOCK 1: INIT
MYSQL *connection, mysql;
MYSQL_RES *result;
MYSQL_ROW row;
int query_state;
mysql_init(&mysql);
connection = mysql_real_connect(&mysql, "localhost", "root", "secret", "beginner_db",0,0,0);
//BLOCK 2: SEND QUERY
/* do something to insert image to table */
//BLOCK 3: DISPLAY QUERY RESULTS
result = mysql_store_result(connection);
/* do something with result */
//BLOCK 4: FREE
mysql_free_result(result);
mysql_close(connection);
return 0;
}
For this scenario, a good solution would be to use the mysql_stmt_send_long_data() function.
There is an example on the MySQL Manual page that I linked to, but here is a more relevant example of sending file contents:
#ifdef _WIN32
#include <windows.h>
#endif
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <boost/scope_exit.hpp>
#include <mysql.h>
#define ARR_LEN(arr_id) ((sizeof (arr_id))/(sizeof (arr_id)[0]))
int main()
{
using namespace std;
MYSQL *pconn = mysql_init(NULL);
BOOST_SCOPE_EXIT( (pconn) ) {
mysql_close(pconn);
} BOOST_SCOPE_EXIT_END
const char *db_name = "test";
if (!mysql_real_connect(pconn, "localhost", "test", "********", db_name, 0, NULL, CLIENT_COMPRESS)) {
cerr << "Error: mysql_real_connect() failed to connect to `" << db_name << "`." << endl;
return EXIT_FAILURE;
}
MYSQL_STMT *pinsert_into_images_stmt = mysql_stmt_init(pconn);
BOOST_SCOPE_EXIT( (pinsert_into_images_stmt) ) {
mysql_stmt_close(pinsert_into_images_stmt);
} BOOST_SCOPE_EXIT_END
const char sql1[] = "INSERT INTO images(data) VALUES (?)";
if (mysql_stmt_prepare(pinsert_into_images_stmt, sql1, strlen(sql1)) != 0) {
cerr << "Error: mysql_stmt_prepare() failed to prepare `" << sql1 << "`." << endl;
return EXIT_FAILURE;
}
MYSQL_BIND bind_structs[] = {
{ 0 } // One for each ?-placeholder
};
unsigned long length0;
bind_structs[0].length = &length0;
bind_structs[0].buffer_type = MYSQL_TYPE_BLOB;
bind_structs[0].is_null_value = 0;
if (mysql_stmt_bind_param(pinsert_into_images_stmt, bind_structs) != 0) {
cerr << "Error: mysql_stmt_bind_param() failed." << endl;
return EXIT_FAILURE;
}
const char *file_name = "image.jpg";
FILE *fp = fopen(file_name, "rb");
BOOST_SCOPE_EXIT( (fp) ) {
fclose(fp);
} BOOST_SCOPE_EXIT_END
// Use mysql_stmt_send_long_data() to send the file data in chunks.
char buf[10*1024];
while (!ferror(fp) && !feof(fp)) {
size_t res = fread(buf, 1, ARR_LEN(buf), fp);
if (mysql_stmt_send_long_data(pinsert_into_images_stmt, 0, buf, res) != 0) {
cerr << "Error: mysql_stmt_send_long_data() failed." << endl;
return EXIT_FAILURE;
}
}
if (!feof(fp)) {
cerr << "Error: Failed to read `" << file_name << "` in its entirety." << endl;
return EXIT_FAILURE;
}
if (mysql_stmt_execute(pinsert_into_images_stmt) != 0) {
cerr << "Error: mysql_stmt_execute() failed." << endl;
return EXIT_FAILURE;
}
cout << "Inserted record #" << mysql_insert_id(pconn) << endl;
return EXIT_SUCCESS;
}
I am using the following definition of table `images`:
CREATE TABLE images (
id INT UNSIGNED NOT NULL AUTO_INCREMENT,
data MEDIUMBLOB NOT NULL,
PRIMARY KEY (id)
);
Upon running this program, it successfully sent the 38,339-byte JPEG image.jpg to the server and outputted "Inserted record #1".
You can verify that the correct number of bytes were sent:
mysql> SELECT octet_length(data) FROM images WHERE id=1;
+--------------------+
| octet_length(data) |
+--------------------+
| 38339 |
+--------------------+
1 row in set (0.00 sec)
I found this solution that worked... for images under 10kb.
//http://zetcode.com/tutorials/mysqlcapitutorial/
//g++ -o output source.cpp $(mysql_config --cflags) $(mysql_config --libs)
#include <stdio.h>
#include <iostream>
#include <mysql.h>
int main(int argc, char **argv)
{
MYSQL *conn;
int len, size;
char data[1000*1024];
char chunk[2*1000*1024+1];
char query[1024*5000];
FILE *fp;
conn = mysql_init(NULL);
mysql_real_connect(conn, "localhost", "root", "secret", "beginner_db", 0, NULL, 0);
fp = fopen("filename.png", "rb");
size = fread(data, 1, 1024*1000, fp);
mysql_real_escape_string(conn, chunk, data, size);
char *stat = "INSERT INTO pic_tbl(name, pic) VALUES('cexample', '%s')";
len = snprintf(query, sizeof(stat)+sizeof(chunk) , stat, chunk);
mysql_real_query(conn, query, len);
fclose(fp);
mysql_close(conn);
}
Something like this:
CString SaveFile( CMemoryFile& File )
{
*pFileKey = -1;
SQLRETURN retcode;
SQLHSTMT hstmt;
CLoggEntryList LoggEntryList( this ); // logg entries cannot be made while busy inside the hstmt, use this class to add them later
SQLINTEGER cbDocumentBlock; // For binding the main image
long lDocumentBufferSize = 0;
unsigned char* pDocumentBuffer; // Will be set to point to the buffer that should be written into the document blob field
unsigned char pDummyChar[] = {'0'}; // Dummy buffer to write in the image/thumbnail blob fields when using external storage
lDocumentBufferSize = File.m_lBufferSize;
pDocumentBuffer = File.m_pFileBuffer;
// Allocate statement handle
retcode = SQLAllocHandle(SQL_HANDLE_STMT, m_Database.m_hdbc, &hstmt);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{ // Create a result set
CString szSQL;
szSQL = ( "INSERT INTO ObjectTable (ObjectData) VALUES ( ? )");
retcode = SQLPrepare(hstmt, (SQLCHAR*)szSQL.GetBuffer(), SQL_NTS);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{
// Bind the parameters. For parameter 1, pass the parameter number in ParameterValuePtr instead of a buffer address.
SQLINTEGER cbNULL = 0;
SQLINTEGER cbTEXT = SQL_NTS;
int nColumn = 1;
// Bind ObjectData
cbDocumentBlock = SQL_LEN_DATA_AT_EXEC(0); //SQL_LEN_DATA_AT_EXEC(lImageBufferSize);
retcode = SQLBindParameter(hstmt, nColumn++, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY,
0, 0, (SQLPOINTER) DOCUMENT, 0, &cbDocumentBlock);
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{
// Set values so data for parameter 1 will be passed at execution. Note that the length parameter in
// the macro SQL_LEN_DATA_AT_EXEC is 0. This assumes that the driver returns "N" for the
// SQL_NEED_LONG_DATA_LEN information type in SQLGetInfo.
retcode = SQLExecute(hstmt);
const long nMaxChunkSize = 400000;
// For data-at-execution parameters, call SQLParamData to get the parameter number set by SQLBindParameter.
// Call InitUserData. Call GetUserData and SQLPutData repeatedly to get and put all data for the parameter.
// Call SQLParamData to finish processing this parameter.
while (retcode == SQL_NEED_DATA)
{
SQLPOINTER pToken;
retcode = SQLParamData(hstmt, &pToken);
switch( (int)pToken )
{
case DOCUMENT:
{
if (retcode == SQL_NEED_DATA)
{
for( int nPos = 0; nPos < lDocumentBufferSize; nPos += nMaxChunkSize )
{
int nBufferSize = min( lDocumentBufferSize - nPos, nMaxChunkSize );
SQLRETURN retcode2 = SQLPutData(hstmt, pDocumentBuffer+nPos, nBufferSize );
if (retcode2 != SQL_SUCCESS && retcode2 != SQL_SUCCESS_WITH_INFO)
{
SQLCHAR Sqlstate[6];
SQLINTEGER NativeError;
SQLCHAR MessageText[201];
SQLSMALLINT TextLengthPtr;
retcode2 = SQLGetDiagRec( SQL_HANDLE_STMT, hstmt, 1, Sqlstate, &NativeError, MessageText, 200, &TextLengthPtr );
if (retcode2 == SQL_SUCCESS || retcode2 == SQL_SUCCESS_WITH_INFO)
{
MessageText[TextLengthPtr] = 0;
Sqlstate[5] = 0;
CString szSQLState( Sqlstate );
CString szMessageText( MessageText );
CString szMessage;
szMessage.Format("Error in SaveFile(). SQL State %s. Native %ld. Source: %s", szSQLState, NativeError, szMessageText );
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
return szMessage;
}
}
}
}
break;
}
default:
{
CString szMessage;
szMessage.Format("Error in SaveBuffer(). Unknown parameter buffer.");
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
return szMessage;
}
break;
}
}
}
SQLRETURN retcode3;
retcode3 = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
ASSERT(retcode3 == SQL_SUCCESS);
}
}
}
This code is not tested or even compiled, but it should point you in the right direction.