mirall: (Default)
    В процессе попыток скомпилировать существующий код в Oracle XE (10.2.0.1) обнаружила одну неприятную особенность: возможность создания объекта только через позиционную нотацию. Т.е. вместо
select my_object (num_val => t.num_val, str_val => t.str_val) from my_table t
приходится использовать
select my_object (t.num_val, t.str_val) from my_table t
    Это мелочь, если объекты маленькие. А у меня попадаются экземпляры на двадцать атрибутов.
    И ещё всякое )
mirall: (job)
    Загвоздка была (совершенно классически) в том, что несколько процессов одновременно пытались редактировать одну и ту же строку в таблице.
    Процедура, о которую споткнулось приложение, принимала на вход сложный объект с атрибутами-массивами, данные из которых нужно было разложить по таблицам.
    Первый вариант реализации был прост и незатейлив: существовала отдельная процедура, которая записывала результат для одной строки, и вызывалась в цикле (не оптимально, но удобно). Споткнулись о deadlock.
    Второй вариант: заменила цикл на bulk merge (до вчерашнего дня и не подозревала, что bulk merge возможен наравне с bulk insert и bulk update). Не помогло. Вернее помогло частично: deadlock стал появляться не сразу, а через минуту где-то после запуска приложения.
    Собралась с силами, переделала bulk merge в merge по select * from table (input_array). И, похоже, сработало. По крайней мере, тесты, оставленные гоняться ночью, ошибок не выкинули.
    Мораль сей басни такова. Циклы must die — это раз. Bulk update/merge имеет смысл использовать только если обычный update/merge ну никак невозможен — это два.
    Побочный эффект, который ещё придётся преодолеть: массив там не просто массив, а массив сложных объектов, каждый из которых также имеет атрибут-массив, который тоже нужно сохранить. Так что пора изобрести какой-то волшебный способ сделать прямой select из этого массива. Чем сейчас и займусь.

PLS-00231

Jul. 9th, 2010 12:35 pm
mirall: (job)
    Нельзя вызвать private функцию из SQL. Типа, объяснение: "How SQL engine which is external to the package can access a procedure that is private to the package?"
mirall: (job)
ORA-56900: bind variable is not supported inside pivot|unpivot operation
Оказывается, не только DDL не поддерживают переменные привязки.
mirall: (job)
    После вдумчивого ковыряния asktom.oracle.com, документации и металинка получилась следующая процедурка.
    Код )

utPLSQL

Mar. 29th, 2010 06:19 pm
mirall: (job)
    Добрались до юнит-тестов. Пока тоскливо.
    Тем не менее, мелкий нюанс уже всплыл.
    utAssert.eq_refc_query принимает на вход последним параметром запрос, который потом сравнивает c ref_cursor. И вся эта бодяга вместо того, чтобы честно сравнивать наборы данных, начала возвращать ошибку ORA-06502: PL/SQL: numeric or value error: dbms_sql.describe_columns overflow, col_name_len=33. Use describe_columns2. Тем более мерзостно, что у меня всё приложение работает на базе ref_cursor. Победилось тупым ковырянием пакета utplsql_util и по совету компилятора заменой describe_columns на describe_columns2, а DBMS_SQL.desc_tab на DBMS_SQL.desc_tab2.
    Всё равно не работает, но, по крайней мере, падает уже с другой ошибкой.
mirall: (job)
    Задача: имеется некий запрос с динамически настраиваемым условием where. Параметры передаются с веб-интерфейса, при этом если параметр пуст, т.е. is null, то он не должен включаться в условие where. Дополнительное условие — постраничный вывод данных, но это мы уже проходили.
    Подход я придумала сама, давно уже. А выношу этот вопрос на публику сейчас, потому что сегодня наткнулась на статью приснопамятного Тома Кайта как раз на эту тему. Мой личный подход концептуально не отличается, но кажется более сложным, у Кайта как-то полегче. Но переделывать, наверное, уже не буду — слишком много в приложении на него завязано. Хотя кое-что можно попробовать поковырять с целью повышения производительности.
    Подробности и много кода )
mirall: (job)
    Система построена таким образом, что pl/sql процедуры возвращают в java ref cursor. Время от времени возникает необходимость вернуть столбец status, содержащий либо 'SUCCESS', либо сообщение об ошибке (ну вот договорились так). Если нужно вернуть только статус, то это делается стандартной процедурой returns.ReturnTextSuccess / returns.ReturnTextError, и всё прекрасно.
    Сегодня влетела с треском, когда статус нужно было вернуть в рамках многостолбцового курсора. Вернее даже не знаю, кто тут виноват, я или JDBC. Но вместо 'SUCCESS' в java приходило 'S'. А на меня катили бочки. При этом, кстати, сообщения об ошибках возвращались нормально и полностью.
    Устранилось просто и незамысловато.
procedure RetVal (o_cur out sys_refcursor) is
begin
  open o_cur for
    select 'SUCCESS' status
      from dual;
end;
заменила на
procedure RetVal (o_cur out sys_refcursor) is
  SUCCESS_MESSAGE constant varchar2(10 char) := 'SUCCESS';
begin
  open o_cur for
    select SUCCESS_MESSAGE status
      from dual;
end;
    Где там на пути от базы к java-приложению строковая константа превращалась в char, непонятно.
mirall: (job)
    Особенность проекта — доступ к БД только через хранимые процедуры. Все процедуры возвращают output cursor. Поэтому для тех, которые возвращают заведомо одно значение, работает мелкий пакет returns. В т.ч. returns.ReturnTextSuccess.
    Текст )
    Т.е. вернуть фиксированное значение с возможностью задать имя столбца. По умолчанию возвращается 'SUCCESS'.
    Сегодня процедура GetEmailDefaultAttr начала возвращать этот самый 'SUCCESS'. Понятное дело, потому что значение атрибута было null. Но как-то я оказалась к такому выверту не готова :)
mirall: (job)
    Баг за номером 7174888.
declare
  sValue varchar2(50);
  cOut sys_refcursor;
  procedure p1 (o_cur out sys_refcursor)
  begin
    open o_cur for
      select 'value' value from dual;
  end p1;
begin
  p1( o_cur => cOut );
  fetch cOut r into sValue;
  close cOut
end;
    Падает на этапе fetch с ошибкой ORA-06504: PL/SQL: Return types of Result Set variables or query do not match

    Workaround.
    Открыть предварительно курсор.
declare
  sValue varchar2(50);
  cOut sys_refcursor;
  procedure p1 (o_cur out sys_refcursor)
  begin
    open o_cur for
      select 'value' value from dual;
  end p1;
begin
  open cOut for 'select 1 from dual';
  p1( o_cur => cOut );
  fetch cOut r into sValue;
  close cOut
end;
mirall: (job)
    Для того, чтобы стало возможным использование пакетов UTL_TCP, UTL_SMTP, UTL_MAIL, UTL_HTTP, UTL_INADDR необходимо некоторое количество танцев с бубном. В частности, настроить т.н. Access Control Lists (это примочка XML DB).
    Полностью процесс описан в документации: Oracle® Database Security Guide -> 4 Configuring Privilege and Role Authorization.
    Вкратце же, вся бодяга выглядит следующим образом.
  1. Создаётся access list (в дальнейшем - список контроля доступа)
    DBMS_NETWORK_ACL_ADMIN.CREATE_ACL (
      acl          => 'file_name.xml', 
      description  => 'file description',
      principal    => 'user_or_role',
      is_grant     => TRUE|FALSE, 
      privilege    => 'connect|resolve',
      start_date   => null|timestamp_with_time_zone,
      end_date     => null|timestamp_with_time_zone);
    причём параметр privilege чувствителен к регистру.
  2. Списку присваивается один или несколько адресов.
     DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL (
      acl         => 'file_name.xml',
      host        => 'network_host', 
      lower_port  => null|port_number,
      upper_port  => null|port_number);
  3. Привилегия на использование списка предоставляется пользователю или роли.
    DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE ( 
      acl         => 'file_name.xml', 
      principal   => 'user_or_role',
      is_grant    => TRUE|FALSE, 
      privilege   => 'connect|resolve', 
      position    => null|value, 
      start_date  => null|timestamp_with_time_zone,
      end_date    => null|timestamp_with_time_zone);
Если все манипуляции провести аккуратно, то получится с первого раза. Поскольку я патологически невнимательна, то у меня на всё про всё ушло около часа.
Page generated Jul. 14th, 2025 08:42 pm
Powered by Dreamwidth Studios