无法使用SQL Server ODBC Driver执行同义词存储过程;适用于OLEDB

时间:2016-02-09 15:44:48

标签: sql-server winapi odbc

  

此问题是Microsoft ODBC中一系列错误的一部分   驱动程序:

           

微软表示他们不会在他们的ODBC中修复这些错误   驱动程序。

我有(很多)存储过程实际上是同义词。存储过程在一个数据库中规范地存在,但在其他数据库中可见。

存储过程在SQL Server Management Studio中执行正常:

EXECUTE Report_ThirdParty @ContosoGUID = '{CC0ECA32-BEFA-11E5-8E2A-C86000D0B92A}'

如果我使用任何OLEDB提供程序连接到SQL Server:

  • SQL Server Native Client 10.0 OLE DB提供程序Provider=SQLNCLI10;Data Source=contoso.stackoverflow.com;User ID=ContosoManager;Password=correct horse battery staple;
  • 用于SQL Server的Microsoft OLE DB提供程序Provider=SQLOLEDB;Data Source=contoso.stackoverflow.com;User ID=contoso.stackoverflow.com;Password=correct horse battery staple;

然后存储过程执行正常。我得到了结果。每个人都很高兴。

但不是使用ODBC驱动程序

使用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'是一个同义词对象

ErrorsConnection集合提供了更多信息:

  • 错误#1

    • 数量: 0x80040E14
    • 来源:用于ODBC驱动程序的Microsoft OLE DB提供程序
    • 说明: [Microsoft] [ODBC SQL Server驱动程序] [SQL Server]程序请求' Report_ThirdParty'失败,因为' Report_ThirdParty'是一个同义词对象。
    • SQLState: 37000
    • NativeError :2809
  • 错误#2

    • 数量: 0x80040E14
    • 来源:用于ODBC驱动程序的Microsoft OLE DB提供程序
    • 说明: [Microsoft] [ODBC SQL Server驱动程序] [SQL Server]未声明游标。
    • SQLState: 37000
    • NativeError: 16945

放弃切换到ODBC没有任何害处。而且我不会停止使用同义词。

但是有什么问题,我怎么告诉ODBC驱动程序让SQL Server工作?

SQL事件探查器结果

  • RPC:开始声明@p1 int set @ p1 = 0声明@p3 int set @ p3 = 16388声明@p4 int set @ p4 = 8193声明@ p5 int set @ p5 = 0 exec sp_cursoropen @ p1 output,N' EXECUTE Report_ThirdParty @ContosoGUID ='' {3492C4E6-D500-4A23-9CAB-CB6582C27ABD}''', @ p3输出,@ p4输出,@ p5输出选择@ p1,@ p3,@ p4,@ p5
  • 例外错误:2809,严重性:18,状态:1
  • 用户错误消息程序请求' Report_ThirdParty'失败,因为' Report_ThirdParty'是一个同义词对象。
  • 例外错误:16945,严重性:16,状态:2
  • 用户错误消息未声明游标。
  • RPC:已完成 :: 声明@ p1 int set @ p1 = 0声明@ p3 int set @ p3 = 16388声明@p4 int set @ p4 = 8193声明@ p5 int set @ p5 = 0 exec sp_cursoropen @ p1 output,N' EXECUTE Report_ThirdParty @ContosoGUID ='' {3492C4E6-D500-4A23-9CAB-CB6582C27ABD}'''' ,@ p3输出,@ p4输出,@ p5输出选择@ p1,@ p3,@ p4,@ p5

备注

  • 原生(即非.NET)代码。你可以假装它是C,C ++,汇编或Delphi。
  • Microsoft SQL Server 2008 R2(SP2) - 10.50.4000.0(X64)

ODBC的其他非预期功能(在OLEDB中有效)

奖金阅读

1 个答案:

答案 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;
}

那么,您的设置有什么不同?

总结我的设置:

  • SQL Server 2014 Express Edition
  • SQL Server本机客户端11.0版本2011.110.3000.00(但它也只使用{SQL Server}作为驱动程序)
  • Windows 7教授
  • 使用visual studio 2013编辑。
  • 使用odbc版本3.8。
  • 同义词和存储过程在同一个数据库中,即使在此数据库中的同一模式中也是如此。