We are using an Azure SQL Server 2017 database and wish to connect to it via c++. We have already achieved this incredible feat on windows but it is necessary to run this on ubuntu.
We installed the Linux ODBC 13 driver using this tutorial and our /etc/odbcinst.ini
file contains the following
[ODBC Driver 13 for SQL Server]
Description=Microsoft ODBC Driver 13 for SQL Server
Driver=/opt/microsoft/msodbcsql/lib64/libmsodbcsql-13.0.so.1.0
UsageCount=1
[ODBC]
Trace = Yes
TraceFile = /dev/stdout
Our code is as follows:
#include <iostream>
#include <string>
#include <sqlext.h>
#include <sqltypes.h>
#include <sql.h>
#include <stdio.h>
using namespace std;
int main() {
#define SQL_RESULT_LEN 240
#define SQL_RETURN_CODE_LEN 1024
//define handles and variables
SQLHDBC hdbc = SQL_NULL_HDBC; // Connection handle
SQLHANDLE sqlConnHandle = NULL;
SQLHANDLE sqlStmtHandle = NULL;
SQLHANDLE sqlEnvHandle;
SQLCHAR outstr[SQL_RETURN_CODE_LEN];
SQLRETURN retcode;
SQLSMALLINT outstrlen;
//allocations
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &sqlEnvHandle))
cout << "SQLAllocHandle err (ENV)" << endl;
if (SQL_SUCCESS != SQLSetEnvAttr(sqlEnvHandle, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0))
cout << "SQLSetEnvAttr err" << endl;
if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_DBC, sqlEnvHandle, &sqlConnHandle))
cout << "SQLAllocHandle (DBC) err" << endl;
//output
cout << "Attempting connection to SQL Server..." << endl;
//Connect to server
retcode = SQLDriverConnect(hdbc, NULL, (SQLCHAR *)"Driver={ODBC Driver 13 for SQL Server};Server=tcp:cppdatabase.database.windows.net,1433;Database=stockData;Uid=admin@cppdatabase;Pwd=password;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;", SQL_NTS, outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_NOPROMPT);
switch (retcode) {
case SQL_SUCCESS:
cout << "Successfully connected to SQL Server" << endl;
break;
case SQL_SUCCESS_WITH_INFO:
cout << "Successfully connected to SQL Server"<< endl;
break;
case SQL_INVALID_HANDLE:
cout << "Could not connect to SQL Server" << endl;
break;
case SQL_ERROR:
cout << "Could not connect to SQL Server ERR" << endl;
break;
default:
break;
}
}
Which we compile with g++ as follows: g++ -g mssql.cpp -fpermissive -lodbc -o mssql
This code however fails to connect and we get the following output (no compiling errors):
[ODBC][17915][1559000402.543184][__handles.c][460]
Exit:[SQL_SUCCESS]
Environment = 0xf04d10
[ODBC][17915][1559000402.543204][SQLSetEnvAttr.c][189]
Entry:
Environment = 0xf04d10
Attribute = SQL_ATTR_ODBC_VERSION
Value = 0x3
StrLen = 0
[ODBC][17915][1559000402.543216][SQLSetEnvAttr.c][363]
Exit:[SQL_SUCCESS]
[ODBC][17915][1559000402.543223][SQLAllocHandle.c][375]
Entry:
Handle Type = 2
Input Handle = 0xf04d10
[ODBC][17915][1559000402.543232][SQLAllocHandle.c][493]
Exit:[SQL_SUCCESS]
Output Handle = 0xf05610
Attempting connection to SQL Server...
[ODBC][17915][1559000402.543250][SQLDriverConnect.c][686]Error: SQL_INVALID_HANDLE
Could not connect to SQL Server
Could not connect to SQL Server ERR
The connection string we used came directly from the Azure portal (while the sensitive data has been replaced with generic variants) so we doubt there is any issue with that. We doubt it is a driver issue as ODBC successfully logs to stdout. So we imagine it must be a coding problem.
Any pointers (no pun intended)?
We solved it using a Domain Source Name (DNS). In our /etc/odbc.ini file we wrote:
[mssql]
Description = "Test for Microsoft SQL Server 2017 using ODBC 2013 driver"
Driver = /opt/microsoft/msodbcsql/lib64/libmsodbcsql-13.0.so.1.0
Database = stockData
Server = cppdatabase.database.windows.net
Port = 1433
And then we connected using the following code:
#include <iostream>
#include <string>
#include <sqlext.h>
#include <sqltypes.h>
#include <sql.h>
#include <stdio.h>
#include <cstdlib>
using namespace std;
int main() {
SQLHENV henv;
SQLHDBC hdbc;
SQLHSTMT hstmt;
SQLRETURN retcode;
SQLCHAR * OutConnStr = (SQLCHAR * )malloc(255);
SQLSMALLINT * OutConnStrLen = (SQLSMALLINT *)malloc(255);
// Allocate environment handle
retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
// Set the ODBC version environment attribute
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
// Allocate connection handle
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
// Set login timeout to 5 seconds
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);
// Connect to data source
retcode = SQLConnect(hdbc, (SQLCHAR*) "mssql", SQL_NTS, (SQLCHAR*) "QuantitateAdmin", 15, "SomeRandomPassword1", 19);
// Allocate statement handle
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
cout << "Success!" << endl;
retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
// Process data
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
}
SQLDisconnect(hdbc);
} else {
cout << "Error" << endl;
}
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
}
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.