mysql++ insert how to? - c++

I am having problem to INSERT some values into database. Database name is users, and table is heroes. I am doing some mmorpg game developing for purpose of learning.
This is mysql code that works
INSERT INTO heroes (HeroID,Strenght, Dexterity, Vitality, Wisdom, Inteligence, Luck, Name, Level, XP) VALUES (NULL, 17, 13, 17, 15, 9, 8, 'works', 4, 3750);
But when I try that from c++ via mysql++ I get error.
Code:
#include <mysql++/mysql++.h>
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
// Connect to the database.
mysqlpp::Connection conn(false);
if (conn.connect("users", "localhost",
"root", "toor"))
{
mysqlpp::Query query = conn.query();
query << "INSERT INTO heroes" <<
"VALUES (NULL, 17, 13, 17, 15, 9, 8, doSomething,3, 3260);";
query.execute();
if (mysqlpp::StoreQueryResult res = query.store())
{
// nothing to do here
}
else
{
cerr << "Failed to get item list: " << query.error() << endl;
return 2;
}
return 0;
}
else
{
cerr << "DB connection failed: " << conn.error() << endl;
return 1;
}
}
Error I get is: Failed to get item list; You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'NULL, 17, 13, 17, 15, 9, 8, doSOmething,3, 3260)' at line 1
p.s. I am sending NULL becouse that field is auto-increment (using for ID)
I tried almost all possible alternatives like adding '', separataning and whatnot. Can somebody help me with this line of code, since I can't find ang good tutorial that helps on this matter.
Thanks in advance

Have you tried to add an space in your string?
query << "INSERT INTO heroes " <<
"VALUES (NULL, 17, 13, 17, 15, 9, 8, 'doSomething', 3, 3260);";
Also, as pointed out by hmjd, doSomething needs to be quoted, like 'doSomething'.

The string doSomething needs quoted:
query << "INSERT INTO heroes "
<< "VALUES (NULL, 17, 13, 17, 15, 9, 8, 'doSomething', 3, 3260);";
and as pointed out by Streppel a space is required between heroes and VALUES.

If your field is auto-increment, just don't mention it in your query, and that's it !
But then you would need to name all the fields in your insert query, which is actually a best-practice anyway !
query << "INSERT INTO heroes (fieldName1,fieldName2,...) " <<
"VALUES (17, 13, 17, 15, 9, 8, doSomething,3, 3260);";
Where fieldname1 is your first field right after the id field (or any other field actually, you can use whatever order you wish).

you can create a header and paste this in. i will use table1.h
#include <mysql++.h>
#include <ssqls.h>
#include <vector>
//you may get some weird underlines but don't panic, have some vitality.
sql_create_10(heroes, 1, 10,
mysqlpp::sql_int, HeroId, mysqlpp::sql_int,
Strenght, mysqlpp::sql_int, Dexterity, mysqlpp::sql_int, Vitality,
mysqlpp::sql_int, Wisdom, mysqlpp::sql_int, Inteligence,
mysqlpp::sql_int, Luck, mysqlpp::sql_varchar, Name, mysqlpp::sql_int,
Level, mysqlpp::sql_bigint, Xp)
//if bigint doesn't work for you u can use just int.
then in the main method paste this in
//connect to database
mysqlpp::Connection conn(false);
try{
conn.connect("users", "localhost", "j0y57/Qxx", "rootsman");
heroes row(0, 17, 13, 17, 15, 9, 8, "doSomething", 3, 3260 );
mysqlpp::Query query = conn.query();
query.insert(row);
query.execute();
} catch (const mysqlpp::BadQuery& bq){
cerr << "query error: " << bq.what() << endl;
return -1;
}

Related

C++ Apache Orc is not filtering data correctly

I am posting a simple c++ Apache orc file reading program which:
Read data from ORC file.
Filter data based on the given string.
Sample Code:
#include <iostream>
#include <list>
#include <memory>
#include <chrono>
// Orc specific headers.
#include <orc/Reader.hh>
#include <orc/ColumnPrinter.hh>
#include <orc/Exceptions.hh>
#include <orc/OrcFile.hh>
int main(int argc, char const *argv[])
{
auto begin = std::chrono::steady_clock::now();
orc::RowReaderOptions m_RowReaderOpts;
orc::ReaderOptions m_ReaderOpts;
std::unique_ptr<orc::Reader> m_Reader;
std::unique_ptr<orc::RowReader> m_RowReader;
auto builder = orc::SearchArgumentFactory::newBuilder();
std::string required_symbol("FILTERME");
/// THIS LINE SHOULD FILTER DATA BASED ON COLUMNS.
/// INSTEAD OF FILTERING IT TRAVERSE EACH ROW OF ORC FILE.
builder->equals("column_name", orc::PredicateDataType::STRING, orc::Literal(required_symbol.c_str(), required_symbol.size()));
std::string file_path("/orc/file/path.orc");
m_Reader = orc::createReader(orc::readFile(file_path.c_str()), m_ReaderOpts);
m_RowReader = m_Reader->createRowReader(m_RowReaderOpts);
m_RowReaderOpts.searchArgument(builder->build());
auto batch = m_RowReader->createRowBatch(5000);
try
{
std::cout << builder->build()->toString() << std::endl;
while(m_RowReader->next(*batch))
{
const auto &struct_batch = dynamic_cast<const orc::StructVectorBatch&>(*batch.get());
/** DO CALCULATIONS */
}
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
auto end = std::chrono::steady_clock::now();
std::cout << "Total Time taken to read ORC file: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << " ms.\n";
return 0;
}
I tried searching on google for almost a week and tried to convert every possible java program into c++ to make my code works.
I tried to use the example in the STACKOVERFLOW LINK which has a similar issue but didn't work for me.
**Question:**
1. Am I wiring filtering code correctly. If yes then why it is not filtering data based on the given string.
2. Where can I find the C++ or 'relevant Java code' for row-level or strip-level filter.
Finally after trying multiple scenarios, I have resolved the above issue with ORC data filtering.
It was because of using the incorrect column number, I am not sure why there is a difference between the column id of the columns to fetch and columns to filter.
In above example I tried to filter data with column name and issue of filtering ORC with column name is still there. But unfortulately it is working fine with column number.
New Code:
#include <iostream>
#include <list>
#include <memory>
#include <chrono>
// Orc specific headers.
#include <orc/Reader.hh>
#include <orc/ColumnPrinter.hh>
#include <orc/Exceptions.hh>
#include <orc/OrcFile.hh>
int main(int argc, char const *argv[])
{
auto begin = std::chrono::steady_clock::now();
orc::RowReaderOptions m_RowReaderOpts;
orc::ReaderOptions m_ReaderOpts;
std::unique_ptr<orc::Reader> m_Reader;
std::unique_ptr<orc::RowReader> m_RowReader;
auto builder = orc::SearchArgumentFactory::newBuilder();
std::string required_symbol("FILTERME");
// <-- HERE COLUMN IDS ARE STARTING FROM 0-N. -->
std::list<uint64_t> cols = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
m_RowReaderOpts.include(cols);
int column_id = 7; // IN cols ABOVE, THIS COLUMN_ID 7 IS ACTUALLY 6. WHICH MEANS COLUMN_ID TO FILTER COLUMN IS +1 OF COLUMN ID PROVIDED IN DATA FETCH.
builder->equals(column_id, orc::PredicateDataType::STRING, orc::Literal(required_symbol.c_str(), required_symbol.size()));
std::string file_path("/orc/file/path.orc");
m_Reader = orc::createReader(orc::readFile(file_path.c_str()), m_ReaderOpts);
m_RowReader = m_Reader->createRowReader(m_RowReaderOpts);
m_RowReaderOpts.searchArgument(builder->build());
auto batch = m_RowReader->createRowBatch(5000);
try
{
std::cout << builder->build()->toString() << std::endl;
while(m_RowReader->next(*batch))
{
const auto &struct_batch = dynamic_cast<const orc::StructVectorBatch&>(*batch.get());
/** DO CALCULATIONS */
}
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
auto end = std::chrono::steady_clock::now();
std::cout << "Total Time taken to read ORC file: " << std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count() << " ms.\n";
return 0;
}
As per my understanding while resolving above issue is, column ids for fetching data starts from 0-N and for filtering it is 1-N. This is why you should provide 1, when you require to filter data at column 0.
To explain the confusion in the above answer:
In ORC, column field id is a different thing than column type id:
For files that have structs as the top-level object, field id 0 corresponds to the first struct field, field id 1 for the second struct field, and so on. See comments here: https://github.com/apache/orc/blob/v1.7.3/c++/include/orc/Reader.hh#L122-L123
Column type id is the pre-order traversal index of the type tree. As mentioned in the spec: The type tree is flattened in to a list via a pre-order traversal where each type is assigned the next id. Clearly the root of the type tree is always type id 0.
So if there are no nested types (struct/array/map) in the ORC file, we can see columnTypeId == columnFieldId + 1 on all columns except the root struct type.
The ids used in building sargs are column type ids. However, the ids used in RowReaderOptions::include(const std::list<uint64_t>& include) are column field ids. To have a consistent id mapping, I'd recommend using the include method for type ids:
RowReaderOptions::includeTypes(const std::list<uint64_t>& types);

How to retrieve multiple named output parameters in MS ODBC stored procedure call

I am trying to call a stored procedure which has two output arguments, and get the output programmatically in a C++ program.
Code snippet for executing a query:
char const* const query =
"DECLARE #iMM int, #sMM varchar(100); "
"EXEC sp_myproc #sFoo = 'abcdef', #sBar = 'ghij', #iQux = 1,"
"#iOutInt = #iMM output, #sOutString = #sMM output;"
"PRINT #iMM; PRINT #sMM;";
auto result = SQLExecDirectA(handle, (SQLCHAR*)query, SQL_NTS);
This returns SQL_SUCCESS_WITH_INFO ., but SQLGetDiagRecA does not retrieve the printed output . SQLMoreResults returns 1, SQLParamData returns -1.
The same query does execute successfully in SSMS but I can't figure out how to get the output parameter values programmatically. There are various code examples using SQLBindParameter to retrieve multiple output parameters but none of them use named parameters.
I managed to get the data this way (maybe not optimal but at least it works):
char const* const query =
"EXEC sp_myproc #sFoo = 'abcdef', #sBar = 'ghij', #iQux = 1,"
"#iOutInt = ? output, #sOutString = ? output;"
short out_int;
SQLBindParameter(handle, 1, SQL_PARAM_OUTPUT, SQL_C_SSHORT, SQL_SMALLINT,
0, 0, &out_int, 1, NULL);
char outbuf[61];
SQLBindParameter(handle, 2, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_VARCHAR,
60, 0, outbuf, 60, NULL);
auto result = SQLExecDirectA(handle, (SQLCHAR*)query, SQL_NTS);
if ( result == SQL_SUCCESS_WITH_INFO )
{
std::cout << out_int << ", '" << outbuf << "'\n";
}
Using SQL_CHAR instead of SQL_VARCHAR meant the result string was always right-padded with spaces .

How to create json message having a number or value in C++ using boost

can any one suggest the solution,
how I can create json of below format using boost json in C++
json required format is as below
{
"myarray":
[
[ 12, 12, 120, 120 ],
[ 120, 12, 129, 120 ],
[ 12, 120, 120, 129 ]
],
"count": 3,
}
I tried using ptree put method, but it seems numbers are getting converted to string.
Is it possible somehow using basic_tree or translator or something else in available in boost json library?
As already mentioned by other user, boost ptree has some limitations.
If this is the only format you need, then you could code your own solution (tabs and newlines are only for readability):
using MyArray = vector<int>;
using MyArrays = vector<MyArray>;
string CreateJson(const MyArrays& v)
{
ostringstream json;
json << "{\n\t" << R"("myarray":[)" << "\n";
for (const auto& vv : v)
{
json << "\t\t[";
for (auto el : vv) json << el << ", ";
json.seekp(-1, json.cur);
json << "],\n";
}
json.seekp(-2, json.cur);
json << "\n";
json << "\t\t],\n\t" << R"("count":)" << v.size() << "\n}";
return json.str();
}
Live Demo
With a little additional templating, you could adjust it for more types

Why does sqlite's delete always succeed, even when the row to delete does not exist?

After I create a table, insert data into it, and then delete a non-existent row, the operation succeeds even though the row does not exist. When I delete a row that actually exists, it succeeds as well and the row is actually deleted. Why doesn't an error occur when I try to delete a row that does not exist?
I am using sqlite3 with c++ on eclipse.
I've been working with some code found on the web, as well as my own.
Other operations, like SELECT and INSERT work fine. DELETE works when rows exist and even when they don't exist.
// Creating a table
sql = "CREATE TABLE COMPANY(" \
"ID INT PRIMARY KEY NOT NULL," \
"NAME TEXT NOT NULL," \
"AGE INT NOT NULL," \
"ADDRESS CHAR(50)," \
"SALARY REAL );";
// Inserting data
sql = "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) " \
"VALUES (1, 'Paul', 32, 'California', 20000.00 ); " \
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) " \
"VALUES (2, 'Allen', 25, 'Texas', 15000.00 ); " \
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)" \
"VALUES (3, 'Teddy', 23, 'Norway', 20000.00 );" \
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)" \
"VALUES (4, 'Mark', 25, 'Rich-Mond ', 65000.00 );";
// Deleting (this is where the deletion should fail because there is no
ID 30)
rc = sqlite3_open("test.db", &db);
if( rc ) {
cout << "ERROR ----> " << zErrMsg << endl;
return(0);
} else {
fprintf(stderr, "Opened database successfully\n");
}
/* Create SQL statement */
sql = "DELETE FROM COMPANY WHERE ID = 30";
/* Execute SQL statement */
rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
if( rc != SQLITE_OK ) {
cout << "ERROR DELETING" << endl;
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
} else {
fprintf(stdout, "Deletion operation done successfully\n");
}
sqlite3_close(db);
I expect the message "ERROR DELETING" to be displayed, but "Deletion operation done successfully" always displays, even when the ID deleted does not exist.
Why doesn't an error occur when I try to delete a row that does not exist?
Databases return number of rows affected (deleted in your case), they don't throw error, unless there is something wrong with the query.
The only guaranteed method to check if the row has been deleted is to execute a SELECT statement with the same conditions. Transaction control is an important factor here, i.e. what happens if something causes a rollback? Are you explicitly committing transactions, or allowing them to auto-commit? You shouldn't just rely on return codes for this. If you do a COUNT as well, then you will know for sure, at least within your session:
SELECT COUNT(*) FROM COMPANY WHERE ID = 30
If after the DELETE, the COUNT is 0, the row no longer exists.
Note: This approach will be helpful if you need concurrency, which will force you to use a different database engine (e.g. PostgreSQL).
I guess the answer is "this is by design".
If you need to know if zero (or more) rows were affected by the last DELETE statement (or INSERT or UPDATE for that matter) then you could look into using:
int sqlite3_changes(sqlite3*);
That will allow you to react accordingly if no rows were deleted.
See https://www.sqlite.org/c3ref/changes.html

Junk varchar entries in MSSQL database using ODBC

I'm trying to insert a string-variable into a varchar(100)-field, but if the string is longer than 15 elements only junk is inserted (e.g. "0‰?").
First my setup:
Development: Win7 (64bit) / VS2013 / C++11 / 64bit Application
Database: Win8 (64bit) / Microsoft SQL Server Express 2014 (64bit)
Driver: SQL Server Native Client 11.0
Second the binding of the paramter:
std::string mMessageText;
SQLHANDLE mSqlStatementHandle;
std::string mExecString;
bool initConnection()
{
mExecString = "{? = CALL dbo.InsertTestProcedure(?, ?, ?, ?, ?)}";
(...)
// bind parameters
SQLBindParameter(mSqlStatementHandle, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, 100, 0, (SQLPOINTER)mMessageText.c_str(), mMessageText.length(), NULL);
(...)
// prepare handle with execution string
if (SQL_SUCCESS != SQLPrepare(mSqlStatementHandle, (SQLCHAR*)mExecString.c_str(), (SQLSMALLINT)mExecString.length()))
{
throwError(SQL_HANDLE_STMT, mSqlStatementHandle);
return false;
}
}
Third the query execution:
bool fillDb()
{
(...)
mMessageText = "This text is longer than 15";
// execute SQL statement
if (SQL_SUCCESS != SQLExecute(mSqlStatementHandle))
{
throwError(SQL_HANDLE_STMT, mSqlStatementHandle);
return false;
}
(...)
}
Header of the procedure:
ALTER PROCEDURE [dbo].[InsertTestProcedure]
#MessageComp VARCHAR(20),
#MessageType VARCHAR(20),
#MessageAction VARCHAR(20),
#MessageText VARCHAR(100),
#MessageName VARCHAR(20)
AS
If the string is shorter than 15 elements, it works fine. And calling the procedure from SQL Management Studio with value lengths > 15 works fine too.
One thing that comes to my mind is the procedure you are calling. Maybe you have table with varchar(100) column, but the procedure has only varchar(15) parameter. Could you post header of that procedure?
Thanks to #erg, here is the solution that worked for me:
char mMessageText[100];
bool initConnection()
{
(...)
// bind parameters
SQLBindParameter(mSqlStatementHandle, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR, 100, 0, (SQLPOINTER)mMessageText, 100, NULL);
(...)
}
bool fillDb()
{
(...)
std::string lMessageText = "This text is longer than 15";
strcpy(mMessageText, lMessageText.c_str());
mMessageText[sizeof(mMessageText) - 1] = 0;
(...)
}