此问题是Microsoft ODBC中一系列错误的一部分 驱动程序:
- ODBC driver fails to raise errors; but instead suppresses them
- Reading columns out of order returns incorrect results
- Cannot execute a stored procedure that is a SYNONYM
微软表示他们不会在他们的ODBC中修复这些错误 驱动程序。
我有(很多)存储过程实际上是同义词。存储过程在一个数据库中规范地存在,但在其他数据库中可见。
存储过程在SQL Server Management Studio中执行正常:
EXECUTE Report_ThirdParty @ContosoGUID = '{CC0ECA32-BEFA-11E5-8E2A-C86000D0B92A}'
如果我使用任何OLEDB提供程序连接到SQL Server:
Provider=SQLNCLI10;Data Source=contoso.stackoverflow.com;User ID=ContosoManager;Password=correct horse battery staple;
Provider=SQLOLEDB;Data Source=contoso.stackoverflow.com;User ID=contoso.stackoverflow.com;Password=correct horse battery staple;
然后存储过程执行正常。我得到了结果。每个人都很高兴。
使用the announcement of the deprecation of OleDb drivers,我想测试使用SQL Server的ODBC驱动程序。当我更改连接以使用其中一个SQL Server ODBC驱动程序(例如" {SQL Server}" )并执行相同的SQL语句
EXECUTE Report_ThirdParty @ContosoGUID = '{CC0ECA32-BEFA-11E5-8E2A-C86000D0B92A}'
我收到错误:
程序请求' Report_ThirdParty'失败,因为' Report_ThirdParty'是一个同义词对象
无论我是使用SQL Server的原始ODBC驱动程序还是本机客户端,都是如此:
SQL Server :Provider=MSDASQL;Driver={SQL Server};Server={contoso.stackoverflow.com};UID={contosoManager};PWD={correct horse battery staple};
SQL Server Native Client 11.0 :Provider=MSDASQL;Driver={SQL Server Native Client 11.0};Server={contoso.stackoverflow.com};UID={ContosoManager};PWD={correct horse battery staple};
在两种变体中我都会得到同样的错误:
[Microsoft] [SQL Server Native Client 11.0] [SQL Server]程序请求' Report_ThirdParty'失败,因为' Report_ThirdParty'是一个同义词对象
或旧的ODBC驱动程序:
[Microsoft] [ODBC SQL Server驱动程序] [SQL Server]程序请求' Report_ThirdParty'失败,因为' Report_ThirdParty'是一个同义词对象
换句话说:
程序请求'%s'失败了因为'%s'是一个同义词对象
Errors
的Connection集合提供了更多信息:
错误#1
错误#2
放弃切换到ODBC没有任何害处。而且我不会停止使用同义词。
但是有什么问题,我怎么告诉ODBC驱动程序让SQL Server工作?
备注
答案 0 :(得分:0)
作为我的评论的后续内容,这里是我的(有点不那么动态)的例子:
一个非常简单的存储过程:
Frame
已创建该程序的同义词(使用gui工具)USE [Test]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[foo]
@p1 int
AS
RETURN 13 + @p1
。
我可以在SQL Server 2014 Management studio中执行:
dbo.fooSyn
两个陈述都没有错误。
这是我的测试代码,使用名称执行一次,并使用同义词:
execute foo @p1 = 2
GO
execute fooSyn @p1 = 3
GO
打印出预期的输出:
#include <windows.h>
#include <tchar.h>
#include <iostream>
#include <sql.h>
#include <sqlext.h>
#include <sqlucode.h>
void printErrDbc(SQLHDBC hDbc)
{
SQLSMALLINT recNr = 1;
SQLRETURN ret = SQL_SUCCESS;
while (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
SQLWCHAR errMsg[SQL_MAX_MESSAGE_LENGTH + 1];
SQLWCHAR sqlState[5 + 1];
errMsg[0] = 0;
SQLINTEGER nativeError;
SQLSMALLINT cb = 0;
ret = SQLGetDiagRec(SQL_HANDLE_DBC, hDbc, recNr, sqlState, &nativeError, errMsg, SQL_MAX_MESSAGE_LENGTH + 1, &cb);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
std::wcerr << L"ERROR; native: " << nativeError << L"; state: " << sqlState << L"; msg: " << errMsg << std::endl;
}
++recNr;
}
}
void printErrStmt(SQLHSTMT hStmt)
{
SQLSMALLINT recNr = 1;
SQLRETURN ret = SQL_SUCCESS;
while (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
SQLWCHAR errMsg[SQL_MAX_MESSAGE_LENGTH + 1];
SQLWCHAR sqlState[5 + 1];
errMsg[0] = 0;
SQLINTEGER nativeError;
SQLSMALLINT cb = 0;
ret = SQLGetDiagRec(SQL_HANDLE_STMT, hStmt, recNr, sqlState, &nativeError, errMsg, SQL_MAX_MESSAGE_LENGTH + 1, &cb);
if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO)
{
std::wcerr << L"ERROR; native: " << nativeError << L"; state: " << sqlState << L"; msg: " << errMsg << std::endl;
}
++recNr;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
SQLRETURN nResult = 0;
SQLHANDLE handleEnv = 0;
nResult = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, (SQLHANDLE*)&handleEnv);
nResult = SQLSetEnvAttr(handleEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3_80, SQL_IS_INTEGER);
SQLHANDLE handleDBC = 0;
nResult = SQLAllocHandle(SQL_HANDLE_DBC, handleEnv, (SQLHANDLE*)&handleDBC);
SQLWCHAR strConnect[256] = L"Driver={SQL Server Native Client 11.0};Server=.\\INSTANCE;Database=Test;Trusted_Connection=yes;";
SQLWCHAR strConnectOut[1024] = { 0 };
SQLSMALLINT nNumOut = 0;
nResult = SQLDriverConnect(handleDBC, NULL, (SQLWCHAR*)strConnect, SQL_NTS, (SQLWCHAR*)strConnectOut, sizeof(strConnectOut),
&nNumOut, SQL_DRIVER_NOPROMPT);
if (!SQL_SUCCEEDED(nResult))
{
printErrDbc(handleDBC);
}
nResult = SQLSetConnectAttr(handleDBC, SQL_ATTR_AUTOCOMMIT, (SQLUINTEGER)SQL_AUTOCOMMIT_OFF, NULL);
if (!SQL_SUCCEEDED(nResult))
{
printErrDbc(handleDBC);
}
SQLHSTMT handleStatement = 0;
nResult = SQLAllocHandle(SQL_HANDLE_STMT, handleDBC, (SQLHANDLE*)&handleStatement);
if (!SQL_SUCCEEDED(nResult))
{
printErrDbc(handleDBC);
}
// Bind return code
SQLINTEGER res = 0;
SQLLEN cb = 0;
SWORD sParm1 = 0;
SQLLEN cbParm1 = SQL_NTS;
nResult = SQLBindParameter(handleStatement, 1, SQL_PARAM_OUTPUT, SQL_C_SSHORT, SQL_INTEGER, 0, 0, &sParm1, 0, &cbParm1);
if (!SQL_SUCCEEDED(nResult))
{
printErrStmt(handleStatement);
}
// And call using synonym name
nResult = SQLExecDirect(handleStatement, L"{? = call fooSyn(3)}", SQL_NTS);
if (!SQL_SUCCEEDED(nResult))
{
printErrStmt(handleStatement);
}
nResult = SQLFetch(handleStatement);
std::wcout << L"Result is: " << sParm1 << std::endl;
// Note: It also works using EXECUTE - but I dont remember how to read return value like that.
nResult = SQLExecDirect(handleStatement, L"execute foo @p1 = 2", SQL_NTS);
if (!SQL_SUCCEEDED(nResult))
{
printErrStmt(handleStatement);
}
else
{
std::wcout << L"Working using name" << std::endl;
}
nResult = SQLExecDirect(handleStatement, L"execute fooSyn @p1 = 2", SQL_NTS);
if (!SQL_SUCCEEDED(nResult))
{
printErrStmt(handleStatement);
}
else
{
std::wcout << L"Working using synonym" << std::endl;
}
return 0;
}
那么,您的设置有什么不同?
总结我的设置: