Sp_oamethod上传大小超过8000的文件

时间:2016-09-27 13:08:25

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

这是我返回@v_buffer变量的过程的一部分。 问题是,我要上传的文件大小大于8000字节。这就是我需要使用varbinary(max)类型的原因。 但sp_oamethod读取返回错误。 有人知道使用sp_oamethod解决我的问题很热吗?

declare @returnCode int
declare @v_file int
declare @v_buffer varbinary(max)
declare @v_fullpath nvarchar(400) --pdf file phusical location

exec @returncode = sp_oacreate 'adodb.stream', @v_file out  

exec @returncode = sp_oamethod @v_file, 'open'  

exec @returncode = sp_oasetproperty @v_file, 'type', 1

exec @returncode = sp_oasetproperty @v_file, 'loadfromfile', @v_fullpath  


exec @returnCode = sp_oamethod @v_file, 'read', @v_buffer out, -1
if @returncode <> 0  
begin  
    exec sp_oageterrorinfo @v_file
end  

exec @returnCode = sp_OAMethod @v_file, 'Close'   
exec @returnCode = sp_OADestroy @v_file   

sp_oageterrorinfo返回的错误消息:

  

0x8004271A,ODSOLE扩展过程,srv_convert中的错误。

4 个答案:

答案 0 :(得分:2)

请不要使用OLE自动化存储过程(即sp_OA*),因为自SQL Server 2005发布以来,它们已被弃用。使用SQLCLR(即SQL Server中存在的基于.NET的对象),您要做的事情相当简单。您可以创建标量函数来接受文件路径并使用File.ReadAllBytes方法返回其字节。通过byte[]类型返回SqlBytes

您需要将程序集设置为PERMISSION_SET = EXTERNAL_ACCESS。为了实现这一点,请将数据库设置为TRUSTWORTHY ON,因为这是一个不必要的安全风险。而是,签署程序集(使用密码),然后在DLL中的master数据库中创建一个非对称密钥,然后从该密钥创建一个登录,最后授予登录EXTERNAL ACCESS ASSEMBLY权限。 / p>

有关使用SQLCLR的更多信息,包括许多示例,请参阅我在SQL Server Central上撰写的关于此主题的系列文章:Stairway to SQLCLR(该网站确实需要免费注册才能阅读他们的内容)。

或者,如果您不想处理任何编码,我创建了一个包含270多个函数和存储过程的库,名为SQL#。有几个与文件系统相关的功能,但免费版本中没有一个可用。仍然,这里有帮助的是: File_GetFileBinary

答案 1 :(得分:0)

如果尝试将大于4000个字符但长度小于或等于8000个字符的字符串传递给sp_OASetProperty或sp_OAMethod OLE自动化扩展存储过程,则输入字符串将在其之前以无提示方式截断为4000个字符被传递给对象,不会返回任何错误。

如果尝试通过sp_OASetProperty OLE自动化扩展存储过程将属性设置为大于8000个字符的字符串,或者尝试将输入参数传递给长度超过8000的sp_OAMethod OLE自动化扩展存储过程字符,您收到以下错误信息:

Console.ReadLine();

https://support.microsoft.com/en-us/kb/325492

答案 2 :(得分:0)

如果有人有同样的问题,我这样做了: 在我的程序中,我创建了临时#IMG表:

create table #IMG (FileID2 nvarchar(50), img image)

如果文件大小超过8k,我将其拆分为大小为8000的部分并更新#IMG:

    exec @returnCode = sp_oamethod @v_file, 'read', @v_buffer out, 8000
    update #IMG set img = @v_buffer
    SELECT @ptrval = TEXTPTR(Img) FROM #IMG WHERE FileID2 = @v_FileID2

    --file split section
    select  @v_Blocks = @v_FileSize/8000+1
    if @v_Blocks = 1
    begin
        WRITETEXT #IMG.Img  @ptrval @v_buffer
    end
    else
    begin 
        WRITETEXT #IMG.Img @ptrval @v_buffer
        set @j=@v_blocks-1
        while @j>0
        begin
            exec @returnCode = sp_oamethod @v_file, 'read',  @v_buffer out , 8000
            set @i=(select DATALENGTH(Img) from #IMG WHERE FileID2= @v_FileID2)
            UPDATETEXT  #IMG.Img @ptrval @i 0 @v_buffer 
        set @j=@j-1
        end
    end

答案 3 :(得分:0)

您可以使用与0x8004271A ODSOLE Extended Procedure Error in srv_convert.

中所述相同的解决方法

在你的情况下,行

exec @returnCode = sp_oamethod @v_file, 'read', @v_buffer out, -1

应替换为

Create table #tmp(dt varbinary(max))

insert into #tmp
exec @hr = sp_oamethod @v_file, 'read', @mode = -1

Select dt from #tmp -- single column/single row.
Drop Table #tmp -- clean up

警告:此代码未经过测试。但是,以下代码适用于32KB xml输出:

Create table #tmp(dt xml)

insert into #tmp
exec @hr = sp_OAGetProperty @obj, 'responseXML.XML'
/*
  Here is the trick: inserting from the returned result set, i.e.
  `insert into <table>(<columns>) select <columns>`
*/

Select dt from #tmp -- single column/single row.
Drop Table #tmp -- clean up
调用responseXML.XML后,

MSXML2.ServerXMLHttp.send返回整个xml文档。该技巧根据sp_OAMethodResult Sets部分工作。

table变量类型可用时,代码可以更短:

DECLARE @xml(val xml);
insert into @xml
exec @hr = sp_OAGetProperty @obj, 'responseXML.XML'

Select * from @xml; -- just to see the output

即。没有必要清理。