This question is part in a series of bugs in the Microsoft ODBC driver:
- 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
Microsoft has said they will not be fixing these bugs in their ODBC driver.
I have (many) stored procedures that are actually synonyms. The stored procedure exists canonically in one database, but are visible in others.
The stored procedure executes fine from within SQL Server Management Studio:
EXECUTE Report_ThirdParty @ContosoGUID = '{CC0ECA32-BEFA-11E5-8E2A-C86000D0B92A}'
And if I connect to SQL Server using any OLEDB provider:
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;
Then the stored procedure executes fine. I get results. And everyone's happy.
With the announcement of the deprecation of OleDb drivers, I wanted to test using the ODBC drivers for SQL Server. When I change the connection to use one of the SQL Server ODBC drivers (e.g. "{SQL Server}") and execute the same SQL statement
EXECUTE Report_ThirdParty @ContosoGUID = '{CC0ECA32-BEFA-11E5-8E2A-C86000D0B92A}'
I get the error:
The request for procedure 'Report_ThirdParty' failed because 'Report_ThirdParty' is a synonym object
This is true whether I use the original ODBC driver for SQL Server, or the native client:
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};
In both variations i get the same error:
[Microsoft][SQL Server Native Client 11.0][SQL Server]The request for procedure 'Report_ThirdParty' failed because 'Report_ThirdParty' is a synonym object
or for the older ODBC driver:
[Microsoft][ODBC SQL Server Driver][SQL Server]The request for procedure 'Report_ThirdParty' failed because 'Report_ThirdParty' is a synonym object
In other words:
The request for procedure '%s' failed because '%s' is a synonym object
The Errors
collection of the Connection provides more information:
Error#1
Error#2
There's no harm in abandoning the switch to ODBC. And I'm not going to stop using synonyms.
But what is wrong, and how do i tell the ODBC Driver for SQL Server to work?
Notes
As a follow up to my comment, here is my (somewhat no-so-mimimal) example that works here:
A very simple stored procedure:
USE [Test]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER procedure [dbo].[foo]
@p1 int
AS
RETURN 13 + @p1
And a synonym to that procedure has been created (using gui tools) named dbo.fooSyn
.
I can execute both from within SQL Server 2014 Management studio:
execute foo @p1 = 2
GO
execute fooSyn @p1 = 3
GO
both statements complete with no error.
And here is my test code to execute once using the name and once using the synonym:
#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;
}
This prints out the expected output:
Result is: 16
Working using name
Working using synonym
So, what is the difference to your setup?
To summarize my setup:
User contributions licensed under CC BY-SA 3.0