Increase blob upload performance - c++

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.

Related

How to read values from memory address with DLL injected?

I successfully added Discord Rich Presence to an old game through DLL injection.
When I open the game the RPC kicks in, and it successfully updates my Discord Status.
I want go to further and make the RPC dynamic, reading values from the client itself.
I got the memory addresses from the client using Cheat Engine, these values are persisting through close/open the game again and again.
Now, I have tried several approaches to get this done.
As I am using an internal dll, I can directly read the values from the memory.
I want to read the level from the player
In the following code I'm trying to obtain the value from the address that stores the level of the player.
I'm using three different GetModuleHandles, just to see which could work.
DWORD moduleBase = (DWORD)GetModuleHandle("1.exe"); //GetModule1
DWORD anothermethod = (DWORD)GetModuleHandleA(0); //GetModule2
uintptr_t* p = (uintptr_t*)((uintptr_t)ExeBaseAddress + 0xD35240);
uintptr_t ModuleBaseAdrs = (DWORD&)*p;
printf("ModBaseAdrsLoc - %p, ModuleBaseAdrs - %X\n", p, ModuleBaseAdrs);
int* level = (int*)GetPointerAddress(moduleBase + 0xD35240, {});
DWORD level2DWORD = (DWORD)(anothermethod + 0x0D35240);
size_t ModuleBase = (size_t)GetModuleHandle("1.exe"); //GetModule3
size_t* Adr = reinterpret_cast<size_t*>((*reinterpret_cast<size_t*>(ModuleBase + 0xD35240)));
DWORD* levellevel = (DWORD*)0x0D35240;
Sleep(2000);
int PID = find("1.exe");
std::cout << "PID: " << PID << std::endl;
std::cout << "level2DWORD: " << level2DWORD << std::endl; //GetModule2
std::cout << "Level: " << level << std::endl; //GetModule1
std::cout << "LevelLevel: " << levellevel << std::endl;
std::cout << "Adr: " << Adr << std::endl; //GetModule3
This is what I get on the console
As you can see, I have tried different approaches but none of them results on the desired output.
Could you please light my path?
How can I successfully read from the memory addresses?

C++ 'speechapi_cxx.h': No such file or directory Visual Studio

I'm trying voice to text functions at Visual Studio 2019. I found this code on Microsoft website yet compiler says 'speechapi_cxx.h': No such file or directory.
........................................................................
#include <iostream> // cin, cout
#include <speechapi_cxx.h>
using namespace std;
using namespace Microsoft::CognitiveServices::Speech;
void recognizeSpeech() {
// Creates an instance of a speech config with specified subscription key and service region.
// Replace with your own subscription key and service region (e.g., "westus").
auto config = SpeechConfig::FromSubscription("YourSubscriptionKey", "YourServiceRegion");
// Creates a speech recognizer
auto recognizer = SpeechRecognizer::FromConfig(config);
cout << "Say something...\n";
// Starts speech recognition, and returns after a single utterance is recognized. The end of a
// single utterance is determined by listening for silence at the end or until a maximum of 15
// seconds of audio is processed. The task returns the recognition text as result.
// Note: Since RecognizeOnceAsync() returns only a single utterance, it is suitable only for single
// shot recognition like command or query.
// For long-running multi-utterance recognition, use StartContinuousRecognitionAsync() instead.
auto result = recognizer->RecognizeOnceAsync().get();
// Checks result.
if (result->Reason == ResultReason::RecognizedSpeech) {
cout << "We recognized: " << result->Text << std::endl;
}
else if (result->Reason == ResultReason::NoMatch) {
cout << "NOMATCH: Speech could not be recognized." << std::endl;
}
else if (result->Reason == ResultReason::Canceled) {
auto cancellation = CancellationDetails::FromResult(result);
cout << "CANCELED: Reason=" << (int)cancellation->Reason << std::endl;
if (cancellation->Reason == CancellationReason::Error) {
cout << "CANCELED: ErrorCode= " << (int)cancellation->ErrorCode << std::endl;
cout << "CANCELED: ErrorDetails=" << cancellation->ErrorDetails << std::endl;
cout << "CANCELED: Did you update the subscription info?" << std::endl;
}
}
}
int main(int argc, char** argv) {
setlocale(LC_ALL, "");
recognizeSpeech();
return 0;
}
Speech SDK is not installed on your machine. You may download it here https://learn.microsoft.com/en-us/azure/cognitive-services/speech-service/speech-sdk

Native C++ node.js module addon WinHttp Detect Auto Proxy Config Url Error return

I am stuck in a tight spot and I need some help with some C++ code. This is my first attempt at doing C++ and it born mostly from necessity at this point.
I am trying (unsuccessfully it feels) to build a native NAN module for Node.JS that will be used by an Electron app on Windows.
I need it to return the WinHttpDetectAutoProxyConfigUrl when the users Proxy configuration is set to Auto Detect.
I have built this exact thing in C# for another application and it works seamlessly in our distributed user BYOD environment. However in this case I do not wish to be dependent on the dot.net framework unnecessarily.
Right know I am at the extent of my knowledge when it comes to C++ as most of my knowledge over the years has thus far been theoretical. I am hoping that someone that actually works in C++ daily can look at my code and help correct the error that is happening.
I have been trying to debug using the “std::cout” in VSCode.
As you can see from the output at the bottom of the image, that some of it appears to be working and the code is dropping into the “Get Auto URL” IF block as expected. However the output is very iritic (“�����”) and nothing like the wpad.dat URL I was expecting to see returned from the wpad protocol implemented by the winhttp.dll.
My Problem:
It is as though the result is blank and then the “char buffer[2083];” is being sent to the stdOut and the characters are all encoded wrong.
Any help on this would be very helpful so thanks in advance.
Please see the code below.
main.cpp
#include <nan.h>
#include <Windows.h>
#include <Winhttp.h>
#include <iostream>
#pragma comment(lib, "winhttp.lib")
using namespace std;
// NAN_METHOD is a Nan macro enabling convenient way of creating native node functions.
// It takes a method's name as a param. By C++ convention, I used the Capital cased name.
NAN_METHOD(AutoProxyConfigUrl) {
cout << "AutoProxyConfigUrl" << "\n";
v8::Isolate* isolate = info.GetIsolate(); // args.GetIsolate();
LPWSTR strConfigUrl = NULL;
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG MyProxyConfig;
if(!WinHttpGetIEProxyConfigForCurrentUser(&MyProxyConfig))
{
//check the error DWORD Err = GetLastError();
DWORD Err = GetLastError();
cout << "WinHttpGetIEProxyConfigForCurrentUser failed with the following error number: " << Err << "\n";
switch (Err)
{
case ERROR_FILE_NOT_FOUND:
cout << "The error is ERROR_FILE_NOT_FOUND" << "\n";
break;
case ERROR_WINHTTP_INTERNAL_ERROR:
cout << "ERROR_WINHTTP_INTERNAL_ERROR" << "\n";
break;
case ERROR_NOT_ENOUGH_MEMORY:
cout << "ERROR_NOT_ENOUGH_MEMORY" << "\n";
break;
default:
cout << "Look up error in header file." << "\n";
break;
}//end switch
//TODO this might not be a good idea but it is worth trying
strConfigUrl = L"http://wpad/wpad.dat"; //Default to Fallback wpad
}//end if
else
{
//no error so check the proxy settings and free any strings
cout << "Auto Detect is: " << MyProxyConfig.fAutoDetect << "\n";
if(MyProxyConfig.fAutoDetect){
cout << "Get Auto URL" << "\n";
if (!WinHttpDetectAutoProxyConfigUrl(WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A, &strConfigUrl))
{
cout << "Error getting URL" << "\n";
//This error message is not necessarily a problem and can be ignored if you are using direct connection. you get this error if you are having direct connection.
//check the error DWORD Err = GetLastError();
DWORD Err = GetLastError();
if (ERROR_WINHTTP_AUTODETECTION_FAILED == Err)
{
strConfigUrl = L"http://wpad/wpad.dat"; //Default to Fallback wpad
}
//TODO work out what to do with the other errors
}
}
if(NULL != MyProxyConfig.lpszAutoConfigUrl)
{
wcout << "AutoConfigURL (MyProxyConfig.lpszAutoConfigUrl) is: " << MyProxyConfig.lpszAutoConfigUrl << "\n";
GlobalFree(MyProxyConfig.lpszAutoConfigUrl);
}
if(NULL != MyProxyConfig.lpszProxy)
{
wcout << "AutoConfigURL (MyProxyConfig.lpszProxy) is: " << MyProxyConfig.lpszProxy << "\n";
GlobalFree(MyProxyConfig.lpszProxy);
}
if(NULL != MyProxyConfig.lpszProxyBypass)
{
wcout << "AutoConfigURL is: " << MyProxyConfig.lpszProxyBypass << "\n";
GlobalFree(MyProxyConfig.lpszProxyBypass);
}
}//end else
//cout << "strConfigUrl" << strConfigUrl << "\n";
char buffer[2083];
wcstombs( buffer, strConfigUrl, wcslen(strConfigUrl) ); // Need wcslen to compute the length of the string
// convert it to string
std::string returnUrl(buffer);
// Create an instance of V8's String type
auto message = Nan::New(returnUrl).ToLocalChecked();
// 'info' is a macro's "implicit" parameter - it's a bridge object between C++ and JavaScript runtimes
// You would use info to both extract the parameters passed to a function as well as set the return value.
info.GetReturnValue().Set(message);
if(strConfigUrl)
GlobalFree(strConfigUrl);
}
// Module initialization logic
NAN_MODULE_INIT(Initialize) {
// Export the `Hello` function (equivalent to `export function Hello (...)` in JS)
NAN_EXPORT(target, AutoProxyConfigUrl);
}
// Create the module called "addon" and initialize it with `Initialize` function (created with NAN_MODULE_INIT macro)
NODE_MODULE(proxyautodetect, Initialize);
main.js
// note that the compiled addon is placed under following path
//const {AutoProxyConfigUrl} = require('./build/Release/proxyautodetect.node');
const {AutoProxyConfigUrl} = require('./build/Debug/proxyautodetect.node');
// `Hello` function returns a string, so we have to console.log it!
console.log(AutoProxyConfigUrl());
Build and Run output:
C:\Code\Work\wpad-auto-detect>if not defined npm_config_node_gyp (node "C:\Program Files\nodejs\node_modules\npm\node_modules\npm-lifecycle\node-gyp-bin\\..\..\node_modules\node-gyp\bin\node-gyp.js" rebuild --debug ) else (node "C:\Program Files\nodejs\node_modules\npm\node_modules\node-gyp\bin\node-gyp.js" rebuild --debug )
Building the projects in this solution one at a time. To enable parallel build, please add the "/m" switch.
main.cpp
win_delay_load_hook.cc
Creating library C:\Code\Work\wpad-auto-detect\build\Debug\proxyautodetect.lib and object C:\Code\Work\wpad-auto-detect\build\Debug\proxyautodet
ect.exp
proxyautodetect.vcxproj -> C:\Code\Work\wpad-auto-detect\build\Debug\\proxyautodetect.node
PS C:\Code\Work\wpad-auto-detect> npm start
> proxyautodetect#1.0.0 start C:\Code\Work\wpad-auto-detect
> node main.js
AutoProxyConfigUrl
Auto Detect is: 1
Get Auto URL
"
"��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������1��J╗
PS C:\Code\Work\wpad-auto-detect>
Image of code output
I did a sort of Trim
int urlLen = wcslen(strConfigUrl) ;
#if DEBUG
cout << "strConfigUrl wcslen : " << urlLen << "\n";
#endif
char buffer[2083]; //This is the max length a URL can be in IE
wcstombs( buffer, strConfigUrl, wcslen(strConfigUrl) ); // Need wcslen to compute the length of the string
// convert it to string
std::string returnUrl(buffer);
// Create an instance of V8's String type and Return only the Length needed so kind of Trim the extra char
auto message = Nan::New(returnUrl.substr(0, urlLen)).ToLocalChecked();

AWS CPP TransferManager vs GetObjectRequest Stream to File fstream OOM

I am using the AWS CPP SDK ( https://github.com/aws/aws-iot-device-sdk-cpp ) to download a file from S3 on a small Linux system ( only 32 MB RAM ). I was using the GetObjectRequest class as shown below. It worked great and downloaded the file to the FStream on my system so that it did not consume too much RAM.
Now, I want to convert the download code to the TransferManager method in order to get progress callbacks. I've rewritten that part of the code and it is shown below as well. It starts out fine, prints the percentage downloaded, but when it reached ~14 MB RAM ( roughly the amount available in Linux at the time of download ) it is killed by the kernel for using too much RAM.
I created a file stream just like I did for the GetObjectRequest. What am I doing wrong? How can I fix this? Thanks.
Old way that did not use all the RAM:
// Old way
GetObjectRequest getObjectRequest;
getObjectRequest.SetBucket(bucket.c_str());
getObjectRequest.SetKey(keyName.c_str());
getObjectRequest.SetResponseStreamFactory([&destination](){
return Aws::New<Aws::FStream>(
"s3file", destination, std::ios_base::out); });
GetObjectOutcome getObjectOutcome = SessionClient->GetObject(getObjectRequest);
if(getObjectOutcome.IsSuccess())
{
std::cout << "<AWS DOWNLOAD> Get FW success!" << std::endl;
}
else
{
std::cout << "<AWS DOWNLOAD> Get FW failed: " << getObjectOutcome.GetError().GetMessage() << std::endl;
exit(1);
}
New way that eventually uses too much RAM and is killed by the kernel:
// New way
Aws::Transfer::TransferManagerConfiguration transferConfig;
transferConfig.s3Client = SessionClient;
std::shared_ptr<Aws::Transfer::TransferHandle> requestPtr(nullptr);
transferConfig.downloadProgressCallback =
[](const Aws::Transfer::TransferManager*, const Aws::Transfer::TransferHandle& handle)
{
std::cout << "\r" << "<AWS DOWNLOAD> Download Progress: " << static_cast<int>(handle.GetBytesTransferred() * 100.0 / handle.GetBytesTotalSize()) << " Percent " << handle.GetBytesTransferred() << " bytes\n";
};
Aws::Transfer::TransferManager transferManager(transferConfig);
requestPtr = transferManager.DownloadFile(bucket.c_str(), keyName.c_str(), [&destination](){
Aws::FStream *stream = Aws::New<Aws::FStream>("s3file", destination, std::ios_base::out);
stream->rdbuf()->pubsetbuf(NULL, 0);
return stream; });
requestPtr->WaitUntilFinished();
size_t retries = 0;
//just make sure we don't fail because a download part failed. (e.g. network problems or interuptions)
while (requestPtr->GetStatus() == Aws::Transfer::TransferStatus::FAILED && retries++ < 5)
{
std::cout << "<AWS DOWNLOAD> FW Download trying download again!" << std::endl;
transferManager.RetryDownload(requestPtr);
requestPtr->WaitUntilFinished();
}
// Check status
if ( requestPtr->GetStatus() == Aws::Transfer::TransferStatus::COMPLETED ) {
if ( requestPtr->GetBytesTotalSize() == requestPtr->GetBytesTransferred() ) {
std::cout << "<AWS DOWNLOAD> Get FW success!" << std::endl;
exit(0);
}
else {
std::cout << "<AWS DOWNLOAD> Get FW failed - Bytes downloaded did not equal requested number of bytes: " << requestPtr->GetBytesTotalSize() << requestPtr->GetBytesTransferred() << std::endl;
exit(1);
}
}
else {
std::cout << "<AWS DOWNLOAD> Get FW failed - download was never completed even after retries" << std::endl;
exit(1);
}
TransferManager only really makes things easier once you are in the land of 10mb or larger and you want to take advantage of parallelization. It will allocate the max heap size up front and not grow the heap larger than that. Given your RAM constraints, I wouldnt use TransferManager. You can still receive the progress notifications. Check the callback mechanisms in the AmazonWebServiceRequest class.

Poco C++ with MS SQL using ODBC

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