Oracle DB, Oracle APEX, Linux etc.

вторник, 5 мая 2015 г.

ORDS 3.0: Проблема с настройкой подключения к нескольким БД

Один экземпляр Oracle REST Data Services (ORDS) может работать сразу с несколькими базами данных. Для этого необходимо задать настройки для подключения к ним и выбрать метод, по которому ORDS будет определять, к какой БД хочет обращается клиент. Подробней можно прочитать здесь: REST Data Services Installation, Configuration, and Development Guide — 2.1 Configuring Multiple Databases.

Но недавно вышедший ORDS 3.0.0.121 при добавлении настроек для дополнительной БД создаёт неверные файлы конфигурации. Как пример, результат настройки для базы с именем apex40:

$ java -jar ords3.war setup --database apex40
[skipped]
$ cd $APEX_CONFIG_DIR/conf
$ cat apex40.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<comment>Saved on Tue May 05 01:49:57 EEST 2015</comment>
<entry key="db.password">...</entry>
<entry key="db.username">APEX_PUBLIC_USER</entry>
</properties>
Отсутствуют имя хоста и порт (что в моём случае несущественно), имя службы. Без этой информации ORDS использует настройки подключения по умолчанию из $APEX_CONFIG_DIR/defaults.xml и подключается не к той БД.

Исправить досадный баг просто, достаточно добавить настройки подключения в файлы $APEX_CONFIG_DIR/conf/<имя_БД>*.xml вручную:




Saved on Tue May 05 01:49:57 EEST 2015
...
...
...
...
APEX_PUBLIC_USER

Надеюсь, это поправят в ближайшем обновлении ORDS.

Читать далее

понедельник, 4 мая 2015 г.

Немного камней по дороге к APEX 5.0

Как писал раньше, для начала планировал создать отдельную подключаемую БД, в которой уже потом разворачивать APEX 5.0. Для этого решил создать контейнерную БД Oracle 12.1.0.2.3 (CDB) на Linux 86-64, смигрировать уже имеющуюся холодную не-контейнерную БД (non-CDB) в виде подключаемой (PDB) в новосозданную и на её копию установить новый APEX. Создал и обновил БД, на следующем шаге воспользовался руководством: Multitenant : Migrate a Non-Container Database (CDB) to a Pluggable Database (PDB) in Oracle Database 12c Release 1 (12.1). И это было ошибкой. :)

Как промежуточный результат, получил CDB, в которой APEX уже был установлен в корневом контейнере и мог быть обновлён только для всех контейнеров сразу. Если попытаться обновить его только в одном из контейнеров, то те из них, в которых версия APEX не совпадала с версией в корневом контейнере, просто открывались в ограниченном режиме, оставляя сообщения об ошибках в PDB_PLUG_IN_VIOLATIONS:

> alter session set container=cdb$root

session SET altered.

> select message from pdb_plug_in_violations 
 where type = 'ERROR' 
   and status <> 'RESOLVED';

MESSAGE                                                                                            
----------------------------------------------------------------------------------------------------
APEX mismatch: PDB installed version 4.2.6.00.03 CDB installed version 4.2.5.00.08                   

Поэтому пришлось удалять полученную PDB, затем удалять APEX из CDB (Multitenant : Uninstall APEX from the CDB in Oracle Database 12c Release 1 (12.1)) и создавать PDB как копию non-CDB с установленным APEX заново. Но и на этом всё не закончилось: PDB открывалась со следующей ошибкой:

Sync PDB failed with ORA-65177 during 'alter user APEX_PUBLIC_USER account unlock'

Гугл на это сказал немного, как и MOS. Поскольку в корневом контейнере такого пользователя не обнаружил, а в PDB у него были лишь права DML на FLOWS_FILES.WWV_FLOW_FILE_OBJECTS$, то решил его пересоздать в PDB, не мудрствуя лукаво:

conn / as sysdba
alter session set container=pdb1;
drop user apex_public_user;

На что Oracle ответил:

28014. 00000 -  "cannot drop administrative users"
*Cause:    An attempt was made to drop administrative users.
           Administrative users can be dropped only by SYS during
           migration mode.
*Action:   Try dropping administrative users during migration mode.

Немного погуглив, изменил подход:
alter pluggable database pdb1 close immediate;
alter pluggable database pdb1 open upgrade;
alter session set "_oracle_script"=true;
alter session set container=pdb1;
drop user apex_public_user;
alter pluggable database pdb1 close;
alter pluggable database pdb1 open;
PDB открылась без ошибок. После этого можно было пересоздать пользователя APEX_PUBLIC_USER:
alter session set container=pdb1;
create user apex_public_user identified by apex_public_user;
grant select, insert, update, delete on flows_files.WWV_FLOW_FILE_OBJECTS$ 
  to apex_public_user;
grant connect to apex_public_user;

Пользователь на месте, PDB успешно открыта. Увы, попытка достучаться из ORDS к базе возвращала 503 Service unavailable. В alert.log нашёл «воодушевляющее» сообщение:

ORA-00600: internal error code, arguments: [kpdbAttachSga: bad pdb], [0], [pdb1.workgroup], [], [],[], [], [], [], [], [], []

Поиск на MOS вывел на похожий параметром ORA-00600 баг 20438519 и устраняющий его патч 19972766. После установки последнего наконец-то всё заработало.

Читать далее

понедельник, 20 апреля 2015 г.

Oracle APEX 5.0!

Вот так пару дней поболел и пропустил выход долгожданной новой версии. Ну что, сценарий для изучения теперь проще с Multitenant:
  1. Скачать новый APEX.
  2. Создать БД для тестирования:
    create pluggable database apx5 from tmpl file_name_convert( '/app/oracle/oradata/tmpl', '/app/oracle/oradata/apx5' );
  3. Установить свежий APEX 5.0 и посмотреть, что стало лучше, а что перестало работать. :)

Читать далее

среда, 15 апреля 2015 г.

Oracle Multitenant и ORA-28000

Наткнулся недавно на небольшую проблему — ORDS на Glassfish отказывался создавать подключения к БД, выводя на экран "503 — Service Unavailable" со следующим сообщением в server.log:
The pool named: apex is not correctly configured, error: ORA-28000: the account is locked


Посмотрел пользователя БД в файле конфигурации ORDS для пула apex ${configdir}/ords/conf/apex.xml:
...
<entry key="db.username">APEX_PUBLIC_USER</entry>
...

Настройки для соединения взял из ${configdir}/ords/defaults.xml:
...
<entry key="db.hostname">hostname</entry>
<entry key="db.port">1521</entry>
<entry key="db.servicename">pdb1.workgroup</entry>
...

Подсоединился к pdb1.workgroup, проверил пользователя APEX_PUBLIC_USER — открыт. И вот тут я потратил достаточно много времени, прежде чем вспомнил, что с появлением Multitenant Architecture в Oracle 12c появились общие пользователи. Переключился в корневую БД, и точно — заблокирован APEX_PUBLIC_USER!

alter user apex_public_user account unlock;
alter user apex_public_user identified by ...;

После этого ORDS смог подключиться, проблема была решена.

Читать далее

воскресенье, 22 февраля 2015 г.

Oracle APEX: разбивка на страницы интерактивных отчётов

Благодаря дискуссии на SQL.RU, решил проверить, как на самом деле происходит выдача страницы данных для интерактивного отчёта в Oracle APEX. Использовал версию 4.2.5, но не думаю, что что-то будет сильно отличаться вплоть до 4.1 включительно. Создал приложение с простым интерактивным отчётом, у которого в качестве источника данных был следующий запрос:

select * from emp

Изначально я ставил на то, что движок выполнения отчётов переписывает указанный разработчиком запрос и помимо прочей обёртки добавляет к нему один из известных приёмов по выдаче части отсортированных данных. Например:

select {select list}
  from ( select {select list}, row_number() over( order by {ordering} ) apx$rn 
           from ( {filtering, computing etc.} ) 
          order by {ordering} )
 where apx$rn between :page_min_row and :page_max_row

Результаты отладки меня слегка удивили:


Была слабая надежда, что это не окончательный запрос, и где-то там его ещё дополнительно обернут… Однако, после поиска в исходниках и вдумчивого чтения разврапленного wwv_flow_worksheet.plb я обнаружил, что всё намного печальней: в WWV_FLOW_WORKSHEET.get_report открывается курсор по тексту запроса, в котором нет никакого намёка на первую и последнюю строки страницы. Вместо этого курсор в цикле вхолостую считывается, пока не доходит до первой строки страницы. Затем начинается вывод строк, пока не дойдёт до последней.

Какие из полученных знаний можно сделать выводы:
  1. Каждая следующая страница интерактивного отчёта, к которой перейдёт пользователь, будет требовать чтения всё большего объёма данных. Пользователей нужно учить пользоваться всеми инструментами ИО, такими как фильтры, сортировки и т.п., а не рассматривать его как большую решётку Excel, в которой вместо Page Down можно жать на ссылку к следующей странице отчёта.
  2. Пользоваться настройкой максимального отображаемого количества строк в интерактивных отчётах всё-таки необходимо. Собственно, этому и учит нас документация APEX и другие материалы, как теперь видно — обоснованно. В отличие от границ страницы, ограничение числа строк в текст запроса добавляется и влияет на план выполнения.
  3. Оптимизатор может решить выполнять Ваш тяжёлый запрос для отчёта в режиме ALL_ROWS, несмотря на необходимость для вывода на страницу всего лишь в первых паре сотен строк. Уговорить его этого не делать Вы сможете с трудом, например созданием дополнительного процесса Before Header, в котором будет выставляться явно соответствующий режим:
    execute immediate 'alter session set optimizer_mode = all_rows';
    Кроме того, в WWV_FLOW_WORKSHEET.get_worksheet_report_query при оборачивании текста запроса используется поле WWV_FLOW_WORKSHEETS.sql_hint, название которого намекает на возможное светлое будущее, где разработчику APEX предоставят интерфейс для указания хинтов запросу отчёта.

Читать далее