My goal is to insert a column into a SQLite Table and then return the entry so that I can get the primary key value. I have the following code that executes generic insert statements for me:
int SQLiteHelper::ExecuteWriteStatement(Platform::String^ statement)
{
char* zErrMsg;
int rc;
LPCWSTR input = statement->Data();
char sql[MAX_PATH + 1];
memset(sql, 0, sizeof(sql));
WideCharToMultiByte(CP_UTF8, 0, input, -1, sql, sizeof(sql), NULL, NULL);
const char* data = "Callback function called";
rc = sqlite3_exec(m_db, sql, WriteCallback, (void*)data, &zErrMsg);
if(rc != SQLITE_OK)
{
OutputDebugString(L"Failed to Write to database");
sqlite3_free(zErrMsg);
}
else
{
OutputDebugString(L"Succesfully wrote to database");
}
}
My callback is implemented as follows (note that it is a static private class method):
int SQLiteHelper::WriteCallback(void *NotUsed, int argc, char** argv, char** azColName)
{
////do some stuff
}
I am aware that I will probably use the void* NotUsed callback parameter to return data and I'm pretty sure it maps to the (void*)data from the sqlite3_exec() function call. The problem I have is that when I run an insert statement, the code does not reach the callback function.
If you run an insert command using sqlite3_exec shouldn't it call the callback method?
Is there a different sqlite command I should be using?
Thanks!
The sqlite3_exec callback gets called if the statement returns some data.
This can happen only for SELECT and some PRAGMA statements.
To get the rowid of the inserted record, call sqlite3_last_insert_rowid.
Related
I do not know how to implement prepared statements in my Sqlite3 code
#include <iostream>
#include <sqlite3.h>
#include <stdio.h>
static int callback (void* NotUsed, int argc, char** argv, char** azColName) {
int i;
for (i = 0; i < argc; i++) {
std::cout << ("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
std::cout << ("\n");
return 0;
}
int main (int argc, char* argv[]) {
sqlite3* db;
char* zErrMsg = 0;
int rc;
char* sql;
/* Open database */
rc = sqlite3_open ("test.db", &db);
if (rc) {
std::cerr << "Can't open database: \n" << sqlite3_errmsg (db);
return (0);
}
else {
std::cout << "Opened database successfully\n";
}
std::string newName;
std::cin >> newName;
/* Create SQL statement */
sql = "UPDATE company SET name = newName WHERE id = 1";
/* Execute SQL statement */
rc = sqlite3_exec (db, sql, callback, 0, &zErrMsg);
if (rc != SQLITE_OK) {
std::cout << "SQL error: \n" << zErrMsg;
sqlite3_free (zErrMsg);
}
else {
std::cout << "Records created successfully\n";
}
sqlite3_close (db);
return 0;
}
The user has to input newName and this variable should be used to Update a field in the Database. This way it does not work, because the Sql script is searching for a column. In the internet I found, that I had to use a prepared statement, but I do not know how to implement it.
You start with an sql statement that has placeholders for the parameters that you wish to bind later. Here, I use a single question mark for the placeholder, but there are other options described in the documentation.
std::string sql = "UPDATE company SET name = ? WHERE id = 1";
Then you construct a prepared statement (or "compile", as they say it in sqlite documentation). You'll normally use sqlite_prepare_v2 function, but there are others (for when your statement is encoded in something else than utf-8, for example).
sqlite3_stmt* stmt; // will point to prepared stamement object
sqlite3_prepare_v2(
db, // the handle to your (opened and ready) database
sql.c_str(), // the sql statement, utf-8 encoded
sql.length(), // max length of sql statement
&stmt, // this is an "out" parameter, the compiled statement goes here
nullptr); // pointer to the tail end of sql statement (when there are
// multiple statements inside the string; can be null)
Then you bind the parameter(s). There's a whole bunch of avaliable functions. Which one exactly you use depends on the type
of data that you're binding to the parameter. Here, we bind text, so we use sqlite3_bind_text:
std::string newName = /* get name from user */;
sqlite3_bind_text(
stmt, // previously compiled prepared statement object
1, // parameter index, 1-based
newName.c_str(), // the data
newName.length(), // length of data
SQLITE_STATIC); // this parameter is a little tricky - it's a pointer to the callback
// function that frees the data after the call to this function.
// It can be null if the data doesn't need to be freed, or like in this case,
// special value SQLITE_STATIC (the data is managed by the std::string
// object and will be freed automatically).
So, the prepared statement is ready to go. Now you execute it by passing it to sqlite3_step:
sqlite3_step(stmt); // you'll want to check the return value, read on...
Now, when you step through a statement that's supposed to return rows of a result table, this function will keep returning SQLITE_ROW as long as there are result rows to process, and SQLITE_DONE when there are none left. You can use sqlite3_column_* family of functions to get the single columns from a result row. I'll let you figure this out on your own.
For a simple update statements that you have, sqlite3_step will return SQLITE_DONE on the first call. More info and possible error codes are here.
When it's all done, you finish by destructing the prepared statement.
sqlite3_finalize(stmt);
I hope this should get you started.
I'm currently working on a project where I want to use SQLite to store some data. Everything is working well except when I want to insert new data into the table. When I run the application, I get segmentation fault, but I can't find the problem.
void sqlite(char *id, char *sensorname, char *sensorvalue){
sqlite3 *db;
char *zErrMsg = 0;
int rc;
char *sql;
const char* data = "Callback function called";
/* Open database */
rc = sqlite3_open("/home/macho/Documents/sensor_database.db", &db);
if( rc ){
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
exit(0);
}else{
fprintf(stderr, "Opened database successfully\n");
}
sql = "INSERT INTO sensors (id,sensorname,sensorvalue) VALUES(";
char* split = ",";
strcat(sql, id);
strcat(sql, ",");
strcat(sql, sensorname);
strcat(sql, ",");
strcat(sql, sensorvalue);
strcat(sql, ");");
rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}else{
fprintf(stdout, "Operation done successfully\n");
}
sqlite3_close(db);
}
And in the main, I'm calling the sqlite() function:
sqlite("1","sensor","sensor1");
Any idea what the problem can be?
Thanks!
You assign sql a static (read-only) string and then attempt to append to it. Instead, create a large writeable array either on the stack or use malloc and then assemble your query in that. So
char sql[4096];
strcpy(sql, "INSERT INTO sensors ...
...
Note that you should check for overflow of the buffer based on the lengths of the values.
BTW, the code as written is just asking for an SQL injection attack if accessible to users. Look up Bobby Tables.
I heard of using sqlite3_prepare_v2 instead of sqlite_exec to get integers from database, but I failed to find any examples. This page wasn't helpful also. Now I am getting strings from database, so I need to parse them with atoi and this seems to be slow and ineffective.
There a lot of similar questions on SO, but they are about obj-c and iOS SDK. I need C/C++ hint or example.
Thanks in advance.
After sqlite3_prepare has succeeded, you must not forget to clean up the statement with sqlite3_finalize.
To get the result records, call sqlite3_step until it does not return SQLITE_ROW.
To get the values of the current result record, call the sqlite3_column_* functions:
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db, "SELECT 42", -1, &stmt, NULL) != SQLITE_OK)
...error...
else {
for (;;) {
int rc = sqlite3_step(stmt);
if (rc == SQLITE_DONE)
break;
if (rc != SQLITE_ROW) {
...error...
break;
}
printf("value: %d\n", sqlite3_column_int(stmt, 0));
}
sqlite3_finalize(stmt);
}
sqlite3_column_int(result, columnNum); will return one column from the current row of your result as an int.
Your prepare function is to prepare your query, it has nothing to do with how the results are interpreted. All data in sqlite3 is stored textually, you use the appropriate function to retrieve a value in the type you believe it should be.
I'm trying to learn c++, so apologies if this is a silly question. I am trying to replicate what I can do in C# when accessing field names of a database query
so
myRow["field"]
would return the value of the field in the current row
Now here is the code I have to create a std:map which models the table and Rows.
void DATAENGINE_API DataEngine::ExecuteQuery(char * sqlStatement)
{
SQLRETURN retCode;
SQLHANDLE hEnv;
SQLHANDLE hConn;
SQLHANDLE hStmt;
SQLCHAR* dsnName;
SQLCHAR* uid;
SQLCHAR* pwd;
SQLCHAR* query;
SQLLEN numRows;
SQLSMALLINT numCols;
retCode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv);
CHECK(retCode, "allocate environment handle");
retCode = SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
CHECK(retCode, "setting the environment attribute setting to ODBC version 3");
CHECK(SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hConn), "allocate handle");
dsnName = (SQLCHAR*)dsn;
uid = (SQLCHAR*)userId;
pwd = (SQLCHAR*)password;
retCode = SQLConnectA(hConn, dsnName, SQL_NTS, uid, SQL_NTS, pwd, SQL_NTS);
if (!CHECK(retCode, "SqlConnectA", false)) {
Status(SQL_HANDLE_DBC, hConn, __LINE__);
}
CHECK(SQLAllocHandle(SQL_HANDLE_STMT, hConn, &hStmt), "allocate handle for statement");
query = (SQLCHAR*)sqlStatement;
CHECK(SQLExecDirectA(hStmt, query, SQL_NTS), "execute query");
retCode = SQLFetch(hStmt);
CHECK(retCode, "first sqlFetch");
retCode = SQLRowCount(hStmt, &numRows);
retCode = SQLNumResultCols(hStmt, &numCols);
// traverse the results to create a table view.
std::map<int, Row> t;
for (int i = 1; i <= numRows; i++) {
std::map<std::string, std::string> r;
for (int j = 1; j <= numCols; j++) {
SQLCHAR colName[256];
char buf[256];
SQLSMALLINT colNameLen, dataType, numDecimalDigits, allowsNullValues;
SQLUINTEGER columnSize;
SQLINTEGER numBytes;
std::string fieldName;
retCode = SQLDescribeColA(hStmt, j, colName, 255, &colNameLen, &dataType, &columnSize, &numDecimalDigits, &allowsNullValues);
fieldName = (char*)colName;
retCode = SQLGetData(
hStmt,
j, // COLUMN NUMBER of the data to get
SQL_C_CHAR, // the data type that you expect to receive
buf, // the place to put the data that you expect to receive
255, // the size in bytes of buf (-1 for null terminator)
&numBytes // size in bytes of data returned
);
// r.insert(std::make_pair(fieldName, buf))
r.insert(std::make_pair(fieldName, buf));
}
t[i] = r;
}
}
However when I try and use the following code
r["myfield"]
VS is throwing 'no operator "[]" matches these operands' error.
Looking at this link std::map access operator deprecated? no operator [] matches these operands
I have even tried
r.insert(std::make_pair(fieldName, buf));
based on a suggestion here; How to create a std::map of constant values which is still accessible by the [] operator?
and I still get the same error.
I would expect this to work - so what am I doing wrong?
Thanks in advance.
Regarding your problem description, which as I’m writing this says that
” when I try and use the following code
r["myfield"]
VS is throwing 'no operator "[]" matches these operands' error.
Well the following works:
#include <map>
#include <string>
auto main() -> int
{
std::map< std::string, std::string > r;
r["blah"] = "foo";
}
So there your interpretation of things is incorrect. Most likely the code you have presented is not the real code. I would surmise that you are correctly quoting the error message.
The operator[] takes the same type as the key. Your key is a string, but you are passing a constant character pointer.
This is similar to 01d55's answer about your incorrect pair types. Using his suggestion of creating string using the character pointer should fix both problems.
Your use of std::make_pair is the problem. You need to create an std::pair<std::string, std::string> explicitly. The std::make_pair function template creates a pair based on the types of its inputs.
char buf[256];
// [...]
r.insert(std::make_pair(fieldName, buf));
// std::make_pair returns std::pair<std::string, char*>
Normally, in C++, a char* will implicitly convert to std::string. It looks like your compiler or your standard library is not picking up the conversion between the pair containing the type.
Try this instead:
r.insert(std::pair<std::string, std::string>(fieldName, buf));
If you prefer, you can shorten this with a typedef:
typedef std::pair<std::string, std::string> string_pair;
r.insert(string_pair(fieldName, buf));
I heard of using sqlite3_prepare_v2 instead of sqlite_exec to get integers from database, but I failed to find any examples. This page wasn't helpful also. Now I am getting strings from database, so I need to parse them with atoi and this seems to be slow and ineffective.
There a lot of similar questions on SO, but they are about obj-c and iOS SDK. I need C/C++ hint or example.
Thanks in advance.
After sqlite3_prepare has succeeded, you must not forget to clean up the statement with sqlite3_finalize.
To get the result records, call sqlite3_step until it does not return SQLITE_ROW.
To get the values of the current result record, call the sqlite3_column_* functions:
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(db, "SELECT 42", -1, &stmt, NULL) != SQLITE_OK)
...error...
else {
for (;;) {
int rc = sqlite3_step(stmt);
if (rc == SQLITE_DONE)
break;
if (rc != SQLITE_ROW) {
...error...
break;
}
printf("value: %d\n", sqlite3_column_int(stmt, 0));
}
sqlite3_finalize(stmt);
}
sqlite3_column_int(result, columnNum); will return one column from the current row of your result as an int.
Your prepare function is to prepare your query, it has nothing to do with how the results are interpreted. All data in sqlite3 is stored textually, you use the appropriate function to retrieve a value in the type you believe it should be.