#include #include #include #include #include #include #include #include void CheckFunction (SQLRETURN theReturnCode, char const * theFileName, int theLineNumber) { if (theReturnCode != SQL_SUCCESS && theReturnCode != SQL_SUCCESS_WITH_INFO && theReturnCode != SQL_NO_DATA) { std::ostringstream out; out << "SQL function returned " << theReturnCode << " at " << theLineNumber << " in " << theFileName; throw std::runtime_error (out.str ()); } } #define CHECK(rc) CheckFunction (rc, __FILE__, __LINE__) void TestODBCConnection () { SQLHENV env = SQL_NULL_HENV; CHECK (SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, & env)); CHECK (SQLSetEnvAttr (env, SQL_ATTR_ODBC_VERSION, reinterpret_cast (SQL_OV_ODBC3), SQL_IS_INTEGER)); SQLHDBC dbc = SQL_NULL_HDBC; CHECK (SQLAllocHandle (SQL_HANDLE_DBC, env, & dbc)); SQLCHAR inConnectString [] = "DSN=MSSQL;UID=uid;PWD=password;DATABASE=databasename"; SQLCHAR outConnectString [4096]; SQLSMALLINT outStringLength = 0; CHECK (SQLDriverConnect (dbc, nullptr, inConnectString, std::size (inConnectString) - 1, outConnectString, std::size (outConnectString), & outStringLength, SQL_DRIVER_NOPROMPT)); long sessionId = 0; { SQLHSTMT stmt = SQL_NULL_HSTMT; CHECK (SQLAllocHandle (SQL_HANDLE_STMT, dbc, & stmt)); CHECK (SQLSetStmtAttr (stmt, SQL_ATTR_CURSOR_SENSITIVITY, reinterpret_cast (SQL_INSENSITIVE), SQL_IS_UINTEGER)); SQLCHAR stmtText [] = "select @@spid"; CHECK (SQLExecDirect (stmt, stmtText, std::size (stmtText) - 1)); SQLLEN bufLen = 0; CHECK (SQLBindCol (stmt, 1, SQL_C_SLONG, & sessionId, sizeof (sessionId), & bufLen)); CHECK (SQLFetch (stmt)); CHECK (SQLFreeHandle (SQL_HANDLE_STMT, stmt)); } CHECK (SQLSetConnectAttr (dbc, SQL_PRESERVE_CURSORS, reinterpret_cast (SQL_PC_ON), SQL_IS_INTEGER)); CHECK (SQLSetConnectAttr (dbc, SQL_ATTR_TXN_ISOLATION, reinterpret_cast (SQL_TXN_READ_UNCOMMITTED), SQL_IS_UINTEGER)); CHECK (SQLSetConnectAttr (dbc, SQL_AUTOCOMMIT_OFF, reinterpret_cast (SQL_AUTOCOMMIT_OFF), SQL_IS_UINTEGER)); { SQLHSTMT stmt = SQL_NULL_HSTMT; CHECK (SQLAllocHandle (SQL_HANDLE_STMT, dbc, & stmt)); CHECK (SQLSetStmtAttr (stmt, SQL_ATTR_CURSOR_SENSITIVITY, reinterpret_cast (SQL_INSENSITIVE), SQL_IS_UINTEGER)); SQLCHAR stmtText [] = "set xact_abort off set dateformat ymd"; CHECK (SQLExecDirect (stmt, stmtText, std::size (stmtText) - 1)); CHECK (SQLFreeHandle (SQL_HANDLE_STMT, stmt)); } SQLSetConnectAttr (dbc, SQL_ATTR_AUTOCOMMIT, reinterpret_cast (SQL_AUTOCOMMIT_OFF), SQL_IS_UINTEGER); { SQLHSTMT stmt = SQL_NULL_HSTMT; CHECK (SQLAllocHandle (SQL_HANDLE_STMT, dbc, & stmt)); CHECK (SQLSetStmtAttr (stmt, SQL_ATTR_CURSOR_SENSITIVITY, reinterpret_cast (SQL_INSENSITIVE), SQL_IS_UINTEGER)); SQLCHAR stmtText2 [] = "delete from LOCKTABLE where SESSIONID=?"; CHECK (SQLPrepare (stmt, stmtText2, std::size (stmtText2) - 1)); SQLSMALLINT dataType = 0; SQLULEN paramSize = 0; SQLSMALLINT scale = 0; SQLSMALLINT isNullable = 0; CHECK (SQLDescribeParam (stmt, 1, & dataType, & paramSize, & scale, & isNullable)); SQLLEN bufLen = 0; CHECK (SQLBindParameter (stmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, dataType, paramSize, scale, & sessionId, sizeof (sessionId), & bufLen)); CHECK (SQLExecute (stmt)); CHECK (SQLFreeHandle (SQL_HANDLE_STMT, stmt)); } { SQLHDBC dbc = SQL_NULL_HDBC; CHECK (SQLAllocHandle (SQL_HANDLE_DBC, env, & dbc)); CHECK (SQLSetConnectAttr (dbc, SQL_PRESERVE_CURSORS, reinterpret_cast (SQL_PC_ON), SQL_IS_INTEGER)); SQLCHAR dsn [] = "HermesEntMSQ"; SQLCHAR uid [] = "HERMES001"; SQLCHAR pwd [] = "Sopho~24Kles"; CHECK (SQLConnect (dbc, dsn, std::size (dsn) - 1, uid, std::size (uid) - 1, pwd, std::size (pwd) - 1)); { SQLHSTMT stmt = SQL_NULL_HSTMT; CHECK (SQLAllocHandle (SQL_HANDLE_STMT, dbc, & stmt)); CHECK (SQLSetStmtAttr (stmt, SQL_ATTR_CURSOR_SENSITIVITY, reinterpret_cast (SQL_INSENSITIVE), SQL_IS_UINTEGER)); SQLCHAR stmtText [] = "select @@spid"; CHECK (SQLExecDirect (stmt, stmtText, std::size (stmtText) - 1)); SQLLEN bufLen = 0; CHECK (SQLBindCol (stmt, 1, SQL_C_SLONG, & sessionId, sizeof (sessionId), & bufLen)); CHECK (SQLFetch (stmt)); CHECK (SQLFreeHandle (SQL_HANDLE_STMT, stmt)); } { SQLHSTMT stmt = SQL_NULL_HSTMT; CHECK (SQLAllocHandle (SQL_HANDLE_STMT, dbc, & stmt)); CHECK (SQLSetStmtAttr (stmt, SQL_ATTR_CURSOR_SENSITIVITY, reinterpret_cast (SQL_INSENSITIVE), SQL_IS_UINTEGER)); SQLCHAR stmtText [] = "set xact_abort off set dateformat ymd"; CHECK (SQLExecDirect (stmt, stmtText, std::size (stmtText) - 1)); CHECK (SQLFreeHandle (SQL_HANDLE_STMT, stmt)); } CHECK (SQLSetConnectAttr (dbc, SQL_AUTOCOMMIT_OFF, reinterpret_cast (SQL_AUTOCOMMIT_OFF), SQL_IS_UINTEGER)); CHECK (SQLSetConnectAttr (dbc, SQL_ATTR_TXN_ISOLATION, reinterpret_cast (SQL_TXN_READ_UNCOMMITTED), SQL_IS_UINTEGER)); SQLHSTMT stmt = SQL_NULL_HSTMT; SQLCHAR state [6]; SQLSMALLINT stateLength = 0; CHECK (SQLAllocHandle (SQL_HANDLE_STMT, dbc, & stmt)); CHECK (SQLSetStmtAttr (stmt, SQL_ATTR_CURSOR_SENSITIVITY, reinterpret_cast (SQL_INSENSITIVE), SQL_IS_UINTEGER)); SQLRETURN rc = SQLCloseCursor (stmt); if (rc == SQL_ERROR) { CHECK (SQLGetDiagField (SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_SQLSTATE, state, std::size (state), & stateLength)); if (strcmp (reinterpret_cast (state), "24000") != 0) CHECK (rc); } SQLCloseCursor (stmt); if (rc == SQL_ERROR) { CHECK (SQLGetDiagField (SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_SQLSTATE, state, std::size (state), & stateLength)); if (strcmp (reinterpret_cast (state), "24000") != 0) CHECK (rc); } SQLCloseCursor (stmt); if (rc == SQL_ERROR) { CHECK (SQLGetDiagField (SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_SQLSTATE, state, std::size (state), & stateLength)); if (strcmp (reinterpret_cast (state), "24000") != 0) CHECK (rc); } SQLCloseCursor (stmt); if (rc == SQL_ERROR) { CHECK (SQLGetDiagField (SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_SQLSTATE, state, std::size (state), & stateLength)); if (strcmp (reinterpret_cast (state), "24000") != 0) CHECK (rc); } CHECK (SQLFreeStmt (stmt, SQL_UNBIND)); CHECK (SQLFreeStmt (stmt, SQL_RESET_PARAMS)); SQLCHAR stmtText2 [] = "select CUSTOMERWOLEADS.PERSONNO,SD$ADDRESS$CONTACT$PHONE.NAME1,SD$ADDRESS$CONTACT$PHONE.COUNTRY," "SD$ADDRESS$CONTACT$PHONE.POSTCODE,SD$ADDRESS$CONTACT$PHONE.CITY,SD$ADDRESS$CONTACT$PHONE.PHONENUMBERFULL," "SD$ADDRESS$CONTACT$PHONE.MOBILENUMBERFULL,CUSTOMER.ACCOUNTDEBTOR,SD$LICENSEINFO.MAINTENANCECONTRACT," "KUNGRP.BRANCHE,SD$ADDRESS$CONTACT$PHONE.EMAILADDRESS,SD$ADDRESS$CONTACT$PHONE.STREETPOBOX," "SD$ADDRESS$CONTACT$PHONE.NAME2,SD$ADDRESS$CONTACT$PHONE.FAXNUMBERFULL,SD$ADDRESS$CONTACT$PHONE.FULLNAME," "CUSTOMER.NOTE,SD$ADDRESS$CONTACT$PHONE.SALUTATION,SD$ADDRESS$CONTACT$PHONE.SALUTATIONTITLE," "SD$ADDRESS$CONTACT$PHONE.DEPARTMENT,CUSTOMER.EUIDENTNO,CUSTOMER.INTERNALNUMBER " "from CUSTOMERWOLEADS,SD$ADDRESS$CONTACT$PHONE,CUSTOMER,SD$LICENSEINFO,KUNGRP where ((CUSTOMER.PERSONNO = CUSTOMERWOLEADS.PERSONNO " "and KUNGRP.PERSONNO = CUSTOMERWOLEADS.PERSONNO " "and SD$ADDRESS$CONTACT$PHONE.PERSONID = 'K' " "and SD$ADDRESS$CONTACT$PHONE.PERSONNO = CUSTOMERWOLEADS.PERSONNO) and " "(contains(CUSTOMERWOLEADS.PERSONNO,'\"+4921919355*\"') " "or contains(SD$ADDRESS$CONTACT$PHONE.MOBILENORMALIZED,'\"+4921919355*\"') " "or contains(SD$ADDRESS$CONTACT$PHONE.PHONENORMALIZED,'\"+4921919355*\"'))) " "order by CUSTOMERWOLEADS.U_PERSONNO"; CHECK (SQLPrepare (stmt, stmtText2, std::size (stmtText2) - 1)); SQLULEN rowArraySize = 0; CHECK (SQLGetStmtAttr (stmt, SQL_ATTR_ROW_ARRAY_SIZE, & rowArraySize, SQL_IS_UINTEGER, nullptr)); SQLSMALLINT numberOfResultColumns = 0; CHECK (SQLNumResultCols (stmt, & numberOfResultColumns)); std::vector , std::unique_ptr >> buffer; SQLULEN const rowsToFetch = 100; buffer.reserve (numberOfResultColumns); for (SQLSMALLINT i = 0; i < numberOfResultColumns; ++i) { SQLCHAR columnName [128] = {}; SQLSMALLINT columnNameLength = 0; SQLSMALLINT dataType = 0; SQLULEN columnSize = 0; SQLSMALLINT numberOfDecimals = 0; SQLSMALLINT isNullable = 0; SQLLEN displaySize = 0; CHECK (SQLDescribeCol (stmt, i + 1, columnName, std::size (columnName), & columnNameLength, & dataType, & columnSize, & numberOfDecimals, & isNullable)); CHECK (SQLColAttribute (stmt, i + 1, SQL_DESC_DISPLAY_SIZE, nullptr, 0, nullptr, & displaySize)); buffer.emplace_back (std::make_unique (rowsToFetch * (displaySize + 1)), std::make_unique (rowsToFetch)); CHECK (SQLBindCol (stmt, i + 1, SQL_C_CHAR, buffer.back ().first.get (), displaySize + 1, buffer.back ().second.get ())); } CHECK (SQLSetStmtAttr (stmt, SQL_ATTR_ROW_ARRAY_SIZE, reinterpret_cast (rowsToFetch), SQL_IS_UINTEGER)); CHECK (SQLExecute (stmt)); SQLUSMALLINT rowStatus [rowsToFetch]; SQLULEN rowsFetched = 0; CHECK (SQLSetStmtAttr (stmt, SQL_ATTR_ROW_STATUS_PTR, rowStatus, SQL_IS_POINTER)); CHECK (SQLSetStmtAttr (stmt, SQL_ATTR_ROWS_FETCHED_PTR, & rowsFetched, SQL_IS_POINTER)); CHECK (SQLFetch (stmt)); } } int main () { try { TestODBCConnection (); } catch (std::exception const & theError) { std::cerr << theError.what () << std::endl; } return (0); }