Question

I am trying to push binary data from SQL Server to an Oracle LONG RAW column. I have a linked server created on SQL Server that connects to the Oracle server. I have a stored procedure on the Oracle side that I am trying to call from SQL Server. I can't seem to get the binary to pass into the stored procedure. I've tried changing the from and to types; however, the data ultimately needs to end up in a LONG RAW column. I have control of the Oracle stored procedure and the SQL Server code, but I do not have control of the predefined Oracle table structure.

varbinary(max) -> long raw ORA-01460: unimplemented or unreasonable conversion requested

varbinary(max) -> blob PLS-00306: wrong number or types of arguments in call to 'ADDDOC'

varbinary -> long raw No errors, but get data truncation or corruption

The varbinary(max) does work if I set the @doc = null.

Below is the Oracle procedure and the SQL Server.

Oracle:

CREATE OR REPLACE
PROCEDURE ADDDOC (param1 IN LONG RAW)
AS
BEGIN
  -- insert param1 into a LONG RAW column
  DBMS_OUTPUT.PUT_LINE('TEST');
END ADDDOC;

SQL Server:

declare @doc varbinary(max)
select top 1 @doc = Document from Attachments

execute ('begin ADDDOC(?); end;', @doc) at ORACLE_DEV

-- tried this too, same error
--execute ('begin ADDDOC(utl_raw.cast_to_raw(?)); end;', @doc) at ORACLE_DEV

I've also tried creating the record in the Oracle Documents table then updating the LONG RAW field from SQL Server without invoking a stored procedure, but the query just seems to run and run and run and run...

--already created record and got the Id of the record I want to put the data in
--hard coding for this example
declare @attachmentId, @documentId
set @attachmentId = 1
set @documentId = 1

update ORACLE_DEV..MYDB.Documents
set Document = (select Document from Attachments where Id = @attachmentId)
where DocumentId=@documentId
Was it helpful?

Solution

As noted in the comments, LONG RAW is very difficult to work with; unfortunately, our vendor is using the datatype in their product and I have no choice but to work with it. I found that I could not pass binary data from SQL Server to an Oracle stored procedure parameter. I ended up having to create a new record with a NULL value for the LONG RAW field then using an OPENQUERY update to set the field to the VARBINARY(MAX) field; I did try using an update with the four part identifier, as noted in my code sample, but it took over 11 minutes for a single update, this new approach completes in less than 3 seconds. I am using an Oracle stored procedure here because in my real world scenario I am creating multiple records in multiple tables and coded business logic that is not relevant then tying them together with the docId.

This feels more like a workaround than a solution, but it actually works with acceptable performance.

Oracle:

create or replace procedure ADDDOC(docId OUT Number)
as
begin
    select docseq.nextval into docId from dual;

    -- insert new row, but leave Document LONG RAW field null for now
    insert into DOC (Id) values(docId);
end ADDDOC;

SQL Server:

declare @DocId float, @AttachmentID int, @Qry nvarchar(max)
set @AttachmentID = 123 -- hardcoded for example

execute('begin ADDDOC(?); end;', @DocId output) at ORACLE_DEV

-- write openquery sql that will update Oracle LONG RAW field from a SQL Server varbinary(max) field
set @Qry = '
    update openquery(ORACLE_DEV, ''select Document from Documents where Id=' + cast(@DocId as varchar) + ''')
    set Document = (select Document from Attachments where Id = ' + cast(@AttachmentID as varchar) + ')
    '
execute sp_executesql @Qry
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top