Poco C++ with MS SQL using ODBC - c++

I am trying to connect to the Microsoft SQL Server database with Poco C++ via ODBC. I have tried to find examples, but havent come across any.
I am simply trying to connect to my database with the following code
#include <iostream>
#include <string>
#include "Poco/Data/Session.h"
using namespace std;
using namespace Poco::Data;
int main()
{
cout << "Testing Poco C++ with MS SQL Server" << endl;
const string CONNECTION_STRING("DRIVER={SQL Server};Server=DESKTOP-32BKOVJ\\SQLEXPRESS;Database=Test2;User ID=sa;Password=IaSS1982;Trusted_Connection=yes;");
Session session("ODBC", CONNECTION_STRING);
return 0;
}
Every time I run this code, I get the following assertion failure:
Assertion violation: _connectors.end() != it [in file "src\SessionFactory.cpp", line 70]
How can I create a simple connection to the MS SQL Database using Poco C++ and ODBC and then print some records on the console?
I was referring to the article Poco ODBC and while SQL loop while trying to write this code.
Any help will be greatly appreciated.
Thank you

I am able to connect to my Microsoft SQL Server 2014 Database using Poco C++ library. Once you have the ODBC drivers installed which are a part of the Windows SDK, the following code should do all basic operations such as
- Create
- Read
- Update
- Delete
#include <iostream>
#include <string>
#include <sstream>
#include "Poco/Data/RecordSet.h"
#include "Poco/Data/Session.h"
#include "Poco/Data/ODBC/Connector.h"
using namespace std;
using namespace Poco::Data;
bool AddUser(Session& session, const size_t& USER_ID, const string& FIRST_NAME, const string& LAST_NAME); // [C]reate
void PrintUsers(Session& session); // [R]etrieve
bool UpdateLastName(Session& session, const string& FIRST_NAME, const string& NEW_LAST_NAME); // [U]pdate
bool DeleteUser(Session& session, const size_t& USER_ID); // [D]elete
int main()
{
try
{
cout << "Testing Poco C++ with MS SQL Server" << endl;
Poco::Data::ODBC::Connector::registerConnector();
const string CONNECTION_STRING("DRIVER={SQL Server};Server=DESKTOP-32BKOVJ\\SQLEXPRESS;Database=Test2;User ID=sa;Password=abc");
//const string CONNECTION_STRING("DSN=PocoMsSQLTest;Uid=sa;Pwd=abc");
Session session("ODBC", CONNECTION_STRING);
if (session.isConnected())
{
PrintUsers(session);
cout << "\n" << endl;
AddUser(session, 5, "Loki", "Moki");
PrintUsers(session);
cout << "\n" << endl;
UpdateLastName(session, "Loki", "Poki");
PrintUsers(session);
cout << "\n" << endl;
DeleteUser(session, 5);
PrintUsers(session);
cout << "\n" << endl;
}
else
{
cerr << "Session not able to connect" << endl;
}
}
catch (const exception& e)
{
cerr << "Exception: " << e.what() << endl;
}
////////////////////////////////////////////////////////
Poco::Data::ODBC::Connector::unregisterConnector();
return 0;
}
// Create
bool AddUser(Session& session, const size_t& USER_ID, const string& FIRST_NAME, const string& LAST_NAME)
{
Statement select(session);
stringstream ss;
ss << "INSERT INTO Users (UserID, FirstName, LastName) VALUES (";
ss << USER_ID << ", " << "\'" << FIRST_NAME << "\'" << ", " << "\'" << LAST_NAME << "\')";
const string& SQL = ss.str();
select << SQL;
return select.execute();
}
// Retrieve
void PrintUsers(Session& session)
{
Statement select(session);
select << "SELECT * FROM Users";
select.execute();
RecordSet rs(select);
bool more = rs.moveFirst();
if (more)
{
cout << rs.columnName(0) << "\t" << rs.columnName(1) << "\t" << rs.columnName(2) << endl;
}
while (more)
{
cout << rs[0].convert<string>() << "\t" << rs[1].convert<string>() << "\t\t" << rs[2].convert<string>() << endl;
more = rs.moveNext();
}
}
// Update
bool UpdateLastName(Session& session, const string& FIRST_NAME, const string& NEW_LAST_NAME)
{
Statement select(session);
stringstream ss;
ss << "UPDATE Users SET LastName=" << "\'" << NEW_LAST_NAME << "\'" << " WHERE FirstName=" << "\'" << FIRST_NAME << "\'";
const string& SQL = ss.str();
select << SQL;
return select.execute();
}
// Delete
bool DeleteUser(Session& session, const size_t& USER_ID)
{
Statement select(session);
stringstream ss;
ss << "DELETE FROM Users WHERE UserID = " << USER_ID;
const string& SQL = ss.str();
select << SQL;
return select.execute();
}
The CONNECTION_STRING that I am using is using the ODBC drivers directly to connect to the database. If you want to use a DSN to connect to the database then comment this CONNECTION_STRING and uncomment the one below.
I did a little bit of research on what is DSN and how to create it in Windows 10. My findings are given below.
What is a DSN?
See https://en.wikipedia.org/wiki/Data_source_name
Creating an ODBC Data Source Name (DSN)
1. Windows 10 search for ODBC
2. Click on Set up ODBC data sources (32-bit)
3. Under the tab "User DSN", click Add
Create New Data Source wizard will start.
4. Select SQL Server and click Finish
5. In the next window
- Give a name. This is the DSN
- Give description
- Click the drop down associated with Server
- Wait for a few seconds
- Databases on your computer or network will show
- Select the database server you want to connect to.
- Click Next
6. In the next window
- Select with SQL Server Authentication
- Enter your Login ID (Username) and Password for that database
- Click Next
7. In the next window
- Select "Change the default database to:" the database you want to connect.
- Click Next
8. In the next window you don't have to change anything just click Finish.
9. A new window appears which has all your DSN information.
10. To test the DSN connection click on "Test Data Source..."
- If everything is ok, a new window appears "TESTS COMPLETED SUCCUSSFULLY!"
- Click OK to exit the result window.
11. Click OK again finish the setup.
12. In the main Window under User Data Sources you will see your newly created DSN.
13. Click OK to exit.
Source: https://www.youtube.com/watch?v=ehVFtmhPwxs

Related

C++ app MySQL odbc database connection error: terminate called after throwing an instance of 'otl_tmpl_exception<>

I am currently debugging a containerized C++ application, it seems like it's throwing exception and complaining about the database connection, error:
terminate called after throwing an instance of 'otl_tmpl_exception<odbc::otl_exc, odbc::otl_conn, odbc::otl_cur>'
Aborted
The code in main() is below:
int main(int ac, char *av[])
{
auto otl_connect = std::make_unique<odbc::otl_connect>("Driver={/usr/local/lib/libmyodbc8a.so};server=xxx.x.x.x;port=xxxx;database=xxxx;user=xxx;password=xxx");
std::stringstream query;
query << "SELECT x FROM xxx.xxxs;";
odbc::otl_stream the_stream(1000, query.str().c_str(), *otl_connect);
std::string
int val;
while(!the_stream.eof())
{
the_stream >> xxx >> val;
std::cout << xxx << " " << val << "\n";
}
the_stream.close();
}
I'm totally new to C++, can someone explain what the codes in main() is doing and how to fix the exception error message, I've been working on this for a whole afternoon, exhausted....help!!!!
I'm not very familiar with the Oracle, ODBC and DB2-CLI Template Library but I had a go using it with a MySql database on my Ubuntu Linux.
This is how I was able to run a simple query. I think the code below is fairly self-explanatory.
As you'll see, it's quite different from your code. The driver is mysql. You have to substitute ... with the real database name, user name and password of your database. You also have to initialise the ODBC environment first and connect to your database using rlogon().
#include <iostream>
#define OTL_ODBC // Compile OTL 4.0/ODBC
#define OTL_ODBC_UNIX
#include "otlv4.h"
int main()
{
otl_connect db; // connect object
otl_connect::otl_initialize(); // initialize ODBC environment
try {
db.rlogon("DRIVER=mysql;DB=...;UID=...;PWD=..."); // connect to ODBC
otl_stream os(50, "SELECT id FROM task", db);
int id;
// SELECT automatically executes when all input variables are assigned
while (!os.eof())
{
os >> id;
std::cout << "id=" << id << std::endl;
}
}
catch(otl_exception& p) { // intercept OTL exceptions
std::cerr << p.msg << std::endl; // print out error message
std::cerr << p.stm_text << std::endl; // print out SQL that caused the error
std::cerr << p.sqlstate << std::endl; // print out SQLSTATE message
std::cerr << p.var_info << std::endl; // print out the variable that caused the error
}
return 0;
}
Make sure that you have a variable for each field you want to read from the query result. It seems that you can't extract values into std::string variables; you have to use char arrays (e.g. char name[20]) instead.
Hope this helps.

Increase blob upload performance

I am working on integrating a c++ application with Azure blob storage.
To achieve this I have implemented a wrapper class around wastorage 4.0 APIs.
#include "stdafx.h"
#include "AzureStorage.h"
// Microsoft Azure Library Header Includes.
#include "was\storage_account.h"
#include "was\blob.h"
struct RadAzureData{
azure::storage::cloud_storage_account storage_account;
azure::storage::cloud_blob_client blob_client;
azure::storage::cloud_blob_container container;
};
RadAzureStorage::RadAzureStorage():
RadCloudStorageInterface(RAD_STORAGE_TYPE::AZURE_CLOUD)
{
}
RadAzureStorage::RadAzureStorage(std::string accountName1, std::string accountKey1, std::string containerName1) : RadCloudStorageInterface(RAD_STORAGE_TYPE::AZURE_CLOUD)
{
std::wstring accountNameWS(accountName1.begin(), accountName1.end());
std::wstring accountKeyWS(accountKey1.begin(), accountKey1.end());
std::wstring containerNameWS(containerName1.begin(), containerName1.end());
d = new RadAzureData();
accountName = accountNameWS;
accountKey = accountKeyWS;
containerName = containerNameWS;
std::wstring connStr1 = L"AccountName=" + accountName + L";AccountKey=" + accountKey + L";DefaultEndpointsProtocol=https";
d->storage_account = azure::storage::cloud_storage_account::parse(connStr1.c_str());
// Create a blob container
d->blob_client = d->storage_account.create_cloud_blob_client();
d->container = d->blob_client.get_container_reference(containerName.c_str());
CreateContainer();
}
bool RadAzureStorage::CreateContainer()
{
try
{
d->container.create_if_not_exists();
}
catch (const azure::storage::storage_exception& e)
{
cout<<"Exception in container creation: " << e.what()<<endl;
cout <<"The request that started at:" << e.result().start_time().to_string().c_str() << " and ended at " << e.result().end_time().to_string().c_str() << " resulted in HTTP status code " << e.result().http_status_code() << " and the request ID reported by the server was " << e.result().service_request_id().c_str()<<endl;
return false;
}
return true;
}
bool RadAzureStorage::UploadFile(std::string blockBlobName, std::string dicomFileLocation)
{
std::wstring blockBlobNameWS(blockBlobName.begin(), blockBlobName.end());
std::wstring dicomFileLocationWS(dicomFileLocation.begin(), dicomFileLocation.end());
// Create a Block Blob Object.
azure::storage::cloud_block_blob block_blob = d->container.get_block_blob_reference(blockBlobNameWS.c_str());
// Upload Block Blob to container.
try
{
block_blob.upload_from_file(dicomFileLocationWS.c_str());
}
catch (const azure::storage::storage_exception& e)
{
cout<< "Exception in file upload: " << e.what() << endl;
cout<< "The request that started at:" << e.result().start_time().to_string().c_str() << " and ended at " << e.result().end_time().to_string().c_str() << " resulted in HTTP status code " << e.result().http_status_code() << " and the request ID reported by the server was " << e.result().service_request_id().c_str() << endl;
return false;
}
return true;
}
#undef __FILENAME__
From the application, it instantiates RadAzureStorage class and calls UploadFile API.
RadAzureStorage* clsi = new RadAzureStorage(accountname, acesskey, containername);
<<timer.start>>
clsi->UploadFile(blockBlobName, file);
<<timer.end>>
cout << timer.ellapsedMilliSeconds<< "ms"<< endl;
UploadFile API takes 14-16 ms for file sizes ranging between 190-250 KB.
Are there some parameters on wastorage initialization that can be modified to achieve this under 10 ms.
The current testing environment is hosted in Azure South India:
1. VM: Windows server 2016, 4v Core, 16 GB ram.
2. Hot tier access, storage account.
Please note: similar logic is implemented on C# where upload per file is being achieved under 10 ms for the same dataset.
This delay could be also caused by the type of storage accounts used. When using Premium storage accounts, you get higher performance vs GPV1.
there's also a new product that's still in Azure Premium blobs. Premium storage accounts are stored on SSD vs HDD, so you get a better performance as well when using GPV2 premium.

how to execute postgresql function with unnest array as parameter using libpqxx c++

I have created a postgresql function,
create or replace function check4(interval_ int[],password_ text[])
returns void as
$$
begin
EXECUTE '
INSERT INTO test(id,password)
SELECT unnest($1),unnest($2)'
USING $1,$2;
end;
$$
language plpgsql;
Then i tried to execute the above procedure from c++ using libpqxx
try
{
connection *conn;
conn = new connection("dbname = test user = postgres password = postgres hostaddr = 127.0.0.1 port = 5432");
if (conn->is_open()) {
cout<<"Opened database successfully:"<<std::endl<<std::flush;
}
else {
cout << "Can't open database" << std::endl << std::flush;
}
int arr_id[2] = { 1,2 };
string arr_pass[2] = { "hi","bye" };
work P(*conn);
conn->prepare("example", "select check4(UNNEST(:$1), UNNEST(:$2));");
for (int i = 0; i < 2; i++)
{
P.prepared("example")(arr_id[i])(arr_pass[i]).exec();
}
P.commit();
cout << "Records created successfully" << endl;
}
catch (const std::exception &e) {
cerr << e.what() << std::endl;
}
In this code, data is inserted one by one but i want the data to be inserted in bulk.I want to create array of 5000 records and insert in one shot.
Please anyone suggest me, How to pass array as parameter to a function?
Any help appreciated.
Thank you.

Simple solutions for integrating MySQL with C++?

What solutions are there for making a simple connection to a MySQL database in C++?
I find MySQL Connector from dev.mysql.com hard to integrate.
Anticipated thanks!
Its pretty simple to communicate with MySQL from C/C++ application
you need to include mysql.h header file
three basic APIs to connect and execute query
mysql_connect()
mysql_query()
mysql_close()
Link with mysql library (libMysql)
You could try the ODBC path, with a support library.
Some year ago I used OTL to interface SqlServer and found it efficient. Now I've tried to interface MySql, without any problem so far:
#include <otlv4.h>
#include <iostream>
using namespace std;
int otl_x_sql_main(int argc, char **argv)
{
otl_connect db; // connect object
otl_connect::otl_initialize(); // initialize ODBC environment
try {
db.rlogon("DRIVER=mysql;DB=...;UID=...;PWD=..."); // connect to ODBC
// parametrized SELECT
otl_stream i(50, "SELECT product_id,model FROM product WHERE product_id >= :f<int> AND product_id < :ff<int>", db);
int product_id;
char model[100];
i << 1000 << 2000; // assigning product_id range
// SELECT automatically executes when all input variables are assigned
while (!i.eof()) {
i >> product_id >> model;
cout << "product_id=" << product_id << ", model=" << model << endl;
}
}
catch(otl_exception& p) { // intercept OTL exceptions
cerr << p.msg << endl; // print out error message
cerr << p.stm_text << endl; // print out SQL that caused the error
cerr << p.sqlstate << endl; // print out SQLSTATE message
cerr << p.var_info << endl; // print out the variable that caused the error
}
return 0;
}

SOCI (SQL C++ wrapper) - PostgreSQL doesn't execute commands (?)

When i figured out how to compile a simple program, now I have other problem ... I installed PostgreSQL and created database and table:
1) createdb testDB 2) create table cities (city varchar(80), location
varchar(80));
And my still very simple program :
#include <iostream>
#include <soci.h>
#include <postgresql/soci-postgresql.h>
#include <string>
using namespace std;
int main(int argc, char **argv)
{
try
{
soci::session sql(soci::postgresql, "dbname=testDB");
string row = "";
sql << "select * from cities;", soci::into(row);
sql << "insert into cities values('London', 'UK')";
sql << "select * from cities;", soci::into(row);
cout << row << "\n";
}
catch (soci::postgresql_soci_error const & e)
{
std::cerr << "PostgreSQL error: " << e.sqlstate() << " " << e.what() << std::endl;
}
catch (std::exception const & e)
{
std::cerr << "Some other error: " << e.what() << std::endl;
}
return 0;
}
This code shows me only rows I already have in my testDB and doesn't show a row that I've just inserted. For example: in my testDB, in table cities, I have:
Warsaw Poland
Berlin Germany
Paris France
and above code shows me:
Warsaw Poland
but doesn't show:
Berlin Germany
Paris France
London UK
Please, help:(
So, adding commit after sql << "insert into cities values ('London', 'UK')";
solve this problem.