我需要帮助来了解为什么使用SQL Server 2008 Express进行的RESTORE DATABASE
操作失败,并且HRESULT代码为0x80040e14。
操作环境概述
我们有一个在多个协作终端上运行的销售点应用程序,这些终端的体系结构是拥有一个包含所有运营数据的主终端以及零个或多个在处理交易时更新运营数据的卫星终端。
存在另一种体系结构,其中备份主终端是终端组的一部分。作为建立组或执行备用主终端的一部分,有一条命令可以同步主终端和备用主终端的运行数据。
大多数操作总计数据存储在磁盘上的一组平面文件中,但是我们使用Microsoft SQL Server Express来保存PLU总计。
作为同步操作的一部分,我们还传输了SQL Server数据库备份。 RESTORE DATABASE
操作失败,我需要帮助找出问题所在。
该应用程序是用C ++编写的,并且正在使用ADO作为SQL Server接口。
测试设置使用的是Microsoft SQL Server Express 2008 R2,该版本是使用默认实例安装的,以便与多年前的SQL Server 2000 Express的原始安装兼容。 POS应用程序在连接字符串中指定默认实例。
已使用功能的源代码
还原功能如下:
ULONG CnPluTotalDb::RestoreDB(LPCTSTR szSQlCode){
CString szSQL;
USHORT usError = 0;
USHORT usErrorCount = 0;
CString activeConn;
activeConn.Format(ConnectionStringTemp,L"master");
_bstr_t strConnect = activeConn;
//We set the database to be in single user mode while we do this database reset
//so that no one else can access the database information while we reset the DB
//SR 725 JHHJ
SINGLE_USER_DB:
szSQL.Format(L"ALTER DATABASE %s SET SINGLE_USER WITH ROLLBACK IMMEDIATE", szSQlCode);
m_hr = __pRecO->OpenRec(CnVariant(szSQL), strConnect, adOpenForwardOnly,adLockOptimistic,adCmdText);
//Close the recordset object so we can open a new one
//for the next SQL command
__pRecO->Close();
if (FAILED(m_hr))
{
char xBuff[128];
sprintf(xBuff, "CnPluTotalDb::RestoreDB() SET SINGLE_USER FAILED: HRESULT m_hr = 0x%8.8x", m_hr);
NHPOS_ASSERT_TEXT(0, xBuff);
usError = 1;
goto MULTI_USER_DB;
}
//We will drop the database because the information in it is out of date
//so that we can restore it in the next call.
szSQL.Format(L"DROP DATABASE %s", szSQlCode);
m_hr = __pRecO->OpenRec(CnVariant(szSQL), strConnect, adOpenForwardOnly,adLockOptimistic,adCmdText);
__pRecO->Close();
if (FAILED(m_hr))
{
char xBuff[128];
sprintf(xBuff, "CnPluTotalDb::RestoreDB() DROP DATABASE FAILED: HRESULT m_hr = 0x%8.8x", m_hr);
NHPOS_ASSERT_TEXT(0, xBuff);
}
//Restore the database from the file that the master/backupmaster has just sent over.
szSQL.Format(PLUTOTAL_DB_BACKUP_RESTORE, szSQlCode, szSQlCode);
m_hr = __pRecO->OpenRec(CnVariant(szSQL), strConnect, adOpenForwardOnly,adLockOptimistic,adCmdText);
__pRecO->Close();
if (FAILED(m_hr))
{
char xBuff[128];
sprintf(xBuff, "CnPluTotalDb::RestoreDB() RESTORE DATABASE FAILED: HRESULT m_hr = 0x%8.8x", m_hr);
NHPOS_ASSERT_TEXT(0, xBuff);
}
MULTI_USER_DB:
//Return the database back to multi-user mode.
szSQL.Format(L"ALTER DATABASE %s SET MULTI_USER", szSQlCode);
m_hr = __pRecO->OpenRec(CnVariant(szSQL), strConnect, adOpenForwardOnly,adLockOptimistic,adCmdText);
__pRecO->Close(); // one shot!!!
if (FAILED(m_hr))
{
char xBuff[128];
sprintf(xBuff, "CnPluTotalDb::RestoreDB() SET MULTI_USER FAILED: HRESULT m_hr = 0x%8.8x", m_hr);
NHPOS_ASSERT_TEXT(0, xBuff);
usErrorCount++;
if (usErrorCount < 5) goto MULTI_USER_DB;
return PLUTOTAL_E_FAILURE;
} else if (usError)
{
usError = 0;
goto SINGLE_USER_DB;
}
return PLUTOTAL_SUCCESS;
}
使用的连接字符串模板为:
ConnectionStringTemp = L"Provider=MSDASQL;DRIVER={SQL Server};SERVER=lpc:(local);DATABASE=%s;UID=; Password=;";
用于参数的定义为:
#define PLUTOTAL_DB_BACKUP_PATH L"C:\\TempDisk\\NCR\\Saratoga\\Database\\" // was _T("C:\\Program Files\\Microsoft SQL Server\\MSSQL\\Data\\")
#define PLUTOTAL_DB_BACKUP_RESTORE L"RESTORE DATABASE %s FROM DISK = 'C:\\TempDisk\\NCR\\Saratoga\\Database\\%s_BAK.dat' WITH REPLACE"
#define PLUTOTAL_DB_BACKUP_BACKUP L"BACKUP DATABASE %s TO DISK = 'C:\\TempDisk\\NCR\\Saratoga\\Database\\%s_BAK.dat' WITH INIT"
观察到的行为和生成的日志
我可以看到主终端上的BACKUP DATABASE
操作确实生成了一个备份文件,并且该文件已传输到备份主终端上。
备份主服务器似乎正进入单用户模式,并且DROP DATABASE
正在工作。
生成的显示错误的日志如下:
PluTtlDb.cpp, 440, CnPluTotalDb::RestoreDB() RESTORE DATABASE FAILED: HRESULT m_hr = 0x80040e14
PluTtlDb.cpp, 454, CnPluTotalDb::RestoreDB() SET MULTI_USER FAILED: HRESULT m_hr = 0x80040e14
PluTtlDb.cpp, 454, CnPluTotalDb::RestoreDB() SET MULTI_USER FAILED: HRESULT m_hr = 0x80040e14
PluTtlDb.cpp, 454, CnPluTotalDb::RestoreDB() SET MULTI_USER FAILED: HRESULT m_hr = 0x80040e14
PluTtlDb.cpp, 454, CnPluTotalDb::RestoreDB() SET MULTI_USER FAILED: HRESULT m_hr = 0x80040e14
PluTtlDb.cpp, 454, CnPluTotalDb::RestoreDB() SET MULTI_USER FAILED: HRESULT m_hr = 0x80040e14
TtlPluBk.c, 190, **WARNING: TTL_BKUPPLUDBFAIL PluTotalRestoreDB() returned ulSts 9999 0x270f
编辑A:在方法OpenRec()
中添加了其他日志以获取更详细的错误信息之后,事实证明这是相当普遍的HRESULT,我获得了以下新信息。由于错误描述超出了错误日志限制(110个字符),因此这些日志中有一些重复的文本,因此大多数错误描述都是通过两个日志API调用记录的,以记录错误描述的前一半和后一半。
, rce\nhpos\plutotal\CnAdoXP.h, 342, IDispatch error #3092
, rce\nhpos\plutotal\CnAdoXP.h, 345, [Microsoft][ODBC SQL Server Driver][SQL Server]The media family on device 'C:\TempDisk\NCR\Saratoga\Database\PluTtlDC_BA
, rce\nhpos\plutotal\CnAdoXP.h, 349, sk\NCR\Saratoga\Database\PluTtlDC_BAK.dat' is incorrectly formed. SQL Server cannot process this media family.
, PluTtlDb.cpp, 440, CnPluTotalDb::RestoreDB() RESTORE DATABASE FAILED: HRESULT m_hr = 0x80040e14
, rce\nhpos\plutotal\CnAdoXP.h, 342, IDispatch error #3092
, rce\nhpos\plutotal\CnAdoXP.h, 345, [Microsoft][ODBC SQL Server Driver][SQL Server]User does not have permission to alter database 'PluTtlDC', the database
, rce\nhpos\plutotal\CnAdoXP.h, 349, database 'PluTtlDC', the database does not exist, or the database is not in a state that allows access checks.
, PluTtlDb.cpp, 454, CnPluTotalDb::RestoreDB() SET MULTI_USER FAILED: HRESULT m_hr = 0x80040e14
, rce\nhpos\plutotal\CnAdoXP.h, 342, IDispatch error #3092
, rce\nhpos\plutotal\CnAdoXP.h, 345, [Microsoft][ODBC SQL Server Driver][SQL Server]User does not have permission to alter database 'PluTtlDC', the database
, rce\nhpos\plutotal\CnAdoXP.h, 349, database 'PluTtlDC', the database does not exist, or the database is not in a state that allows access checks.
, PluTtlDb.cpp, 454, CnPluTotalDb::RestoreDB() SET MULTI_USER FAILED: HRESULT m_hr = 0x80040e14
, rce\nhpos\plutotal\CnAdoXP.h, 342, IDispatch error #3092
, rce\nhpos\plutotal\CnAdoXP.h, 345, [Microsoft][ODBC SQL Server Driver][SQL Server]User does not have permission to alter database 'PluTtlDC', the database
, rce\nhpos\plutotal\CnAdoXP.h, 349, database 'PluTtlDC', the database does not exist, or the database is not in a state that allows access checks.
, PluTtlDb.cpp, 454, CnPluTotalDb::RestoreDB() SET MULTI_USER FAILED: HRESULT m_hr = 0x80040e14
, rce\nhpos\plutotal\CnAdoXP.h, 342, IDispatch error #3092
, rce\nhpos\plutotal\CnAdoXP.h, 345, [Microsoft][ODBC SQL Server Driver][SQL Server]User does not have permission to alter database 'PluTtlDC', the database
, rce\nhpos\plutotal\CnAdoXP.h, 349, database 'PluTtlDC', the database does not exist, or the database is not in a state that allows access checks.
, PluTtlDb.cpp, 454, CnPluTotalDb::RestoreDB() SET MULTI_USER FAILED: HRESULT m_hr = 0x80040e14
, rce\nhpos\plutotal\CnAdoXP.h, 342, IDispatch error #3092
, rce\nhpos\plutotal\CnAdoXP.h, 345, [Microsoft][ODBC SQL Server Driver][SQL Server]User does not have permission to alter database 'PluTtlDC', the database
, rce\nhpos\plutotal\CnAdoXP.h, 349, database 'PluTtlDC', the database does not exist, or the database is not in a state that allows access checks.
, PluTtlDb.cpp, 454, CnPluTotalDb::RestoreDB() SET MULTI_USER FAILED: HRESULT m_hr = 0x80040e14
, TtlPluBk.c, 190, **WARNING: TTL_BKUPPLUDBFAIL PluTotalRestoreDB() returned ulSts 9999 0x270f
其他源代码
OpenRec()
方法如下:
virtual HRESULT OpenRec(CnVariant Source,_bstr_t ActiveConnection,
CursorTypeEnum CursorType = adOpenKeyset,
LockTypeEnum LockType = adLockOptimistic,
long Options = adCmdUnknown)
{
CString errorMessage;
try {
if (m_pConnection->State != adStateOpen)
{
m_pConnection->ConnectionString = ActiveConnection;
m_pConnection->Open("", "", "", -1);
}
m_hr = m_pRecordSet->Open((VARIANT)Source, _variant_t((IDispatch *)m_pConnection),CursorType,LockType,Options);
}
catch( _com_error &e) {
_bstr_t bstrSource(e.Description());
TCHAR *description;
description = bstrSource;
errorMessage.Format(_T("ERROR OpenRec %s %s"), e.ErrorMessage(), description);
m_hr = e.Error();
}
if (!FAILED(m_hr)) {
m_bOpened = TRUE;
}
else {
TRACE3("%S(%d): %s\n", __FILE__, __LINE__, errorMessage);
}
return m_hr;
}
其中m_pRecordSet
的类型为_RecordsetPtr
,由ADO提供。