C++ sql pass integer to sql string - c++

I have built a database in MS Access.
There I have a table called Customers which also has a cell called Employee type: integer.
I also built a program in C++ which controls all data.
Let's say I have a string like this:
string sqlString = "SELECT * FROM Customers Where Customers.Employee = '" + id + "' ";
Id passes through my function correctly and is an integer, so I get an error in compilation saying: "Invalid pointer addition".
If I declare id as a string of course there's no error but there are no results in my form also. If I declare in database cell Employee as text and build my query like this:
string sqlString = "SELECT * FROM Customers WHERE Customers.Employee = 128";
I get results, but I need that Employee as an integer cause its a foreign key from another table.
So, what should I do with my query to have results passing integer as parameter through variable id, to be ok with the cell Employee from database which is also integer?
Any ideas? I would really appreciate some help here.
As I said, if I convert id to string, there are no results in my form since Employee in database is an integer. So this:
std::ostringstream buf;
buf << "SELECT * FROM Customers Where Customers.Employee = '" << id << "' ";
string str = buf.str();
won't do the job or any other conversion.
How can I pass id as an integer in my query?

You could use sprintf, but in C++ you can do:
std::ostringstream buf;
buf << "SELECT * FROM Customers Where Customers.Employee = '" << id << "' ";
string str = buf.str();
(untested)

You need to convert id to a string, then your first approach should work.
See this question for how to do the conversion:
Alternative to itoa() for converting integer to string C++?

use
std::ostringstream buf; buf << "SELECT * FROM Customers Where Customers.Employee = " << id ; string str = buf.str();
This should work please try '12' --- quote should not be placed before and after 12

you can use boost::format with boost::str
string = boost::str(boost::format("This is a string with some %s and %d numbers") %"strings" %42);
this should be better approach since you will have all the replacement variable in one place at the end.

Related

How to efficiently create const c string from string literal and appended int or long value

In c++ how can I efficiently create a c string based on a literal and appended long/int value? I logically want to do something like this:
const char *sql = "select * from MyTable where ID = " + longId;
Where longId is an int/long parameter.
This compiles an answer from user4581301 comment and I offer to delete if user4581301 makes their own answer and asks me to.
As suggested by user4581301, you can do:
std::string s = "select * from MyTable where ID = " + std::to_string(longId);
You can get a C string equivalent using s.c_str(), e.g.:
std::cout << s.c_str() << std::endl;
I think the answer from H.S. is perfect, given the question asked. Just a quick FYI, since I'm using Qt (which I didn't mention in the OP), I ended up using this code:
QString sql = QStringLiteral("SELECT v.drive_path_if_builtin, "
"m.full_filepath "
"FROM media_table m "
"INNER JOIN volume_table v "
"ON (v.id = m.volume_id) "
"WHERE m.id = %1;").arg(id);
... and then in the appropriate place, where I need a c-string, I used qPrintable(sql).

Creating a char* of specific format with specific values

I am attempting to create a char* type in a specific format, using values given by the other areas of the program, the values within the VALUES() brackets are the values that are given by the program.
The format should look like so:
char* sql = "INSERT INTO RecurringEvents (title,description,duration,recurtype,startfrom,endingtype,dateend,occurences,venueid) " \
"VALUES ('title','description','duration','recurtype','startfrom','endingtype','dateend',occurences,venueid); "
As you can see, text values must be within ' ' punctuation, while int values are left alone, so a usual command may be like so:
"INSERT INTO RecurringEvents (title,description,duration,recurtype,startfrom,endingtype,dateend,occurences,venueid) " \
"VALUES ('thetitle','thedesc','theduration','recurtype','startfrom','enddddtype','dateend',2,4); ";
The function in which this is required is below,not that it all matters, but to explain, it converts the event's(class) data all into string/int values, so they can be used to form an INSERT command(this is the proble), and then executed on a database, once this is done (and the record is verified for plausability) its added to the vector and the database is closed.
void addRecEvent(newRecurringEvent event, vector <newRecurringEvent> &events){
sqlite3 *db;
int rc;
char *sql;
int tableCheck;
char *zErrMsg = 0;
rc = sqlite3_open("data.sqlite", &db);
string title = event.getTitle();
string description = event.getDescription();
string duration = to_string(event.getDuration());
string recurType = recToString(event.getRecurType());
string startfrom = to_string( event.getStartFrom());
string endingtype = etypeToStr(event.getEndingType());
string dateend = to_string(event.getDateEnd());
int occurences = event.getOccurences();
int venueid = event.getVenuid();
/*CREATE INSERT COMMAND USING char*sql IN FORMAT REQUIRED*/
rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg); //execute the command
if (rc != SQLITE_OK){
cout << stderr << "SQL error: %s \n", zErrMsg;
}
else{
cout << stdout << "Records created succesfully";
events.push_back(event);
}
sqlite3_close(db);
}
I once attempted to create the format all in string within another function (by passing the values to it), and then returning it as a char*, but came accross the problem of the single quotation marks used on the text fields (like title,description etc).
Sorry if any of this is confusing, but to make it short, I just want to form a character sequence in the format in the first snippet of code, that uses given values to form its sequence.Any help is appreciated, as I am new to c++.
The comment left by whozcraig solved my question, I must use a prepared statement to feed my values to the statement

C++ user input to sqlite3

I have a class assignment that asks us to write a C++ program that tracks spending, allows modification of the records, and returns "satisfaction" numbers about individual expenses (i.e. how good the user felt about spending that money). Our instructor has indicated that he'd like us to use sqlite3 in this program. He's given us a sample program that builds a table in sqlite3 and inputs predetermined values for the columns. This program runs just fine without issue.
What I am trying to do is modify the program to accept user inputs and store them in the sqlite3 database. This is the code I have thus far:
int main()
{
string salesDesc;
int price;
int satisf;
sqlite3 *db;
char *szErrMsg = 0;
cout << "Description of Expense: ";
cin >> saleDesc;
cout << endl;
cout << "Price: ";
cin >> price;
cout << endl;
cout << "Your Satisfaction: ";
cin >> satisf;
cout << endl;
// open database
int rc = sqlite3_open("spending_track.sqlite", &db);
if (rc)
{
cout << "Cannot open database\n";
}
else
{
cout << "Database opened successfully\n";
}
const char *pSQL[6];
pSQL[0] = "CREATE TABLE IF NOT EXISTS expenses(id INTEGER PRIMARY KEY "
"AUTOINCREMENT NOT NULL, logged TIMESTAMP DEFAULT "
"CURRENT_TIMESTAMP NOT NULL, desc VARCHAR(40), price INT,"
"satisfaction INT)";
pSQL[1] = "INSERT INTO expenses('" + string(saleDesc) + "'," price "," satisf ")";
pSQL[2] = "SELECT * FROM expenses";
pSQL[3] = "SELECT sum(satisf) FROM expenses";
// blablabla the rest of the program
When I try to compile this, I receive the following error:
error: cannot convert 'std::_cxx11::basic_string' to 'const char*' in assignment
pSQL[1] = "INSERT INTO expenses('" + string(saleDesc) + "'," price "," satisf ")";
If I change string(saleDesc) to saleDesc, I get the same error.
If I change string saleDesc; to char* saleDesc;, I receive the following error:
error: invalid operands of types 'const char[23]' and 'char*' to binary 'operator+'
pSQL[1] = "INSERT INTO expenses('" + string(saleDesc) + "'," price "," satisf ")";
I'm not sure what else to try to get this to work. I have also heard that it's a bad idea to allow users to directly input to sqlite3 tables. What would be a more "proper" way to do this?
Since this is just a class assignment, I doubt that you are going to have to worry about SQL injection attacks, so I wouldn't bother trying to sanitize your input.
Your other issue is you are confusing char*s and std::strings. The sqlite API requires you to pass it char*s so it can be used from C code, however that doesn't mean you need to use them. std::string is a wrapper for the char array, which you can get with the c_str() method. I don't think you really need to put the SQL statements in an array at the end. How about something like this:
std::string addTable = "CREATE TABLE IF NOT EXISTS expenses(id INTEGER PRIMARY KEY "
"AUTOINCREMENT NOT NULL, logged TIMESTAMP DEFAULT "
"CURRENT_TIMESTAMP NOT NULL, desc VARCHAR(40), price INT,"
"satisfaction INT)";
std::string insertExpense = "INSERT INTO expenses('" + saleDesc + "'," + std::to_string(price) "," + std::to_string(satisf) + ")";
std::string selectAllExpenses = "SELECT * FROM expenses";
Then when you want to pass it to the sqlite API, you could use c_str()
sqlite3_exec(db, addTable.c_str(), ...
Thanks everyone for the responses. I spent about an hour and a half with my professor yesterday going over this, and this actually stumped him. I eventually found a way to make this work with the array, but I want to stress that the solution I came up with is pretty much only good for this assignment. For anyone reading this with a similar problem, this method is not only messy, but also allows for SQL injection which should be avoided.
The problem, as many here have mentioned in comments, was that I was trying to stick a string into a char* array. The workaround we came up with was to add the SQL commands with the variables expanded in them directly to a string variable, like so:
string insertExpense = "INSERT INTO expenses(desc, price, satisf) VALUES ('" + saleDesc + "', "
""+ to_string(price) + ", " + to_string(satisf) + ")";
We then made that variable a c_str and assigned it to a char* variable, like so:
const char *line1 = insertExpense.c_str();
We then simply assigned this char* variable directly to the correct position in the array, like so:
const char *pSQL[6];
pSQL[0] = "CREATE TABLE IF NOT EXISTS expenses(id INTEGER PRIMARY KEY "
"AUTOINCREMENT NOT NULL, logged TIMESTAMP DEFAULT "
"CURRENT_TIMESTAMP NOT NULL, desc VARCHAR(40), price REAL,"
"satisf INT)";
pSQL[1] = line1;
pSQL[2] = "SELECT * FROM expenses";
pSQL[3] = "SELECT sum(satisf) FROM expenses";
This method correctly makes the SQL table and populates it with the correct statements as stored in their respective variables. I want to stress again that this method is both very messy and dangerous, and for anyone with a similar issue, it is probably a much better idea to use prepared statements, as others in the comments have already mentioned. Thank you everyone!

Winapi GetOpenFileName Extension Filter not working

I'm trying to apply file's extension filters to the file's selection dialog.
This way works:
ofn.lpstrFilter =
"(*.exe) Windows Executable\0*.exe\0"
"(*.ini) Windows Initialization file \0*.ini\0"
"(*.dll) Dynamic Link Library \0*.dll\0"
"(*.lib) Windows Library file \0*.lib\0"
"(*.conf) Windows Configuration file \0*.conf\0";
But when I'm assigning extension filters dynamically, via parameters, it fails, filters don't appear in the combo box:
LPCSTR filter = (LPCSTR)extFilter; //Contains string "bmp"
stringstream s;
s << "(*.exe) Windows Executable\0" << "*." << filter << "\0";
string ffilter = s.str();
ofn.lpstrFilter = ffilter.c_str();
I'm assuming the problem is in strings conversion, but can't figure it out.
This line:
s << "(*.exe) Windows Executable\0" << "*." << filter << "\0";
Is passing null-terminated char* strings to operator<<(), and thus is effectively behaving the same as this code at runtime:
s << "(*.exe) Windows Executable" << "*." << filter << "";
The nulls never make it into s.
To insert the nulls correctly, you need to assign them to the stringstream as individual char values and not as char* values:
s << "(*.exe) Windows Executable" << '\0' << "*." << filter << '\0';
Also, the fact that you are type-casting extFilter is suspicious. If you have to do that to get rid of a compiler error then extFilter is not a compatible data type to begin with, the type-cast is hiding a bug in your code. Get rid of the type-cast:
LPCSTR filter = extFilter; //Contains string "bmp"
If the code fails to compile then you are doing something wrong and need to fix it properly.
On the other hand, if extFilter is a null-terminated char string to begin with, you don't need to assign it to a variable before passing it to operator<<():
s << "(*.exe) Windows Executable" << '\0' << "*." << extFilter << '\0';
You are using a pointer to some temporary string that, according to http://www.cplusplus.com/reference/string/string/c_str/, "may be invalidated by further calls to other member functions that modify the object."
Finally found an answer:
const char * extensionFilter = myParamVar; //Contains "JPG" string
string sFilter;
sFilter.append("Format: ");
sFilter.append(extensionFilter);
sFilter.push_back('\0');
sFilter.append("*.");
sFilter.append(extensionFilter);
sFilter.push_back('\0');
//Current filter content --> Format: JPG\0*.JPG\0
const char * filter = sFilter.c_str(); //Char string conversion
ofn.lpstrFilter = filter; //Set the filter to the sctructure's member.
//Opens the dialog and it successfully applies the filter.
if (GetOpenFileName(&ofn)==TRUE){
. . .
A shorter version:
ofn.lpstrFilter = _T("Format: XML\0*.xml\0");

SQLite overwrites my existing records : C++

I am new to SQLite and I may be missing something very basic. I am creating a table as shown below with the following statement.
Creation of Table statement
std::string strQuery = "CREATE TABLE IF NOT EXISTS ";
strQuery += tableNames[msgTable];
strQuery += " (RecKey INTEGER PRIMARY KEY, Origin TEXT NOT NULL, Type INT, Target INT, Header TEXT NOT NULL, Content TEXT)";
Then I am inserting records using the following statement.
Insert statement
std::string appendRecStr = "INSERT INTO " + tableNames[msg._type] + " (RecKey, Origin, Type, Target, Header, Content) VALUES (";
appendRecStr += std::string("NULL") + ", " +
AddQuote4SQL(msg._orig) +", " +
AddQuote4SQL((short)msg._type) +", " +
AddQuote4SQL((short)msg._target) +", " +
AddQuote4SQL(msg._head) +", " +
AddQuote4SQL(msg._data) + ");";
Also,
inline std::string AddQuote4SQL( const std::string & s ) {return std::string("'") + s +
std::string("'");}
inline std::string AddQuote4SQL( short s )
{
std::stringstream ss;
ss << "'" << std::to_string(s) << "'";
return ss.str();
}
The problem is the insert statement overwrites existing records. What is going wrong?
I think you are missing indeed something basic about sql here. An INSERT statement always inserts a new row. What you want in this case is an UPDATE statement, which uses a certain value to recognize its a duplicate (i.e. column1 = "somevalue": below). In case no rows are found that match the value, you should insert, since no duplicates exist. See code below:
UPDATE Table1 SET (...) WHERE Column1='SomeValue'
IF ##ROWCOUNT=0
INSERT INTO Table1 VALUES (...)