while(in) {
memset(str, 0,1024);
in.getline(str, 1024); // delim defaults to '\n'
string output = modifyString(str);
if (output != ""){
cout << output << endl;
string output1 = "INSERT INTO DATA_SRC "\
"VALUES (" + output + ");";
cout << output1 << endl;
const char * command = output1.c_str();
cout << output << endl;
rc = sqlite3_exec(db, command, callback, 0, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
return 1;
}
}
for here, I + two string together.
And the out put intially is:
'D3318','D.A. Kline','Quantitative determination of sugars in fruits by GLC separation of TMS derivatives',1970,'Journal of AOAC International',53,6,1198,1202
which is good. But after I combine it to others.
Expected:
INSERT INTO DATA_SRC VALUES ('D3318','D.A. Kline','Quantitative determination of sugars in fruits by GLC separation of TMS derivatives',1970,'Journal of AOAC International',53,6,1198,1202);
Reality:
INSERT INTO DATA_SRC VALUES ('D3318','D.A. Kline','Quantitative determination of sugars in fruits by GLC separation of TMS derivatives',1970,'Journal of AOAC In);rnational',53,6,1198,1202
I do not now why.
Your modifyString function (which you didn't show) is copying a null byte to the end of the string. The string output functions will stop on a null byte, in order to be compatible with C-strings.
Related
I don't have problem inserting UTF-8 (korean character in my case) using direct sql command in PGAdmin or psql console. But when I need to insert values in C++ by using libpq library, I got the encoding error and I couldn't resolve it until now.
I have tested DB connection, etc and works well. So I will just share the insertion code only :
/* INSERT demo */
res = PQexec(conn,
"insert into db_test values('testval', '군포지사','N00225','영동선','0500','E',13.67,14.18);");
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
std::cout << "Insert into table failed: " << PQresultErrorMessage(res)
<< std::endl;
}
else
std::cout << "inserted" << std::endl;
PQclear(res);
Below is the error :
Insert into table failed: ERROR: invalid byte sequence for encoding "UTF8": 0xb1
I have managed to solve it, sorry for my lack of understanding in encoding processing. I just need to convert ANSI to UTF-8, below is my working code. If there's a better solution, please post your answer.
int AnsiToUTF8(char* szSrc, char* strDest, int destSize)
{
WCHAR szUnicode[255];
char szUTF8code[255];
int nUnicodeSize = MultiByteToWideChar(CP_ACP, 0, szSrc, (int)strlen(szSrc), szUnicode, sizeof(szUnicode));
int nUTF8codeSize = WideCharToMultiByte(CP_UTF8, 0, szUnicode, nUnicodeSize, szUTF8code, sizeof(szUTF8code), NULL, NULL);
assert(destSize > nUTF8codeSize);
memcpy(strDest, szUTF8code, nUTF8codeSize);
strDest[nUTF8codeSize] = 0;
return nUTF8codeSize;
}
/* INSERT demo */
char queryUtf8[100];
std::string queryAnsi = "insert into db_test values('testval', '군포지사','N00225','영동선','0500','E',13.67,14.18);";
AnsiToUTF8(&queryAnsi[0u], queryUtf8, 100);
res = PQexec(conn, queryUtf8);
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
std::cout << "Insert into table failed: " << PQresultErrorMessage(res)
<< std::endl;
}
else
std::cout << "inserted" << std::endl;
PQclear(res);
The proper solution is to set the client_encoding parameter to the correct value (the encoding your client uses). You can do that when connecting to the database:
PGconn *conn;
conn = PQconnectdb("user=carl password=secret client_encoding=LATIN1");
I'm working on a basic program to learn how to use SQLite3; a user gives input on a song they'd like to add to a SQLite database, and it is inserted. As far as I can seen, the insert statement I'm generating- while not pretty- is a valid statement, but once it reaches my queryDatabase() function it enters the error clause. It prints "Error in execution: ", but when it moves on to errmsg, it seems to enter into a state where nothing happens/no actual error message is printed until I enter .quit. I've tried altering the print line like cout << "ERROR EXECUTING SQL: " << errmsg << "End";, and "End" never prints.
Here is the section of code that calls the queryDatabase() function/passes the command string. args refers to a vector that contains the user input:
string sqlq;
sqlq = "INSERT INTO songs (sid, title, composer) VALUES(";
sqlq.append(args[2]); sqlq.append(", "); sqlq.append("\'"); sqlq.append(args[3]); sqlq.append("\'"); sqlq.append(", "); sqlq.append("\'"); sqlq.append(args[4]); sqlq.append("\'"); sqlq.append(");");
data.queryDatabase(sqlq);
and here is the queryDatabase() function:
sqlite3 *db;
char * errmsg = 0;
int rc;
void Data::queryDatabase(string queryString){
if(queryString.empty()) return;
const char * sqlQuery = queryString.c_str();
rc = sqlite3_exec(db, sqlQuery, callback, (void *) data, &errmsg);
if( rc != SQLITE_OK) {
cout << "Error in execution: " << errmsg;
} else {
cout << "\nSQL QUERY SUCCEEDED\n";
}
}
Both queryString and sqlQuery print INSERT INTO songs (sid, title, composer) VALUES(1905, 'Anti-rage', 'Emperor X'); which as far as I know is a valid command, as copy and pasting this when working direct in the database from terminal results in the song being added. Why might this not be inserting correctly, and why am I not being given an error message?
MODIFIED FOR MORE INFO:
Here's the callback
static int callback(
void * data, //pass through data provided to sqlite3_exec() [4th argument]
int argc, //# of cols in table row
char ** argv, //array of strings representing table row values
char ** azColName //array of strings representing column names
){
for (int i=0; i<argc; i++){
cout << argv[i] << ", ";
}
cout << "\n";
return 0;
}
I've got a fairly simple c++ application that uses ODBC to connect to a SQL Server instance that uses a stored procedure to populate.
I use the lines of a wstring object to build a query that is then passed through to the stored procedure. Everything works fine if I run it a single time - however, I want to be able to loop through a quite extensive amount of code (3000+ excel rows) and as I do it the cursor error mentioned in the title occurs.
This is the stored procedure:
GO
CREATE PROCEDURE s_addHistorical
#Symbol nchar(10),#Date datetime,
#Open decimal(8,2),#Close decimal(8,2),#MinPrice decimal(8,2),
#MaxPrice decimal(8,2),#Volume int
AS
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
MERGE HistoricalStock WITH (UPDLOCK) AS myTarget
USING (SELECT #Symbol AS Symbol,
#Date AS Date, #Open AS [Open], #Close AS [Close],
#MinPrice AS MinPrice, #MaxPrice AS MaxPrice,#Volume AS Volume) AS mySource
ON mySource.Symbol = myTarget.Symbol AND mySource.Date = myTarget.Date
WHEN MATCHED
THEN UPDATE
SET [Open] = mySource.[Open], [Close] = mySource.[Close],
MinPrice = mySource.MinPrice, MaxPrice = mySource.MaxPrice, Volume = mySource.Volume
WHEN NOT MATCHED
THEN
INSERT(Symbol,Date,[Open],[Close],MinPrice,MaxPrice,Volume)
VALUES(#Symbol,#Date,#Open,#Close,#MinPrice,#MaxPrice,#Volume);
COMMIT
GO
And this is the connector:
#include "stdafx.h"
#include "database_con.h"
////////////////////////////////////////////////////////////////////////
// Show errors from the SQLHANDLE
void database_con::show_error(unsigned int handletype, const SQLHANDLE& handle)
{
SQLWCHAR sqlstate[1024];
SQLWCHAR message[1024];
if (SQL_SUCCESS == SQLGetDiagRec(handletype, handle, 1, sqlstate, NULL, message, 1024, NULL))
wcout << "Message: " << message << "\nSQLSTATE: " << sqlstate << endl;
}
////////////////////////////////////////////////////////////////////////
// Builds the stored procedure query.
std::wstring database_con::buildQuery(vector<std::wstring> input)
{
std::cout << "Building the query" << std::endl;
std::wstringstream builder;
builder << L"EXEC sp_addHistorical " << "#Symbol='" << L"" << input.at(0) << "'," <<
"#Date=" << (wstring)L"" << input.at(1) << "," <<
"#Open=" << (wstring)L"" << input.at(2) << "," <<
"#Close=" << (wstring)L"" << input.at(3) << "," <<
"#MaxPrice=" << (wstring)L"" << input.at(4) << "," <<
"#MinPrice=" << (wstring)L"" << input.at(5) << "," <<
"#Volume=" << (wstring)L"" << input.at(6) << ";";
return builder.str();
}
////////////////////////////////////////////////////////////////////////
// Adds a substring of the string before the delimiter to a vector<wstring> that is returned.
std::vector<wstring> database_con::parseData(wstring line, char delim) {
size_t pos = 0;
std::vector<std::wstring> vOut;
while ((pos = line.find(delim)) != std::string::npos) {
vOut.push_back(line.substr(0, pos));
line.erase(0, pos + 2);
}
vOut.push_back(line.substr(0, pos));
return vOut;
}
std::wstring database_con::StringToWString(const std::string& s)
{
std::wstring temp(s.length(), L' ');
std::copy(s.begin(), s.end(), temp.begin());
return temp;
}
database_con::database_con(std::string historical){
/*
Set up the handlers
*/
/* Allocate an environment handle */
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
/* We want ODBC 3 support */
SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0);
/* Allocate a connection handle */
SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);
/* Connect to the DSN */
SQLDriverConnectW(dbc, NULL, L"DRIVER={SQL Server};SERVER=ERA-PC-STUART\\JBK_DB;DATABASE=master;UID=geo;PWD=kalle123;", SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);
/* Check for success */
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt))
{
show_error(SQL_HANDLE_DBC, dbc);
std::cout << "Failed to connect";
}
std::wstringstream stream(StringToWString(historical));
std::wstring line;
while (std::getline(stream, line)) {
vector<wstring> vHistorical = parseData(L"" + line, ',');
std::wstring SQL = buildQuery(vHistorical);
if (SQL_SUCCESS != SQLExecDirectW(stmt, const_cast<SQLWCHAR*>(SQL.c_str()), SQL_NTS)) {
show_error(SQL_HANDLE_STMT, stmt);
}
}
}
database_con::~database_con() {
}
I've been looking around at google and on SO, but I can't seem to find any questions that are usable in my current question. Most of them seem to be revolving around stored procedures sending back some sort of extracts, whereas my SP is simply inserting / updating.
Any sort of help would be greatly appriciated. :)
Anyone?
You need to call SQLCloseCursor to release the Cursor.
Change your code to:
while (std::getline(stream, line)) {
vector<wstring> vHistorical = parseData(L"" + line, ',');
std::wstring SQL = buildQuery(vHistorical);
if (SQL_SUCCESS != SQLExecDirectW(stmt, const_cast<SQLWCHAR*>(SQL.c_str()), SQL_NTS)) {
show_error(SQL_HANDLE_STMT, stmt);
}
// Close Cursor before next iteration starts:
SQLRETURN closeCursRet = SQLCLoseCursor(stmt);
if(!SQL_SUCCEEDED(closeCursRet))
{
// maybe add some handling for the case that closing failed.
}
}
See: https://msdn.microsoft.com/en-us/library/ms709301%28v=vs.85%29.aspx
I am using SQLite3 header files in my C++ program and trying to create a table and insert data onto it, it works fine on a regular input.
It shows error when I use it in a C++ loop with changing variables.
I am using the database to insert my reading from RS-232.
Here is my code:
sqlite3 *db;
char *zErrMsg = 0;
int rc;
char *sql;
std::string sql_str;
std::ostringstream temp;
std::string command;
/* Open database */
rc = sqlite3_open("test_1.db", &db);
if (rc){
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
exit(0);
}
else{
fprintf(stderr, "Opened database successfully\n");
}
std::string str;
std::ostringstream oss;
oss << id_count; // stornig the primary id int values into a string
str = "INSERT INTO M_DATA (ID, DETAILS) VALUES(";
str += oss.str(); //copying the int primary id
str += ", '";
std::string str_t1(szBuffer); //Copying character aray to a string
str += str_t1; //concatening the string
str += "');";
//printing what the database takes
//output_file << std::endl << str << std::endl;
char * writable = new char[str.size() + 1];
std::copy(str.begin(), str.end(), writable);
writable[str.size()] = '\0'; // don't forget the terminating 0
sql = writable;
output_file << std::endl << "## SQL COMMAND : " << sql << "#" << std::endl;
// don't forget to free the string after finished using it
delete[] writable;
rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
if (rc != SQLITE_OK){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
output_file << std::endl << "** SQL ERROR : " << zErrMsg << "*" << std::endl;
sqlite3_free(zErrMsg);
}
else{
fprintf(stdout, "Records created successfully\n");
}
// _sleep(3000);
sqlite3_close(db);
My issue is I have a szBuffer which changes everytime, and I have to insert it as a new entry into the table.
Is there a way to increment the Primary Key and store my string into it?
The sz buffer at a single line will give data like: For Ex:
szBuffer : ersion = 1 [SPI]: MinorVersion = 2 [SPI]: Real Time
= 1434260351 [SPI]: SR # = SBB-ST1000090
The SQL command in the string I pass is like this:
SQL COMMAND : INSERT INTO M_DATA (ID, DETAILS) VALUES(9,
'ersion = 1 [SPI]: MinorVersion = 2 [SPI]: Real Time = 1434260351
[SPI]: SR # = SBB-ST1000090');
The Error which I get is like:
SQL ERROR : near "¸”_": syntax error
I am not sure if I am doing this right or wrong.
Can we use the insert statement in a loop? Am I passing the string the right way? (It looks correct to me when I print it out.)
But why do I get an error?
Is there any better way to enter my data?
I am very new to this so I tried search the internet, but no one is doing it the way I did it.
Please help.
Many Thanks.
(Almost) never build a SQL statement via string concatenation. Use a prepared statement and bind the parameter values.
// Prepare the statement
sqlite3_stmt* stmt;
int result = sqlite3_prepare_v2(db, "INSERT INTO M_DATA (ID, DETAILS) VALUES(?, ?);", -1, &stmt, nullptr);
// TODO: Handle when result != SQLITE_OK
while(/* whatever you wanted to loop on */)
{
// Bind in the parameter values
result = sqlite3_bind_int(stmt, 1, id_count);
// TODO: Handle when result != SQLITE_OK
result = sqlite3_bind_text(stmt, 2, szBuffer, -1, SQLITE_STATIC);
// TODO: Handle when result != SQLITE_OK
// Invoke the statement
result = sqlite3_step(stmt);
// TODO: Handle when result != SQLITE_OK
// Reset the statement to allow binding variables on the next iteration
result = sqlite3_reset(stmt);
}
// Release the statement
sqlite3_finalize(stmt);
I am trying to save the contents of the key and value of a map into a database table. The .dbo file is created, but nothing goes into the table. It doesn't create table but it doesn't exit. I wonder what is wrong with my code.
void names_table( std::map<std::string, unsigned int> &names ){
std::string sql;
std::string str1;
std::string str2;
std::string str3;
sqlite3_stmt *stmt;
const char *file_names = create_db_file( ); /* default to temp db */
sqlite3 *db;
sqlite3_initialize( );
int rc = sqlite3_open_v2( file_names, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
if ( rc != SQLITE_OK) {
sqlite3_close( db );
cout << "Error: Database cannot open!" << endl;
exit( EXIT_FAILURE);
}
sql = "CREATE TABLE IF NOT EXISTS names_table (offset INTEGER PRIMARY KEY, stname TEXT);";
sqlite3_prepare_v2(db, sql.c_str(), sql.size(), &stmt, NULL);
if (sqlite3_step(stmt) != SQLITE_DONE) cout << "Didn't Create Table!" << endl;
for (auto pm = names.begin(); pm != names.end(); pm++) {
str2 = "'" + pm->first + "'";
char tmp[15];
sprintf(tmp,"%u",pm->second);
str3 = tmp;
str1 = (((("INSERT INTO names_table VALUES(" + str3) + ", ") + str2) + ");");
std::cout << str1 << std::endl;
sql = (char *)str1.c_str();
// stmt = NULL;
rc = sqlite3_prepare_v2(db, sql.c_str(), sql.size(), &stmt, NULL);
if ( rc != SQLITE_OK) {
sqlite3_close(db);
cout << "Error: Data cannot be inserted!" << endl;
exit ( EXIT_FAILURE);
}
}
sqlite3_close( db );
}
INSERT INTO names_table VALUES(ramsar, 8329) - I hope you're aware that string literals in SQL need to be enclosed in quotes. Try this: INSERT INTO names_table VALUES('ramsar', 8329).
EDIT: Actually, your code will never do what you want, because you're not even calling sqlite3_step after sqlite3_prepare_v2, which means that you're only compiling your SQL statement, but never evaluating it. Where did you find this bad example? See here and here decent examples on how to use the SQLite C++ interface properly.
PS: Stop messing around with sprintf in C++. You have std::stringstream for it.