Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 Передача курсора с клиента на серверную ХП как входной параметр  [new]
makondo
Member

Откуда:
Сообщений: 428
Delphi, Oracle 9i, ODAC

С сервера получен ряд курсоров, который в ODACе сидят в коллекции TOraDataSet'ов. Получены они обычно как выходные параметры REF CURSOR разных ХП. Пользователь хочет сохранить одно или несколько полей (например, поле IDшника) обратно в БД в отдельную таблицу.
Для этого я хочу передать курсор обратно другой ХП.

Тема обсуждалась раньше и здесь и
здесь

К сожалению, передача в виде массива не годится, потому как не все данные вытащены, а их может быть много.

В первом треде гуру ни к чему не пришли, и я уж подумал, что это нереально.


На стороне сервера

function create_list_by_cur( i_refcur IN REF_CURSOR, 
		 			  i_listname in varchar2,
 					  o_count out number
					  ) 
return number
IS
 cmpndrow CMPND%ROWTYPE;
 n number;
 l_idlist number;
begin

 if not(i_refcur%ISOPEN) then
  return -1;
 else
  n := 0;
  l_idlist := lstlist_lib.create_obj( i_listname, null, 'IDNUMBER');
  if l_idlist<= 0 then 
   return -1;
  end if;

--   ЦИКЛ ОБРАБОТКИ КУРСОРА

   LOOP
   fetch i_refcur INTO cmpndrow;
   EXIT WHEN i_refcur%notfound;  
   
   INSERT INTO IDLIST(part, IDNUMBER) VALUES (l_idlist, cmpndrow.IDNUMBER);
   commit;
   n := n+1;
      
  END LOOP; --  i_refcur

--------------   ЦИКЛ ОБРАБОТКИ КУРСОРА
  o_count := n; 
  return l_i_refcur%ROWCOUNT;
 end if; 
 
exception
	when others then
		return 0; 
end; -- function create_list( i_cur IN REF_CURSOR,


на стороне клиента:

Вызов

 ds := ( self.CRDBGridCmpnd.DataSource.DataSet as TOraDataSet);
 ds.DisableControls;
 dmChs.CreateListByCur( ds, floatToStr(usrdb_id)+'selection', idlist, n)
finally
 ds.EnableControls;
end;//fin
/////////////////////////////////////////////////////////////////

function TdmChS.CreateListByCur(i_refcur: ORA_TYPE_CURSOR;
  i_listname: String; var idlist, o_count: Double): boolean;
var
 tmp : TOraStoredProc;
begin
 try
   tmp := TOraStoredProc.Create(nil);

    tmp.Session := OraSession1;
    tmp.StoredProcName := 'cmpnd_lib.create_list_by_cur';
    tmp.PrepareSQL;
    tmp.ParamByName('i_refcur').ParamType := ptInput;
    tmp.ParamByName('i_refcur').AsCursor := i_refcur.Cursor;

    tmp.ParamByName('i_listname').AsString := i_listname;

    tmp.Execute;
   
    o_count :=     tmp.ParamByName('o_count').ASFLOAT;
    idlist  :=     tmp.ParamByName('RESULT').ASFLOAT;
   
 except
   result := false;
 end;//exc
end; 



Указанный вызов возвращает ошибку ORA-01406: fetched column value was truncated
Это странно, что не INVALID CURSOR или что-то в этом роде. Значит, он туда все-таки передался, но не смог обработаться...

Естественно, набор данных у i_refcur соответствует записи из CMPND.

Можно ли с этим сто-то сделать? Или где я мог ошибиться при вызове ХП?

Есть подозрение, что
tmp.ParamByName('i_refcur').ParamType := ptInput;
tmp.ParamByName('i_refcur').AsCursor := i_refcur.Cursor;
не есть хорошо...
8 фев 07, 01:41    [3753536]     Ответить | Цитировать Сообщить модератору
 Re: Передача курсора с клиента на серверную ХП как входной параметр  [new]
Alexei_Unregistered
Guest
1. Для того, чтобы фетчить из refcursor-а в stored процедуре,
его нужно туда передавать in out параметром.
2. ORA-01406 может возникнуть, если есть расхождение
в длине отдельных полей курсора и поле принимающей переменной.
8 фев 07, 09:34    [3753988]     Ответить | Цитировать Сообщить модератору
 Re: Передача курсора с клиента на серверную ХП как входной параметр  [new]
OracleX
Member

Откуда:
Сообщений: 1998
Вот так будет работать:
    LOOP 
       fetch i_refcur INTO cmpndrow;
       n := n+1;
       EXIT WHEN i_refcur%ROWCOUNT<N;
       
       INSERT INTO IDLIST(part, IDNUMBER) VALUES (l_idlist, cmpndrow.IDNUMBER);
       commit;
    END LOOP; --  i_refcur
На клиенте,
вызывайте хранимку с помощью TOraSQL, чтобы не зафетчилась ни одна строка ref курсора.
Также, Oracle по завершению процедуры даст fetch_out_of_sequence, просто нужно игнорировать.
  try
    tmp.Execute;
  except
     --Если ошибка fetch_out_of_sequence (-01002), то все нормально
  end;
Может еще кто подскажет, как побороть fetch_out_of_sequence.
8 фев 07, 15:26    [3756854]     Ответить | Цитировать Сообщить модератору
 Re: Передача курсора с клиента на серверную ХП как входной параметр  [new]
makondo
Member

Откуда:
Сообщений: 428
OracleX
Вот так будет работать:
    LOOP 
       fetch i_refcur INTO cmpndrow;
       n := n+1;
       EXIT WHEN i_refcur%ROWCOUNT<N;
       
       INSERT INTO IDLIST(part, IDNUMBER) VALUES (l_idlist, cmpndrow.IDNUMBER);
       commit;
    END LOOP; --  i_refcur


Можно комментарий, почему это лучше, чем

   LOOP
   fetch i_refcur INTO cmpndrow;
   EXIT WHEN i_refcur%notfound;  
   
   INSERT INTO IDLIST(part, IDNUMBER) VALUES (l_idlist, cmpndrow.IDNUMBER);
   commit;
   n := n+1;
      
  END LOOP; --  i_refcur

?


На клиенте,
вызывайте хранимку с помощью TOraSQL, чтобы не зафетчилась ни одна строка ref курсора.
Также, Oracle по завершению процедуры даст fetch_out_of_sequence, просто нужно игнорировать.
  try
    tmp.Execute;
  except
     --Если ошибка fetch_out_of_sequence (-01002), то все нормально
  end;
Может еще кто подскажет, как побороть fetch_out_of_sequence.


вызывайте хранимку с помощью TOraSQL,

Можно привести пример вызова?

И кстати, возникает вопрос. Если я сделал на клиенте dataset.open , то из курсора при этом сразу считались 25 записей. Если я посылаю его после этого на сервер, там он будет считывать с 26й ?
А можно, чтобы с 1ой ?
8 фев 07, 15:34    [3756917]     Ответить | Цитировать Сообщить модератору
 Re: Передача курсора с клиента на серверную ХП как входной параметр  [new]
Elic
Member

Откуда:
Сообщений: 29984
makondo
А можно, чтобы с 1ой ?
Дежавю?! STFF Курсорная переменная в приложение и обратно
8 фев 07, 15:39    [3756960]     Ответить | Цитировать Сообщить модератору
 Re: Передача курсора с клиента на серверную ХП как входной параметр  [new]
OracleX
Member

Откуда:
Сообщений: 1998
makondo
Можно комментарий, почему это лучше
Пардон, я наврал, у Вас было правильно. Уберите временно Insert и Commit, чтобы упростить.
8 фев 07, 15:39    [3756962]     Ответить | Цитировать Сообщить модератору
 Re: Передача курсора с клиента на серверную ХП как входной параметр  [new]
OracleX
Member

Откуда:
Сообщений: 1998
makondo
А можно, чтобы с 1ой ?
Можно, я и написал, как это сделать.
8 фев 07, 15:42    [3756987]     Ответить | Цитировать Сообщить модератору
 Re: Передача курсора с клиента на серверную ХП как входной параметр  [new]
OracleX
Member

Откуда:
Сообщений: 1998
  OraSQL1.Execute;
  OraStoredProc1.ParamByName('i_refcur').AsCursor := OraSQL1.ParamByName('i_refcur').AsCursor;
  try
    OraStoredProc1.Execute;
  except
     //Если ошибка fetch_out_of_sequence (-01002), то все нормально
  end;
8 фев 07, 15:44    [3757016]     Ответить | Цитировать Сообщить модератору
 Re: Передача курсора с клиента на серверную ХП как входной параметр  [new]
Elic
Member

Откуда:
Сообщений: 29984
OracleX
makondo
А можно, чтобы с 1ой ?
Можно, я и написал, как это сделать.
Это всего лишь "как на клиенте не сместить позицию с 1". А это немного не то :)
8 фев 07, 15:50    [3757064]     Ответить | Цитировать Сообщить модератору
 Re: Передача курсора с клиента на серверную ХП как входной параметр  [new]
OracleX
Member

Откуда:
Сообщений: 1998
Если гора не идет...
8 фев 07, 15:52    [3757081]     Ответить | Цитировать Сообщить модератору
 Re: Передача курсора с клиента на серверную ХП как входной параметр  [new]
makondo
Member

Откуда:
Сообщений: 428
OracleX
  OraSQL1.Execute;
  OraStoredProc1.ParamByName('i_refcur').AsCursor := OraSQL1.ParamByName('i_refcur').AsCursor;
  try
    OraStoredProc1.Execute;
  except
     //Если ошибка fetch_out_of_sequence (-01002), то все нормально
  end;



А что выше этого кода? Как инициализировать runtime OraSQL1 ?
Я им ни разу не пользовался просто...
8 фев 07, 16:23    [3757292]     Ответить | Цитировать Сообщить модератору
 Re: Передача курсора с клиента на серверную ХП как входной параметр  [new]
OracleX
Member

Откуда:
Сообщений: 1998
  object OraSQL1: TOraSQL
    Session = OraSession1
    SQL.Strings = (
      'begin'
      '  cmpnd_lib.refc_slct(:I_REFCUR);'
      'end;')
    Left = 272
    Top = 24
    ParamData = <
      item
        DataType = ftCursor
        Name = 'I_REFCUR'
      end>
  end
Также проникнись тем, что сказал Elic.
На клиенте ты этот курсор фетчить НЕ ДОЛЖЕН, ты его можешь только передать
из одной хранимки в другую посредством довольно стремных вызовов с клиента.
8 фев 07, 16:31    [3757371]     Ответить | Цитировать Сообщить модератору
 Re: Передача курсора с клиента на серверную ХП как входной параметр  [new]
makondo
Member

Откуда:
Сообщений: 428
Учитель, мое понимание углубляется.. :)
8 фев 07, 18:18    [3758158]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить