bool OdbcConnection::Connect()
{
	if (m_szDSN.length() == 0)
		return false;

	tstring szConn = _T("DSN=") + m_szDSN + _T(";");
	// Reconnect if we need to.
	if (isConnected())
		Disconnect();

	// Allocate enviroment handle
	if (!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_envHandle)))
	{
		ReportSQLError(SQL_HANDLE_ENV, m_envHandle, _T("SQLAllocHandle"), _T("Unable to allocate environment handle."));
		goto error_handler;
	}

	// Request ODBC3 support
	if (!SQL_SUCCEEDED(SQLSetEnvAttr(m_envHandle, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0)))
	{
		ReportSQLError(SQL_HANDLE_ENV, m_envHandle, _T("SQLSetEnvAttr"), _T("Unable to set environment attribute (SQL_ATTR_ODBC_VERSION)."));
		goto error_handler;
	}

	// Allocate the connection handle
	if (!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_DBC, m_envHandle, &m_connHandle)))
	{
		ReportSQLError(SQL_HANDLE_ENV, m_envHandle, _T("SQLAllocHandle"), _T("Unable to allocate connection handle."));
		goto error_handler;
	}

	if (m_szUser.length())
	{
		szConn += _T("UID=") + m_szUser + _T(";");
		if (m_szPass.length())
			szConn += _T("PWD=") + m_szPass + _T(";");
	}

	// Enable multiple active result sets
	if (m_bMarsEnabled)
		szConn += _T("MARS_Connection=yes;");

	if (!SQL_SUCCEEDED(SQLDriverConnect(m_connHandle, NULL, (SQLTCHAR *)szConn.c_str(), SQL_NTS, NULL, NULL, NULL, NULL)))
	{
		ReportSQLError(SQL_HANDLE_DBC, m_connHandle, _T("SQLDriverConnect"), _T("Unable to establish connection."));
		goto error_handler;
	}

	for (auto itr = m_commandSet.begin(); itr != m_commandSet.end(); itr++)
		(*itr)->SetConnectionHandle(m_connHandle);

	return true;

error_handler:
	ResetHandles();
	return false;
}
bool OdbcConnection::Connect()
{
	if (m_szDSN.empty())
		return false;

	FastGuard lock(m_lock);

	tstring szConn = _T("DSN=") + m_szDSN + _T(";");
	// Reconnect if we need to.
	if (isConnected())
		Disconnect();

	// Allocate enviroment handle
	if (!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_envHandle)))
	{
		ReportSQLError(SQL_HANDLE_ENV, m_envHandle, _T("SQLAllocHandle"), _T("Unable to allocate environment handle."));
		goto error_handler;
	}

	// Request ODBC3 support
	if (!SQL_SUCCEEDED(SQLSetEnvAttr(m_envHandle, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0)))
	{
		ReportSQLError(SQL_HANDLE_ENV, m_envHandle, _T("SQLSetEnvAttr"), _T("Unable to set environment attribute (SQL_ATTR_ODBC_VERSION)."));
		goto error_handler;
	}

	// Allocate the connection handle
	if (!SQL_SUCCEEDED(SQLAllocHandle(SQL_HANDLE_DBC, m_envHandle, &m_connHandle)))
	{
		ReportSQLError(SQL_HANDLE_ENV, m_envHandle, _T("SQLAllocHandle"), _T("Unable to allocate connection handle."));
		goto error_handler;
	}

	if (m_szUser.length())
	{
		szConn += _T("UID=") + m_szUser + _T(";");
		if (m_szPass.length())
			szConn += _T("PWD=") + m_szPass + _T(";");
	}

	// Enable multiple active result sets
	if (m_bMarsEnabled)
	{
		if (!SQL_SUCCEEDED(SQLSetConnectAttr(m_connHandle, SQL_COPT_SS_MARS_ENABLED, SQL_MARS_ENABLED_YES, SQL_IS_UINTEGER)))
		{
			printf("** WARNING **\n\n");
			printf("Attempted to used MARS (Multiple Active Result Sets), but this\n");
			printf("feature is not supported by your ODBC driver or SQL Server version.\n\n");
			printf("To benefit from MARS, you need to be using at least SQL Server 2005, and at\n");
			printf("least the 'SQL Native Client' ODBC driver (as opposed to the vastly outdated\n'SQL Server' driver).\n\n");
			printf("Continuing to connect without MARS.\n\n");
			m_bMarsEnabled = false;
		}

		// NOTE: We can enable MARS via specifying the following, but we are unable to detect if it's supported this way.
		// szConn += _T("MARS_Connection=yes;");
	}

	if (!SQL_SUCCEEDED(SQLDriverConnect(m_connHandle, SQL_NULL_HANDLE, (SQLTCHAR *)szConn.c_str(), SQL_NTS, 0, 0, 0, 0)))
	{
		ReportSQLError(SQL_HANDLE_DBC, m_connHandle, _T("SQLDriverConnect"), _T("Unable to establish connection."));
		goto error_handler;
	}

	for (auto itr = m_commandSet.begin(); itr != m_commandSet.end(); itr++)
		(*itr)->SetConnectionHandle(m_connHandle);

	return true;

error_handler:
	ResetHandles();
	return false;
}
Beispiel #3
0
/***************************************************
CUGODBCDatasource::Browse : call this function to invoke the
ODBC driver to prompt for connection params.

    This function gathers information about all of the  
    tables in the datasource selected, storing the information
    in the array m_dsInfoArray for later retrieval.  

    This function also saves the resulting connect string for
    later use.  

****************************************************/
int CUGODBCDatasource::Browse(HWND hwnd){


	HENV henv;
	HDBC hdbc;
	HSTMT hstmt;
	RETCODE retcode;
	SQLTCHAR  buf[255];

	SQLTCHAR  sqlerror[255];
	SQLTCHAR  sqlstate[255];
	SDWORD nerr, cbVal;
	SWORD num;

	// for table info....
	SQLTCHAR	szTableQualifier[128];
	SQLTCHAR	szTableOwner[128];
	SQLTCHAR	szTableName[128];
	SQLTCHAR	szTableType[128];
	SQLTCHAR	szRemarks[255];

	// close open db
	Close();
	
	// clean up previous data
	m_connectString = "";

	m_tableCount = 0;


	
	retcode = SQLAllocEnv(&henv);              // Environment handle 

	if (retcode == SQL_ERROR) {
		AfxMessageBox(_T("Probable memory allocation error in SQLAllocEnv"));
		return (int) retcode;
	}


	retcode = SQLAllocConnect(henv,&hdbc);

	if (retcode == SQL_ERROR) {
		ReportSQLError(henv, SQL_NULL_HDBC, SQL_NULL_HSTMT, retcode, _T("SQLAllocConnect"));
		SQLFreeEnv(henv);
		return (int) retcode;
	}		

	if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

		// Set login timeout to 5 seconds. 
		 SQLSetConnectOption(hdbc, SQL_LOGIN_TIMEOUT, 5);
		// Connect to data source 
        // this should cause the ODBC Driver to come up with the
		// necessary prompts to form a connect string...
		retcode = SQLDriverConnect(hdbc,hwnd,(SQLTCHAR*)_T(""),
							0,buf,254,&num,SQL_DRIVER_PROMPT);

							
		if (retcode != SQL_SUCCESS) {
			#ifdef UG_REPORT_ERROR
				ReportSQLError(henv, hdbc, SQL_NULL_HSTMT, retcode, _T("SQLDriverConnect"));
			#endif
			// user probably cancelled connection...
                if (retcode != SQL_SUCCESS_WITH_INFO) {
    			SQLFreeConnect(hdbc);
    			SQLFreeEnv(henv);
				return retcode;
                }
		}

			

		if(retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO){
			// retcode from SQLDriverConnect...
			// should be cool to try to open a recordset with the info 
			// we have here in buf...
			CDatabase db;
			TCHAR buf2[255];
			UGStr::stprintf(buf2,255,_T("ODBC;%s"),buf);

            // now we have the connect string in buf2 - but wait to
            // see if we can actually open the db before storing 
            // it in m_connectString...

			try {
				retcode = db.Open(NULL,FALSE,FALSE,buf2);
			}		
			catch(CMemoryException* e){
				#ifdef UG_ODBC_REPORTERROR
					e->ReportError();
				#endif
				e->Delete();
				AfxAbort();
			}
			catch(CDBException* e){
				// standard procedure for ODBC - save the 
				// RETCODE code for the return value - 
				// Report on the error - optional -
				// use Delete to delete the exception object
				RETCODE er = e->m_nRetCode;
				#ifdef UG_ODBC_REPORTERROR
					e->ReportError();
				#endif
				e->Delete();
    			SQLFreeConnect(hdbc);
    			SQLFreeEnv(henv);
				return (int)er;
			}

			// now, given an open connection, we should
			// be able to set up a statement handle..
			retcode = SQLAllocStmt(hdbc, &hstmt);

			
			switch (retcode) {
				case SQL_SUCCESS: {
				//	AfxMessageBox("SQLAllocStmt returned success ");
				//	AfxMessageBox((LPCSTR)buf);
					break;
				}
				case SQL_SUCCESS_WITH_INFO:{
					AfxMessageBox(_T("SQLAllocStmt returned success with info"));
					// this indicates that there is a driver specific warning
					// to be investigated...
					SQLError(SQL_NULL_HENV,hdbc,SQL_NULL_HSTMT,sqlstate,
											&nerr,sqlerror,254,&num);
					AfxMessageBox((LPCTSTR)sqlstate);
					AfxMessageBox((LPCTSTR)sqlerror);
					break;
				}
				case SQL_NO_DATA_FOUND:{
					AfxMessageBox(_T("SQLAllocStmt returned no data found"));
					break;
				}
				case SQL_ERROR:{
					AfxMessageBox(_T("SQLAllocStmt returned sql error"));
					SQLError(SQL_NULL_HENV,hdbc,SQL_NULL_HSTMT,sqlstate,&nerr,sqlerror,254,&num);
					AfxMessageBox((LPCTSTR)sqlstate);
					AfxMessageBox((LPCTSTR)sqlerror);
					break;
				}
				case SQL_INVALID_HANDLE:{
					AfxMessageBox(_T("SQLDriverConnect returned invalid handle"));
					break;
				}
				default:
					break;
				}

				// ok - now lets see if we can enumerate the tables
				// contained in the database...

				retcode = SQLTables(hstmt,	// statement handle for
												// retrieved results
						  NULL,					// szTableQualifier
						  SQL_NTS,				// cbTableQualifier
						  NULL,					// szTableOwner
						  SQL_NTS,				// cbTableOwner
						  NULL,					// szTableName
						  SQL_NTS,				// cbTableName
						  (SQLTCHAR*)_T("'TABLE','VIEW',\
						  'SYSTEM TABLE','GLOBAL TEMPORARY','LOCAL TEMPORARY',\
						  'ALIAS','SYNONYM'"),			// szTableType (list of
												// table types to match)
						  SQL_NTS);					// cbTableTypes
				
                if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO) {
					ReportSQLError(henv, hdbc, hstmt, retcode, _T("SQLTables"));
        			SQLFreeStmt(hstmt, SQL_DROP);
		        	SQLDisconnect(hdbc);
        			SQLFreeConnect(hdbc);
			        SQLFreeEnv(henv);
                    return retcode;         // unable to query tables 
                                            // User should see message box
                }


                // now - can we iterate through the tables found?
#ifndef _UNICODE
				SQLBindCol(hstmt, 1, SQL_C_CHAR, szTableQualifier, 128, &cbVal);
				SQLBindCol(hstmt, 2, SQL_C_CHAR, szTableOwner, 128, &cbVal);
				SQLBindCol(hstmt, 3, SQL_C_CHAR, szTableName, 128, &cbVal);
				SQLBindCol(hstmt, 4, SQL_C_CHAR, szTableType, 128, &cbVal);
				SQLBindCol(hstmt, 5, SQL_C_CHAR, szRemarks, 255, &cbVal);
#else
				SQLBindCol(hstmt, 1, SQL_UNICODE_CHAR, szTableQualifier, 128, &cbVal);
				SQLBindCol(hstmt, 2, SQL_UNICODE_CHAR, szTableOwner, 128, &cbVal);
				SQLBindCol(hstmt, 3, SQL_UNICODE_CHAR, szTableName, 128, &cbVal);
				SQLBindCol(hstmt, 4, SQL_UNICODE_CHAR, szTableType, 128, &cbVal);
				SQLBindCol(hstmt, 5, SQL_UNICODE_CHAR, szRemarks, 255, &cbVal);
#endif
				retcode = SQLFetch(hstmt);

				if (retcode == SQL_ERROR || retcode == SQL_SUCCESS_WITH_INFO)
					ReportSQLError(henv, hdbc, hstmt, retcode, _T("SQLFetch"));

				if (retcode != SQL_NO_DATA_FOUND)
					m_connectString = (LPTSTR)buf2;	// save connection string!


                // Subsequent calls to GetTableInfo will be able to 
                // retrieve this information...
				while (retcode != SQL_NO_DATA_FOUND) {
					UGStr::tcscpy((LPTSTR)m_dsInfoArray[m_tableCount].tableQualifier,128,(LPTSTR)szTableQualifier);
					UGStr::tcscpy((LPTSTR)m_dsInfoArray[m_tableCount].tableOwner,128, (LPTSTR)szTableOwner);
					UGStr::tcscpy((LPTSTR)m_dsInfoArray[m_tableCount].tableName,128,(LPTSTR)szTableName);
					UGStr::tcscpy((LPTSTR)m_dsInfoArray[m_tableCount].tableType,128,(LPTSTR)szTableType);
					UGStr::tcscpy((LPTSTR)m_dsInfoArray[m_tableCount].remarks,255,(LPTSTR)szRemarks);
					
					m_tableCount++;
					if (m_tableCount >= MAX_TABLES)
						break;
					retcode = SQLFetch(hstmt);

				}
			}