Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

564 lines
12 KiB

// ***************************************************************************
// Copyright (C) 2000- Microsoft Corporation.
// @File: sqlenum.cpp
//
// PURPOSE:
//
// Enumerate the sqlservers available on the local node.
//
// NOTES:
//
//
// HISTORY:
//
// @Version: Whistler/Shiloh
// 68067 srs 11/06/00 ntsnap fix
// 67026 srs 10/05/00 Server enumeration bugs
//
//
// @EndHeader@
// ***************************************************************************
#ifdef HIDE_WARNINGS
#pragma warning( disable : 4786)
#endif
#include <stdafx.h>
#include <clogmsg.h>
////////////////////////////////////////////////////////////////////////
// Standard foo for file name aliasing. This code block must be after
// all includes of VSS header files.
//
#ifdef VSS_FILE_ALIAS
#undef VSS_FILE_ALIAS
#endif
#define VSS_FILE_ALIAS "SQLENUMC"
//
////////////////////////////////////////////////////////////////////////
//-------------------------------------------------------------------
// ODBC error reporter
//
void PrintODBCError
(
SQLSMALLINT HandleType,
SQLHANDLE hHandle,
CLogMsg &msg
)
{
CVssFunctionTracer ft(VSSDBG_SQLLIB, L"PrintODBCError");
INT i;
INT j;
SDWORD NativeErr;
INT severity;
INT msgstate;
DBUSMALLINT LineNumber;
WCHAR szSQLState[SQL_SQLSTATE_SIZE + 1];
WCHAR szMsg [1024 + 1];
WCHAR ServerName[SQL_MAX_SQLSERVERNAME + 1];
WCHAR ProcName [SQL_MAX_SQLSERVERNAME + 1];
if (SQLGetDiagField(
HandleType,
hHandle,
0,
SQL_DIAG_NUMBER,
&i,
sizeof(i),
NULL) == SQL_ERROR )
{
ft.Trace(VSSDBG_SQLLIB, L"SQLGetDiagField failed");
}
else
{
for (j = 1; j <= i; j++)
{
if (SQLGetDiagRecW (
HandleType,
hHandle,
(SQLSMALLINT)j,
(SQLWCHAR*)szSQLState,
&NativeErr,
(SQLWCHAR*) szMsg,
sizeof(szMsg) / sizeof(WCHAR),
NULL) == SQL_ERROR )
{
ft.Trace (VSSDBG_SQLLIB, L"SQLGetDiagRec failed");
}
else
{
// Get driver specific diagnostic fields
//
if (SQLGetDiagField(
HandleType,
hHandle,
(SQLSMALLINT)j,
SQL_DIAG_SS_MSGSTATE,
&msgstate,
SQL_IS_INTEGER,
NULL) == SQL_ERROR )
{
msgstate = 0;
}
if (SQLGetDiagField(
HandleType,
hHandle,
(SQLSMALLINT)j,
SQL_DIAG_SS_SEVERITY,
&severity,
SQL_IS_INTEGER,
NULL) == SQL_ERROR )
{
severity = 0;
}
if (SQLGetDiagField(
HandleType,
hHandle,
(SQLSMALLINT)j,
SQL_DIAG_SS_SRVNAME,
&ServerName,
sizeof(ServerName),
NULL) == SQL_ERROR )
{
ServerName[0] = L'\0';
}
if (SQLGetDiagField(
HandleType,
hHandle,
(SQLSMALLINT)j,
SQL_DIAG_SS_PROCNAME,
&ProcName,
sizeof(ProcName),
NULL) == SQL_ERROR )
{
ProcName[0] = L'\0';
}
if (SQLGetDiagField(
HandleType,
hHandle,
(SQLSMALLINT)j,
SQL_DIAG_SS_LINE,
&LineNumber,
SQL_IS_SMALLINT,
NULL) == SQL_ERROR )
{
LineNumber = 0;
}
ft.Trace
(
VSSDBG_SQLLIB,
L"ODBC Error: Msg %d, SevLevel %d, State %d, SQLState %s\n%s\n",
NativeErr,
severity,
msgstate,
szSQLState,
szMsg
);
WCHAR buf[80];
swprintf(buf, L"Error: %d, Severity: %d, State: %d, SQLState: ", NativeErr, severity, msgstate);
msg.Add(buf);
msg.Add(szSQLState);
msg.Add(L"\n ProcName: ");
msg.Add(ProcName);
swprintf(buf, L", Line Number: %d, ServerName: ", LineNumber);
msg.Add(buf);
msg.Add(L"\n");
msg.Add(szMsg);
}
} // for( j = 1; j <= i; j++ )
}
}
//------------------------------------------------------------
// Scanner to locate servernames in a "BrowseConnect" string.
//
class BrowseServers
{
public:
const WCHAR* FindFirst (const WCHAR* source, unsigned* nameLen);
const WCHAR* FindNext (unsigned* nameLen);
private:
const WCHAR* m_CurrChar;
};
const WCHAR*
BrowseServers::FindFirst (const WCHAR *source, unsigned* nameLen)
{
CVssFunctionTracer ft(VSSDBG_SQLLIB, L"BrowseServers::FindFirst");
const WCHAR* pChar;
const WCHAR Prefix[] = L"Server={";
m_CurrChar = NULL;
if (source == NULL)
return NULL;
pChar = wcsstr (source, Prefix);
if (pChar == NULL)
return NULL;
m_CurrChar = pChar + wcslen (Prefix);
if (*m_CurrChar == L'}')
{
// The server list is empty
//
m_CurrChar = NULL;
return NULL;
}
if (nameLen)
{
*nameLen = wcscspn (m_CurrChar, L",;}");
}
return m_CurrChar;
}
const WCHAR*
BrowseServers::FindNext (unsigned* nameLen)
{
const WCHAR* pChar;
if (m_CurrChar == NULL)
return NULL;
pChar = wcschr (m_CurrChar, L',');
if (pChar == NULL)
{
m_CurrChar = NULL;
return NULL;
}
m_CurrChar = pChar + 1;
if (nameLen)
{
*nameLen = wcscspn (m_CurrChar, L",;}");
}
return m_CurrChar;
}
//------------------------------------------------------------------------
// Return true if we could fetch the version of the SQLServer ODBC driver
//
bool
GetSQLDriverVersion (int* major, int* minor)
{
CVssFunctionTracer ft(VSSDBG_SQLLIB, L"GetSQLDriverVersion");
DWORD status;
HKEY hKey;
WCHAR driver[MAX_PATH+1];
DWORD vType;
DWORD pathLen = MAX_PATH;
status = RegOpenKeyExW (
HKEY_LOCAL_MACHINE,
L"Software\\ODBC\\ODBCINST.INI\\SQL Server",
0,
KEY_QUERY_VALUE,
&hKey);
if (status != ERROR_SUCCESS)
{
ft.Trace (VSSDBG_SQLLIB, L"SQL not installed. Regkey status %d", status);
return false;
}
status = (DWORD) RegQueryValueExW (
hKey,
L"Driver",
NULL,
&vType,
(BYTE*)driver,
&pathLen);
RegCloseKey (hKey);
if (status != ERROR_SUCCESS)
{
ft.Trace(VSSDBG_SQLLIB, L"SQL Driver installed wrong: %d\n", status);
return false;
}
char versionInfo [4096];
if (!GetFileVersionInfoW (driver, 0, 4096, versionInfo))
{
ft.Trace(VSSDBG_SQLLIB, L"SQL Driver version not found: %d", GetLastError ());
return false;
}
VS_FIXEDFILEINFO* pInfo;
UINT infoSize;
if (!VerQueryValueW (versionInfo, L"\\", (LPVOID*)&pInfo, &infoSize))
{
ft.Trace(VSSDBG_SQLLIB, L"version info resource not found: %d", GetLastError ());
return false;
}
*major = pInfo->dwFileVersionMS >> 16;
*minor = pInfo->dwFileVersionMS & 0x0FFFF;
return true;
}
//------------------------------------------------------------------------
// Build the list of servers on the current machine.
// Throws exception if any errors occur.
//
StringVector*
EnumerateServers ()
{
CVssFunctionTracer ft(VSSDBG_SQLLIB, L"EnumerateServers");
SQLHENV henv = SQL_NULL_HANDLE;
SQLHDBC hdbc = SQL_NULL_HANDLE;
RETCODE rc;
LPWSTR lpBuffer = NULL;
StringVector* serverList = new StringVector;
CLogMsg msg;
int major, minor;
if (!GetSQLDriverVersion (&major, &minor))
{
// SQL isn't installed right, so just ignore it, return empty list.
//
return serverList;
}
if (major < 2000)
{
// Require the modern MDAC to give a proper enumeration.
//
ft.LogError(VSS_ERROR_SQLLIB_UNSUPPORTEDMDAC, VSSDBG_SQLLIB << major << minor);
throw HRESULT (E_SQLLIB_NO_SUPPORT);
// ORIGINAL CODE:
// May have a 6.5 or 7.0 server. We aren't sure, but the
// caller can determine if the server is up itself.
//
//serverList->push_back (L"(local)");
//return serverList;
}
// SQL2000 or better
//
try
{
if (SQLAllocHandle(SQL_HANDLE_ENV, NULL, &henv) == SQL_ERROR)
{
ft.LogError(VSS_ERROR_SQLLIB_SQLAllocHandle_FAILED, VSSDBG_SQLLIB);
THROW_GENERIC;
}
rc = SQLSetEnvAttr(
henv,
SQL_ATTR_ODBC_VERSION,
(SQLPOINTER)SQL_OV_ODBC3,
0);
if (rc != SQL_SUCCESS)
{
PrintODBCError(SQL_HANDLE_ENV, henv, msg);
if (rc == SQL_ERROR)
{
ft.LogError(VSS_ERROR_SQLLIB_ODBC_ERROR, VSSDBG_SQLLIB << L"SQLSetEnvAttr" << msg.GetMsg());
THROW_GENERIC;
}
}
rc = SQLSetEnvAttr(
henv,
SQL_ATTR_CONNECTION_POOLING,
(SQLPOINTER)SQL_CP_OFF,
0);
if (rc != SQL_SUCCESS)
{
PrintODBCError(SQL_HANDLE_ENV, henv, msg);
if (rc == SQL_ERROR)
{
ft.LogError(VSS_ERROR_SQLLIB_ODBC_ERROR, VSSDBG_SQLLIB << L"SQLSetEnvAttr" << msg.GetMsg());
THROW_GENERIC;
}
}
rc = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
if (rc != SQL_SUCCESS)
{
PrintODBCError(SQL_HANDLE_ENV, henv, msg);
if (rc == SQL_ERROR)
{
ft.LogError(VSS_ERROR_SQLLIB_ODBC_ERROR, VSSDBG_SQLLIB << L"SQLSetAllocHandle" << msg.GetMsg());
THROW_GENERIC;
}
}
// Note: older versions of sqlsvr32 don't support
// these connect attributes, but the failure to
// recognize them isn't detected until the actual
// SQLBrowseConnect call. For old sqlsrv32, the
// "list of servers" performs a domain search!
//
rc = SQLSetConnectAttr (
hdbc,
SQL_COPT_SS_BROWSE_CONNECT,
(SQLPOINTER)SQL_MORE_INFO_YES,
SQL_IS_UINTEGER);
if (rc != SQL_SUCCESS)
{
PrintODBCError(SQL_HANDLE_DBC, hdbc, msg);
if (rc == SQL_ERROR)
{
ft.LogError(VSS_ERROR_SQLLIB_ODBC_ERROR, VSSDBG_SQLLIB << L"SQLSetConnectAttr" << msg.GetMsg());
THROW_GENERIC;
}
}
rc = SQLSetConnectAttrW (
hdbc,
SQL_COPT_SS_BROWSE_SERVER,
(SQLPOINTER)L"(local)",
SQL_NTS);
if (rc != SQL_SUCCESS)
{
PrintODBCError(SQL_HANDLE_DBC, hdbc, msg);
if (rc == SQL_ERROR)
{
ft.LogError(VSS_ERROR_SQLLIB_ODBC_ERROR, VSSDBG_SQLLIB << L"SQLSetConnectAttr" << msg.GetMsg());
THROW_GENERIC;
}
}
// We use the maximum buffer supported in ODBC.
//
#define MAX_BUFFER 0x7ff0
lpBuffer = new WCHAR [MAX_BUFFER];
SQLSMALLINT browseLen;
rc = SQLBrowseConnectW (
hdbc,
L"Driver={SQL Server}",
SQL_NTS,
lpBuffer,
MAX_BUFFER,
&browseLen);
//ft.Trace(VSSDBG_SQLLIB, L"browse connect rc: %d", rc);
if (rc != SQL_NEED_DATA)
{
PrintODBCError(SQL_HANDLE_DBC, hdbc, msg);
if (rc == SQL_ERROR)
{
ft.LogError(VSS_ERROR_SQLLIB_ODBC_ERROR, VSSDBG_SQLLIB << L"SQLSetConnectAttr" << msg.GetMsg());
THROW_GENERIC;
}
}
// check for SQL6.5 in any of the servers
//
WCHAR *pVersion = lpBuffer;
int srvVer;
while (1)
{
pVersion = wcsstr (pVersion, L";Version:");
if (!pVersion)
break;
pVersion += 9;
srvVer = 0;
swscanf (pVersion, L"%u", &srvVer);
if (srvVer < 7)
{
ft.LogError(VSS_ERROR_SQLLIB_UNSUPPORTEDSQLSERVER, VSSDBG_SQLLIB << srvVer);
throw HRESULT (E_SQLLIB_NO_SUPPORT);
}
}
//ft.Trace(VSSDBG_SQLLIB, L"BrowseResult:%s", lpBuffer);
// Scan to count the servers
//
BrowseServers scanner;
if (NULL == scanner.FindFirst (lpBuffer, NULL))
{
ft.Trace(VSSDBG_SQLLIB, L"No servers found!\n");
}
else
{
unsigned i,nameLen;
const WCHAR* pServerName;
unsigned int cServers = 1;
while (scanner.FindNext (NULL) != NULL)
{
cServers++;
}
serverList->reserve (cServers);
pServerName = scanner.FindFirst (lpBuffer, &nameLen);
serverList->push_back (std::wstring (pServerName, nameLen));
i = 1;
while (i < cServers)
{
pServerName = scanner.FindNext (&nameLen);
serverList->push_back (std::wstring (pServerName, nameLen));
i++;
}
}
if (lpBuffer)
{
delete [] lpBuffer;
}
if (hdbc)
{
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
if (henv)
{
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
}
catch (...)
{
if (lpBuffer)
{
delete [] lpBuffer;
}
if (hdbc)
{
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
}
if (henv)
{
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
delete serverList;
throw;
}
return serverList;
}