tag:blogger.com,1999:blog-10489686088512027572024-03-13T18:14:08.264+02:00PPLab<i>Recently I was writing here about Oracle Database, Oracle APEX, Linux.
Now I'm more interested in PostgreSQL and AWS, but Oracle will always be in my heart. :)</i>
<b>suPPLer</b>suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.comBlogger76125tag:blogger.com,1999:blog-1048968608851202757.post-79698926935618595682016-10-25T14:10:00.001+03:002016-10-25T14:10:11.078+03:00Oracle Multitenant: Data Pump + DATA_PUMP_DIR = ORA-39001Основная фича Oracle 12c -- Multitenant -- вместе с удобством администрирования привнесла и проблемы. Одна из них -- невозможность экспорта из и импорта в подключаемые БД, используя создаваемую по умолчанию директорию <tt>DATA_PUMP_DIR</tt>:<br />
<br />
<blockquote>The default Data Pump directory object, DATA_PUMP_DIR, does not work with PDBs. You must define an explicit directory object within the PDB that you are exporting or importing.</blockquote><div style="float: right;"><a href="http://docs.oracle.com/database/121/SUTIL/GUID-49A847B1-3193-4C45-B7F3-B7F514B75C71.htm#SUTIL4335">Using Data Pump to Move Databases Into a CDB</a></div><br />
При этом вы можете спокойно использовать эту директорию из подключаемой БД, работая с файлами через <tt>UTL_FILE</tt>. Похоже, проблема в том, что Data Pump фильтрует доступные в БД директории по <tt>ORIGIN_CON_ID</tt>:<br />
<br />
<pre class="brush:sql;highlight:8,14">SQL> select origin_con_id
2 from dba_directories
3 where directory_name = 'DATA_PUMP_DIR'
4 /
ORIGIN_CON_ID
-------------
1
SQL> show con_id
CON_ID
-------------
3 </pre><br />
Проблема решается одним из двух способов:<br />
<ol><li>Создать свою директорию в подключаемой БД и дать права на её чтение и запись отдельному пользователю, если требуется:<br />
<br />
<pre class="brush:sql">SQL> create directory pdb1_data_pump_dir as '/path/to/dir';
Directory created.
SQL> grant read, write on directory pdb1_data_pump_dir to system;
Grant succeeded.</pre></li>
<li>Удалить директорию <tt>DATA_PUMP_DIR</tt> в корневом контейнере и создать её там с параметром сессии <tt>"_oracle_script"=FALSE</tt>, а затем создать её же в каждой подключаемой БД (и в шаблоне БД):<br />
<pre class="brush:sql">SQL> conn / as sysdba
Connected.
SQL> show con_id
CON_ID
----------------
1
SQL> drop directory data_pump_dir;
Directory dropped.
SQL> alter session set "_oracle_script" = false;
Session altered.
SQL> create directory data_pump_dir as '/path/to/dir';
Directory created.
SQL> grant read, write on directory data_pump_dir to system;
Grant succeeded.
SQL> alter session set container = pdb1;
Session altered.
SQL> create directory data_pump_dir as '/path/to/dir';
Directory created.
SQL> grant read, write on directory data_pump_dir to system;
Grant succeeded.</pre></li>
</ol>suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-81250519882941002872016-07-21T20:40:00.001+03:002016-07-21T20:40:25.671+03:00ORA-28374, OPEN_NO_MASTER_KEY и другие проблемы, связанные с TDEХорошая статья, подробно описывающая проблемы, возникающие с ключами и их хранилищами для Transparent Data Encryption, причины возникновения и решения: <a href="http://sethmiller.org/oracle-2/oracle-public-cloud-ora-28374-typed-master-key-not-found-in-wallet/">Oracle Public Cloud Database Service – ORA-28374: typed master key not found in wallet</a> by Seth Miller.suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-22616582261042514152015-05-05T02:10:00.000+03:002015-05-05T02:14:57.681+03:00ORDS 3.0: Проблема с настройкой подключения к нескольким БДОдин экземпляр Oracle REST Data Services (ORDS) может работать сразу с несколькими базами данных. Для этого необходимо задать настройки для подключения к ним и выбрать метод, по которому ORDS будет определять, к какой БД хочет обращается клиент. Подробней можно прочитать здесь: <a href="http://docs.oracle.com/cd/E56351_01/doc.30/e56293/config.htm#AELIG7188">REST Data Services Installation, Configuration, and Development Guide — 2.1 Configuring Multiple Databases</a>.<br />
<br />
Но недавно вышедший ORDS 3.0.0.121 при добавлении настроек для дополнительной БД создаёт неверные файлы конфигурации. <span class="fullpost">Как пример, результат настройки для базы с именем apex40:<br />
<br />
<pre class="brush:bash">$ 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>
</pre>Отсутствуют имя хоста и порт (что в моём случае несущественно), имя службы. Без этой информации ORDS использует настройки подключения по умолчанию из <tt>$APEX_CONFIG_DIR/defaults.xml</tt> и подключается не к той БД. <br />
<br />
Исправить досадный баг просто, достаточно добавить настройки подключения в файлы <tt>$APEX_CONFIG_DIR/conf/<имя_БД>*.xml</tt> вручную:<br />
<br />
<pre class="brush:xml; highlight: [5,6,7]"><?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.hostname">...</entry>
<entry key="db.port">...</entry>
<entry key="db.servicename">...</entry>
<entry key="db.password">...</entry>
<entry key="db.username">APEX_PUBLIC_USER</entry>
</properties></pre><br />
Надеюсь, это поправят в ближайшем обновлении ORDS.</span>suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-86728463555888781242015-05-04T02:31:00.001+03:002015-05-04T02:31:31.594+03:00Немного камней по дороге к APEX 5.0Как писал раньше, для начала планировал создать отдельную подключаемую БД, в которой уже потом разворачивать APEX 5.0. Для этого решил создать контейнерную БД Oracle 12.1.0.2.3 (CDB) на Linux 86-64, смигрировать уже имеющуюся холодную не-контейнерную БД (non-CDB) в виде подключаемой (PDB) в новосозданную и на её копию установить новый APEX. Создал и обновил БД, на следующем шаге воспользовался руководством: <a href="http://oracle-base.com/articles/12c/multitenant-migrate-non-cdb-to-pdb-12cr1.php#using-dbms_pdb">Multitenant : Migrate a Non-Container Database (CDB) to a Pluggable Database (PDB) in Oracle Database 12c Release 1 (12.1)</a>. И это было ошибкой. :) <br />
<br />
<span class="fullpost">Как промежуточный результат, получил CDB, в которой APEX уже был установлен в корневом контейнере и мог быть обновлён только для всех контейнеров сразу. Если попытаться обновить его только в одном из контейнеров, то те из них, в которых версия APEX не совпадала с версией в корневом контейнере, просто открывались в ограниченном режиме, оставляя сообщения об ошибках в <tt>PDB_PLUG_IN_VIOLATIONS</tt>:<br />
<br />
<pre class="brush:sql">> 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 </pre><br />
Поэтому пришлось удалять полученную PDB, затем удалять APEX из CDB (<a href="http://oracle-base.com/articles/12c/multitenant-uninstall-apex-from-the-cdb-12cr1.php">Multitenant : Uninstall APEX from the CDB in Oracle Database 12c Release 1 (12.1)</a>) и создавать PDB как копию non-CDB с установленным APEX заново. Но и на этом всё не закончилось: PDB открывалась со следующей ошибкой:<br />
<br />
<pre class="brush:text">Sync PDB failed with ORA-65177 during 'alter user APEX_PUBLIC_USER account unlock'</pre><br />
Гугл на это сказал немного, как и MOS. Поскольку в корневом контейнере такого пользователя не обнаружил, а в PDB у него были лишь права DML на <tt>FLOWS_FILES.WWV_FLOW_FILE_OBJECTS$</tt>, то решил его пересоздать в PDB, не мудрствуя лукаво:<br />
<br />
<pre class="brush:sql">conn / as sysdba
alter session set container=pdb1;
drop user apex_public_user;</pre><br />
На что Oracle ответил:<br />
<br />
<pre class="brush:text">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.</pre><br />
Немного погуглив, изменил подход:<br />
<pre class="brush:sql">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;</pre>PDB открылась без ошибок. После этого можно было пересоздать пользователя APEX_PUBLIC_USER:<br />
<pre class="brush:sql">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;</pre><br />
Пользователь на месте, PDB успешно открыта. Увы, попытка достучаться из ORDS к базе возвращала <tt>503 Service unavailable</tt>. В <tt>alert.log</tt> нашёл «воодушевляющее» сообщение:<br />
<br />
<pre class="brush:text">ORA-00600: internal error code, arguments: [kpdbAttachSga: bad pdb], [0], [pdb1.workgroup], [], [],[], [], [], [], [], [], []</pre><br />
Поиск на MOS вывел на похожий параметром ORA-00600 баг 20438519 и устраняющий его патч 19972766. После установки последнего наконец-то всё заработало.</span>suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-75169322228553891062015-04-20T12:51:00.000+03:002015-04-20T12:51:04.087+03:00Oracle APEX 5.0!Вот так пару дней поболел и пропустил выход долгожданной новой версии. Ну что, сценарий для изучения теперь проще с Multitenant:<br />
<ol><li>Скачать новый <a href="http://www.oracle.com/technetwork/developer-tools/apex/downloads/index.html">APEX</a>.</li>
<li>Создать БД для тестирования:<br />
<pre class="brush:sql">create pluggable database apx5 from tmpl file_name_convert( '/app/oracle/oradata/tmpl', '/app/oracle/oradata/apx5' );</pre></li>
<li>Установить свежий APEX 5.0 и посмотреть, что стало лучше, а что перестало работать. :)</li>
</ol>suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com2tag:blogger.com,1999:blog-1048968608851202757.post-64365588596646278222015-04-15T02:12:00.000+03:002015-04-15T02:12:56.765+03:00Oracle Multitenant и ORA-28000Наткнулся недавно на небольшую проблему — ORDS на Glassfish отказывался создавать подключения к БД, выводя на экран "503 — Service Unavailable" со следующим сообщением в <tt>server.log</tt>:<br />
<pre class="brush:plain">The pool named: apex is not correctly configured, error: ORA-28000: the account is locked</pre><span class="fullpost"><br />
<br />
Посмотрел пользователя БД в файле конфигурации ORDS для пула <b>apex</b> <tt>${configdir}/ords/conf/apex.xml</tt>:<br />
<pre class="brush:xml">...
<entry key="db.username">APEX_PUBLIC_USER</entry>
...</pre><br />
Настройки для соединения взял из <tt>${configdir}/ords/defaults.xml</tt>:<br />
<pre class="brush:xml">...
<entry key="db.hostname">hostname</entry>
<entry key="db.port">1521</entry>
<entry key="db.servicename">pdb1.workgroup</entry>
...</pre><br />
Подсоединился к <tt>pdb1.workgroup</tt>, проверил пользователя <tt>APEX_PUBLIC_USER</tt> — открыт. И вот тут я потратил достаточно много времени, прежде чем вспомнил, что с появлением Multitenant Architecture в Oracle 12c появились <a href="https://docs.oracle.com/database/121/DBSEG/users.htm#DBSEG573">общие пользователи</a>. Переключился в корневую БД, и точно — заблокирован <tt>APEX_PUBLIC_USER</tt>! <br />
<br />
<pre class="brush:sql">alter user apex_public_user account unlock;
alter user apex_public_user identified by ...;</pre><br />
После этого ORDS смог подключиться, проблема была решена.</span>suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-39492290809207365612015-02-22T00:23:00.002+02:002015-02-22T00:23:44.325+02:00Oracle APEX: разбивка на страницы интерактивных отчётовБлагодаря <a href="http://www.sql.ru/forum/1059246-2/pomogite-po-jquery-monitor-izmeneniy?mid=17292303#17292303">дискуссии на SQL.RU</a>, решил проверить, как на самом деле происходит выдача страницы данных для интерактивного отчёта в Oracle APEX. Использовал версию 4.2.5, но не думаю, что что-то будет сильно отличаться вплоть до 4.1 включительно. Создал приложение с простым интерактивным отчётом, у которого в качестве источника данных был следующий запрос:<br />
<br />
<pre class="brush:sql">select * from emp</pre><br />
Изначально я ставил на то, что движок выполнения отчётов переписывает указанный разработчиком запрос и помимо прочей обёртки добавляет к нему один из известных приёмов по выдаче части отсортированных данных. Например:<br />
<br />
<pre class="brush:sql">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
</pre><br />
Результаты отладки меня слегка удивили:<br />
<br />
<div class="separator" style="clear: both; text-align: center;"><a href="http://4.bp.blogspot.com/-MWc2sPWrXIA/VOj99CN-G4I/AAAAAAAAAKE/RNfTYlTbepI/s1600/screenshot-dark-place%2B8180%2B2015-02-21%2B23-51-00.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-MWc2sPWrXIA/VOj99CN-G4I/AAAAAAAAAKE/RNfTYlTbepI/s320/screenshot-dark-place%2B8180%2B2015-02-21%2B23-51-00.png" /></a></div><br />
Была слабая надежда, что это не окончательный запрос, и где-то там его ещё дополнительно обернут… Однако, после поиска в исходниках и вдумчивого чтения разврапленного <tt>wwv_flow_worksheet.plb</tt> я обнаружил, что всё намного печальней: в <tt>WWV_FLOW_WORKSHEET.get_report</tt> открывается курсор по тексту запроса, в котором нет никакого намёка на первую и последнюю строки страницы. Вместо этого курсор в цикле вхолостую считывается, пока не доходит до первой строки страницы. Затем начинается вывод строк, пока не дойдёт до последней.<br />
<br />
Какие из полученных знаний можно сделать выводы:<ol><li>Каждая следующая страница интерактивного отчёта, к которой перейдёт пользователь, будет требовать чтения всё большего объёма данных. Пользователей нужно учить пользоваться всеми инструментами ИО, такими как фильтры, сортировки и т.п., а не рассматривать его как большую решётку Excel, в которой вместо Page Down можно жать на ссылку к следующей странице отчёта.</li>
<li>Пользоваться настройкой максимального отображаемого количества строк в интерактивных отчётах всё-таки необходимо. Собственно, этому и учит нас документация APEX и другие материалы, как теперь видно — обоснованно. В отличие от границ страницы, ограничение числа строк в текст запроса добавляется и влияет на план выполнения.</li>
<li>Оптимизатор может решить выполнять Ваш тяжёлый запрос для отчёта в режиме <tt>ALL_ROWS</tt>, несмотря на необходимость для вывода на страницу всего лишь в первых паре сотен строк. Уговорить его этого не делать Вы сможете с трудом, например созданием дополнительного процесса Before Header, в котором будет выставляться явно соответствующий режим: <pre class="brush:sql">execute immediate 'alter session set optimizer_mode = all_rows';</pre>Кроме того, в <tt>WWV_FLOW_WORKSHEET.get_worksheet_report_query</tt> при оборачивании текста запроса используется поле <tt>WWV_FLOW_WORKSHEETS.sql_hint</tt>, название которого намекает на возможное светлое будущее, где разработчику APEX предоставят интерфейс для указания хинтов запросу отчёта.</li>
</ol>suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-21086941786052595842014-10-19T03:48:00.000+03:002015-05-09T00:05:28.699+03:00JasperReports Integration + GlassFishДелюсь инструкцией по установке сервлета, позволяющего использовать JasperReports из APEX. В качестве контейнера используется GlassFish. По ходу описания я расскажу, как обновить в сервлете JasperReports Library и настроить соединение с Oracle в GlassFish.<br />
<span class="fullpost"><br />
<b>Потребуются:</b><br />
<ul><li>установленный APEX (<a href="http://www.oracle.com/technetwork/developer-tools/apex/application-express/apex-archive-42-1885734.html">4.2.6</a>);</li>
<li>установленный GlassFish (<a href="https://glassfish.java.net/">4.1</a>), каталог установки в инструкции обозначен как GLASSFISH_ROOT;</li>
<li>JasperReports Library (<a href="http://sourceforge.net/projects/jasperreports/files/jasperreports/JasperReports%205.6.0/jasperreports-5.6.0-project.tar.gz/download">5.6.0</a>), далее <i>JRL</i>;</li>
<li>JasperReports Integration (<a href="http://www.opal-consulting.de/downloads/free_tools/JasperReportsIntegration/2.1.0/JasperReportsIntegration-2.1.0.0.zip">2.1.0</a>), далее <i>JRI</i>.</li>
</ul><br />
<b>Установка и настройка:</b><br />
<br />
<ol><li>Распаковать JRI в какой-либо пустой каталог (далее <tt>$JRI_ROOT</tt>).</li>
<li>Переписать файлы <tt>*.jar</tt> из папки <tt>$JRI_ROOT/lib</tt> в каталог <tt>$GLASSFISH_ROOT/glassfish/domains/domain1/lib</tt>:<br />
<pre class="brush:shell">cp $JRI_ROOT/lib/*.jar $GLASSFISH_ROOT/glassfish/domains/domain1/lib</pre></li>
<li>Извлечь из веб-приложения JRI файл web.xml для указания каталога, в котором будут расположены каталог конфигурационных файлов, каталог отчётов, каталог файлов протокола работы приложения:<br />
<pre class="brush: shell;">cd $JRI_ROOT
java -jar bin/truezip.jar cp webapp/JasperReportsIntegration.war/WEB-INF/web.xml web.xml</pre></li>
<li>Изменить в файле <tt>web.xml</tt> параметр <tt>oc.jasper.config.home</tt> (тег <tt>param-value</tt>):<br />
<pre class="brush: xml;"><context-param>
<param-name>oc.jasper.config.home</param-name><param-value>/path/to/jasperreports/config/dir</param-value></context-param>
</pre><br />
Каталог в настройке (далее <tt>$JRI_CONF_HOME</tt>) должен давать права на чтение и запись пользователю ОС, под которым запускается GlassFish. </li>
<li>Обновить файл web.xml в архиве веб-приложения:<br />
<pre class="brush: shell;">cd $JRI_ROOT
java -jar bin/truezip.jar cp web.xml webapp/JasperReportsIntegration.war/WEB-INF/web.xml</pre></li>
<li>Создать каталог <tt>$JRI_CONF_HOME</tt>, если он ещё не создан, настроить права. </li>
<li>Переписать в этот каталог <tt>$JRI_CONF_HOME</tt> папки <tt>$JRI_ROOT/{conf,logs,reports}</tt>.</li>
<li>Зайти в веб-консоль GlassFish и установить приложение: Applications→Deploy. Выбрать архив с обновлённым web.xml. <br />
<pre class="brush:text">Context Root=/jri</pre></li>
<li>Создать JDBC Connection Pool с произвольным именем (далее $POOL_NAME). JDBC→JDBC Connection Pools→New:<br />
<pre class="brush:text">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
</pre></li>
<li>Проверить пул, выбрав его и нажав Ping.</li>
<li>Создать JDBC Resource, с которым будет работать приложение. JDBC→JDBC Resource→New:<br />
<pre class="brush:text">JNDI Name: Строка из букв и чисел с префиксом, отделённым косой чертой (например, jdbc/default, jdbc/mydbuser1)
Pool Name: $POOL_NAME</pre></li>
<li>В файле <tt>$JRI_CONF_HOME/conf/application.properties</tt> настроить JNDI-префикс и подключения:<br />
<pre class="brush: plain;">...
jndiPrefix=jdbc/
...
[datasource:default]
type=jndi
name=default
# Для ресурса JNDI убирается префикс и указывается оставшаяся строка
</pre></li>
<li>Распаковать JasperReports Library в какой-либо каталог (далее $JRL_ROOT);</li>
<li>Остановить домен GlassFish в консоли:<br />
<pre class="brush: shell;">asadmin stop-domain domain1</pre></li>
<li>Обновить библиотеку JasperReports в составе JRI. Для этого перейти в <tt>$GLASSFISH_ROOT/glassfish/domains/domain1/applications/JasperReportsIntegration/WEB-INF/lib</tt> и выполнить для удаления старой библиотеки:<br />
<pre class="brush: shell;">chmod u+x _jasper-reports-delete-libs-5.1.0.sh
./_jasper-reports-delete-libs-5.1.0.sh</pre></li>
<li>Переписать в <tt>$GLASSFISH_ROOT/glassfish/domains/domain1/applications/JasperReportsIntegration/WEB-INF/lib</tt> все файлы из каталога <tt>$JRL_ROOT/lib и файл $JRL_ROOT/dist/jasperreports-5.6.0.jar</tt>. <br />
<pre class="brush:shell">cp $JRL_ROOT/lib/* $JRL_ROOT/dist/jasperreports-5.6.0.jar $GLASSFISH_ROOT/glassfish/domains/domain1/applications/JasperReportsIntegration/WEB-INF/lib</pre></li>
<li>Запустить домен GlassFish в консоли: <pre class="brush: shell;">asadmin start-domain domain1</pre></li>
<li>Выполнить скрипт <tt>$JRI_ROOT/sql/sys_install.sql</tt>. Потребуется указать схему БД, в которой будет размещаться API для формирования отчётов из PL/SQL.</li>
<li>Выполнить скрипт <tt>$JRI_ROOT/sql/sys_install_acl.sql</tt>. Потребуется указать схему БД, в которой будет размещаться API для формирования отчётов из PL/SQL.</li>
<li>Выполнить скрипт <tt>$JRI_ROOT/sql/user_install.sql</tt> от имени пользователя, в схеме которого будет размещаться API для формирования отчётов из PL/SQL.</li>
<li>Для проверки работоспособности веб-приложения открыть <tt>http://<сервер с GlassFish>:<настроенный для приложений порт>/<context root=""></tt></li>
<li>Для проверки обращений и примера использования JRI из APEX установить приложение из <tt>$JRI_ROOT/apex</tt>.</li>
</ol></span>suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com2tag:blogger.com,1999:blog-1048968608851202757.post-68212086612140226682013-08-19T03:23:00.002+03:002013-08-19T03:24:40.150+03:00Плагин TabGridНебольшая вариация на тему грида Ext JS в APEX: <a href="http://apex.oracle.com/pls/otn/apex/f?p=40749:1">http://apex.oracle.com/pls/otn/apex/f?p=40749:1</a><br />
Логин/пароль: <i>demo/demo</i><br />
<br />
Направление развития: фильтры, работающие на сервере.<br />
<br />
PS: Есть желание замахнуться на небольшой фреймворк в качестве альтернативы FOEX.suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-34736710794813520932013-05-31T20:37:00.001+03:002013-05-31T20:37:12.666+03:00Oracle: запрос для отображения комментариев к таблице в виде DDLПростой запрос для получения готовых DDL-операторов COMMENT с комментариями к таблице и её столбцам:<br />
<br />
<pre class="brush:sql">with par as (
select nvl('&owner', user) owner -- Владелец схемы с таблицей
, '&table_name' table_name -- Таблица
from dual
)
select ddl_stmt
from (select p.owner
, p.table_name
, '' column_name
, comments
, 'comment on table "'||p.owner||'"."'||p.table_name||'" is ''' || comments ||''';' ddl_stmt
from par p
left join
all_tab_comments tc on p.owner = tc.owner and p.table_name = tc.table_name
union all
select c.owner
, c.table_name
, c.column_name
, tc.comments
, 'comment on column "'||c.owner||'"."'||c.table_name||'"."'||c.column_name||'" is ''' || comments ||''';' ddl_stmt
from (select owner, table_name, column_name
from par p natural join all_tab_columns c) c
left join
all_col_comments tc on c.owner = tc.owner and c.table_name = tc.table_name and c.column_name = tc.column_name)
order by owner, table_name, column_name nulls first
/
</pre><br />
Полезен как заготовка в ситуациях, когда нужно создать скрипт добавления или изменения комментариев к таблице.suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com2tag:blogger.com,1999:blog-1048968608851202757.post-13274739758550179012013-03-14T15:00:00.000+02:002013-03-14T15:00:48.171+02:00Oracle APEX: Remote DebugСлучайно узнал, что можно включить <a href="http://suppler.blogspot.com/2010/11/oracle-apex-oracle-sql-developer.html">удалённую отладку</a> установкой в URL значения <b>REMOTE</b> для аргумента <a href="http://docs.oracle.com/cd/E37097_01/doc/doc.42/e35125/concept_url.htm#r6c1-t17">Debug</a>. При этом подключение для удалённой отладки происходит в самом начале этапов Page Processing и Page Rendering и создаётся к удалённому хосту из переменной REMOTE_ADDR окружения CGI на порт 4000.<br />
<br />
В документации об этом почему-то ни слова. <br />
<br />
Пользуясь случаем, напоминаю, что уровнем отладки (и количеством выдаваемой информации) можно управлять, используя значения <b>LEVEL<i>n</i></b> для аргумента Debug, где <b><i>n</i></b> -- уровень отладки от 1 до 9. По умолчанию, для значения <b>YES</b> используется уровень 4.<br />
suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-31995588518393264062013-02-14T21:55:00.000+02:002013-02-15T01:49:06.158+02:00Oracle APEX: Report Template PreviewДа, я знаю, что обещал заметку о том, как создавать плагин-регион. Но пока я её готовлю, могу предложить описание поиска ошибки в APEX Application Builder и её исправления.<br />
<br />
Ошибка заключается в том, что в APEX уже <a href="https://forums.oracle.com/forums/thread.jspa?threadID=2142068">довольно давно</a> поломался предпросмотр шаблонов отчётов. <span class="fullpost"><br />
<a href="http://1.bp.blogspot.com/-jKTHCn84lgw/UR0wTKv_YBI/AAAAAAAAAHE/11x3Y4bakpA/s1600/01.jpg" imageanchor="1" ><img border="0" src="http://1.bp.blogspot.com/-jKTHCn84lgw/UR0wTKv_YBI/AAAAAAAAAHE/11x3Y4bakpA/s600/01.jpg" /></a><br />
<br />
Для шаблонов страниц работает, для регионов тоже, а отчёты показывают крайне информативное сообщение:<br />
<pre class="brush: plain; gutter: false;">report error:
ORA-01002: fetch out of sequence</pre><br />
Как всё поправить? Для начала, нужно разобраться, что выполняется на странице. Смотрим в адресную строку:<br />
<pre class="brush: plain;">/apex/f?p=4000:245:7846987198961::::F4000_P245_ID:2451412072364242</pre><br />
Заглядываем в словарь APEX, что там за регионы на странице 245 приложения 4000:<br />
<pre class="brush: sql">column region_name format a20
column region_id format 999999999999999999999999
column source_type format a15
column region_source format a80
set long 700
select region_name, region_id, source_type, region_source
from apex_040200.apex_application_page_regions
where application_id = 4000 and page_id = 245
/
</pre><pre class="brush: plain; gutter: false;">REGION_NAME REGION_ID SOURCE_TYPE REGION_SOURCE
-------------------- ------------------------- --------------- --------------------------------------------------------------------------------
Breadcrumb 6539000463209372 Breadcrumb
Template Preview 14562627207747006 PL/SQL wwv_render_report3.show(
p_query => '
select 1 COL1, ''[...]'' COL2, ''[...]
Template Preview 14573702151806062 HTML/Text <p>This page provides a preview of the identified report template.</p>Template Details 82014114667920662 Report select ROW_TEMPLATE_NAME N, ROW_TEMPLATE_TYPE T
from WWV_FLOW_ROW_TEMPLATES
preview-report 88449328191587806 Report select 1 COL1, '[...]' COL2, '[...]' COL3, sysdate COL4 from dual union
select
</pre><br />
Судя по названиям и содержимому, нас интересуют регионы с REGION_ID <b>14562627207747006</b> и <b>88449328191587806</b>. Первый выполняет обращение к <b>wwv_render_report3.show</b>, второй, как мы сейчас увидим, служит для хранения настроек, которые используются в этом вызове:<br />
<pre class="brush: sql">column region_source format a700
set long 700
select region_id, region_source
from apex_040200.apex_application_page_regions
where region_id in (14562627207747006, 88449328191587806)
/</pre><pre class="brush: plain; gutter: false;">REGION_ID REGION_SOURCE
------------------------- --------------------------------------------------------------------------------
14562627207747006 wwv_render_report3.show(
p_query => '
select 1 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual union
select 2 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual union
select 3 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual union
select 4 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual union
select 5 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual union
select 6 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual
order by 1',
p_row_template_id => :f4000_p245_id,
p_region_id => 88449328191587806
);
88449328191587806 select 1 COL1, '[...]' COL2, '[...]' COL3, sysdate COL4 from dual union
select 2 COL1, '[...]' COL2, '[...]' COL3, sysdate COL4 from dual union
select 3 COL1, '[...]' COL2, '[...]' COL3, sysdate COL4 from dual union
select 4 COL1, '[...]' COL2, '[...]' COL3, sysdate COL4 from dual union
select 5 COL1, '[...]' COL2, '[...]' COL3, sysdate COL4 from dual union
select 6 COL1, '[...]' COL2, '[...]' COL3, sysdate COL4 from dual
order by 1
</pre>Значит, путь наш лежит в <b>wwv_render_report3.show</b>. Чтобы посмотреть, что именно там происходит, потребуется <a href="http://blog.teusink.net/2010/04/unwrapping-oracle-plsql-with-unwrappy.html">разврапировать</a> тело пакета и установить его в схему APEX. Тело находится в файле <b>reports3.plb</b>.<br />
<br />
Затем включить <a href="http://suppler.blogspot.com/2010/11/oracle-apex-oracle-sql-developer.html">удалённую отладку</a>, для чего потребуется скомпилировать этот пакет с поддержкой отладки. Ещё в рамках подготовки к удалённой отладке потребуется временно изменить содержимое региона <b>14562627207747006</b>, окружив вызов обращениями к <b>dbms_debug_jdwp</b>:<br />
<pre class="brush: sql">update wwv_flow_page_plugs
set plug_source = q'{dbms_debug_jdwp.connect_tcp('localhost',50001);
wwv_render_report3.show(
p_query => '
select 1 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual union
select 2 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual union
select 3 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual union
select 4 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual union
select 5 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual union
select 6 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual
order by 1',
p_row_template_id => :f4000_p245_id,
p_region_id => 88449328191587806
);
dbms_debug_jdwp.disconnect;}'
where id = 14562627207747006
/</pre>Я использую localhost как имя удалённого хоста, потому что пробросил через SSH свой порт 4000, на котором работает Debug Listener, на порт 50001 сервера с Oracle. Если файерволы Вам позволяют, можете вместо localhost указывать IP машины, на которой работает OSD с удалённой отладкой, тогда порт необходимо указать тот, который выбрали при запуске Remote Debug.<br />
<a href="http://3.bp.blogspot.com/-y6TJhxVsy7U/UR1AOz9hFiI/AAAAAAAAAHc/F-wvEEMlPp8/s1600/02.jpg" imageanchor="1" ><img border="0" src="http://3.bp.blogspot.com/-y6TJhxVsy7U/UR1AOz9hFiI/AAAAAAAAAHc/F-wvEEMlPp8/s600/02.jpg" /></a><br />
<br />
Итак, подготовились к отладке, запустили Remote Debug, зашли на страницу с предпросмотром шаблона отчёта. Началась отладка. За несколько итераций становится ясно, что ошибка возникает при попытке фетчить открытый курсор с запросом отчёта, который ещё не был выполнен. А происходит это, потому что в вызове <b>wwv_render_report3.show</b> не указано значение параметра <b>p_plug_source_type</b>. Исправляем:<br />
<pre class="brush: sql; highlight: 13">update wwv_flow_page_plugs
set plug_source = q'{wwv_render_report3.show(
p_query => '
select 1 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual union
select 2 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual union
select 3 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual union
select 4 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual union
select 5 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual union
select 6 COL1, ''[...]'' COL2, ''[...]'' COL3, sysdate COL4 from dual
order by 1',
p_row_template_id => :f4000_p245_id,
p_region_id => 88449328191587806,
p_plug_source_type => 'SQL_QUERY'
);}'
where id = 14562627207747006
/</pre><br />
Проверяем:<br />
<a href="http://1.bp.blogspot.com/-gyf4aM6nQ34/UR1AEe-wjpI/AAAAAAAAAHU/YXkvCMvaqNA/s1600/03.jpg" imageanchor="1" ><img border="0" src="http://1.bp.blogspot.com/-gyf4aM6nQ34/UR1AEe-wjpI/AAAAAAAAAHU/YXkvCMvaqNA/s600/03.jpg" /></a><br />
<br />
Вот так ищутся и правятся небольшие баги в APEX. Не забывайте делиться своими решениями.</span>suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com3tag:blogger.com,1999:blog-1048968608851202757.post-73382636477945430692012-10-15T13:04:00.000+03:002012-10-15T13:04:13.801+03:00APEX 4.2 ушёл в печать!<a href="http://www.oracle.com/technetwork/developer-tools/apex/downloads/index.html">http://www.oracle.com/technetwork/developer-tools/apex/downloads/index.html</a><br />
<br />
PS: Что-то я редко стал сюда что-нибудь добавлять... Потому анонс: в следующих сообщениях расскажу о создании плагинов. Начнём с плагина-региона.suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-42598129377903184882012-06-22T10:59:00.000+03:002012-06-22T10:59:18.330+03:00Oracle APEX 4.2 EA1 ушёл в народ!На <a href="http://www.oracle.com/technetwork/developer-tools/apex/overview/index.html">официальной странице</a> APEX появилась приятная новость о доступном Early Adapter (как Oracle именует публичные беты продуктов).<br />
<ol><li><a href="https://apexea.oracle.com/i/index.html">Регистрируйтесь!</a></li>
<li><a href="http://apex.oracle.com/pls/apex/f?p=38997:1">Пробуйте!</a></li>
<li><a href="https://apexea.oracle.com/pls/apex/f?p=4840:1">Пишите предложения и жалобы!</a></li>
</ol>Приятных выходных! ;)suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com1tag:blogger.com,1999:blog-1048968608851202757.post-92102056329280575212012-05-12T02:46:00.000+03:002012-05-12T02:46:14.148+03:00Oracle APEX: Мелочь, а не хватает...Казалось бы, не так велик труд: выбрать что-то при редактировании страницы и удалить. Но будь возможность делать это сразу из всплывающего меню! При интенсивном редактировании страницы надоедает вначале заходить в редактировании того же региона, или кнопки, или поля, или... А потом уже DELETE, "Да, я согласен" и обратно к редактированию страницы.<br />
<br />
На всякий случай добавил в <a href="https://forums.oracle.com/forums/thread.jspa?threadID=2329000">APEX 4.2 Wish List</a>.suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-23567387976658530232012-03-10T01:01:00.000+02:002012-03-10T01:12:46.028+02:00Oracle APEX Listener: Файл настроекЭто небольшая заметка о файле настроек <b>Oracle APEX Listener</b> (OAL), развёрнутом на <b>GlassFish 3</b>. <span class="fullpost"><br />
<br />
По умолчанию OAL создаёт и ищет файл настроек <mono>${java.io.tmpdir}/apex/apex-config.xml</mono>, где значение <mono>java.io.tmpdir</mono> для GlassFish установлено в <mono>/tmp</mono>. Любые временные директории — не место для хранения файлов настроек, поскольку время от времени их содержимое удаляется. <br />
<br />
Чтобы изменить это поведение раз и навсегда, необходимо:<br />
<ol><li>Распаковать файл <mono>apex.war</mono>. Это обычный zip-архив, проблем с разархивацией возникнуть не должно. Например, разархивируем архив в директорию <mono>tmp</mono>: <br />
<pre class="brush: bash">unzip -d tmp apex.war</pre></li>
<li>Изменить параметр <mono>config.dir</mono> в файле <mono>WEB-INF/web.xml</mono>. Найдём в нём следующие строки, устанавливающие значение параметра: <br />
<pre class="brush: xml"><!--
<context-param>
<param-name>config.dir</param-name>
<param-value>${java.io.tmpdir}/APEX</param-value>
</context-param>
-->
</pre>Раскомментируем и заменим значение параметра:<br />
<pre class="brush: xml"> <context-param>
<param-name>config.dir</param-name>
<param-value>${user.dir}</param-value><
</context-param>
</pre>Параметр user.dir для приложения, развёрнутого на GlassFish в домен <mono>domain_1</mono>, будет иметь значение <mono><Директория GlassFish>/glassfish/domains/domain_1/config</mono>. OAL создаст по этому пути поддиректорию <mono>apex</mono> и разместит файл настроек <mono>apex-config.xml</mono> в ней.<br />
</li>
<li>Создать архив <mono>apex.war</mono> с изменённым файлом. Перейдём в директорию tmp и соберём архив:<br />
<pre class="brush: bash">zip -r apex.war ./*</pre></li>
</ol><br />
Всё, архив с приложением готов к установке.</span>suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-71117947106342858802012-01-18T01:02:00.000+02:002012-01-26T00:10:02.571+02:00Oracle SQL Developer: проблема с горячими клавишами<b>Предыстория:</b> Не так давно обновил Debian на домашней машине до testing, из-за чего встретился с Gnome 3. Если бы у меня был планшет, наверно, всё было по-другому, однако для настольных ПК это DE недружелюбно. Итогом встречи стал переход на XFCE 4.8, который устроил практически всем. Но...<br />
<br />
<b>Проблема:</b> Oracle SQL Developer отказался распознавать текстовые символы с включёнными модификаторами <tt>Alt</tt>, <tt>Ctrl</tt> и любыми их комбинациями. То есть, о горячих клавишах можно было забыть.<br />
<span class="fullpost"><br />
<b>Причина:</b> Разброд и шатание в настройках клавиатуры.<br />
<br />
<b>Ход мыслей:</b> Поначалу я подумал на баги очередного EA, как раз обновил Oracle SQL Developer. Но откат на стабильную версию и удаление настроек (с созданием резервной копии, конечно) ситуацию не изменили. Пришлось внимательнее почитать Сеть. Несколько тем с похожими проблемами натолкнули на мысль, что что-то не так с настройками клавиатуры. И я начал читать про раскладки, X.org, XFCE, udev, evdev и грабли, на которые уже наткнулось прогрессивное человечество.<br />
<br />
Развитие X.org server, вначале отказавшегося от хранения настроек в <tt>xorg.conf</tt> в пользу HAL, а затем — и от HAL в пользу udev, evdev и задания настроек несколькими файлами через <tt>/etc/X11/xorg.conf.d</tt>, вынудило меня убрать развёвшийся в <tt>xorg.conf</tt> бардак. Я убрал секции <tt>InputDevice</tt> для мышки и клавиатуры, убрал ссылки на них в секции <tt>ServerLayout</tt>. Cоздал файл <tt>/etc/X11/xorg.conf.d/99-keyboard.conf</tt>, который задаёт для класса устройств типа Keyboard со строкой keyboard в названии драйвер, модель, раскладки и опции:<br />
<br />
<pre class="brush:text">Section "InputClass"
Identifier "evdev keyboard catchall"
MatchIsKeyboard "on"
MatchDevicePath "/dev/input/event*"
MatchProduct "keyboard"
Driver "evdev"
Option "XkbModel" "logicd"
Option "XkbRules" "xorg"
Option "XkbLayout" "us,ru"
Option "XkbVariant" ",winkeys"
Option "XkbOptions" "grp:caps_toggle,compose:rwin,terminate:ctrl_alt_bksp"
EndSection</pre><br />
Также, перезагружая иксы и проглядывая раз за разом <tt>/var/log/Xorg.0.log</tt>, я удалил не поддерживаемые расширения и модули, ненужные видеорежимы и прочий мусор. В <tt>/etc/default/keyboard</tt> были внесены те же правила для клавиатуры. Однако <tt>setxkbmap -print -verbose 10</tt> показывал совсем не то. Оказалось, что <tt>xfce4-xkb-plugin</tt> отчего-то переопределяет системные настройки, не смотря на соответствующую опцию. За что и был заменён на <tt>xxkb</tt>.<br />
<br />
<b>Итог:</b> Oracle SQL Developer снова работает с горячими клавишами, в настройке устройств ввода наведён небольшой порядок, место индикатора раскладок занял <tt>xxkb</tt>.</span>suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-20404039716348015772011-12-31T18:20:00.004+02:002011-12-31T18:21:16.747+02:00НГ-2012Желаю в наступающем Новом году счастья, здоровья, достаточно воображения для задумок и достаточно сил для их воплощения!suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-76161211082643551922011-10-12T22:18:00.001+03:002011-10-12T22:18:19.045+03:00Oracle: ORA-00600 [16305] + ORA-03113 при открытии БДОбновил в очередной раз Debian на своей домашней машине, запускаю экземпляр Oracle - и что я вижу? ORA-03113 в консоли + ORA-00600 [16305] в alert.log. Порыскав немного по OTN Forums и MOS и попутно заглядывая в трассу PMON, наткнулся на Doc ID <a href="https://supporthtml.oracle.com/ep/faces/secure/km/DocumentDisplay.jspx?id=466056.1&h=Y">466056.1</a>. Проверяя кэйс, выполнил <b>ifconfig</b> - а в выводе нет работающего loopback-интерфейса. В общем, для решения проблемы было достаточно его поднять:
<pre class="brush:bash">sudo ifup lo</pre>
И можно смело запускать экземпляр.suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-24806801420793291692011-10-12T21:59:00.000+03:002011-10-12T22:19:32.441+03:00Oracle: V$SESSION_LONGOPS и несколько одновременных длинных операцийДля того, чтобы отразить в <b>V$SESSION_LONGOPS</b> состояние нескольких одновременных длительных операций - например, общее выполнение процесса и конкретный большой шаг - нужно сохранять значение параметра <b>slno</b> процедуры <b><a href="http://download.oracle.com/docs/cd/E11882_01/appdev.112/e25788/d_appinf.htm#i996999">DBMS_APPLICATION_INFO.set_session_longops</a></b>. Используя затем пару значений (<b>rindex</b>,<b>slno</b>), можно менять необходимую строку в <b>V$SESSION_LONGOPS</b>.
Вот пример работы с двумя длительными операциями:
<pre class="brush:sql">declare
first_row pls_integer := dbms_application_info.set_session_longops_nohint;
second_row pls_integer := dbms_application_info.set_session_longops_nohint;
slno1 pls_integer;
slno2 pls_integer;
begin
dbms_application_info.set_session_longops(rindex => first_row
,slno => slno1
,op_name => '1_op'
,sofar => 1
,totalwork => 2
,units => 'step'
);
dbms_application_info.set_session_longops(rindex => second_row
,slno => slno2
,op_name => '2_op'
,sofar => 1
,totalwork => 1
,units => 'step'
);
dbms_application_info.set_session_longops(rindex => first_row
,slno => slno1
,op_name => '1_op'
,sofar => 2
,totalwork => 2
,units => 'step'
);
end;
/
select MESSAGE from v$session_longops where (sid,serial#) =
(select sid,serial# from v$session where audsid = USERENV('SESSIONID'));</pre>
Тема на <b>SQL.RU</b>: <a href="http://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=872856&msg=11108962">set_session_longops Можно ли вернуться к предидущей строке?</a>suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-48638305138428628822011-08-05T12:22:00.005+03:002011-08-05T14:18:32.051+03:00Oracle APEX: Процедуры в URL - ZПоследняя из "маленьких" встроенных процедур APEX, которые можно использовать в URL: <b>Z</b>.<br />
<br />
<span class="fullpost">Эта процедура используется для подсчёта кликов по ссылкам. Обёрткой вокруг неё является <a href="http://download.oracle.com/docs/cd/E17556_01/doc/apirefs.40/e15519/apex_util.htm#CHDBHDFF"><b>APEX_UTIL.COUNT_CLICK</b></a>, поэтому можно смело ориентироваться на документацию, меняя в примерах <b>APEX_UTIL.COUNT_CLICK</b> на <b>Z</b>. У <b>Z</b> есть следующие параметры:<br />
<br />
<ul><li><b>p_url</b> — URL, к которому необходимо перейти.</li>
<li><b>p_cat</b> — категория, к которой Z причисляет клик. </li>
<li><b>p_id</b> — вторичный <i>числовой</i> идентификатор клика. ID приложения, номер страницы — всё то, что поможет Вам в дальнейшем выделить именно эти клики из остальных.</li>
<li><b>p_user</b> — пользователь, который сделал клик.</li>
<li><b>p_company</b>, <b>p_workspace</b> — ID рабочего пространства. Если <b>p_company</b> пустое, то используется <b>p_workspace</b>. Если оба эти параметра пустые, то <b>Z</b> не сохраняет информацию о клике, а просто перенаправляет на <b>p_url</b>.</li>
</ul><br />
Пример URL с этой процедурой: <br />
<br />
<pre class="brush:plain">z?p_url=w3.org&p_cat=w3c&p_company=&WORKSPACE_ID.</pre><br />
Информацию, собранную <b>Z</b>, можно просмотреть в представлении APEX_WORKSPACE_CLICKS. <br />
<br />
<br />
Сообщения по теме: <br />
<a href="http://suppler.blogspot.com/2011/07/oracle-apex-url-f.html">Oracle APEX: Процедуры в URL - F</a> <br />
<a href="http://suppler.blogspot.com/2011/08/oracle-apex-url-p.html">Oracle APEX: Процедуры в URL - P</a><br />
</span>suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-27771815100497478692011-08-04T02:05:00.007+03:002011-08-05T14:17:51.538+03:00Oracle APEX: Процедуры в URL - PЕщё одна используемая при создании URL процедура: <b>P</b>.<br />
<br />
<span class="fullpost">Она не завраплена, так что её код можно легко увидеть:<br />
<br />
<pre class="brush:sql">create or replace
procedure p (
n in varchar2 default null,
p_mime_type in varchar2 default null,
p_inline in varchar2 default 'NO')
-- Copyright (c) Oracle Corporation 2001. All Rights Reserved.
--
-- DESCRIPTION
-- View a page given a page ID
--
-- SECURITY
-- Public shortcut
--
-- NOTES
--
-- EXAMPLES:
--
is
begin
if n is null then
htp.p(wwv_flow_lang.system_message('p.valid_page_err'));
return;
end if;
--
wwv_flow_file_mgr.get_file (
p_id => n,
p_mime_type => p_mime_type,
p_inline => p_inline);
end p;
</pre><br />
<b>P</b> используется, чтобы скачать загруженные файлы, которые можно найти в представлении <b>APEX_APPLICATION_FILES</b> (aka <b>WWV_FLOW_FILES</b>, построено на таблице <b>FLOW_FILES.WWV_FLOW_FILE_OBJECTS$</b>). У этой процедуры не так много параметров:<br />
<ul><li><b>n</b> — ID файла, который необходимо скачать.</li>
<li><b>p_mime_type</b> — устаревший параметр для указания MIME-типа файла. Сейчас информация берётся из соответствующих столбцов записи в <b>APEX_APPLICATION_FILES</b>.</li>
<li><b>p_inline</b> — <i>NO</i>, чтобы предложить пользователю скачать файл; <i>YES</i>, чтобы браузер отобразил его.</li>
</ul>Пример относительного URL для скачивания файла с ID=1234567891011: <pre class="brush:plain">p?n=123456789101112&p_inline=NO</pre><br />
<br />
Сообщения по теме:<br />
<a href="http://suppler.blogspot.com/2011/07/oracle-apex-url-f.html">Oracle APEX: Процедуры в URL - F</a><br />
<a href="http://suppler.blogspot.com/2011/08/oracle-apex-url-z.html">Oracle APEX: Процедуры в URL - Z</a><br />
</span>suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-68963485556583531302011-07-20T08:51:00.009+03:002011-08-05T14:20:39.108+03:00Oracle APEX: Процедуры в URL - FВ APEX переход по страницам приложения - это обращение к процедурам. И одной из самых используемых процедур является <b>F</b>. <span class="fullpost">Чтобы увидеть её, можно просто почаще смотреть в строку адреса во время работы с APEX. Там обнаружится что-то вроде такого:<br />
<br />
<pre class="brush:plain">http://work:8080/apex/f?p=4000:1500:434361572702804:::::</pre><br />
С помощью этой процедуры можно создавать ссылки к различным страницам приложений APEX. Я не буду здесь повторять раздел документации <a href="http://download.oracle.com/docs/cd/E17556_01/doc/user.40/e15517/concept.htm#BEIFCDGF">Oracle® Application Express Application Builder User's Guide: 2 Application Builder Concepts - Understanding URL Syntax</a>. По крайней мере, ту его часть, которая описывает структуру значений параметра <b>P</b>. Давайте лучше поговорим о том, что упоминается не так часто.<br />
<br />
Итак, <b>F</b> - это своеобразная обёртка для <b>WWV_FLOW.SHOW</b> (aka <b>APEX_APPLICATION.FLOW</b>). В этой процедуре устанавливаются различные глобальные переменные, использующиеся для отображения страницы, параметр P разбирается на составляющие, которые передаются в <b>APEX_APPLICATION.FLOW</b>.<br />
<br />
Кроме параметра <b>P</b> у процедуры <b>F</b> есть ещё параметры. Часть из них описана в документации, часть можно увидеть в URL при работе с приложениями. Вот неполный список:<br />
<br />
<ul><li><b>p_sep</b> - разделитель, который используется, чтобы разбить значение параметра P в PL/SQL-коллекцию.<br />
<li><b>p_trace</b> - если равен "YES", apex_application.show будет создавать трассировочный файл. Подробнее в документации: <a href="http://download.oracle.com/docs/cd/E17556_01/doc/user.40/e15517/debug.htm#HTMDB10004">Enabling SQL Tracing and Using TKPROF</a>.<br />
<li><b>c</b> - workspace_id или название (workspace) рабочего пространства из apex_workspaces. По значению этого параметра выбирается и устанавливается группа безопасности (aka security group ID). Это понадобится, к примеру, при вызове страниц приложения с тем же псевдонимом в другом рабочем пространстве. Упоминается в документации: <a href="http://download.oracle.com/docs/cd/E17556_01/doc/user.40/e15517/concept.htm#BCECAIFD">Calling a Page Using an Application and Page Alias</a>.<br />
<li><b>cs</b> - контрольная сумма, которой проверяются значения параметров. Первый символ - тип кинтрольной суммы, остальная строка - собственно контрольная сумма.<br />
<li><b>success_msg</b> - текст для отображения сообщения об успешном выполнении.<br />
<li><b>notification_msg</b> - текст для отображения уведомления.<br />
<li><b>tz</b>, <b>p_lang</b>, <b>p_territory</b> - NLS-параметры: временная зона, язык и территория. Значением <b>p_lang</b> можно менять язык сессии, который используется при переводе приложения с настройкой <i>Application Language Derived From</i> = <i>Session</i>. </ul>
<br />
Сообщения по теме: <br />
<a href="http://suppler.blogspot.com/2011/08/oracle-apex-url-p.html">Oracle APEX: Процедуры в URL - P</a> <br />
<a href="http://suppler.blogspot.com/2011/08/oracle-apex-url-z.html">Oracle APEX: Процедуры в URL - Z</a> <br />
</span>suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0tag:blogger.com,1999:blog-1048968608851202757.post-76785337056804841672011-07-08T02:43:00.002+03:002012-05-23T00:45:24.059+03:00Oracle APEX: Убить БиллаКак удалить вручную сессию APEX, если известен её ID? Всё довольно просто. <br />
<br />
Для начала подумаем, где должна использоваться возможность удаления сессии. Правильно, там где пользователь завершает сеанс в приложении - смотрим на ссылку <b>LOGOUT_URL</b>:<br />
<br />
<pre class="brush:plain">http://localhost:8888/apex/wwv_flow_custom_auth_std.logout?p_this_flow=4000&p_next_flow_page_sess=4550:8:8297564516445573</pre><br />
Нужное нам находится в <b>wwv_flow_custom_auth_std.logout</b>. Давайте глянем ещё на процесс, который выполняется при принудительном удалении сессий администратором экземпляра APEX. Заходим в <i>Administration->Application Express Internal Administration</i>, переходим на <i>Manage Instance->Session State->Purge Session, by age</i>. Это страница <b>66</b> приложения <b>4050</b>. Посмотрим, что за процессы выполняются при обработке этой страницы:<br />
<br />
<pre class="brush:sql; highlight: [8];">set long 5000
select process_source
from apex_application_page_proc
where application_id = 4050 and page_id = 66;
PROCESS_SOURCE
--------------------------------------------------------------------------------
wwv_flow_cache.purge_oldest_sessions (
p_num_sessions_to_purge => :P66_MAX_SESSIONS,
p_purge_sess_older_then_hrs => :P66_AGE * 24);</pre><br />
Ещё одна наводка - пакет <b>wwv_flow_cache</b> с множеством процедур <b>purge_%</b>.<br />
<br />
Произведя ритуал Unwrap над этими пакетами, можно увидеть, что удаляется сессия APEX с идентификатором :p_id довольно просто:<br />
<br />
<pre class="brush:sql">delete apex_040000.wwv_flow_sessions$ where id = :p_id;</pre><br />
Всё, остальные изыски из этих процедур вроде подсчёта удалённых сессий, переноса их в wwv_flow_purged_sessions$ и изменения значения в печеньке на -1 нам не нужны. <br />
<br />
Убить <s>Билла</s> сессию APEX - проще простого. Была бы лицензия на убийство в виде соответствующей привилегии на таблицу <b>apex_040000.wwv_flow_sessions$</b>...suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com2tag:blogger.com,1999:blog-1048968608851202757.post-36110212162350776592011-06-18T13:26:00.001+03:002011-06-18T13:27:14.972+03:00PL/SQL Challenge: Now with APEX flavor!Сегодня на <a href="http://plsqlchallenge.com/">PL/SQL Challenge</a> появилась первая викторина по APEX. Надеюсь, многие захотят поучаствовать: для проверки знаний, из интереса, ради призов и чтобы узнать что-то новое.<br />
<br />
Удачи!suPPLerhttp://www.blogger.com/profile/01186200400558858674noreply@blogger.com0