Конференция "Сети" » передача Recordset через tcp [D7, WinXP]
 
  • dm37 (21.07.10 12:02) [0]
    Подскажите, как можно передать полученный recordset (ADO) в одной программе в другую через TCP
    Нужно что-то типа (конечно такая конструкция не работает - rs - это указатель на recordset):
    var
     ms: TMemoryStream;
     rs: _Recordset;
    begin
     ms.Write(rs,SizeOf(rs));
     TcpClient1.SendStream(ms);
    end;

    Одна программа получает данные с SQL Server и раздаёт их другим клиентам по tcp ().
    Может есть другой способ получения результата выполнения SQL-запроса, который позволит это сделать?
  • sniknik © (21.07.10 12:42) [1]
    > Нужно что-то типа (конечно такая конструкция не работает - rs - это указатель на recordset):
    естественно, указатель с одной машины на другой ничего не значит.
    копируй данные. есть возможность загнать их в ADOStream, а после передачи загрузить из него.

    > Может есть другой способ получения результата выполнения SQL-запроса, который позволит это сделать?
    трехзвенка, midas, soap, ...
  • dm37 (21.07.10 14:12) [2]
    если можно, то покажите на примере
    нашёл один пример, но там идёт преобразование через XML, а это будет достаточно долго (есть правда через ADTG (Advanced Data Tablegram), но как его дальше использовать не понимаю):
    var
     adoStream: OleVariant;
     St: TStrings;
    begin
     // Сначала ADODB.RecordSet -> ADODB.Stream через XML
     adoStream := CreateOLEObject('ADODB.Stream');
     Variant(ARecordSet).Save(adoStream, adPersistXML);
     // Теперь XML -> TStrings
     St := TStringList.Create;
     St.Text := adoStream.ReadText(adoStream.Size);
     // Ну а теперь всё просто
     AddFromStrings(AName, St);
     // Чищу память
     St.Free;
     adoStream := UnAssigned;

    Изначально я думал, что можно сделать так:
    у _RecordSet есть метод Save(FileName: WideString, PersistFormat: TOleEnum)
    сохранить данные в файл (только не на диске, а в памяти) и записать двоичные данные в TMemoryStream (поток сначало содержит структуру, где указывается тип данных следуемых далее в потоке) и всё это передать одним потоком по tcp.
    Но с реализацией ничего пока не получилось, вообще это возможно?

    Нужно что-бы работало по возможности быстро.
  • Медвежонок Пятачок © (21.07.10 18:08) [3]
    а это будет достаточно долго

    "достаточно долго" - это когда сохранение данных рекордсета занимает больше времени, чем последущая передача этих данных по сети

    так что на самом деле все наоборот - это "все достаточно быстро"
  • sniknik © (22.07.10 00:18) [4]
    > записать двоичные данные в TMemoryStream
    procedure SendDataset(Content: TStream; DataSet: TADODataSet);
    var
     adoStream: OleVariant;
     Buffer: Variant;
     PBuffer: pointer;
     size: integer;
    begin
     adoStream:= CreateOLEObject('ADODB.Stream');
     try
       Variant(DataSet.Recordset).Save(adoStream, adPersistADTG);
       size:= adoStream.Size;

       Buffer := adoStream.Read(size);
       PBuffer:= VarArrayLock(Buffer);
       try
         Content.WriteBuffer(PBuffer^, size);
       finally
         VarArrayUnlock(Buffer);
       end;
     finally
       adoStream:= UnAssigned;
     end;
    end;

  • dm37 (22.07.10 07:03) [5]
    Спасибо,
    будем пробовать
  • dm37 (22.07.10 07:24) [6]
    Дополнительно вопрос:
    в Buffer будет данные в формате который определяет ADO?
    а если результат SQL-запроса получать в Linux (например, с PostgreSQL) и передавать его по сети, то формат данных в переменной Buffer (в потоке) будет другим?
    Здесь наверно лучше использовать преобразование результат SQL-запроса в XML? Существуют стандарты на единый формат данных результата SQL-запроса?

    имеется ввиду, что программа получения данных с SQL Server (PostgreSQL) будет написана под Linux, а не доступ к SQL Server (linux) из Windows через ODBC.

    Спасибо.
  • Плохиш © (22.07.10 10:49) [7]

    > трехзвенка, midas, soap


    > dm37   (21.07.10 14:12) [2]
    >
    > если можно, то покажите на примере

    Этой теме посвящено больше двух трети толстенной книги "Руководство для разработчика" от указанной D7.
  • dm37 (22.07.10 13:46) [8]
    to sniknik
    если не затруднит, то можно ещё пример обратного преобразования
    TStream -> Recordset

    Спасибо за помощь
  • dm37 (22.07.10 14:46) [9]
    В итоге получилось это. Укажите пожалуйста на возможные ошибки (но пока работает):
    procedure AddRecordsetToStream(stream: TStream; const Recordset: _Recordset);
    var
     rs: Variant;
    begin
     if(Recordset = nil) then Exit;
     try
       rs:=CreateOleObject('ADODB.Recordset');
       rs:=Recordset;
       rs.Save(TStreamAdapter.Create(stream) as IUnknown, adPersistADTG);
     finally
     end;
    end;

    function RecordsetFromStream(const stream: TStream; pos: int64; size: int64): _Recordset;
    var
     rs: Variant;
     temp: TStream;
    begin
     Result := nil;
    //  stream.Position:=pos;
     temp:=TMemoryStream.Create;
     temp.CopyFrom(stream,size);
     try
       temp.Position:=0;
       rs:=CreateOleObject('ADODB.Recordset');
       rs.Open(TStreamAdapter.Create(temp) as IUnknown);
       Result:=IUnknown(rs) as _Recordset;
     finally
       temp.Free;
     end;
    end;
  • Slym © (23.07.10 09:24) [10]
    dm37   (22.07.10 14:46) [9]
    TStreamAdapter.Create(stream) as IUnknown

    точно не помню - он точно самоуничтожится? так надежней
    procedure AddRecordsetToStream(stream: TStream; Recordset: _Recordset);
    var
     st:TStreamAdapter;
     rs:variant;
    begin
    if(Recordset = nil) then Exit;
    st:=TStreamAdapter.Create(stream);
    try
      rs:=Recordset as IDispatch;
      rs.Save(st as IUnknown, adPersistADTG);
    finally
     st.Free;
    end;
    end;

 
Конференция "Сети" » передача Recordset через tcp [D7, WinXP]
Есть новые Нет новых   [134437   +27][b:0][p:0.001]