TADOStoredProc+MSSQL+varchar(max) OUTPUT - как получить значение?

WinterGraveyard
Дата: 05.05.2011 10:17:53
Сабж. Как пользоваться поиском, и как получать OUTPUT-поля - знаю. Всё прекрасно работает, если out-параметр, например, varchar(8000). При varchar(max) всё это не работает. Пример процедуры:
CREATE procedure [dbo].[sp_foo](@bar varchar(max) output) as
begin
	set @bar='';
	select @bar=@bar+name from sys.all_objects;
end;
GO
Проверяем:
declare
@zot varchar(max)
exec [dbo].[sp_foo] @zot out
select @zot,LEN(@zot)
go
Вывод:

(No column name)                             (No column name)
sysrscolssysrowsetssysallocunitssysfiles1... 43390

Далее в delphi (использую RAD Studio 2010):
  DMUnit.ConToLocal.Connected:=True;
  with DMUnit.sp_foo do
  begin
    Connection:=DMUnit.ConToLocal;
    ProcedureName:='sp_foo';
    Parameters.Refresh;
    Parameters.FindParam('@bar').Direction:=pdOutput;
    ExecProc;
    writeln('test done: '+IntToStr(Length(Parameters.FindParam('@bar').Value)));
  end;
и получаю:

Project SPTest.exe raised exception class EOleException with message
'Неправильно определен объект Parameter. Предоставлены несовместимые или неполные сведения.'

При замене в ХП varchar(max) на varchar(8000) все работает нормально, но varchar(8000) для требуемой задачи недостаточно. Исходя из того, что при varchar(max) данные предоставляются в виде потока, пытался сделать так:
var
  StrStream: TStringStream;
  AStream: TStreamAdapter;
begin
  DMUnit.ConToLocal.Connected:=True;
  StrStream := TStringStream.Create('');
  AStream := TStreamAdapter.Create(StrStream);
  with DMUnit.sp_foo do
  begin
    Connection:=DMUnit.ConToLocal;
    ProcedureName:='sp_foo';
    Parameters.Refresh;
    Parameters.FindParam('@bar').Direction:=pdOutput;
    Parameters.FindParam('@bar').Value:=IStream(AStream);
    ExecProc;
    writeln('test done');
  end;
end;
Результат:

Project SPTest.exe raised exception class EOleException with message
'Приложение использует для текущей операции значение неверного типа.'

Пытался дополнительно указывать тип данных параметра, менять pdOutput на pdInputOutput - без толку.
Кто-нибудь сталкивался с подобным?
LPDem
Дата: 05.05.2011 20:44:34
Сталкивался, напрямую решить не удалось.
Можно использовать TADOQuery, результат процедуры возвращать как поле набора данных.
WinterGraveyard
Дата: 22.06.2011 15:37:28
В общем, опять столкнулся с описанной выше проблемой, и на сей раз решить её получилось. Решил с использованием компонентов SDAC, как будет с TADO-компонентами - не проверял, т.к. меня вполне устраивает найденный вариант.
ХП:
create procedure sp_foo as 
declare
    @foo nvarchar(max);
begin
    set @foo='';
    select @foo=@foo+' '+name from sys.all_objects;
    select @foo as foo, len(@foo) as len_foo;
end;

В delphi-коде:
procedure TfmMain.btnTestClick(Sender: TObject);
begin
with sp_foo do
    begin
        ExecProc;
        writeln(FieldByName('foo').Value);
        writeln(FieldByName('len_foo').Value);
    end;
end;

В консоли получаем что-то вида

...xp_regenumvalues xp_regread xp_regremovemultistring xp_regwrite xp_repl_convert_encrypt_sysadmin_wrapper
xp_replposteor xp_revokelogin xp_runwebtask xp_sendmail xp_servicecontrol xp_sprintf xp_sqlagent_enum_jobs
xp_sqlagent_is_starting xp_sqlagent_monitor xp_sqlagent_notify xp_sqlagent_param xp_sqlmaint xp_sscanf xp_startmail
xp_stopmail xp_subdirs xp_sysmail_activate xp_sysmail_attachment_load xp_sysmail_format_query xp_test_mapi_profile
63207

Решение, оказывается, было весьма простым.
Всем спасибо.
WinterGraveyard
Дата: 22.06.2011 15:40:50
Да, забыл про поправку к исходному условию: разумеется, мы все out-параметры ХП из сигнатуры ХП выносим в select - у меня это отличие от исходной постановки никаких возражений не вызвало.
Зайцев Фёдор
Дата: 22.06.2011 16:57:28
нужно было указать размер для параметра и брать строку тупо как value