如何避免sp_OACreate限制?

时间:2014-12-11 13:31:50

标签: sql-server sql-server-2008 tsql

Declare @Object as Int; 
Declare @ResponseText as Varchar(8000); 
Declare @Url as Varchar(MAX);

set @Url = 'http://mysite.ru/cgi-bin/my_xml.cgi'

Exec sp_OACreate 'MSXML2.XMLHTTP', @Object OUT; 
Exec sp_OAMethod @Object, 'open', NULL, 'get', @Url, 'false' 
Exec sp_OAMethod @Object, 'send' 
Exec sp_OAMethod @Object, 'responseText', @ResponseText OUTPUT 
Exec sp_OADestroy @Object

SELECT @ResponseText

网址中的XML长度为4210,@ResponseText返回NULL,当我将长度更改为3970时@ResponseText会返回数据。 sp_OACreate是否限制400?如果可以,可以避免吗?

4 个答案:

答案 0 :(得分:2)

尽管您的帖子的主题我认为问题可能是sp_OAMethod而不是sp_OACreate本身。

也应该不惜一切代价避免从sql代码访问网站的恕我直言,但这只是我的意见,因为我不喜欢有RDBMS浏览网页的想法。 ^^

为了规避sp_OAMethod的限制,您可以尝试详细说明msdn上的答案。

你的代码应该是这样的:

Declare @Object as Int; 
Declare @ResponseText as Varchar(8000); 
Declare @Url as Varchar(MAX);

set @Url = 'http://mysite.ru/cgi-bin/my_xml.cgi'

Exec sp_OACreate 'MSXML2.XMLHTTP', @Object OUT; 
Exec sp_OAMethod @Object, 'open', NULL, 'get', @Url, 'false' 
Exec sp_OAMethod @Object, 'send' 
--Exec sp_OAMethod @Object, 'responseText', @ResponseText OUTPUT 

INSERT #temptable ( appropriatefield )
EXEC @Result = sp_OAGetProperty @Obj, 'YourPropertyName' 

Exec sp_OADestroy @Object

解决方案需要一个具有适当结构和数据类型的临时表来存储远程页面生成的值,这样可以获得超过4k的数据。

答案 1 :(得分:1)

根据sqlservercentral.com上的this thread,sp_OACreate限制为4000个字符。

解决方法是将读取拆分为较小的“块”,然后在SQL中将它们连接在一起。以下是上述链接中的代码段,虽然它从文件而不是通过HTTP读取XML,但它可能对您有所帮助:

EXECUTE @hResult = sp_OACreate  ''Scripting.FileSystemObject'' , @objFileSystem OUT
IF @hResult <> 0 
BEGIN 
    EXEC sp_OAGetErrorInfo @objFileSystem, @ErrorSource OUT, @ErrorDesc OUT 
    SET @ErrorFailPoint = ''Creating FSO''
    GOTO DestroyFSO 
    RETURN 
END     

SET @FileNameAndPath = @Path + ''\'' + @FileName

-- Read file
EXECUTE @hResult = sp_OAMethod @objFileSystem, ''OpenTextFile'', @objTextStream OUT, @FileNameAndPath, 1, false, 0--for reading, FormatASCII
IF @hResult <> 0 
    BEGIN 
        EXEC sp_OAGetErrorInfo @objFileSystem, @ErrorSource OUT, @ErrorDesc OUT 
        SET @ErrorFailPoint = ''Opening Reponse File''
        GOTO Destroy 
        RETURN 
    END 

    SET @ResponseText = ''''

    WHILE @hResult = 0
    BEGIN
        EXECUTE @hResult = sp_OAGetProperty @objTextStream, ''AtEndOfStream'', @YesOrNo OUTPUT
        IF @hResult <> 0 
        BEGIN 
            EXEC sp_OAGetErrorInfo @objTextStream, @ErrorSource OUT, @ErrorDesc OUT 
            SET @ErrorFailPoint = ''Checking AtEndOfStream''
            GOTO Destroy 
            RETURN 
        END     

        IF @YesOrNo <> 0
        BREAK

        EXECUTE @hResult = sp_OAMethod  @objTextStream, ''Read'', @Chunk OUTPUT, 4000
        IF @hResult <> 0 
        BEGIN 
            EXEC sp_OAGetErrorInfo @objTextStream, @ErrorSource OUT, @ErrorDesc OUT 
            SET @ErrorFailPoint = ''Reading Chunk''
            GOTO Destroy 
            RETURN 
        END     
        SET @ResponseText = @ResponseText + ISNULL(@Chunk, '''')
    END

    EXECUTE @hResult = sp_OAMethod  @objTextStream, ''Close''
    IF @hResult <> 0 
    BEGIN 
        EXEC sp_OAGetErrorInfo @objTextStream, @ErrorSource OUT, @ErrorDesc OUT 
        SET @ErrorFailPoint = ''Closing Response File''
        GOTO Destroy 
        RETURN 
    END     

    -- Record response info
    SET @ResponseXml = CAST(@ResponseText AS XML)

Destroy: 
  EXEC sp_OADestroy @objTextStream

DestroyFSO:
  EXEC sp_OADestroy @objFileSystem

答案 2 :(得分:1)

这是我用来克服限制的。我用它来进行RESTful api通信。我可以收到varchar(max)但仍然限制我可以发送的数据量。这可能会让你到达你需要的地方。前5个变量是我用于sproc的参数。

    Declare @url as varchar(1024)
    Declare @connection_type as varchar(6)='GET' --POST, PUT, GET DELETE
    Declare @post_string as varchar(max)=null
    Declare @response_text as Varchar(max)
    Declare @content_type varchar(254)='application/json'

    Declare @oa_object as Int;
    Declare @err_code as Int
    Declare @result_table Table (xml_result varchar(max))

    Select @post_string=dbo.fn_regex_replace('([ ]{2,10})|\r|\n', @post_string,'') --remove carriage returns and multiple spaces

    Exec @err_code=sp_OACreate 'MSXML2.ServerXMLHTTP.3.0', @oa_object OUT;
    If @err_code<>0
        Set @response_text=dbo.fn_oa_error_message(@oa_object)
    Else
    Begin
        Exec @err_code=sp_OAMethod @oa_object, 'open', NULL, @connection_type, @url,'false','d0b1a0aaed2a529356471de4fe99cae2','8e7aa1a91fa68d06cd027914d3aa1140'
        If @err_code<>0
            Set @response_text='Open '+dbo.fn_oa_error_message(@oa_object)
        Else
        Begin
            Exec @err_code=sp_OAMethod @oa_object, 'setRequestHeader', NULL, 'User-Agent', 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)'
            If @err_code<>0
                Set @response_text='setRequestHeader:User-Agent '+dbo.fn_oa_error_message(@oa_object)
            Else
            Begin
                Exec @err_code=sp_OAMethod @oa_object, 'setRequestHeader', NULL, 'Content-Type', @content_type
                If @err_code<>0
                    Set @response_text='setRequestHeader:Content-Type '+dbo.fn_oa_error_message(@oa_object)
                Else
                Begin
                    Exec @err_code=sp_OAMethod @oa_object, 'send', Null, @post_string
                    If @err_code<>0
                        Set @response_text='Send '+dbo.fn_oa_error_message(@oa_object)
                    Else
                    Begin
                        Set @response_text=null--make sure we don't return garbage
                        INSERT @result_table (xml_result)
                        Exec @err_code = sp_OAGetProperty @oa_object, 'responseText' 
                        If @err_code<>0
                            Set @response_text='responseText '+dbo.fn_oa_error_message(@oa_object)
                        Else
                            SELECT @response_text=xml_result FROM @result_table
                    End
                End
            End
        End
    End
    Exec sp_OADestroy @oa_object 

虽然您不需要它,但错误处理程序如下所示。它有助于排除故障。

CREATE FUNCTION
    dbo.n_oa_error_message(@oa_object int)
RETURNS varchar(max)
AS
BEGIN
    Declare @source varchar(255)
    Declare @description varchar(255)   
    exec sp_OAGetErrorInfo @oa_object, @source OUT, @description OUT        
    return 'Error: '+IsNull(@description,'no description')
END

答案 3 :(得分:1)

我使用以下查询来解决此问题。问题可能不是sp_OACreate或sp_OAMethod,而是返回@ResponseText的方法。将数据插入表变量而不是使用“@ResponseText OUTPUT”是关键。请注意,我将@Response更改为VARCHAR(MAX)。

DECLARE @TABLEVAR TABLE (responseXml VARCHAR(MAX))
DECLARE @URL VARCHAR(200) 
SELECT @URL = 'http://mysite/php-start/callxml.php'

DECLARE @Response NVARCHAR(MAX)
DECLARE @Xml XML
DECLARE @Obj INT 
DECLARE @Result INT

EXEC @Result = sp_OACreate 'MSXML2.XMLHttp', @Obj OUT 
EXEC @Result = sp_OAMethod @Obj, 'open', NULL, 'GET', @URL, false
EXEC @Result = sp_OAMethod @Obj, 'setRequestHeader', NULL, 'Content-Type', 'application/x-www-form-urlencoded'
EXEC @Result = sp_OAMethod @Obj, SEND, NULL, ''

INSERT INTO @TABLEVAR
EXEC @Result = sp_OAGetProperty @Obj, 'responseXML.xml'--, @Response OUT 

EXEC sp_OADestroy @Obj

SELECT @Response = responseXml FROM @TABLEVAR
SELECT @Xml = CONVERT(XML, @Response, 2)

DECLARE @handle INT

EXEC sp_xml_preparedocument @handle OUTPUT, @Xml 

SELECT *
FROM OPENXML(@handle, '/data/record', 2)  
    WITH [dbo].[tblDialogTechTemp]

EXEC sp_xml_removedocument @handle
  

我的查询突然返回null而不更改任何内容。将'MSXML2.XMLHttp'更改为'MSXML2.ServerXMLHTTP'后,它又开始运作了。要详细了解这两者之间的区别,请参阅此article和Microsoft documentation