Oracle DB, Oracle APEX, Linux etc.

четверг, 21 июля 2016 г.

ORA-28374, OPEN_NO_MASTER_KEY и другие проблемы, связанные с TDE

Хорошая статья, подробно описывающая проблемы, возникающие с ключами и их хранилищами для Transparent Data Encryption, причины возникновения и решения: Oracle Public Cloud Database Service – ORA-28374: typed master key not found in wallet by Seth Miller.
Читать далее

вторник, 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 предоставят интерфейс для указания хинтов запросу отчёта.

Читать далее

воскресенье, 19 октября 2014 г.

JasperReports Integration + GlassFish

Делюсь инструкцией по установке сервлета, позволяющего использовать JasperReports из APEX. В качестве контейнера используется GlassFish. По ходу описания я расскажу, как обновить в сервлете JasperReports Library и настроить соединение с Oracle в GlassFish.

Потребуются:
  • установленный APEX (4.2.6);
  • установленный GlassFish (4.1), каталог установки в инструкции обозначен как GLASSFISH_ROOT;
  • JasperReports Library (5.6.0), далее JRL;
  • JasperReports Integration (2.1.0), далее JRI.

Установка и настройка:

  1. Распаковать JRI в какой-либо пустой каталог (далее $JRI_ROOT).
  2. Переписать файлы *.jar из папки $JRI_ROOT/lib в каталог $GLASSFISH_ROOT/glassfish/domains/domain1/lib:
    cp $JRI_ROOT/lib/*.jar $GLASSFISH_ROOT/glassfish/domains/domain1/lib
  3. Извлечь из веб-приложения JRI файл web.xml для указания каталога, в котором будут расположены каталог конфигурационных файлов, каталог отчётов, каталог файлов протокола работы приложения:
    cd $JRI_ROOT
    java -jar bin/truezip.jar cp webapp/JasperReportsIntegration.war/WEB-INF/web.xml web.xml
  4. Изменить в файле web.xml параметр oc.jasper.config.home (тег param-value):
    
      oc.jasper.config.home/path/to/jasperreports/config/dir
    

    Каталог в настройке (далее $JRI_CONF_HOME) должен давать права на чтение и запись пользователю ОС, под которым запускается GlassFish.
  5. Обновить файл web.xml в архиве веб-приложения:
    cd $JRI_ROOT
    java -jar bin/truezip.jar cp web.xml webapp/JasperReportsIntegration.war/WEB-INF/web.xml
  6. Создать каталог $JRI_CONF_HOME, если он ещё не создан, настроить права.
  7. Переписать в этот каталог $JRI_CONF_HOME папки $JRI_ROOT/{conf,logs,reports}.
  8. Зайти в веб-консоль GlassFish и установить приложение: Applications→Deploy. Выбрать архив с обновлённым web.xml.
    Context Root=/jri
  9. Создать JDBC Connection Pool с произвольным именем (далее $POOL_NAME). JDBC→JDBC Connection Pools→New:
    Resource Type: javax.sql.DataSource
    Datasource Classname: oracle.jdbc.pool.OracleDataSource
    Properties→User: DB_USER
    Properties→Password: db_password
    Properties→URL: jdbc:oracle:thin:@your.db.host:1521:oracle_sid
    
  10. Проверить пул, выбрав его и нажав Ping.
  11. Создать JDBC Resource, с которым будет работать приложение. JDBC→JDBC Resource→New:
    JNDI Name: Строка из букв и чисел с префиксом, отделённым косой чертой (например, jdbc/default, jdbc/mydbuser1)
    Pool Name: $POOL_NAME
  12. В файле $JRI_CONF_HOME/conf/application.properties настроить JNDI-префикс и подключения:
    ...
    jndiPrefix=jdbc/
    ...
    [datasource:default]
    type=jndi
    name=default
    # Для ресурса JNDI убирается префикс и указывается оставшаяся строка
    
  13. Распаковать JasperReports Library в какой-либо каталог (далее $JRL_ROOT);
  14. Остановить домен GlassFish в консоли:
    asadmin stop-domain domain1
  15. Обновить библиотеку JasperReports в составе JRI. Для этого перейти в $GLASSFISH_ROOT/glassfish/domains/domain1/applications/JasperReportsIntegration/WEB-INF/lib и выполнить для удаления старой библиотеки:
    chmod u+x _jasper-reports-delete-libs-5.1.0.sh
    ./_jasper-reports-delete-libs-5.1.0.sh
  16. Переписать в $GLASSFISH_ROOT/glassfish/domains/domain1/applications/JasperReportsIntegration/WEB-INF/lib все файлы из каталога $JRL_ROOT/lib и файл $JRL_ROOT/dist/jasperreports-5.6.0.jar.
    cp $JRL_ROOT/lib/* $JRL_ROOT/dist/jasperreports-5.6.0.jar $GLASSFISH_ROOT/glassfish/domains/domain1/applications/JasperReportsIntegration/WEB-INF/lib
  17. Запустить домен GlassFish в консоли:
    asadmin start-domain domain1
  18. Выполнить скрипт $JRI_ROOT/sql/sys_install.sql. Потребуется указать схему БД, в которой будет размещаться API для формирования отчётов из PL/SQL.
  19. Выполнить скрипт $JRI_ROOT/sql/sys_install_acl.sql. Потребуется указать схему БД, в которой будет размещаться API для формирования отчётов из PL/SQL.
  20. Выполнить скрипт $JRI_ROOT/sql/user_install.sql от имени пользователя, в схеме которого будет размещаться API для формирования отчётов из PL/SQL.
  21. Для проверки работоспособности веб-приложения открыть http://<сервер с GlassFish>:<настроенный для приложений порт>/
  22. Для проверки обращений и примера использования JRI из APEX установить приложение из $JRI_ROOT/apex.

Читать далее