Oracle DB, Oracle APEX, Linux etc.

понедельник, 27 декабря 2010 г.

Пара фраз о JSON

Вначале - о проблеме. Сколько раз сталкиваюсь, что JSON-парсер в Firefox вдруг по какой-то причине спотыкается на казалось бы правильной JSON-строке. Решение довольно простое - завернуть эту строку в обычные скобки:

  var result = JSON.parse("("+json_string+")");

Теперь - о довольно удобном средстве работы с JSON из PL/SQL. Вам хочется организовать эту работу так?

declare
  l_json json := json();
begin
  l_json.put('name', 'Taras');
  l_json.put('sons', json_list('["Mykola", "Vasyl"]'));
  htp.p(l_result.to_char);
end;
/

Тогда обратите своё внимание на проект PL/JSON. Думаю, он облегчит Вам жизнь - особенно, если Вы не поленитесь просмотреть короткие уроки.
Читать далее

пятница, 10 декабря 2010 г.

Oracle APEX: Медвежья услуга при копировании страницы

С прискорбием вынужден сообщить, что как минимум в версиях 3.2.1 и 4.0.1 я наткнулся на неприятный баг. При копировании страницы автоматически заменяются имена старых элементов: PMXXX заменяется на PNXXX, где M и N - номера оригинальной страницы и копии, соответственно. Проблема в том, что стоило бы заменять PM_XXX.

Для примера: у нас есть страница 5, которая где-то - в переходах, в значении элемента, в процессах - ссылается на элемент P52_X страницы 52. Теперь мы решили скопировать страницу 5 с новым номером 60. После копирования новая страница будет ссылаться на несуществующий элемент P602_X: было 52, стало 602.

Вот такая неприятная штука.
Читать далее

понедельник, 29 ноября 2010 г.

Oracle: Consistency и разминка для ума

Допустим, что в одной сессии выполнится следующее:

drop table t7;
create table t7 as select 1 id, 0 val from dual;
insert into t7 values(2, 0);
update t7 set val = 1;

Затем во второй выполнилось вот это:

update t7 x set val = (select t.val + 1 from t7 t where t.id = x.id);
commit;
select * from t7;

Что выведется во второй сессии на экран?

Теперь повторим в первой сессии тот же блок, что и вначале, а во второй выполним:

update t7 x set val = (select x.val + 1 from t7 t where t.id = x.id);
commit;
select * from t7;

Каким будет результат?

PS: Ответы и информацию для размышления опубликую через пару дней.
Читать далее

суббота, 20 ноября 2010 г.

Oracle APEX: Сколько транзакций в фазе Page Processing?

И правильный ответ... Одна.

Из любопытства я сделал простой тест, чтобы подтвердить, что обработка страницы происходит в одну транзакцию:

0. Создал таблицу и пакет для лога.

create table processing_steps (ordr number, msg varchar2(1000 char));

create or replace package proc_stp_pkg
as
  procedure reset;
  procedure add(p_ordr number, p_msg varchar2);
  procedure add_auton(p_ordr number, p_msg varchar2);
end proc_stp_pkg;
/

create or replace package body proc_stp_pkg
as
  procedure reset
  is
    pragma autonomous_transaction;
  begin
    delete processing_steps;
    commit;
  end;
  
  procedure add(p_ordr number, p_msg varchar2)
  is
  begin
    insert into processing_steps(ordr, msg) values (p_ordr, p_msg);
  end;
  
  procedure add_auton(p_ordr number, p_msg varchar2)
  is
    pragma autonomous_transaction;
  begin
    add(p_ordr=>p_ordr, p_msg=>p_msg);
  
    commit;
  exception
    when others then 
      rollback;
      raise;
  end;
end proc_stp_pkg;
/

1. Создал в APEX страницу с процессом перед проверками, вычислением, проверкой и процессом после вычисления. В каждом из них есть строки:

rollback;
proc_str_pkg.add(..., '...');
proc_str_pkg.add_auton(..., '...');

2. Добавил кнопку и переход на эту же страницу при нажатии.
3. Запустил страницу и нажал на кнопку.
4. Выполнил запрос:

SQL> set pages 9999 line 200
SQL> column msg format a50
SQL> select * from processing_steps
  2  order by ordr;

      ORDR MSG
---------- --------------------------------------------------
         1 Pr: On Submit - Before Computations and Validation
           s - Autonomous Transaction

         3 Computation - Autonomous Transaction
         5 Validation - Autonomous Transaction
         6 Pr: On Submit - After Computations and Validations
         7 Pr: On Submit - After Computations and Validations
            - Autonomous Transaction


SQL>

Пропущенные вставки 0, 2 и 4 откатывались оператором ROLLBACK в последующих блоках обработки. Вставка 6 автоматически зафиксировалась при успешном выполнении последнего блока. Так что будьте осторожней, управляя фиксацией и откатом в Вашем коде - Вы можете повлиять на результаты предыдущих блоков.

Читать далее

понедельник, 15 ноября 2010 г.

Oracle APEX + Oracle SQL Developer = Сила двух

Предлагаю вниманию читателей перевод одной статьи. Она понравилась мне объяснением возможностей удалённой отладки, и я решил перевести её целиком. Надеюсь, она пригодится...

Сила двух
Дэвид Пик
Перевод: Александр Поливаный 

Использование Oracle SQL Developer при разработке в Oracle Application Express.

Oracle Application Express (Oracle APEX) и Oracle SQL Developer (OSD) — это бесплатные инструменты, оба работающие с Oracle Database версии 9.2 и выше. OSD не только помогает Вам в разработке приложений БД, но также даёт Вам возможности просмотра, экспорта, импорта, внедрения и удалённой отладки Ваших приложений Oracle APEX.

Эта статья покажет, как OSD и Oracle APEX работают вместе, способствуя разработке. Мы увидим, как можно просматривать информацию о приложениях Oracle APEX из OSD. Затем мы пройдёмся по примеру удалённой отладки PL/SQL-кода, выполняющегося в браузерном приложении, из OSD.


Введение


Используя OSD в связке с Oracle APEX, Вы можете просматривать несколько приложений и страниц и быстро добираться до конкретных данных. К примеру, в Oracle APEX Вам потребуется два браузера, чтобы глядеть* на код двух списков значений (list of values, LOV) в двух разных приложениях одновременно. В OSD всё, что нужно - развернуть оба приложения в списке подключений (Connections). Также OSD специально для Oracle APEX предоставляет несколько очень полезных и подробных отчётов о приложениях, страницах, схемах и рабочих пространствах (категория Data Dictionary Reports в отчётах).

OSD позволяет Вам экспортировать, импортировать и внедрять приложения во многих рабочих пространствах, экземплярах APEX и базах данных. ПКМ на названии приложения вызывает контекстное меню, при помощи которого можно переносить приложение с его вспомогательными объектами из одного рабочего пространства в другое. Эта возможность особенно полезна при внедрении приложений из разработки в тестирование или производство.

Вы можете копировать SQL-код из Ваших регионов, списков значений и проверок, вставлять их в SQL Worksheet в OSD и выполнять. OSD даст Вам ввести значения для связываемых переменных и запустить EXPLAIN PLAN или AUTOTRACE для запроса, чтобы обнаружить проблемы с производительностью и настроить SQL.

Для примеров в этой статье требуются Oracle APEX 3.0.1 и выше и OSD 1.2.1 и выше. (Обратите внимание, что Вы не сможете выполнить примеры, используя Oracle APEX на apex.oracle.com.) Вам также потребуется рабочее пространство Oracle APEX, связанное со схемой-примером HR, доступной в БД по умолчанию.


Просмотр информации Oracle APEX


Создайте подключение в OSD к схеме HR. Для пошаговых инструкций по созданию подключений в OSD читайте статью "Making Database Connections" в этом выпуске Oracle Magazine.**

Когда соединение установится, Вы сможете увидеть пункт Application Express под подключением HR в списке подключений (Connections), как показано на рисунке (под подключением XE Dpeake):

Пункт Application Express в Oracle SQL Developer


Теперь Вы можете просмотреть приложения Oracle APEX пользователя HR, используя закладки с подробной информацией:
Закладки с подробной информацией о приложении



Удалённая отладка


Вы можете использовать OSD для удалённой отладки PL/SQL-кода. Эта возможность особенно полезна в случае, когда приложение не прекращает выполнение, но и не даёт результатов, которые Вы ожидали. Чтобы потренироваться, выполните следующие шаги для отладки процедуры в упакованном приложении Oracle APEX "Asset Manager":

Шаг 1: Получение и установка упакованного приложения. Скачайте, импортируйте и разверните приложение в Oracle APEX.

  1. Скачайте и сохраните asset_manager_1.0.zip с сайта http://www.oracle.com/technetwork/developer-tools/apex/application-express/packaged-apps-090453.html#ASSETS .
  2. Разархивируйте файл.
  3. В OSD подключитесь к схеме HR.
  4. ПКМ по пункту Application Express под HR в списке подключений, выберите Import Application (Импортировать приложение).
  5. Найдите и откройте разархивированную папку asset_manager_1.0, выберите файл asset_manager_installer_1.0.sql.
  6. Нажмите Next (Далее).
  7. Установите флажок Run Install Script (Запустить установочный скрипт) и нажмите Next.

    Импорт и внедрение приложения
  8. Нажмите Finish (Завершить).
  9. Нажмите OK в окне, сообщающем об успешной установке.


Шаг 2: Настройка OSD для удалённой отладки. Подготовьте OSD для отладки процедуры EBA_ASSET.update_status, выполняемой в приложении, удалённо.

  1. В OSD подключитесь к базе данных как пользователь с привилегиями DBA.***
  2. Введите следующий код. Если необходимо, замените PUBLIC на имя пользователя, от имени которого запускается Oracle APEX в mod_plsql.
    grant DEBUG CONNECT SESSION to HR; 
    grant DEBUG on HR.EBA_ASSET to PUBLIC;
  3. Нажмите кнопку Run Script (или нажмите F5).
  4. Подключитесь как HR.
  5. В Подключениях откройте пункт Packages (Пакеты) и нажмите EBA_ASSET.
  6. ПКМ по телу пакета EBA_ASSET и выберите Edit (Править).
  7. ПКМ по левому полю в редакторе кода, выберите Toggle Line Numbers (Отображать номера строк).
  8. Перейдите вниз, к строке 113, ПКМ по левому полю в редакторе кода, выберите Toggle Breakpoint (Установить точку остановки).
  9. ПКМ по коду, выберите Compile for Debug (Компилировать для отладки). Заметьте, что выполнение пакета в режиме отладки сильно помешает производительности. Когда тестирование закончится, Вам стоит перекомпилировать пакет без отладочной информации.
  10. ПКМ по подключению HR в Подключениях, выберите Remote Debug (Удалённая отладка).

    Oracle SQL Developer настроен для удалённой отладки
  11. Нажмите OK.


Шаг 3: Настройка Oracle APEX для отладки. Подготовьте Oracle APEX к отладке процедуры EBA_ASSET .update_status:

  1. Войдите в Oracle APEX как разработчик соответствующего рабочего пространства - того, в которое Вы установили приложение "Asset Manager".
  2. Нажмите Application Builder.
  3. Нажмите Asset Manager 1.0.
  4. Откройте страницу 11 - Inventory Details.
  5. В Процессах (Processes) нажмите Update Asset Status.
  6. В поле Source замените код на следующий:
  7. IF :DEBUG = 'YES' THEN
         dbms_debug_jdwp.connect_tcp('localhost',4000);
    END IF;
    eba_asset.update_status(:P11_ASSET_ID);
    IF :DEBUG = 'YES' THEN
         dbms_debug_jdwp.disconnect;
    END IF;
    Этот код будет срабатывать только тогда, когда страница запущена в режиме отладки. Второй блок IF отключает отладочную сессию.
  8. Нажмите Apply Changes (Применить изменения).

Шаг 4: Запуск приложения. Запустите приложение "Asset Manager" в Oracle APEX, вначале в обычном режиме, а затем - в режиме отладки.

  1. В Oracle APEX вернитесь назад, к странице 1 и нажмите Run (Запустить).
  2. Войдите в приложение как HR.
  3. Выберите Assets.
  4. Нажмите иконку редактирования для любой записи.
  5. Нажмите иконку редактирования для записи остатков. Поменяйте значение поля Status (статус).
  6. Нажмите Apply Changes. Приложение нормально обработает изменения, потому оно запущено не в режиме отладки.
  7. Нажмите иконку редактирования для той же записи остатков.
  8. Нажмите Debug (Отладка) на панели инструментов разработчика.
  9. Панель инструментов разработчика в Oracle APEX
  10. Поменяйте статус и нажмите Apply Changes.
  11. Теперь OSD должен перехватить фокус ввода. (Если этого не произошло, то приложение будет показывать частично завершённый процесс загрузки страницы, и Вам нужно будет открыть окно OSD самостоятельно.)
  12. Используйте инструменты OSD, чтобы возобновить выполнение, выполнять отладку пошагово с обходом и со входом в процедуру. Во время отладки процедуры Вы можете видеть изменения значений в переменных и в данных.

Когда процедура закончит выполнение, удалённый отладчик отсоединится.

Вы можете использовать удалённую отладку, чтобы пошагово пройти сквозь сложную PL/SQL обработку, которая не выполняет предназначенное. Наблюдение за значениями переменных и данных во время отладки программы помогает определить ошибку в логике.


Заключение


Вы можете использовать Oracle SQL Developer, чтобы выполнять следующие задачи, когда Вы разрабатываете приложения Oracle Application Express:

  • Быстрое перемещение между компонентами Ваших приложений.
  • Экспорт, импорт и внедрение приложений.
  • Настройка SQL.
  • Удалённая отладка PL/SQL.

Сочетание Oracle SQL Developer и Oracle Application Express может дать Вам значительный рост производительности в разработке Web-приложений.

Примечания переводчика

 
* Дэвид не досказывает либо лукавит, говоря "глядеть" (to view) вместо "работать". Чтобы глядеть, хватит и двух закладок в браузере. Естественно, что все необходимые переменные сессии APEX — рабочее пространство, номер приложения, номер страницы — будут устанавливаться в зависимости от последнего открытого LOV. Кроме того, для одновременной работы с двумя приложениями в одном браузере можно использовать дублирование DNS-имён хоста с APEX. Подробней можно почитать здесь: Martin Giffy D'Souza on Oracle APEX - APEX: How to Develop in 2 Browser Tabs.

** Или просто нажмите F1 и читайте раздел справки SQL Developer Concepts and Usage->Database Connections.

*** Имеется в виду пользователь с правами, достаточными для выдачи привилегий DEBUG CONNECT SESSION и DEBUG HR.EBA_ASSET.

Читать далее

пятница, 12 ноября 2010 г.

Oracle APEX: 4.0.2 на пороге

Если я всё верно понял.

Ждём-с!

UPD 2010-11-20: На MOS уже доступен для загрузки патч 10173973.
Читать далее

пятница, 29 октября 2010 г.

Oracle SQL Developer: ORA-12705

Честно говоря, я лично не сталкивался с этой ошибкой. Под Debian GNU/Linux мне достаточно было указать соответствующие NLS-настройки в Tools->Preferences->Database->NLS:


С учётом моей локали, больше ничего не потребовалось.

suppler@dark-place:~$ locale
LANG=ru_UA.UTF-8
LC_CTYPE="ru_UA.UTF-8"
LC_NUMERIC="ru_UA.UTF-8"
LC_TIME="ru_UA.UTF-8"
LC_COLLATE="ru_UA.UTF-8"
LC_MONETARY="ru_UA.UTF-8"
LC_MESSAGES="ru_UA.UTF-8"
LC_PAPER="ru_UA.UTF-8"
LC_NAME="ru_UA.UTF-8"
LC_ADDRESS="ru_UA.UTF-8"
LC_TELEPHONE="ru_UA.UTF-8"
LC_MEASUREMENT="ru_UA.UTF-8"
LC_IDENTIFICATION="ru_UA.UTF-8"
LC_ALL=

Тем не менее, есть один проверенный способ. Необходимо добавить в один из конфигурационных файлов SQL Developer опции с явным указанием языка и страны. Например, в <sqldeveloper_root_dir>/sqldeveloper/bin/sqldeveloper.conf:

AddVMOption -Duser.language=en
AddVMOption -Duser.country=US

Надеюсь, эта заметка вместе с другой сэкономит кое-кому время.
Читать далее

четверг, 21 октября 2010 г.

Oracle APEX: Кому дать привилегии?

В ситуации, когда приложение работает с несколькими схемами БД, часто возникает вопрос: какому пользователю дать привилегии на запрос/DML/выполнение, чтобы приложение спокойно могло обращаться к объектам этих схем? Ответ прост: дайте привилегии пользователю-владельцу схемы разбора приложения (aka parsing schema). Вы можете узнать имя пользователя, зайдя в Application->Edit Application Properties и глянув на Name->Parsing Schema. Также можно выполнить запрос:
select owner from apex_applications where application_id = :p_your_app_id;
Это тот пользователь, от имени которого выполняются все операторы и PL/SQL-блоки в Вашем приложении, так что именно ему требуется права на всё, с чем работает приложение.

Кое-кто предпочитает дать привилегии всем, дав их роли PUBLIC, но на мой взгляд, простота часто не стоит безопасности. Лучше пожертвовать временем и дать привилегии тем, кому они действительно нужны, чем пожертвовать безопасностью.

Если кто-то заинтересовался, как же в сессии пользователя ANONYMOUS/APEX_PUBLIC_USER выполняются операторы и PL/SQL-код с правами пользователя-владельца схемы разбора, то можно поискать в Сети информацию про недокументированный пакет DBMS_SYS_SQL.

Надеюсь, что вопрос исчерпан. Удачи!
Читать далее

понедельник, 18 октября 2010 г.

Небольшое обновление в блоге

Я обновил Syntax Highlighter до версии 3.0.83, так что теперь, чтобы выделить текст в блоке с кодом, достаточно двойного щелчка по нему. Спасибо Алексу Горбачёву за этот замечательный проект!
Читать далее

воскресенье, 17 октября 2010 г.

Oracle: С опозданием о паре вещей...

0. Oracle SQL Developer 3.0 EA1 вполне себе доступен для скачивания. Список новых возможностей можно посмотреть здесь.
1. Oracle SQL Developer Data Modeler теперь бесплатен! Версию 3.0 EA1 можно скачать здесь.

Я знаю, что это не новости, но тем не менее, вести приятные. Как компенсация - интересный слух с OOW 2010: общественности стало известно, что работы над Oracle XE 11g уже ведутся, и что допустимый объём пользовательских данных поднимут с 4 до 10 ГБ...
Читать далее

четверг, 14 октября 2010 г.

Oracle APEX: Почему возникла ошибка 404?

The requested URL /pls/apex/wwv_flow.accept was not found on this server.

Знакомо? Что-то произошло, но что именно - расскажет лог HTTP-сервера. А что, если к нему нет доступа в эти моменты, или нет времени, чтобы добираться к файлу error_log.xxxxx? Не проблема! Всё, что нужно - добавить следующее в dads.conf/marvel.conf в <Location /pls/apex>:

...
 PlsqlErrorStyle  DebugStyle
 ...

И Вы получите подробное описание ошибки вместо невразумительной Error 404.

А что делать, если Вы используете EPG? Настраивать его DAD через соответствующий пакет, конечно:

exec dbms_epg.set_dad_attribute('APEX', 'error-style', 'DebugStyle');

Выполните вышеуказанный блок от пользователя SYS или другого, у которого есть роль XDBADMIN. И дело в шляпе.
Читать далее

воскресенье, 3 октября 2010 г.

Oracle Materialized Views: DBMS_MVIEW.EXPLAIN_MVIEW с человеческим лицом

Хочу упомянуть одну полезную функцию, которую я нашёл на SQL Snippets. Она автоматизирует весь тот процесс, который обычно выполняется при экспериментах с материализованными представлениями: вызов DBMS_MVIEW.EXPLAIN_MVIEW, вывод информации на экран, очистка MV_CAPABILITIES_TABLE. Теперь достаточно просто вызвать эту функцию в запросе, указав текст или имя материализованного представления:
SQL> set long 5000
SQL> select my_mv_capabilities(q'[select mgr, count(*) from emp group by mgr]', 'REFRESH') from dual;

MY_MV_CAPABILITIES(Q'[SELECTMGR,COUNT(*)FROMEMPGROUPBYMGR]','REFRESH')
--------------------------------------------------------------------------------

Capable of:

  REFRESH_COMPLETE

Not Capable of:

  REFRESH_FAST

  REFRESH_FAST_AFTER_INSERT
    HES.EMP

MY_MV_CAPABILITIES(Q'[SELECTMGR,COUNT(*)FROMEMPGROUPBYMGR]','REFRESH')
--------------------------------------------------------------------------------
    таблица подробных данных не содержит журнал материализованного
    представления

  REFRESH_FAST_AFTER_ONETAB_DML
    см. причину отключения REFRESH_FAST_AFTER_INSERT

  REFRESH_FAST_AFTER_ANY_DML
    см. причину отключения REFRESH_FAST_AFTER_ONETAB_DML

Текст самой функции ниже:
create or replace function my_mv_capabilities
(
  p_mv                       in  varchar2 ,
  p_capability_name_filter   in  varchar2 default '%' ,
  p_include_pct_capabilities in  varchar2 default 'N' ,
  p_linesize                 in  number   default 80
)
  return clob
as
  --------------------------------------------------------------------------------
  -- From http://www.sqlsnippets.com/en/topic-12884.html
  --
  -- Parameters:
  --
  --   p_mv
  --     o this value is passed to DBMS_MVIEW.EXPLAIN_MVIEW's "mv" parameter
  --     o it can contain either a query, CREATE MATERIALIZED VIEW command text,
  --       or a materialized view name
  --
  --   p_capability_name_filter
  --     o use either REFRESH, REWRITE, PCT, or the default
  --
  --   p_include_pct_capabilities
  --     Y - capabilities like REFRESH_FAST_PCT are included in the report
  --     N - capabilities like REFRESH_FAST_PCT are not included in the report
  --
  --   p_linesize
  --     o the maximum size allowed for any line in the report output
  --     o data that is longer than this value will be word wrapped
  --
  -- Typical Usage:
  --
  --   set long 5000
  --   select my_mv_capabilities( 'MV_NAME' ) as mv_report from dual ;
  --
  --   o the value 5000 is arbitraty; any value big enough to contain the
  --     report output will do
  --
  --------------------------------------------------------------------------------

  pragma autonomous_transaction ;

  v_nl constant char(1) := unistr( '\000A' ); -- new line

  v_previous_possible char(1) := 'X' ;

  v_capabilities sys.ExplainMVArrayType ;

  v_output clob ;

begin

  dbms_mview.explain_mview( mv => p_mv, msg_array => v_capabilities ) ;

  for v_capability in
  (
    select
      capability_name ,
      possible ,
      related_text ,
      msgtxt
    from
      table( v_capabilities )
    where
      capability_name like '%' || upper( p_capability_name_filter ) || '%' and
      not
        ( capability_name like '%PCT%' and
          upper(p_include_pct_capabilities) = 'N'
        )
    order by
      mvowner ,
      mvname ,
      possible desc ,
      seq
  )
  loop

    ------------------------------------------------------------
    -- print section heading
    ------------------------------------------------------------

    if v_capability.possible <> v_previous_possible then

      v_output :=
        v_output
        || v_nl
        || case v_capability.possible
           when 'T' then 'Capable of: '
           when 'Y' then 'Capable of: '
           when 'F' then 'Not Capable of: '
           when 'N' then 'Not Capable of: '
           else v_capability.possible || ':'
           end
        || v_nl
      ;

    end if;

    v_previous_possible := v_capability.possible ;

    ------------------------------------------------------------
    -- print section body
    ------------------------------------------------------------
    declare

      v_indented_line_size varchar2(3) := to_char( p_linesize - 5 );

    begin

      -- print capability name indented 2 spaces

      v_output :=
        v_output
        || v_nl
        || '  '
        || v_capability.capability_name
        || v_nl
      ;

      -- print related text indented 4 spaces and word wrapped

      if v_capability.related_text is not null then

        v_output :=
          v_output
          || regexp_replace
             ( v_capability.related_text || ' '
             , '(.{1,'
                 || v_indented_line_size || '} |.{1,'
                 || v_indented_line_size || '})'
             , '    \1' || v_nl
             )
        ;

      end if;

      -- print message text indented 4 spaces and word wrapped

      if v_capability.msgtxt is not null then

        v_output :=
          v_output
          || regexp_replace
             ( v_capability.msgtxt || ' '
             , '(.{1,'
                 || v_indented_line_size || '} |.{1,'
                 || v_indented_line_size || '})'
             , '    \1' || v_nl
             )
        ;

      end if;

    end;

  end loop;

  commit ;

  return( v_output );

end;
/
Большое спасибо автору этой функции! Она упрощает жизнь.
Читать далее

суббота, 2 октября 2010 г.

Nested Materialized Views: Must contain joins or aggregates. No exclusions...

Data Warehousing Guide говорит нам:

You can create a nested materialized view on materialized views, but all parent and base materialized views must contain joins or aggregates. If the defining queries for a materialized view do not contain joins or aggregates, it cannot be nested.

Как по мне, это условие насчёт обязательности агрегатов или соединения иногда только мешает. Например, у нас есть материализованное представление, необходимо на его основе сделать ещё одно, использующее детерминированные пользовательские функции для расчёта значений столбцов и быстро обновляющееся при фиксации изменений (REFRESH FAST ON COMMIT). Попробуйте этого добиться без агрегатов и соединений в запросе материализованного представления - у Вас ничего не выйдет, как бы Вы не ухищрялись с текстом запроса и журналом материализованного представления!

Решение простое: добавьте соединение с тем же самым материализованным представлением, используя rowid в качестве столбца-соединителя, выполните требования к материализованным представлениям с соединением для быстрого обновления - вуаля! Всё работает.

Тест-кейс:
create materialized view log on emp
  with rowid (empno, mgr, sal)
  including new values;
  
create materialized view mv$sub_sal
  refresh fast on commit
  as
select nvl(mgr, empno) mgr, sum(sal) sal, count(sal) sal_cnt, count(*) row_cnt
  from emp
 group by nvl(mgr, empno);
 
create function test_fu(p_mgr number, p_sal number)
  return number
  deterministic
as
begin
  return p_sal * case when p_sal > 5000 or p_mgr = 7788 then 1.2 else 1 end;
end;
/

alter table mv$sub_sal add constraint mv$sub_sal_pk primary key(mgr);

create materialized view log on mv$sub_sal
  with rowid;
  
create materialized view mv$calc_sub_sal
  refresh fast on commit
  as
select m1.mgr, test_fu(m1.mgr, m1.sal) calc_sal, m1.rowid m1_row_id, m2.rowid m2_row_id
  from mv$sub_sal m1, mv$sub_sal m2
 where m1.rowid = m2.rowid;

Удаление:
drop materialized view mv$calc_sub_sal;
drop materialized view log on mv$sub_sal;
drop function test_fu;
drop materialized view mv$sub_sal;
drop materialized view log on emp;

Читать далее

воскресенье, 26 сентября 2010 г.

Зри вокруг...

... если тебе кажется, что ты зришь в корень, но это не даёт результата. :) Сегодня я потратил много времени на то, чтобы определить, почему Tomcat не использует указанные мной в конфигурационном файле роли и пользователей. Я проверил права доступа и переменные окружения, несколько раз менял эти строки. А проблема была не в строках, а вокруг - в окружающих добавленные после примера строки блочных комментариях!

Как подсказал Google, эта проблема с незамеченными и не убранными вовремя комментариями посетила не одного меня... Вывод: будьте внимательней и используйте для правки утилиты с подсветкой кода. :)
Читать далее

четверг, 19 августа 2010 г.

APEX 4.0.1

Good news, everyone! (c) Futurama

Патч 4.0.1.00.23 ушёл в печать! Инструкция здесь.
Читать далее

четверг, 5 августа 2010 г.

APEX 4.0: Список багов

Ничто не идеально.

Поэтому и в новом релизе есть и уже обнаруживаются баги. Список тех из них, с которыми в основном сталкиваются разработчики и пользователи, находится здесь. Прочитайте его, если вдруг Вам покажется, что Вы наткнулись на что-то эдакое. Для некоторых багов уже предложены способы обхода, некоторые будут исправляться патчами.
Читать далее

вторник, 13 июля 2010 г.

Oracle APEX 3: Лишняя ссылка для загрузки LOB

При использовании в формах элемента типа File Browse, если он не пуст, Вы получите ссылку для скачивания рядом с кнопкой выбора файла.


Убрать её, просто очистив Download Link в маске для загрузки LOB в Source, не получится - будет выводится сообщение по умолчанию APEXIR_DOWNLOAD. Поэтому можно написать вместо Download то, что не будет отображаться. Например, пустой тег SPAN. Маска будет выглядеть следующим образом:
PHOTO:MIMETYPE:FILENAME:LAST_UPDATE_DATE::attachment:<span />

Вот и всё:


Читать далее

пятница, 18 июня 2010 г.

Oracle APEX Link Dump #2: APEX 4.0

Небольшой набор полезных ссылок для тех, кто решил начать переходить на Oracle APEX 4.0 с более ранних версий или только начинает знакомство с этим продуктом:
  • Learn Application Express - обучающий материал по APEX 4.0 в виде приложения, созданного на APEX 4.0. Много полезной вводной информации, ссылки на демонстрации возможностей, блоги, форум.
  • New Features in Release 4.0 - перечисление нововведений в 4.0, описание основных из них.
  • Oracle Application Express Documentation - документация по APEX 4.0.
  • Oracle By Examples (OBE) for APEX 4.0 - обучающие примеры работы с новой версией.
  • Посты из Dimitri Gielis Blog с тегом apex 4.0 - рекомендую к прочтению, Димитрий (надеюсь, что транскрипция верна) отлично и подробно описывает возможности новой версии APEX.
  • Oracle APEX 4.0 Early Adopter Blog Coverage by Patrick Wolf: pt. 1, pt. 2, pt. 3 - подборки ссылок от Патрика Вольфа на заметки в блогах, описывающие различные аспекты и возможности новой версии.

Для освоения APEX 4.0 информации более чем достаточно. Успеха!
Читать далее

вторник, 8 июня 2010 г.

APEX: Неочевидное сообщение об ошибке при импорте страницы

This page was exported from a different application or from an application in different workspace. Page cannot be installed in this application.

Такое вот сообщение, знакомое тем, кто разрабатывает приложение одновременно в двух разных рабочих пространствах / БД. APEX показывает его при импорте страницы из приложения рабочего пространства W1 в приложение рабочего пространства W2, таким образом заботясь о целостности приложения. Мало ли, что там на этой странице есть, чего - ещё, уже или вообще - нет в приложении.

Если разработчик уверен, что всё будет в порядке, то достаточно изменить рабочее пространство в файле экспорта:
begin
 
  -- Assumes you are running the script connected to SQL*Plus as the Oracle user APEX_030200 or as the owner (parsing schema) of the application.
  wwv_flow_api.set_security_group_id(p_security_group_id=>2694915948162823);
 
end;
/
В выделенной строке укажите id целевого рабочего пространства, который можно получить следующим запросом (W2 - целевое рабочее пространство):
select workspace_id from apex_workspaces where workspace = 'W2';
Но это всё ещё не гарантирует, что Вы не получите вышеупомянутое сообщение. Почему? Потому что, как было в моём случае, могут не совпасть по формату версии приложений, или версия целевого приложения может быть меньше необходимой для импорта страницы. Глянуть версию в файле экспорта можно здесь:
begin
 
-- This date identifies the minimum version required to import this file.
wwv_flow_api.set_version(p_version_yyyy_mm_dd=>'2009.01.12');
 
end;
/
А вот как её менять - зависит от приложения. Проще всего передать в качестве параметра NULL (страницу можно будет устанавливать в любую версию приложения).
Читать далее

четверг, 13 мая 2010 г.

Небольшая реклама :)

Вам скучно? И Вы считаете, что знаете PL/SQL? Тогда рекомендую в этом удостовериться: попробуйте свои силы, отвечая на вопросы в PL/SQL Challenge! Действительно интересный конкурс, заставляет задуматься.

Играйте честно!
Читать далее

вторник, 11 мая 2010 г.

Запятые точками в FF

Столкнулся с довольно простой проблемой, которую, тем не менее, было интересно решать. В основном, из-за отсутствия знаний о механизме обработки событий клавиатуры (keydown, keypress, keyup) и доступе к их атрибутам в Gecko.

Суть проблемы: при вводе пользователем запятой в input определённого класса заменять её на точку. Решение необходимо было исключительно для движка Gecko.
Путь решения: полазив по Сети, я нашёл несколько реализаций. Самое простое - использовать replace(/\,/g, "."), но при этом курсор пользователя постоянно будет смещаться в конец ввода, кроме того, будет заметна процедура подмены символа. Посложнее - подавлять событие при помощи event.preventDefault() и при помощи манипуляций с obj.selectionStart вставлять на нужное место символ, оставляя курсор там же. Но, как по мне, это слишком сложный вариант.

Потому я решил сделать это через event.preventDefault() и эмуляцию нажатия клавиши, создав и запустив цепочку событий keydown-keypress-keyup. Почитав необходимую документацию и таблицу символов Unicode, я написал следующий код, использующий jQuery:

/* Comma-to-period keypress handler */
/* This code uses jQuery framework */
$(document).ready(function(){
  $("input.decimal").keypress(function(e){
    var pntUniCode = 0x2E, comUniCode = 0x2C; /* Unicode FULL STOP (aka PERIOD) and COMMA hex codes */ 
    
    if (e.which == comUniCode) {
        e.preventDefault();
        var newEvent = document.createEvent("KeyboardEvent");
        newEvent.initKeyEvent('keydown', true, true, null, false, false, false, false, 0, pntUniCode);
        e.target.dispatchEvent(newEvent);
        newEvent.initKeyEvent('keypress', true, true, null, false, false, false, false, 0, pntUniCode);
        e.target.dispatchEvent(newEvent);
        newEvent.initKeyEvent('keyup', true, true, null, false, false, false, false, 0, pntUniCode);
        e.target.dispatchEvent(newEvent);
    }
  });
});

Его можно сохранить в файл и подключить к странице, на которой есть элементы с классом decimal, тогда при вводе запятые будут заменяться на точки. Вуаля!

PS: Поскольку я не считаю себя особым спецом в JavaScript, то любая конструктивная критика только приветствуется.

Читать далее

среда, 28 апреля 2010 г.

Dude, what's with my EPG?

Временами что-то происходит, и Вы не можете соединиться с БД из APEX, картинки не отображаются, постоянно появляется окошко с сообщением "XDB", требующее логин и пароль. В этот случае, если Вы используете Embedded PL/SQL Gateway, стоит проверить, всё ли на месте. В Oracle 11g для этого есть скрипт epgstat.sql, который находится по пути $ORACLE_HOME/rdbms/admin. Вот пример его использования:

$ cd $ORACLE_HOME/rdbms/admin; sqlplus
SQL> conn system
Enter password: 
Connected.
SQL> @epgstat
+--------------------------------------+
| XDB protocol ports:                  |
|  XDB is listening for the protocol   |
|  when the protocol port is non-zero. |
+--------------------------------------+

HTTP Port FTP Port
--------- --------
     8080     2100

1 row selected.

+---------------------------+
| DAD virtual-path mappings |
+---------------------------+

Virtual Path                     DAD Name
-------------------------------- --------------------------------
/apex/*                          APEX

1 row selected.

+----------------+
| DAD attributes |
+----------------+

DAD Name     DAD Param                DAD Value
------------ ------------------------ ----------------------------------------
APEX         database-username        ANONYMOUS
             default-page             apex
             document-table-name      wwv_flow_file_objects$
             request-validation-funct wwv_flow_epg_include_modules.authorize
             ion

             document-procedure       wwv_flow_file_mgr.process_download
             nls-language             american_america.al32utf8
             document-path            docs

7 rows selected.

+---------------------------------------------------+
| DAD authorization:                                |
|  To use static authentication of a user in a DAD, |
|  the DAD must be authorized for the user.         |
+---------------------------------------------------+

no rows selected

+----------------------------+
| DAD authentication schemes |
+----------------------------+

DAD Name             User Name                        Auth Scheme
-------------------- -------------------------------- ------------------
APEX                 ANONYMOUS                        Anonymous

1 row selected.

+--------------------------------------------------------+
| ANONYMOUS user status:                                 |
|  To use static or anonymous authentication in any DAD, |
|  the ANONYMOUS account must be unlocked.               |
+--------------------------------------------------------+

Database User   Status
--------------- --------------------
ANONYMOUS       OPEN

1 row selected.

+-------------------------------------------------------------------+
| ANONYMOUS access to XDB repository:                               |
|  To allow public access to XDB repository without authentication, |
|  ANONYMOUS access to the repository must be allowed.              |
+-------------------------------------------------------------------+

Allow repository anonymous access?
----------------------------------
true

1 row selected.

Этот скрипт показывает массу полезной информации: HTTP- и FTP-порты, которые слушает XDB; настройки DAD; состояние пользователя ANONYMOUS; разрешение анонимного доступа к репозиторию XDB. Проанализировав вывод, существующую проблему будет решать намного проще.

PS: Кроме того, советую показывать эту информацию на форумах и в обсуждениях. Это значительно упростит поиск причин Ваших проблем. ;)
Читать далее

среда, 7 апреля 2010 г.

APEX: Clear Cache и псевдонимы страниц

Псевдонимы страниц - довольно полезная вещь, если Вы не хотите, чтобы Ваше приложение зависело от конкретных номеров страниц. Их можно использовать вместо номеров страниц в списках (Lists), переходах (Branches), кнопках, столбцах-ссылках и т.п. Чтобы заменить одну страницу на другую, достаточно заменить псевдонимы у них.

Но есть как минимум один недочёт: псевдонимы страниц не распознаются в поле Clear Cache. Как в APEX версии 3.2, так и в 4.0. Хотя, возможно, до релиза последней что-то изменится, по крайней мере, Enhancement Request я отправил. :)

PS: Не стесняйтесь отправлять отзывы на tryapexnow.com, ведь, основываясь на них, и будет идти исправление багов и добавление возможностей в APEX 4.0.
Читать далее

понедельник, 29 марта 2010 г.

APEX: Popup Key LOV, onChange и Submit

Сегодня на повестке дня три небольших вопроса, которые возникают относительно Popup Key LOV в APEX. В ответах P1_POPUP_KEY будет использоваться в качестве элемента этого типа.

Внимание: ответы верны для APEX версии 3.2. В принципе, они должны быть правильными и для более ранних версий, но если что не так - задавайте вопросы в комментариях.

0. Как получить значение ключа выбранного значения?


Если попробовать использовать $v("P1_POPUP_KEY"), то мы получим отображаемое значение, а не ключ, ради которого и используется обычно Popup Key LOV. Но если взглянуть в исходный код страницы, то рядом с элементом P1_POPUP_KEY мы увидим ещё один скрытый - P1_POPUP_KEY_HIDDENVALUE, который и хранит ключ.

1. Можно ли использовать событие onChange у элемента Popup Key LOV?


Можно. :) Попробуйте добавить элементу следующий код в HTML Form Element Attributes и изменить его значение в приложении:
onChange="alert($v(this) + ';' + $v(this.id+'_HIDDENVALUE'))"

2. Можно ли сделать Popup LOV, выполняющий SUBMIT при изменении значения?


Зная ответ на предыдущий вопрос, легко понять, что можно. Вот небольшой JavaScript-код с объектом, автоматизирующим этот процесс:
/* Помните, этот код использует jQuery. */
submitPopupLov = {
addSubmitHandlerToPopupLov : function (pLovId, pSubmitRequest){
$("#" + pLovId).addClass("submit-popup-lov submit-popup-lov-processed");
$("#" + pLovId + "_HIDDENVALUE").change(function (){
doSubmit(!!pSubmitRequest ? pSubmitRequest : pLovId);
});
},
setPopupLovSubmit : function (pLovId){
$("#" + pLovId).addClass("submit-popup-lov submit-popup-lov-not-processed");
},
processSubmitablePopupLovs : function (){
$(".submit-popup-lov-not-processed").each(function(){
$(this).removeClass("submit-popup-lov-not-processed").addClass("submit-popup-lov-processed");
$("#"+this.id + "_HIDDENVALUE").change(function(){
doSubmit(this.id);
});
});
}
};


Я надеюсь, вопросов без ответов стало меньше. :)

Читать далее

воскресенье, 21 марта 2010 г.

APEX: Quick Picks (QP)

Прочитав довольно интересный пост о динамически создаваемых быстрых значениях (aka quick picks, далее QP) для элемента, я решил довести дело до более логически завершённого функционала. Вот спецификация пакета, который используется для создания QP:

CREATE OR REPLACE package apex_quick_picks_pkg as 
/* APEX_QUICK_PICKS_PKG
Автор: Александр "suPPLer" Поливаный
Дата релиза: 22.03.2010
Версия: 1.0
Назначение: функции для создания списка быстрых значений (aka quick picks, QP) элемента.

Распространяется под лицензией New BSD (http://cylib.iit.nau.edu.ua/Mirrors/ask.km.ru/unics/bsd.html) :

* Copyright (c) 2010, Александр "suPPLer" Поливаный
*
* Разрешается повторное распространение и использование как в виде исходного
* кода, так и в двоичной форме, с изменениями или без, при соблюдении
* следующих условий:
*
* * При повторном распространении исходного кода должно оставаться
* указанное выше уведомление об авторском праве, этот список условий и
* последующий отказ от гарантий.
* * При повторном распространении двоичного кода должна сохраняться
* указанная выше информация об авторском праве, этот список условий и
* последующий отказ от гарантий в документации и/или в других
* материалах, поставляемых при распространении.
* * Имена владельцев авторских прав не могут быть
* использованы в качестве поддержки или продвижения продуктов,
* основанных на этом ПО без предварительного письменного разрешения.
*
* ЭТА ПРОГРАММА ПРЕДОСТАВЛЕНА ВЛАДЕЛЬЦАМИ АВТОРСКИХ ПРАВ И/ИЛИ ДРУГИМИ
* СТОРОНАМИ "КАК ОНА ЕСТЬ" БЕЗ КАКОГО-ЛИБО ВИДА ГАРАНТИЙ, ВЫРАЖЕННЫХ ЯВНО
* ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ, ПОДРАЗУМЕВАЕМЫЕ
* ГАРАНТИИ КОММЕРЧЕСКОЙ ЦЕННОСТИ И ПРИГОДНОСТИ ДЛЯ КОНКРЕТНОЙ ЦЕЛИ. НИ В
* КОЕМ СЛУЧАЕ, ЕСЛИ НЕ ТРЕБУЕТСЯ СООТВЕТСТВУЮЩИМ ЗАКОНОМ, ИЛИ НЕ УСТАНОВЛЕНО
* В УСТНОЙ ФОРМЕ, НИ ОДИН ВЛАДЕЛЕЦ АВТОРСКИХ ПРАВ И НИ ОДНО ДРУГОЕ ЛИЦО,
* КОТОРОЕ МОЖЕТ ИЗМЕНЯТЬ И/ИЛИ ПОВТОРНО РАСПРОСТРАНЯТЬ ПРОГРАММУ, КАК БЫЛО
* СКАЗАНО ВЫШЕ, НЕ НЕСЁТ ОТВЕТСТВЕННОСТИ, ВКЛЮЧАЯ ЛЮБЫЕ ОБЩИЕ, СЛУЧАЙНЫЕ,
* СПЕЦИАЛЬНЫЕ ИЛИ ПОСЛЕДОВАВШИЕ УБЫТКИ, ВСЛЕДСТВИЕ ИСПОЛЬЗОВАНИЯ ИЛИ
* НЕВОЗМОЖНОСТИ ИСПОЛЬЗОВАНИЯ ПРОГРАММЫ (ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ
* ПОТЕРЕЙ ДАННЫХ, ИЛИ ДАННЫМИ, СТАВШИМИ НЕПРАВИЛЬНЫМИ, ИЛИ ПОТЕРЯМИ
* ПРИНЕСЕННЫМИ ИЗ-ЗА ВАС ИЛИ ТРЕТЬИХ ЛИЦ, ИЛИ ОТКАЗОМ ПРОГРАММЫ РАБОТАТЬ
* СОВМЕСТНО С ДРУГИМИ ПРОГРАММАМИ), ДАЖЕ ЕСЛИ ТАКОЙ ВЛАДЕЛЕЦ ИЛИ ДРУГОЕ
* ЛИЦО БЫЛИ ИЗВЕЩЕНЫ О ВОЗМОЖНОСТИ ТАКИХ УБЫТКОВ.

*/

--
-- Набор функций, которые формируют соответствующий HTML-код QP и возвращают его как varchar2.
--

-- quick_picks_from_query - QP из запроса с двумя столбцами: отображаемые QP и устанавливаемые значения
-- p_item_name - элемент, значения которого устанавливают QP
-- p_query - запрос
-- p_show_clear - отображать QP с пустым значением
-- p_clear_text - отображаемый текст QP с пустым значением
-- p_qp_style - стиль HTML-элемента QP
-- p_qp_class - класс HTML-элемента QP
-- p_container_id - id HTML-элемента, в котором собраны QP (в качестве контейнера используется div)
-- p_container_style - стиль HTML-элемента, в котором собраны QP
-- p_container_class - класс HTML-элемента, в котором собраны QP
function quick_picks_from_query
( p_item_name in apex_application_page_items.item_name%type
, p_query in varchar2
, p_show_clear in varchar2 default 'N'
, p_clear_text in varchar2 default 'Clear'
, p_qp_style in varchar2 default null
, p_qp_class in varchar2 default null
, p_container_id in varchar2 default null
, p_container_style in varchar2 default null
, p_container_class in varchar2 default null)
return varchar2;
-- quick_picks_from_lov - QP на основе LOV из приложения APEX, в котором используются QP
-- p_item_name - элемент, значения которого устанавливают QP
-- p_lov_name - название LOV
-- p_show_clear - отображать QP с пустым значением
-- p_clear_text - отображаемый текст QP с пустым значением
-- p_qp_style - стиль HTML-элемента QP
-- p_qp_class - класс HTML-элемента QP
-- p_container_id - id HTML-элемента, в котором собраны QP (в качестве контейнера используется div)
-- p_container_style - стиль HTML-элемента, в котором собраны QP
-- p_container_class - класс HTML-элемента, в котором собраны QP
function quick_picks_from_lov
( p_item_name in apex_application_page_items.item_name%type
, p_lov_name in apex_application_lovs.list_of_values_name%type
, p_show_clear in varchar2 default 'N'
, p_clear_text in varchar2 default 'Clear'
, p_qp_style in varchar2 default null
, p_qp_class in varchar2 default null
, p_container_id in varchar2 default null
, p_container_style in varchar2 default null
, p_container_class in varchar2 default null)
return varchar2;
-- quick_picks_from_arrays - QP на основе коллекций отображаемых меток QP и устанавливаемых значений. Тип коллекции - dbms_sql.varchar2_table
-- p_item_name - элемент, значения которого устанавливают QP
-- p_texts - отображаемые метки QP
-- p_values - значения, которые устанавливаются QP
-- p_show_clear - отображать QP с пустым значением
-- p_clear_text - отображаемый текст QP с пустым значением
-- p_qp_style - стиль HTML-элемента QP
-- p_qp_class - класс HTML-элемента QP
-- p_container_id - id HTML-элемента, в котором собраны QP (в качестве контейнера используется div)
-- p_container_style - стиль HTML-элемента, в котором собраны QP
-- p_container_class - класс HTML-элемента, в котором собраны QP
function quick_picks_from_arrays
( p_item_name in apex_application_page_items.item_name%type
, p_texts in dbms_sql.varchar2_table
, p_values in dbms_sql.varchar2_table
, p_show_clear in varchar2 default 'N'
, p_clear_text in varchar2 default 'Clear'
, p_qp_style in varchar2 default null
, p_qp_class in varchar2 default null
, p_container_id in varchar2 default null
, p_container_style in varchar2 default null
, p_container_class in varchar2 default null)
return varchar2;

--
-- Набор процедур, который использует htp.p для OWA-вывода сформированного набора QP
--

-- prn_quick_picks_from_query - OWA-вывод сформированных QP из запроса с двумя столбцами: отображаемые QP и устанавливаемые значения
-- p_item_name - элемент, значения которого устанавливают QP
-- p_query - запрос
-- p_show_clear - отображать QP с пустым значением
-- p_clear_text - отображаемый текст QP с пустым значением
-- p_qp_style - стиль HTML-элемента QP
-- p_qp_class - класс HTML-элемента QP
-- p_container_id - id HTML-элемента, в котором собраны QP (в качестве контейнера используется div)
-- p_container_style - стиль HTML-элемента, в котором собраны QP
-- p_container_class - класс HTML-элемента, в котором собраны QP
procedure prn_quick_picks_from_query
( p_item_name in apex_application_page_items.item_name%type
, p_query in varchar2
, p_show_clear in varchar2 default 'N'
, p_clear_text in varchar2 default 'Clear'
, p_qp_style in varchar2 default null
, p_qp_class in varchar2 default null
, p_container_id in varchar2 default null
, p_container_style in varchar2 default null
, p_container_class in varchar2 default null);
-- prn_quick_picks_from_lov - OWA-вывод сформированных QP на основе LOV из приложения APEX, в котором используются QP
-- p_item_name - элемент, значения которого устанавливают QP
-- p_lov_name - название LOV
-- p_show_clear - отображать QP с пустым значением
-- p_clear_text - отображаемый текст QP с пустым значением
-- p_qp_style - стиль HTML-элемента QP
-- p_qp_class - класс HTML-элемента QP
-- p_container_id - id HTML-элемента, в котором собраны QP (в качестве контейнера используется div)
-- p_container_style - стиль HTML-элемента, в котором собраны QP
-- p_container_class - класс HTML-элемента, в котором собраны QP
procedure prn_quick_picks_from_lov
( p_item_name in apex_application_page_items.item_name%type
, p_lov_name in apex_application_lovs.list_of_values_name%type
, p_show_clear in varchar2 default 'N'
, p_clear_text in varchar2 default 'Clear'
, p_qp_style in varchar2 default null
, p_qp_class in varchar2 default null
, p_container_id in varchar2 default null
, p_container_style in varchar2 default null
, p_container_class in varchar2 default null);
-- prn_quick_picks_from_arrays - OWA-вывод сформированных QP на основе коллекций отображаемых меток QP и устанавливаемых значений. Тип коллекции - dbms_sql.varchar2_table
-- p_item_name - элемент, значения которого устанавливают QP
-- p_texts - отображаемые метки QP
-- p_values - значения, которые устанавливаются QP
-- p_show_clear - отображать QP с пустым значением
-- p_clear_text - отображаемый текст QP с пустым значением
-- p_qp_style - стиль HTML-элемента QP
-- p_qp_class - класс HTML-элемента QP
-- p_container_id - id HTML-элемента, в котором собраны QP (в качестве контейнера используется div)
-- p_container_style - стиль HTML-элемента, в котором собраны QP
-- p_container_class - класс HTML-элемента, в котором собраны QP
procedure prn_quick_picks_from_arrays
( p_item_name in apex_application_page_items.item_name%type
, p_texts in dbms_sql.varchar2_table
, p_values in dbms_sql.varchar2_table
, p_show_clear in varchar2 default 'N'
, p_clear_text in varchar2 default 'Clear'
, p_qp_style in varchar2 default null
, p_qp_class in varchar2 default null
, p_container_id in varchar2 default null
, p_container_style in varchar2 default null
, p_container_class in varchar2 default null);
end apex_quick_picks_pkg;
/


Скрипт установки пакета пока находится здесь, возможно, дальше он переместится на что-нибудь более предназначенное для хранения исходников, например, sourceforge.
Как пользоваться этим пакетом для генерации быстрых ссылок:

  1. Создать элемент типа Display Only.

  2. Расположить его где-то рядом с тем элементом, который будут изменять QP. Хорошим вариантом может стать расположение снизу сразу под нужным элементом.

  3. Изменить у него отображение (Display As) на Display As Text (based on PL/SQL, does not save state). Помните, этот тип отображения не доступен изначально при создании, он появляется только при редактировании элемента.

  4. Изменить шаблон метки Template->No Label, очистить поле Label.

  5. Изменить тип источника значения Source Type->PL/SQL Anonymous Block.

  6. И, наконец, в качестве Source value or expression указать соответствующий PL/SQL-блок с вызовом пакета. Например, для создания быстрых значений к элементу P1_TEXT:
    begin
    apex_quick_picks_pkg.prn_quick_picks_from_query
    ( p_item_name=>'P1_TEXT'
    , p_query=>
    'select d, ltrim(to_char(d, ''RЪ'')) r
    from (select 1 d from dual
    union all
    select 2 from dual
    union all
    select 5 from dual)'
    , p_show_clear=>'Y'
    );
    end;




Ну и ещё кое-что для тех, кто не любит каждый раз всё набирать руками. Если Вы используете APEX Builder Plugin, то можно расширить предустановленные наборы (aka Set), которые он добавляет, ещё одним, который установит все необходимые атрибуты у элемента и облегчит написание PL/SQL-кода в Source value or expression (пока что есть набор только для работы с QP на основе LOV). Вот изменённый основной скрипт плагина версии 1.9.1 для FF, им нужно подменить установленный скрипт плагина в GreaseMonkey. Для этого можно открыть следующее: Инструменты->GreaseMonkey->Управление скриптами, выбрать APEX Builder Plugin 1.9, нажать "Изменить", заменить полностью содержимое скрипта текстом скрипта из архива. Затем нужно добавить к уже установленным скриптам плагина новый пользовательский скрипт и выбрать в настройках (Инструменты->GreaseMonkey->Команды скрипта->APEX Builder Plugin Settings) использование пользовательских скриптов для страниц (Adding user scripts for pages). Всё.

Пользуйтесь на здоровье!

PS: Я постараюсь написать нормальную документацию, если этот минипроект будет кому-нибудь интересен, и возникнут вопросы. Кроме того, при возникновении проблем, просьб и интересных мыслей, связанных с этим проектом, буду рад, если они отразятся в комментариях.

Читать далее

понедельник, 15 марта 2010 г.

ORA-38104: Бомба с часовым механизмом

Так сказать, моя небольшая история об неудачном дизайне.

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

Нет проблем, подумал я. Всё это реализуется декларативно, через ограничения целостности. Где-то так:


create table test_params
( param_id number -- параметр
, prev_end_date date -- дата окончания прошлой записи
, start_date date -- дата начала текущей записи
, end_date date -- дата конца текущей записи
, value varchar2(10)
, primary key (param_id, start_date)
, unique (param_id, end_date)
, check(start_date - 1 = prev_end_date)
, check(end_date >= start_date)
, check(start_date = trunc(start_date))
, check(end_date = trunc(end_date))
, check(prev_end_date = trunc(prev_end_date)) );

alter table test_params
add constraint test_params_fk_chain
foreign key (param_id, prev_end_date)
references test_params(param_id, end_date)
deferrable
initially immediate;


В реальной системе всё немного сложнее (param_id ссылается на таблицу с определениями параметров), но это хорошо отражает суть.

Всё было отлично, вокруг таблицы создавался PL/SQL-код... А затем мне понадобилось написать в пакете процедуру для обновления start_date и end_date у заданной записи. Очевидно, что при их изменении нужно соответствующим образом изменить предыдущую и следующую запись в цепочке значений параметра. "Если ты можешь сделать это через SQL - сделай это так," - говорит дядя Том. И я решил сделать это через MERGE. И вот тут-то стремление к минимализму при проектировании меня подвело: изменять поле, которое используется в on_clause, MERGE отказался наотрез. ORA-38104, господа и дамы. А пересоздание ограничений откладываемыми привнесёт ещё больше проблем.

Вывод: сэкономив на поле для суррогатного первичного ключа, я потерял время, которое теперь необходимо для того, чтобы его добавить. Дизайн нужно продумывать с учётом ограничений способов, которыми будет вестись работа. :)

Читать далее

четверг, 4 марта 2010 г.

APEX: Автовход

Пользуясь APEX как разработчик, я пару месяцев назад заскучал по одной определённой возможности, а именно - автовходе. Когда работаешь в одном и том же рабочем пространстве под одной и той же учёткой, вводить логин и пароль каждый раз становится лень. Потому я, недолго думая, написал скрипт для GreaseMonkey:
$s("F4550_P1_COMPANY", "MYWORKSPACE");
$s("F4550_P1_USERNAME", "MYLOGIN");
$s("F4550_P1_PASSWORD", "MYPASSWORD");
$x("LOGIN_BUTTON").click();

Вместо MYWORKSPACE, MYLOGIN и MYPASSWORD, конечно, указаны мои рабочее пространство, логин и пароль.

Если кто-то так же ленив, как и я, возможно, это ему пригодится. :)
Читать далее

четверг, 11 февраля 2010 г.

Oracle SQL Developer+Debian GNU/Linux: Нетривиальный баг

Довелось наткнуться на баг не столько самого OSD, сколько используя его. После очередного обновления пакетов Debian при попытке соединения OSD выдавал lo exception: The Network Adapter could not establish the connection - и хоть ты тресни. После поиска в сети оказалось, что это баг #560044: net.ipv6.bindv6only=1 breaks java networking. Быстрый и грязный фикс для тех, кто уже пользуется веткой testing:
sudo sed -i 's/net.ipv6.bindv6only\ =\ 1/net.ipv6.bindv6only\ =\ 0/' \
/etc/sysctl.d/bindv6only.conf && sudo invoke-rc.d procps restart


Надеюсь, Вы ещё не меняли ничего от отчаяния в tnsnames.ora и listener.ora?..
Читать далее

понедельник, 8 февраля 2010 г.

ОФФ: Снова в эфире из дома!

Наконец-то взял новую видеокарту взамен павшего смертью храбрых в борьбе с пылью старичка 8800GT. Не мудрствуя лукаво и не гоняясь с сверхпроизводительностью на FullHD-экранах, выбрал Gainward GT240 512MB GDDR5 - крепкий середнячок с маленьким энергопотреблением. Пока что всё устраивает: неслышный вентилятор, температура в простое - 30 градусов, производительность сравнима.

Моё домашняя машина снова на ходу! Ура.
Читать далее

суббота, 6 февраля 2010 г.

Oracle DB XE+APEX 3.2.1+JasperReports: Инструкция по сборке на Win32 ч.1

Предисловие



Честно говоря, надоело отношение к установке Oracle DB XE, к обновлению включённого в неё APEX до более поздних версий (в частности, 3.2.1) и к интеграции со всем этим добром хорошего и бесплатного генератора отчётов - ко всему этому как к чему-то сложному и непонятному. Можно по-разному бороться с этим уже сложившимся у некоторых мнением, лично я буду бороться с ним, используя простые примеры. Результатом должна стать инструкция по установке и простейшей настройке Oracle Database Express Edition (дальше - Oracle XE или просто XE), APEX 3.2.1 (дальше - APEX), JasperReports (дальше - JR). В качестве ОС пока будет выступать Win32, но надеюсь, что вскоре я реанимирую свою машину с Debian GNU/Linux, и появится аналогичная статья для Debian-based Linux. Поехали!

Установка XE



Если Вы не в курсе, что такое XE, то советую Вам прочитать следующий тынц: Oracle Database 10g Express Edition. Если вкратце, то это та же самая Oracle Database 10.2.0.1, но с ограничениями на размер пользовательских данных (4 ГБ), размер БД вместе с этими данными (5 ГБ), размер используемого ОЗУ (1 ГБ) и количество используемых ядер процессора (1 ядро). Кроме того, она довольно быстро и легко устанавливается и настраивается. Всё это делает её отличным кандидатом в качестве СУБД для небольших проектов и любящих экспериментировать разработчиков и АБД.

Скачать XE для Win32 можно здесь. Поскольку мы хотим хранить в БД данные с русскими символами и (я надеюсь) не хотим пользоваться недокументированным способом по смене кодировки БД после установки, то скачивать нужно Oracle Database 10g Express Edition (Universal) - тогда в качестве кодировки БД будет использоваться AL32UTF8.

После загрузки стоит прочитать руководство по установке и следовать ему. Для тех, у кого проблемы с английским, краткий перевод шагов:
  1. Войдите в систему как Администратор.
  2. Очистите переменную окружения ORACLE_HOME через Панель управления->Система.
  3. Сходите на сайт...
  4. ... и скачайте файл, который Вы уже скачали.
  5. Запустите его.
  6. Если Вы переустанавливаете XE, то появится опция Repair.
  7. Next.
  8. Accept->Next.
  9. Выбираем, куда установить->Next.
  10. При необходимости указываем порты для прослушивателя, MS Transaction Server и APEX. По умолчанию: 1521, 2030 и 8080.
  11. Вводим пароли для пользователей SYS и SYSTEM. По значимости эти пользователи БД близки к Локальному Администратору ОС и пользователю из группы Администраторов. Так что выбирайте сами сложность паролей.
  12. Install, если всё устраивает.
  13. У Вас есть работающая XE! Можете создавать пользователей и работать. При желании, можете зайти на домашнюю страницу БД. Приложение хорошее, но одна проблема: с обновлением APEX до 3-ей версии это приложение со всеми его прелестями администрирования пропадёт. И нам понадобится что-нибудь для работы с БД, помимо SQL Workshop->SQL Commands. Так что я предлагаю следующее...


Oracle SQL Developer



Довольно неплохое бесплатное средство разработки, администрирования и вообще общения с Oracle DB. Oracle SQL Developer может подключаться и к другим СУБД, но нас пока интересует исключительно наша XE. Домашняя страница проекта - здесь. Скачать последнюю версию можно здесь (на текущий момент это версия 2.1). Для начинающих есть пошаговое обучение. Интерфейс дружественный, в чём-то интуитивный, в чём-то - нет. Трудностей при работе возникнуть не должно, если время от времени заглядывать в Help.

Oracle APEX 3.2.1



После установки XE у Вас уже будет APEX, но почему бы не обновить его до последней версии (на данный момент это версия 3.2.1)? Многие считают, что это сложно. Попробую разубедить.

Домашняя страница APEX находится здесь. Загрузим последнюю доступную версию отсюда. Вообще-то, всё отлично получается при использовании руководства по установке. Но я попробую дать пошаговую простую инструкцию по обновлению:
  1. Скачайте архив с APEX и распакуйте их в каталог C:\tmp.
  2. Запустите cmd: Win+R->cmd. Выполните:
    cd c:\tmp\apex
    sqlplus "sys/syspass as sysdba" @apexins SYSAUX SYSAUX TEMP /i/
    

    Начнётся установка и обновление APEX. Можно сходить попить кофе или ещё как-нибудь провести минут 10-15 времени.
  3. Меняем пароль у администратора APEX:
    sqlplus "sys/syspass as sysdba" @apxchpwd
    

  4. Не выходя из SQL*Plus, настраиваем Embedded PL/SQL Gateway:
    @apex_epg_config c:\tmp

  5. Там же разблокируем пользователя ANONYMOUS, под которым APEX работает с БД...
    alter user anonymous account unlock;

  6. ... установим явно http-порт для XML DB...
    EXEC DBMS_XDB.SETHTTPPORT(8080);

  7. ... и разрешим анонимный доступ к файлам в XML DB.
    SET SERVEROUTPUT ON
    DECLARE
    l_configxml XMLTYPE;
    l_value VARCHAR2(5) := 'true'; -- (true/false)
    BEGIN
    l_configxml := DBMS_XDB.cfg_get();
    
    IF l_configxml.existsNode('/xdbconfig/sysconfig/protocolconfig/httpconfig/allow-repository-anonymous-access') = 0 THEN
    -- Add missing element.
    SELECT insertChildXML
    (
    l_configxml,
    '/xdbconfig/sysconfig/protocolconfig/httpconfig',
    'allow-repository-anonymous-access',
    XMLType('' ||
    l_value ||
    ''),
    'xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd"'
    )
    INTO l_configxml
    FROM dual;
    
    DBMS_OUTPUT.put_line('Element inserted.');
    ELSE
    -- Update existing element.
    SELECT updateXML
    (
    DBMS_XDB.cfg_get(),
    '/xdbconfig/sysconfig/protocolconfig/httpconfig/allow-repository-anonymous-access/text()',
    l_value,
    'xmlns="http://xmlns.oracle.com/xdb/xdbconfig.xsd"'
    )
    INTO l_configxml
    FROM dual;
    
    DBMS_OUTPUT.put_line('Element updated.');
    END IF;
    
    DBMS_XDB.cfg_update(l_configxml);
    DBMS_XDB.cfg_refresh;
    END;
    /
    
    Element updated.

  8. Кроме того, можно открыть удалённый HTTP-доступ:
    exec dbms_xdb.setListenerLocalAccess(l_access => FALSE);

    Чтобы его убрать, достаточно выполнить тот же код, используя в качестве параметра TRUE.


Всё, вы можете заходить на страницу администрирования (http://127.0.0.1:8080/apex/apex_admin), создавать рабочее пространство и администратора для него, потом заходить администратором рабочего пространства в обновлённый APEX (http://127.0.0.1:8080/apex) и добавлять разработчиков и пользователей, потом разработчики могут приниматься за дело... Всё как и должно быть.

В качестве замены встроенного приложения для администрирования в XE можно прочитать здесь список основных задач и способы их выполнения.

О JasperReports и их установке поговорим в следующей части.

Читать далее

среда, 27 января 2010 г.

Link Dump для разработчика Oracle APEX

Предыстория: множество появляющихся вопросов в этом форуме по Oracle APEX просто вынудили меня собрать несколько полезных ссылок для тех, кто вообще никогда не имел дело с Oracle Database, но неожиданно решил освоить разработку приложений Oracle APEX.

Возможно, для кого-то это станет открытием, но для того, чтобы разрабатывать, используя Oracle APEX, нужно знать Oracle SQL и PL/SQL хотя бы в пределах синтаксиса и основных функций. Мне кажется, это неправильно - разрабатывать приложения "наугад". Потому, господа и дамы, настоятельно рекомендую для прочтения и освоения:
  1. Oracle® Database SQL Reference и/или "Секреты Oracle SQL", Санжей Мишра, Алан Бьюли. Это поможет Вам избежать множества вопросов по SQL.

  2. Oracle® Database PL/SQL User's Guide and Reference и/или "Oracle PL/SQL для профессионалов", Стивен Фейерштейн, Билл Прибыл. Это поможет Вам избежать множества вопросов по PL/SQL.

  3. Oracle® Database 2 Day + Application Express Developer's Guide и Oracle® Application Express Advanced Tutorials. Это поможет Вам избежать множества вопросов по APEX и даст массу практического опыта. В принципе, здесь Вы можете остановиться, но если Вам стало интересно...

  4. Oracle® Database Application Developer's Guide - Fundamentals. Это снабдит Вас информацией о множестве способов разработки приложений, использующих Oracle Database.

  5. Ну, и помимо всего прочего, почитывайте Concepts, дядю Тома (1, 2, 3, 4) и другие источники, если Вам интересно, как всё это в принципе работает.


Всего!

PS: Хочу заметить, что упоминание вышеуказанных материалов ни в коей мере не является рекламой. Это просто ссылки на информацию, которую я считаю полезной.

Читать далее

воскресенье, 10 января 2010 г.

APEX: Описание новых возможностей версии 4.0

Я не буду растекаться мыслию по древу, потому что всё уже сделано до меня. Вместо этого я дам ссылку на довольно полезное приложение с описанием новых возможностей APEX 4.0, написанное на APEX 4.0: APEX 4.0 New Feature Descriptions.

Успехов!

PS: Мне кажется, или здесь действительно слишком часто звучит "APEX 4.0"?.. :)
Читать далее