C++ and sql SELECT statement - c++

I have a quick question. I'm new in terms of trying to combine both sql and c++ together. My question is when I enter in the author to look for in the database, it say unknown column 'insert author last name here'. It's because of the input variable 'AuthorLast' not having quotes in the select statement. Thing is, I don't know how to fix it or change it.
#include<mysql.h>
#include<string>
#include<iostream>
using namespace std;
int main()
{
string AuthorLast;
mysql_library_init(0, NULL, NULL);
MYSQL* con = mysql_init(NULL);
if (con == NULL)
{
cout << mysql_error(con);
exit(1);
}
if (mysql_real_connect(con, "Insert Host here", "Insert ID here", "Password", "DataBase here", 0, NULL, 0) == NULL)
{
cout << mysql_error(con);
exit(1);
}
cout << "Enter in an author from the database: ";
getline(cin, AuthorLast);
string sql;
sql = "SELECT AuthorLast FROM Author WHERE AuthorLast= " + AuthorLast + ";";
const char* C = sql.c_str();
mysql_query(con, C);
MYSQL_RES* result = mysql_store_result(con);
if (result == NULL)
{
cout << mysql_error(con);
exit(1);
}
int field_nums = mysql_num_fields(result);
MYSQL_ROW row;
while (row = mysql_fetch_row(result))
{
for (int i = 0; i < field_nums; i++)
cout << row[i] << endl;
}
mysql_free_result(result);
mysql_close(con);
}

As other people have said, just adding single quotes in the SQL text would do the trick, but that leaves you vulnerable to SQL injection. Imagine that someone asks for an author name (written in another line for clarity):
SomeAuthor' or ''='
That would result in:
SELECT AuthorLast FROM Author WHERE AuthorLast= 'SomeAuthor' or ''='';
Which would result in your query returning all of the last names of authors. Although this may seem irrelevant for you, if (for example) you use the same approach in a password checking query, it can lead to an attacker being able to login without knowing the user password (in essence, you are allowing the user to modify your query).
You should thoroughly sanitize the user's input (this is, ensuring that it does not include unexpected characters) before including it in the query or (better still) use prepared statements (for mysql, I think that you can take a look at the mysql_stmt_* methods).
Prepared statements are more or less like telling the database server to execute "SELECT AuthorLast FROM Author WHERE AuthorLast=?", and telling it to use "MyAuthorLast" in place of the ?. So if someone tries to include quotes in the name, the server automatically sanitizes the input for you by adding any required escape characters.

Related

How to get around the \x1a character (or similar characters) in a hash (Crypto++ Library)?

I am relatively new to programming and this project is one of the very first projects that I am doing in my own time.
I am basically trying to make a login registration program that hashes user-entered data and stores it in a text file. The login option basically accesses that text file and compares it with the user entered data to see if there exists any such username and password combinations. The registration option basically writes the user data into the file. I am not very far into the project since I want to add a few more "features" to the program so it works a bit better. Currently, however, I encountered a slight problem while reading the data from the text file for the login option. Basically, one of the hashed passwords stored in the text file contains \x1a as a part of its hash. I think the program always ends whenever it reads this sub-control character since it reaches the end of the file. What I want to know is how to avoid a hash that has such a character.
I am using the crypto++ library (I am not too familiar with it).
The hash function:
void hashingFunc(string originalPass, string& hashedPass) {
using namespace CryptoPP;
SHA3_256 hash;
hash.Update((const byte*)originalPass.data(), originalPass.size());
encryptedPass.resize(hash.DigestSize());
hash.Final((byte*)&encryptedPass[0]);
}
The read function:
void readFileFunc(fstream& outputFile, const string FILE_NAME, string userNameHash, string passWordHash) {
string localUserHash;
string localPassHash;
if (!outputFile) {
cout << "File containing login information failed to open. Please try again." << endl;
cout << "If the problem persists, check file name and location." << endl;
cout << "File Name in the system: " << FILE_NAME << endl;
}
else {
while (outputFile) {
if (outputFile.eof())
break;
getline(outputFile, localUserHash);
getline(outputFile, localPassHash);
if (localUserHash == userNameHash) {
if (localPassHash == passWordHash) {
cout << "Successful Login!" << endl;
}
}
}
}
}

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!

Poco 1.5.2 C++ ODBC throws exceptions on insert

I have a program which reads information about 3D meshes in from a text file, stores the data as a mesh,performs some post-processing on the mesh, then collects information like volume, center of mass, etc.
The program has two threads:
Main thread starts the second thread, reads the file, does the processing, then waits for the second thread. As a part of the processing, it puts information about the meshes its just read onto a queue.
Second thread connects to SQL Server using Poco ODBC, puts some initial information about the file its reading into a database table, then gets information off the queue and assembles a potentially lengthy insert command. When it is done doing so, it submits the command, performs a final update command regarding the results of operations performed, then lets the main thread know it's done, and terminates the 2nd thread.
Everything works, right up until the moment it submits the large insert command. It throws an exception, and i can't figure out why.
Here i will give a simplistic outline of the code that is executing. Assume variables exist and are initialized.
The poco commands i run are:
using namespace Poco;
using namespace Poco::Data::Keywords;
using namespace Poco::Data;
ODBC::Connector::registerConnector();
Session session(SessionFactory::instance().create("ODBC", "Driver={SQL Server};Server=<hostname>;Database=<DB name>;Uid=<username>;Pwd=<password>;"));
session << "INSERT INTO TableName1 (SourceFileName,UserName) VALUES (?,?)",use(_filename),use(username),now;
session << "SELECT SCOPE_IDENTITY()", into(runID),now; //This always runs and returns 0.
string queryString = "Insert into TableName2 (Field1, field2, field3, field4, ...) "+
"VALUES (val1, val2, val3, val4, ...)"+
",(valA, valB, valC, valD, ...),..."
session << queryString,now;
Statement update(session);
update << "UPDATE TableName1 SET Field2 = ?, Field3 = ?, Field4 = ? WHERE Field1 = ?", use(data2), use(data3), use(data3), use(identity);
update.execute();
ODBC::Connector::unregisterConnector();
<send signal to main thread indicating being done.>
I'm trying to figure out a few key things.
How can I tell what state the Session is in?
Is there a way to ask Poco what went wrong and have it print an error message?
Are there any special things I need to set up to be able to specify a big insert statement all together in text like I am? I have tried it using ? placeholders, or executing individual statements, but it always gives me an exception on that part.
Is there a way to have statements execute under the same connection for sure? Normally I would do my INSERT INTO TableName1(...)VALUES(...) SELECT SCOPE_IDENTITY() all as a single operation. I've tried my commands in SQL Server Management Studio and it works properly. Right now, it is always returning a 0 aka NULL, like the statements run in separate connections.
More information:
String query = "INSERT INTO TableName1 (SourceFileName,UserName) VALUES ('"+ __file + "','" + __username + "')";
Statement insertStmt = (session << query);
try{insertStmt.execute(true);}
catch(Poco::Exception exc)
{
cout << exc.displayText() << endl;
}
try{session << "SELECT SCOPE_IDENTITY() as SCOPE_IDENTITY", into(runID), now;
cout << "Run ID: " << runID << endl;}
catch(Poco::Exception exc)
{
cout << exc.displayText() << endl;
}
I greatly appreciate your help or any suggestions on how I can improve this question.
1.:
There are various query members in the Session class - isConnected(), canTransact(), isTransaction() ... (if that is what you are looking for; if not, see the next answer)
1. and 2.:
Wrap your statement into try/catch block:
#include "Poco/Data/ODBC/ODBCException.h"
//...
try
{
session << "INSERT INTO TableName1 (SourceFileName, UserName) VALUES (?, ?) ",use(_filename),use(username),now;
}
catch(Poco::Data::ODBC::ConnectionException& ce){ std::cout << ce.toString() << std::endl; }
catch(Poco::Data::ODBC::StatementException& se){ std::cout << se.toString() << std::endl; }
3.:
I don't think the problem is too large statement. There is a configurable internal setting limiting the string size to 1K, but this applies to value strings, not the whole SQL statement.
If you still think that is the problem, you can increase the max field size, e.g.:
std::size_t fieldSize = 4096; //4K
session.impl()->setProperty("maxFieldSize", Poco::Any(fieldSize));
4.:
Poco::Data::ODBC does not parse or analyze the SQL statement in any way; so from that standpoint, whatever works with your ODBC driver will be fine.

sqlite table code manager?

Fairly new to sqlite (and sql). I have several tables I need to generate with several column names, which can change as I code (in c++). How do I manage them? Am I doing it right? There must be utility codes out there that's much better.
Edit: Specifically, I'd like to avoid run-time errors by having an abstraction of the table and field names at compile time (e.g. using #defines, but maybe something else is better).
E.g. I'm currently thinking about creating a class TableHandler that will:
sqlite *db;
....
TableHandler tb("TableName");
tb.addField("FirstName", "TEXT");
tb.addField("Id", "INTEGER");
tb.createTable(db); //calls sqlite3_exec("create table TableName(FirstName TEXT, Id INTEGER)");
tb.setEntry("FirstName", "bob");
tb.addEntry(); //calls sqlite3_exec("insert ...");
tb.createCode(stdout);
//this will generate
/*
#define kTableName "TableName"
#define kFirstName "FirstName"
#define kId "Id"
...anything else useful?
*/
I asked a similar question and it was down voted so i deleted it. I wrote some code to do the insert if you are interested. But i agreed with the negative comments that static SQL statements are less error prone. Not to mention less cpu intensive.
For insert i took a std::set of std::pair of std::string. The first string being the column name and the second string its value. And the Query returned a similar structure. I played with std::map and std::vector and std::unordered_set all of them would have different benefits here.
What would be great if you get around to it is a small utility program that could read a definition of a class and write all the SQL for you. I started this and gave up because of parsing the C++ header file got way to complicated for the time I would save on future projects.
Added
std::string Insert(std::string table, std::vector< std::pair<std::string,std::string> > row)
{
if (row.size()==0 || table.size()==0)
return "";
std::stringstream name,value;
auto it = row.begin();
name << "INSERT INTO " << table.c_str()<<"('" << (*it).first << "'";
value << "VALUES('" <<(*it).second << "'";
for ( ; it < row.end(); it++)
{
name << ", '" << (*it).first << "'";
value << ", '" <<(*it).second << "'";
}
name << ") ";
value << ");";
name << value.str();
return name.str();
}