In vielen unserer Oracle APEX Kursen kommt die Frage auf: In welcher Version gibt es denn eigentlich die Funktion XY?Deswegen hier mal eine kurze Auflistung der neuen Funktionen, die in den letzten Versionen hinzugekommen sind:APEX 21.1
APEX 21.2
APEX 22.1
APEX 22.2
APEX 23.1
APEX 23.2
Für eine genauere Beschreibung der neuen Funktion in Oracle APEX empfehlen wir natürlich einen unserer (inzwischen 8 verschiedenen) APEX Kurse (z.B. den APEX New Features Kurs, dieser wird gerade für APEX 23.2 überarbeitet)
Als wir auf die Oracle APEX 23.1 Version upgegraded haben, gingen plötzlich unsere REST Authentifizierungen mittels Basic Authent nicht mehr.
Also die richtige Zeit auf etwas neueres zu wechseln, und damit auf OAUTH2.
Vorbereitungen auf der Server Seite:
Wir erstellen einen Client, der sich dann am REST Webservice anmelden soll/darf.
BEGIN OAUTH.create_client( p_name => 'ora_rest_client', p_grant_type => 'client_credentials', p_owner => 'MUSO_REST', p_support_email => 'info@muniqsoft-training.de', p_privilege_names=> 'muso_rest_priv' ); COMMIT; END; /
Wir verbinden den Client mit der Rolle, die unser Modul schützt. (z.B. iHinweis: Wenn Sie es noch nicht erledigt haben, dann erstellen Sie sich bitte eine REST Rolle (z.B. in APEX unter SQL Workshop / Restful Services) und erzeugen zusätzlich ein Privileg, dass die Rolle mit den gewünschten Modulen Verbindet
BEGIN OAUTH.grant_client_role( p_client_name => 'ora_rest_client', p_role_name => 'muso_role' ); COMMIT; END; /
Nun können Sie ermitteln, welche Client ID und welches Secret zur Verfügung gestellt werden.
SELECT id, name, client_id, client_secret FROM user_ords_clients; => 1,ora_rest_client,YYY..,ZZZ..
Diese beiden Informationen setzen Sie bitte im nächsten Select ein.Wenn der REST Service via SSL angesprochen wird (sehr zu empfehlen!!!!), dann brauchen Sie auch noch das Zertifikat vom Server, dass Sie dann in Ihr lokales Wallet einspielen müssen.Das Wallet wird mit einem Passwort gesichert, dass hier im Parameter l_wallet_pwd angegeben werden kann. Auch der Pfad zum Wallet wird benötigt. Er sollte existieren und Oracle sollte wenigstens Leserechte auf dem Ordner besitzen
WITH FUNCTION get_rest (rest_path IN VARCHAR2) RETURN CLOB IS l_wallet_path VARCHAR2(255):='file:/opt/oracle/admin/XE/https_wallet'; l_wallet_pwd VARCHAR2(255):='XXX'; l_client_id VARCHAR2(255):='YYY..'; l_client_secret VARCHAR2(255):='ZZZ..'; l_base_url VARCHAR2(255):='https://www.muniqsoft-training.de/ords/oracle/muso_training/'; l_clob clob; WITH FUNCTION get_rest (rest_path IN VARCHAR2) RETURN CLOB IS l_wallet_path VARCHAR2(255):='file:/opt/oracle/admin/XE/https_wallet'; l_wallet_pwd VARCHAR2(255):='XXX'; l_client_id VARCHAR2(255):='YYY..'; l_client_secret VARCHAR2(255):='ZZZ..'; l_base_url VARCHAR2(255):='https://www.muniqsoft-training.de/ords/oracle/muso_training/'; l_clob clob; BEGIN -- Token holen apex_web_service.oauth_authenticate( p_token_url => l_base_url||'oauth/token', p_client_id => l_client_id, p_client_secret => l_client_secret, p_wallet_path => l_wallet_path, p_wallet_pwd => l_wallet_pwd ); -- Request Authorization header setzen apex_web_service.g_request_headers.delete(); apex_web_service.g_request_headers(1).name := 'Authorization'; apex_web_service.g_request_headers(1).value := 'Bearer ' || apex_web_service.oauth_get_last_token; -- REst Request absetzen: l_clob := apex_web_service.make_rest_request ( p_url => l_base_url||rest_path, p_http_method => 'GET', p_wallet_path => l_wallet_path, p_wallet_pwd => l_wallet_pwd); RETURN l_clob; END; SELECT get_rest('/muso/getTabCount') FROM dual;
Wenn Sie eine Seite mit private Reports exportieren möchten, gibt es da einen Trick:
1. Exportieren Sie die komplette Applikation. Wählen Sie aber bitte an:a, [x] Split into Multiple Filesb, optional [X] Export Public Reportsc, [X] Export Private Reports2. Nun wird ein Zip File exportiert, das Sie bitte entpacken.3. Nun gehen Sie in SQL*Plus oder SQL*Developer und starten bitte folgende Skriptea, f??? (??? für Ihre App ID) / Application / set_environment.sqlb, f??? / Application / Pages / page_00??.sql für alle Seiten die Sie mit interakiven Report mit Public und/oder Private Reports wieder einspielen möchtenc, f??? / Application / end_environment.sql
FERTIG, alle gewünschten Seiten mit interactiven Report sind wieder in Ihrer Applikation
Als vor zwei Wochen die Oracle Version 23c FREE Edition herauskam, waren wir sehr (positiv) überracht, dass die kostenlose Version vor der Produktiv Version veröffentlicht wurde.Es wurde also mal wieder Zeit einen Artikel für die jeweils neusten Oracle Versionen zu schreiben. et voila …
Wir installieren auf einem Server mit der Ip Adresse 172.30.30.99. Sie können natürlich eine andere IP Adresse wählen, sollten dann aber an allen Stellen wo wir diese IP verwenden Ihre eintragen.Da man ja seit Version Oracle 21c nun mit Pluggable Database Containern arbeiten muss, verwenden wir hier den Container apex222. Auch den können Sie natürlich umbenennen.
Wir empfehlen mit mindestens 2 SSH Sessions parallel zu arbeiten um die Zeit drastisch zu verkürzen.Wir nennen im folgenden die beiden Sessions SES_1 und SES_2. Bitte lesen Sie die folgenden Schritte zuerst komplett durch, weil einige Punkte weiter unten zusammengefasst werden :-)
1. Redhat 8 / Centos 8 / Rocky 8 Preinstall Packages für Oracle 23c herunterladen:
https://yum.oracle.com/repo/OracleLinux/OL8/developer/x86_64/getPackage/oracle-database-preinstall-23c-1.0-0.5.el8.x86_64.rpm
2. FREE Edition herunterladenhttps://download.oracle.com/otn-pub/otn_software/db-free/oracle-database-free-23c-1.0-1.el8.x86_64.rpm3. Wir benennen den Pluggable Database Container um( muss man nicht, wenn man mit dem Namen freepdb1 zufrieden ist)
ALTER PLUGGABLE DATABASE freepdb1 CLOSE; ALTER PLUGGABLE DATABASE freepdb1 OPEN RESTRICTED; ALTER SESSION SET CONTAINER=freepdb1; ALTER PLUGGABLE DATABASE RENAME GLOBAL_NAME TO apex222;
Laden Sie APEX 22.2 (oder neuer) herunter:https://download.oracle.com/otn_software/apex/apex_22.2.zip
Laden Sie den neusten Patch für APEX herunter (dazu ist ein gültiger Support-Vertrag mit Oracle notwendig):https://support.oracle.com/epmos/faces/PatchDetail?patchId=34628174
Laden Sie die ORDS-Version herunter (April 2023 war Version 23.1.1 aktuell):https://download.oracle.com/otn_software/java/ords/ords-23.1.1.109.1003.zip
Laden Sie die neueste Apache TomCat 9 Version herunter. Version 10 wird aktuell (01.05.2023) nicht von ORDS unterstützt:https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.74/bin/apache-tomcat-9.0.74.zip
Session SES_1 dnf -y install wget dnf -y update
Download Skript für alle Dateien (bis auf Patch, da müssen Sie beim Support angemeldet sein) in SES_2:
mkdir -p /tmp/oracle cd /tmp/oracle wget https://yum.oracle.com/repo/OracleLinux/OL8/developer/x86_64/getPackage/oracle-database-preinstall-23c-1.0-0.5.el8.x86_64.rpm wget https://download.oracle.com/otn-pub/otn_software/db-free/oracle-database-free-23c-1.0-1.el8.x86_64.rpm wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.rpm wget https://download.oracle.com/otn_software/apex/apex_22.2.zip wget https://download.oracle.com/otn_software/java/ords/ords-23.1.1.109.1003.zip wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.74/bin/apache-tomcat-9.0.74.zip
Nun kann mit der Installation der in SES_2 heruntergeladenen Programme begonnen werden
Session SES_1:
dnf -y install oracle-database-preinstall-23c* dnf -y localinstall oracle-database-free-23c* export DB_PASSWORD=mein_password_fuer_2023 (echo "${DB_PASSWORD}"; echo "${DB_PASSWORD}";) | /etc/init.d/oracle-free-23c configure
In der Datei /etc/oratab die Datenbank auf Autostart (N durch Y in der letzten Zeile am Ende ersetzen)
FREE:/opt/oracle/product/23c/dbhomeFree:Y
Wenn die Oracle Datenbank Instanz und der Oracle Listener beim Start des Betriebssystem mitstarten sollen:
systemctl enable oracle-free-23c
Wenn Oracle DB + Listener manuell gestoppt und gestartet werden sollen:
systemctl stop oracle-free-23c systemctl start oracle-free-23c
Wenn Ihnen der Name oracle-free-23 zulange ist, können Sie auch stattdessen “oracle”als Servicename einrichten
Kopieren Sie dazu nur die Datei /etc/rc.d/init.d/oracle-free-23c in die Datei oracle um:
cp /etc/rc.d/init.d/oracle-free-23c /etc/rc.d/init.d/oracle
... dauert wieder ein paar Minuten .. wir wechseln in SES_2
Session SES_2:
mkdir -p /opt/tomcat mv apache-tomcat-9.0.74.zip /opt/tomcat/ cd /opt/tomcat unzip apache* ln -s apache-tomcat-9.* latest useradd -r tomcat --shell /bin/false chown -R tomcat /opt/tomcat chmod +x /opt/tomcat/latest/bin/*.sh # Passen Sie die Firewall an Ihre Bedürfnisse an. Hier werden in Zone Public einige Ports freigegeben firewall-cmd --zone=public --permanent --add-port=1521/tcp firewall-cmd --zone=public --permanent --add-service=https firewall-cmd --zone=public --permanent --add-service=http firewall-cmd --zone=public --permanent --add-port 8080/tcp firewall-cmd --reload dnf -y localinstall jdk-17* java -version which java
Datei anlegen zum Autostart von TomCatvi /etc/systemd/system/tomcat.service
[Unit] Description=Tomcat 9 servlet container After=network.target [Service] Type=forking User=tomcat Group=tomcat Environment="JAVA_HOME=/usr" Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom -Dconfig.url=/opt/oracle/ords" Environment="CATALINA_BASE=/opt/tomcat/latest" Environment="CATALINA_HOME=/opt/tomcat/latest" Environment="CATALINA_PID=/opt/tomcat/latest/temp/tomcat.pid" Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC" ExecStart=/opt/tomcat/latest/bin/startup.sh ExecStop=/opt/tomcat/latest/bin/shutdown.sh [Install] WantedBy=multi-user.target
Tomcat als Autostart einrichten
systemctl daemon-reload systemctl enable tomcat systemctl start tomcat systemctl status tomcat
Bash Profile für Oracle Benutzer anlegen:
cat << EOF > /home/oracle/.bash_profile export TERM=vt220 export EDITOR=vi export PS1="[\u@\h:\w]>" export DISPLAY=:0.0 export ORACLE_BASE=/opt/oracle export ORACLE_HOME=\$ORACLE_BASE/product/23c/dbhomeFree export ORACLE_SID=FREE export ORACLE_INSTANCE=free export ORACLE_TERM=vt220 export ORA_NLS10=\$ORACLE_HOME/nls/data export LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:\$ORACLE_HOME/lib export NLS_LANG=GERMAN_GERMANY.WE8MSWIN1252 export PATH=\$ORACLE_HOME/bin:\$PATH:/usr/sbin:/usr/ccs/bin alias cdo="cd \$ORACLE_HOME; pwd" alias cdd="cd \$ORACLE_BASE/oradata" alias cda="cd \$ORACLE_BASE/diag/rdbms/\$ORACLE_INSTANCE/\$ORACLE_SID/trace; pwd" alias cdn="cd \$ORACLE_HOME/network/admin; pwd" alias cde="cd \$ORACLE_BASE/admin/\$ORACLE_SID/dpdump" alias sp="\$ORACLE_HOME/bin/sqlplus '/ as sysdba'" alias l="ls -l" alias ll="ls -la" alias ipconfig="/sbin/ifconfig | grep Bcast" echo Folgende Einstellungen wurden gesetzt: env | grep ORA ps aux | grep [t]omcat | awk '{print "Tomcat-Prozess:" \$2}' ps aux | grep [d]b_pmon | awk '{print "Oracle-Prozess:" \$2}' ps aux | grep [t]ns | awk '{print "Listener-Prozess:" \$2}' EOF
. .bash_profile
APEX und ORDS auspacken:
cd /tmp/oracle unzip apex_22* chown -R oracle:oinstall apex* mkdir ords unzip ords-2*.zip -d ords
Session SES_1
APEX muss in der anderen Session bereits ausgepackt worden sein!
su - oracle
REM Bei uns wurde bei der Installation ein exotischer Port für den Listener benutzt. Wenn Sie den Oracle Standard-Port 1521 wieder möchten, ersetzen Sie ihn in der Datei listener.ora
lsnrctl stop IP=$(hostname -I)
cat << EOF >$ORACLE_HOME/network/admin/listener.ora # listener.ora Network Configuration File: /opt/oracle/product/23c/dbhomeFree/network/admin/listener.ora # Generated by Oracle configuration tools. DEFAULT_SERVICE_LISTENER = FREE LISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = \$IP)(PORT = 1521)) ) ) EOF
Nun wird APEX installiert. Hier können verschiedene Passwörter für die Oracle APEX Benutzer gesetzt werden. Wir haben aber bis auf den Internal Workspace Admin Benutzerdas gleiche Passwort gesetzt.
Auch kann ein eigener Tablespace für die Installation verwendet werden. Wir haben hier APEX jedoch in den Tablespace SYSAUX installiert.
lsnrctl start cd /tmp/oracle/apex cat << EOF >preinstall.sql alter system set local_listener='(ADDRESS = (PROTOCOL = TCP)(HOST = \$IP)(PORT = 1521))'; alter system register; host lsnrctl status define pwd_apx=apex define pwd_ws_int=Apex2023# @apxsilentins.sql SYSAUX SYSAUX TEMP /i222/ &pwd_apx. &pwd_apx. &pwd_apx. &pwd_ws_int. EOF sqlplus sys/sys@172.30.30.99/apex222 as sysdba @preinstall.sql
Während die APEX Installation läuft, kann wieder in die andere Session gewechselt werden, dort installieren wir den ORDS…
cd /tmp/oracle/ords bin/ords --config /opt/oracle install [2] Datenbankpool erstellen oder aktualisieren ... [1] Basis (Hostname, Port, Servicename) => 172.30.30.99 => 1521 => apex222 => sys => <Ihr sys-pwd> => SYSAUX => TEMP [1] Datenbankaktionen (aktiviert alle Features) [2] Überspringen
Nun kopieren wir den ORDS in den TomCat Ordner:
cp ords.war /opt/tomcat/latest/webapps/
Dateien von APEX auch in den TomCat Ordner verschieben:
mv /tmp/oracle/apex/images/ /opt/tomcat/latest/webapps/i222
So, das war´s. gar nicht so schwer, oder ? :-)
Wenn man mit zwei Sessions arbeitet und in keine Probleme läuft, sollte das in ca. einer Stunde erledigt sein.
Bonus-Track:
Apache TomCat hat leider keine Redirect Funktion, dazu braucht man den Apache Webserver. Aber Sie können mit einem kleinen Trick dafür sorgen, dass Sie gleich auf Ihre Lieblingsapp weitergeleitet werden, sobald Sie die folgende URL eingeben:
http://172.30.30.99:8080
Wir machen dazu einfach einen Refresh als Meta-Tag auf die Datei index.html
cp /opt/tomcat/latest/webapps/ROOT/index.html /opt/tomcat/latest/webapps/ROOT/index.html.old echo '<html><head><meta http-equiv="refresh" content="0; url=http://172.30.30.99:8080/ords/f?p=100" /></head></html>'>/opt/tomcat/latest/webapps/ROOT/index.html
oder wenn Sie TEST-Maschine haben und kein Problem damit haben, dass Ihr Password im Klartext in einer Datei steht…. können Sie die Anmeldedaten für den Applikation Builder bereits eintragen
echo '<html><head><meta http-equiv="refresh" content="0; url=http://172.30.30.100:8080/ords/f?p=4550:1:1::::F4550_P1_COMPANY,F4550_P1_USERNAME,F4550_P1_PASSWORD:schulung,admin,ganzschöngeheim2023" /></head></html>'>/opt/tomcat/latest/webapps/ROOT/index.html
Hier sind eingetragen:
Workspace-Name (F4550_P1_COMPANY) = schulungUsername (F4550_P1_USERNAME) = adminPassword: (F4550_P1_PASSWORD) = ganzschöngeheim2023
F4550_P1_COMPANY) = schulung
F4550_P1_USERNAME) = admin
F4550_P1_PASSWORD) = ganzschöngeheim2023
Das sollte natürlich von Ihnen angepasst werden :-)
Rufen Sie nun im Browser die Seite http://172.30.30.99:8080/ords auf bzw. wenn der Bonustrack installiert wurde: http://172.30.30.99:8080
Bonus-Bonus-Track:
Unter Windows können Sie auch gleich eine Portweiterleitung einrichten, dann wird Port 80 auf Port 8080 weitergeleitet. Dies geschieht (als Administrator) mit:
netsh interface portproxy add v4tov4 listenaddress=172.30.30.99 listenport=80 connectaddress=172.30.30.99 connectport=8080
Dann lautet der Aufruf nur noch:
http://172.30.30.99
und dann besuchen Sie uns doch bald mal in einer von unseren 48 verschiedenen Oracle Schulungen in München-Unterhaching :-)
In unseren Schulungen werden immer mal Fragen zum Interactiven Grid gestellt, die sehr interessant sind. Hier eine kleine Auswahl:
Vorraussetungen:
var model = apex.region("EMP").widget().interactiveGrid("getViews", "grid").model; model.forEach(function(r) { model.setValue(r, "JOB", $v("P1_JOB" )); // Setzen des Jobs pro Zeile })
2. Es sollen nur die mit der im Grid enthaltenen Checkbox (Spalte 1) ausgewählten Einträge geändert werden:
var grid = apex.region("EMP").widget().interactiveGrid("getViews","grid"); var model = grid.model; var selectedRecords = grid.getSelectedRecords(); //console.log("Records" +selectedRecords.length); for (idx = 0; idx < selectedRecords.length; idx++) { record = model.getRecord(selectedRecords[idx][0]); model.setValue(record, "JOB", $v( "P1_JOB" )); //console.log(idx+ " " + selectedRecords[idx][1] ); //Felder [1] EMPNO [2] ENAME, [3] JOB ... }
3. Sie möchten das zurückschreiben in die DB selbst erledigen, kein Problem. Ersetzen Sie den Prozeß durch:
IF :APEX$ROW_STATUS='C' THEN INSERT INTO emp (empno,ename,job,mgr,hiredate,sal,comm,deptno) VALUES (:EMPNO,:ENAME,:JOB,:MGR,:HIREDATE,:SAL,:COMM,:DEPTNO); ELSIF :APEX$ROW_STATUS='U' THEN UPDATE emp SET ename=:ENAME,job=:JOB, mgr=:MGR,hiredate=:HIREDATE ,sal=:SAL,comm=:COMM, deptno=:DEPTNO WHERE empno=:EMPNO ; ELSIF :APEX$ROW_STATUS='D' THEN DELETE FROM emp WHERE empno=:EMPNO; END IF;
Das war ein kleiner Auszug aus den vielen Fragen in unseren APEX Kursen. Sie haben auch Fragen? Dann kommen Sie doch in einen unserer Kurse…. wir freuen uns auf Sie !
Seit einiger Zeit ist die neue Oracle ORDS Version 23.x zum Download verfügbar. Wie heisst ein berühmtes Zitat: Mann muss in einem System jeden Fehler gemacht haben um das System verstanden zu haben. Na dann sind wir kurz davor alles zu wissen :-) …
Laden Sie die Software von Oracle herunter und packen Sie das ZIP File in einem eigenen Ordner aus.
Prüfen Sie nun Ihre installierte Java Version:
Unix / Linux
java --version java 11.0.16.1 2022-08-18 LTS Java(TM) SE Runtime Environment 18.9 (build 11.0.16.1+1-LTS-1) Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.16.1+1-LTS-1, mixed mode)
Das sieht gut aus … OpenJDK wird offiziell von Oracle nicht unterstützt und kann Probleme verursachen! Verwenden Sie Java 11 oder Java 17
Windows:
java.exe --version openjdk 11 2018-09-25 OpenJDK Runtime Environment 18.9 (build 11+28) OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)
Das ist schlecht, weil Oracle unterstützt wie gesagt keine Java OpenJDK Version. KEINE ! Es kann funktionieren, bei uns trat meist ein Webserver Fehler 500 auf (ohne große Begründung) Unterstützt werden nur die Oracle Java Versionen 11 und 17.
Nach erfolgreicher Installation der Oracle Java Version gehen Sie in den ausgepackten Ordner (z.B. cd c:\temp\ords)
Dort sollte ein “bin” Ordner liegen und da drin eine ords.exe und eine ords Datei
Tragen Sie Java in Ihren Pfad ein:
set PATH=%PATH%;"C:\Program Files\Java\jdk-11\bin"
UNIX:
export PATH=$PATH:/usr/bin/
Wenn Java in Ihrem Pfad eingetragen wurde, starten Sie die Installation mit:
Windows: bin/ords.exe --config c:\oracle\ords install
Tipp: Sie sollten auch nach der Installation des Ords das “bin” Verzeichnis des ORDS und die Datei ords.war nicht wegwerfen. Für nachtägliche Wartungsarbeiten benötigt man die Dateien eventuell nochmal. Sie können die Dateien z.B in den Hauptordner des Config-Verzeichnisses kopieren, also z.B. C:\oracle\ords für Windows, oder /opt/oracle für Linux.
Ab ORDS Version 22.2.x wird der Pfad für den Config Ordner beim Tomcat unter UNIX im Service File eingetragen:
cat /etc/systemd/system/tomcat.service:
… Environment="JAVA_HOME=/usr/lib/jvm/jre" Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom -Dconfig.url=/opt/oracle/ords" …
Windows (wird im Tomcat (tomcat9w.exe) Eigenschaftsfenster Reiter “Java” im Bereich “Java Options” (nicht “Java 9 Options” !!!) eingetragen)
-Dconfig.url=c:\oracle\ords
Unix/Linux:
bin/ords --config /opt/oracle/ords install
Interaktion mit dem Skript:
# bin/ords --config /opt/oracle/ords install ORDS: Release 23.4 Produktion am Mi. Dez 15 06:49:08 2023 Copyright (c) 2010, 2023, Oracle. Konfiguration:/opt/oracle/ords/ Der Konfigurationsordner /opt/oracle/ords enthält keine Konfigurationsdateien. Oracle REST Data Services - Interaktive Installation Geben Sie eine Zahl zur Auswahl des Installationstyps ein [1] ORDS nur in der Datenbank installieren oder upgraden [2] Datenbankpool erstellen oder aktualisieren und ORDS in der Datenbank installieren/upgraden [3] Nur Datenbankpool erstellen oder aktualisieren Choose [2]: Geben Sie eine Zahl zur Auswahl des zu verwendenden Datenbankverbindungstyps ein [1] Basis (Hostname, Port, Servicename) [2] TNS (TNS-Alias, TNS-Verzeichnis) [3] Benutzerdefinierte Datenbank-URL Choose [1]: Geben Sie den Hostnamen der Datenbank ein [localhost]: 172.30.30.141 Listener-Port der Datenbank eingeben [1521]: Datenbankservicename eingeben [orcl]: apex222 Geben Sie einen Datenbankbenutzernamen mit Administratorberechtigungen an. Geben Sie den Administratorbenutzernamen ein: sys Datenbankkennwort für SYS AS SYSDBA eingeben: Verbindung zu Datenbankbenutzer: SYS AS SYSDBA URL: jdbc:oracle:thin:@//172.30.30.141:1521/apex222 wird hergestellt Informationen werden abgerufen. Geben Sie den Default Tablespace für ORDS_METADATA und ORDS_PUBLIC_USER ein [SYSAUX]: Geben Sie den Temporary Tablespace für ORDS_METADATA und ORDS_PUBLIC_USER ein [TEMP]: Geben Sie eine Zahl ein, um zusätzliche Features zum Aktivieren auszuwählen: [1] Datenbankaktionen (aktiviert alle Features) [2] REST-fähige SQL und Datenbank-API [3] REST-fähige SQL [4] Datenbank-API [5] Kein Wert Choose [1]: Geben Sie eine Zahl zum Konfigurieren und Starten von ORDS im Standalone-Modus ein [1] ORDS im Standalone-Modus konfigurieren und starten [2] Überspringen Choose [1]: 2 … INFO: 08:19:07 Validating objects for Oracle REST Data Services. VALIDATION: 08:19:07 Starting validation for schema: ORDS_METADATA VALIDATION: 08:19:07 Validating objects VALIDATION: 08:19:08 Validating roles granted to ORDS_METADATA and ORDS_PUBLIC_USER VALIDATION: 08:19:08 Validating ORDS Public Synonyms VALIDATION: 08:19:08 Total objects: 306, invalid objects: 0, missing objects: 0 VALIDATION: 08:19:08 94 INDEX VALIDATION: 08:19:08 3 LOB VALIDATION: 08:19:08 15 PACKAGE VALIDATION: 08:19:08 14 PACKAGE BODY VALIDATION: 08:19:08 1 PROCEDURE VALIDATION: 08:19:08 52 PUBLIC SYNONYM VALIDATION: 08:19:08 1 SEQUENCE VALIDATION: 08:19:08 32 TABLE VALIDATION: 08:19:08 32 TRIGGER VALIDATION: 08:19:08 20 TYPE VALIDATION: 08:19:08 6 TYPE BODY VALIDATION: 08:19:08 36 VIEW VALIDATION: 08:19:08 Validation completed. INFO: 08:19:08 Completed validation for Oracle REST Data Services. PL/SQL-Prozedur erfolgreich abgeschlossen. Commit abgeschlossen. ------------------------------------------------------------ Containername: APEX222 Skripts für scheduler werden ausgeführt ------------------------------------------------------------ … PL/SQL-Prozedur erfolgreich abgeschlossen. Commit abgeschlossen. 2023-03-15T07:19:15.030Z INFO Installation für Oracle REST Data Services Version 22.4.4.r0411526 wurde abgeschlossen. Verstrichene Zeit: 00:00:27.496 [*** Informationen: Installation für Oracle REST Data Services Version 22.4.4.r0411526 wurde abgeschlossen. Verstrichene Zeit: 00:00:27.496 ] ------------------------------------------------------------ Containername: APEX222 ------------------------------------------------------------ [*** script: ords_configure_gateway.sql] Configured PL/SQL Gateway user APEX_PUBLIC_USER to be proxiable from ORDS_PUBLIC_USER PL/SQL-Prozedur erfolgreich abgeschlossen. 2023-03-15T07:19:15.130Z INFO Konfiguration von PL/SQL-Gatewaybenutzer für Oracle REST Data Services Version 22.4.4.r0411526 wurde abgeschlossen. Verstrichene Zeit: 00:00:00.95 [*** Informationen: Konfiguration von PL/SQL-Gatewaybenutzer für Oracle REST Data Services Version 22.4.4.r0411526 wurde abgeschlossen. Verstrichene Zeit: 00:00:00.95 ]
export DB_PORT=1521 export DB_SERVICE=apex231 export SYSDBA_USER=SYS export SYSDBA_PASSWORD=sys export ORDS_PASSWORD=ords export ORDS_HOME=/opt/oracle/ords export ORDS_CONFIG=/opt/oracle/ords export ORDS_LOGS=$ORDS_CONFIG/logs export PATH=$PATH:$ORDS_HOME/bin
ords --config $ORDS_CONFIG install \ --log-folder $ORDS_LOGS \ --admin-user $SYSDBA_USER \ --db-hostname 127.0.0.1 \ --db-port $DB_PORT \ --feature-db-api true \ --feature-rest-enabled-sql true \ --feature-sdw true \ --gateway-mode proxied \ --gateway-user APEX_PUBLIC_USER \ --proxy-user
Zugriff dann im Browser via: http:server:8080/ords
ords --config $ORDS_CONFIG install \ --db-pool $DB_SERVICE \ --admin-user $SYSDBA_USER \ --db-hostname 127.0.0.1 \ --db-port $DB_PORT \ --db-servicename $DB_SERVICE \ --feature-db-api true \ --feature-rest-enabled-sql true \ --feature-sdw true \ --gateway-mode proxied \ --gateway-user APEX_PUBLIC_USER \ --proxy-user Zugriff dann via: http:server:8080/ords/$DB_SERVICE
set DB_PORT=1521 set DB_SERVICE=apex231 set SYSDBA_USER=SYS set SYSDBA_PASSWORD=sys set ORDS_PASSWORD=ords set ORDS_HOME=c:\oracle\ords set ORDS_CONFIG=c:\oracle\ords set ORDS_LOGS=%ORDS_CONFIG%\logs set PATH=%PATH%;%ORDS_HOME%\bin
ords --config %ORDS_CONFIG% install ^ --log-folder %ORDS_LOGS% ^ --admin-user %SYSDBA_USER% ^ --db-hostname 127.0.0.1 ^ --db-port %DB_PORT% ^ --db-servicename %DB_SERVICE% ^ --feature-db-api true ^ --feature-rest-enabled-sql true ^ --feature-sdw true ^ --gateway-mode proxied ^ --gateway-user APEX_PUBLIC_USER ^ --proxy-user
ords --config %ORDS_CONFIG% install ^ --log-folder %ORDS_LOGS% ^ --db-pool %DB_SERVICE% ^ --admin-user %SYSDBA_USER% ^ --db-hostname 127.0.0.1 ^ --db-port %DB_PORT% ^ --db-servicename %DB_SERVICE% ^ --feature-db-api true ^ --feature-rest-enabled-sql true ^ --feature-sdw true ^ --gateway-mode proxied ^ --gateway-user APEX_PUBLIC_USER ^ --proxy-user
Zugriff dann im Browser via: http:server:80/ords/%DB_SERVICE% Hinweis: der Tomcat Dienst benötigt Leserechte im ORDS Config Verzeichnis !!! icacls %ORDS_CONFIG% /T /grant Benutzer:R
Wir oben beschrieben muss die richtige Java Version installiert worden sein (Oracle Java 11 oder 17) Kann der config Ordner von Oracle/Tomcat Benutzer gelesen werden? Wenn nicht bitte Lese/Schreibrechte an die Dateien vergeben.
Sind alle notwendigen Accounts NICHT gesperrt und stimmt das Passwort ?
select username,account_status,lock_date,expiry_date from dba_users where username like '%PUBLIC%'; USERNAME ACCOUNT_STATUS LOCK_DATE EXPIRY_DATE ------------------------ ------------------ ------------------- ------------------- APEX_PUBLIC_USER LOCKED 15.03.2023 07:57:59 APEX_REST_PUBLIC_USER OPEN 11.09.2024 08:08:32
Das schaut hier nicht gut aus, der Benutzer APEX_PUBLIC_USER ist gesperrt!.
Entsperren mittels:
ALTER USER apex_public_user ACCOUNT UNLOCK IDENTIFIED BY <mein_geheimes_passwort>;
Danach starten wir dem TomCat nochmal durch.
net stop TomCat9 net start TomCat9
Für den Fall, dass Sie das Passwort vom ORDS_PUBLIC_USER in der DB geändert haben und das im ORDS nachtragen möchten:
Für den Default Pool: (wenn der Config Ordner unter /opt/oracle/ords liegt)
ords --config /opt/oracle/ords config --db-pool default secret db.password
Für einen anderen Pool (hier apex231)
ords --config /opt/oracle/ords config --db-pool apex231 secret db.password
Fehlermeldung: Benutzer oder Kennwort für den Verbindungspool namens |default|lo| ist ungültig oder abgelaufen, oder der Account wurde gesperrt
Die naheliegenden Lösungen wären natürlich:
aber in unserem Fall war die Datenbank (pluggable Database Container) im restricted Modus:
Die Lösung war:
alter pluggable database <containername> close immediate; alter pluggable database <containername> open;
Fehlermeldung: Service Unavailable
Request ID: bI7hBYBLvXJ1aZXhH61iMA
Request Timestamp: 2023-10-21T08:58:05.233483445Z
Das Datenbankkennwort-Secret fehlt in dem mit dem Pool |default|lo| verknüpften Wallet
Hier fehlt das Passwort für den ORDS_PUBLIC_USER, oder es ist veraltet oder abgelaufen. Die Lösung unter LINUX ist, das Wallet mit dem Passwort neu anzulegen mittels:
cd /opt/oracle/ords REM dort liegt der Ordner bin aus der Installtion des ORDS!, wenn nicht, gehen Sie bitte in den entsprechenden Ordner sudo bin/ords --config /opt/oracle/ords config secret db.password REM zweimal das Passwort eingeben REM wenn Sie noch weitere Pools besitzen, muss auch hier das Passwort geöndert werden (Pool-Name apex231) sudo bin/ords --config /opt/oracle/ords config --db-pool apex231 secret db.password REM TomCat durchstarten sudo systemctl restart tomcat
Für Windows würde die Lösung so aussehen:
cd c:\oracle\ords bin\ords --config c:\oracle\ords config --db-pool default secret db.password bin\ords --config c:\oracle\ords config --db-pool apex231 secret db.password
Unsere Ordnerstruckur für den Ords sieht wie folgt aus:
Mehr Tipps & Tricks erfahren Sie in unserem Oracle ORDS und im APEX II Kurs. Wir freuen uns auf Sie!
Hatten Sie auch schon einmal den Wunsch, den Anwendern einer Applikation etwas mitzuteilen? Und wäre es nicht manchmal gut, wenn jeder Anwender nachweislich die Information gelesen hat? Die Informationen sollen sofort, also auch in einer laufenden Session, in einem modalen Popup- Fenster angezeigt werden. Dieses Problem stellte sich vor einiger Zeit in einem APEX-Projekt und aus diesem Grund haben wir ein Informationssystem für APEX-Anwendungen entwickelt.
Um die Anforderungen abzudecken brauchen wir im ersten Schritt zwei Tabellen. In der ersten werden die "Nachrichten" gespeichert, in der zweiten die Information, wer wann das Lesen bestätigt hat.
CREATE TABLE INFORMATIONEN( ID NUMBER, -- Eindeutige ID, Trigger und Sequence APP_ID NUMBER, -- Applikations ID der Apexanwendung STATUS CHAR(1), -- A für aktiv oder I für inaktiv INFORMATION VARCHAR2(500), -- Freitext für die Informationsn CONSTRAINT PK_INFORMATIONEN PRIMARY KEY (ID));
CREATE TABLE INFORMATION_READ( INFO_ID NUMBER, -- ID der Information die gelesen wurde APP_USER VARCHAR2(30), -- Welcher User hat gelesen READ_DATE DATE -- Wann wurde gelesen, Trigger mit SYSDATE);
Der nächste Schritt ist, eine Seite in der Applikation zu erstellen auf der die Informationen angezeigt werden sollen. Als Template wählen wir Popup. Im Bereich "Page HTML Body Attribute" kommt noch folgende Anweisung dazu:
style="background:none;background-image:none;background-color:transparent;padding:0;margin:0;overflow:scroll"
Jetzt sollte man sich auch überlegen wie viele Informationen gleichzeitig angezeigt werden müssen. Entsprechend viele Items müssen erzeugt werden.Wir benötigen je Info ein "Display only" Item (PX_INFOTEXT_X). Dabei sollte beachtet werden, dass die Eigenschaft "Escape special characters" auf NO steht, dadurch können HTML Formatierungen in den Text integriert werden. Zu jedem Infotext kommt noch eine Checkbox (return 1 when checked), damit können die Nachrichten einzeln bestätigt werden. Infotext und Checkbox werden nur angezeigt, wenn Infotext "NOT NULL" ist. Schließlich fehlt noch je ein Hidden Item zum Speichern der ID und ein Button zum Bestätigen der Seite.
Jetzt fehlen noch zwei Prozesse, der erste "On Load - Before Header" mit dem die Inhalte gefüllt werden:
declare v_cnt number := 1; v_trenner varchar2(30) := '<p><hr><p>';begin for rec in (select id, information from informationen where app_id = :APP_ID and status = 'A' and id not in (select info_id from information_read where app_user = :APP_USER) order by id) loop if v_cnt = 1 then :PX_ID1 := rec.id; :PX_INFOTEXT_1 := rec.information; end if; if v_cnt = 2 then :PX_ID2 := rec.id; :PX_INFOTEXT_2 := rec.information; end if; v_cnt := v_cnt + 1; end loop;end;
Dann kommt der Prozess zum Speichern der Informationen, wenn der Button gedrückt wurde:
begin if :PX_CHECK1 = 1 then insert into information_read values(:PX_ID1, :APP_USER, SYSDATE); end if; if :PX_CHECK2 = 1 then insert into information_read values(:PX_ID2, :APP_USER, SYSDATE); end if; :FXXX_HIDE := 'TRUE'; :FXXX_INFO := '0';end;
Hier tauchen erstmals die Applikations Items FXXX_HIDE und FXXX_INFO auf. Diese werden für die Steuerung des Infofensters benötigt. Bei Betätigung des Buttons wird auf jeden Fall das Item HIDE auf TRUE gesetzt, damit wird eine weitere Anzeige innerhalb der gleichen Session verhindert. Die Nachrichten können separat bestätigt werden, das heißt der Anwender kann entscheiden, ob sie in der nächsten Session wieder erscheinen sollen.
Nachdem es sich um ein modales Popup-Fenster handelt brauchen wir noch einen Branch, um es nach der Verarbeitung zu schließen. Der Branch Typ ist "Branch to PL/SQL Procedure".
begin htp.p('<body>'); htp.p('<script type="text/java-script">'); htp.p('parent.$("#modalDialog").dialog("close");'); htp.p('</script>'); htp.p('</body>');end;
Kommen wir nun zur Steuerung. Bedingung war ja, dass es auch in einer laufenden Session erscheinen soll. Dafür müssen wir bei jedem Neuladen einer Seite nachsehen, ob es eine Nachricht gibt die der jeweilige User noch nicht gelesen hat. Weiterhin soll es die Möglichkeit geben, das modale Fenster zu schließen ohne die Nachrichten zu bestätigen. Dafür werden die Applikationsitems FXXX_HIDE und FXXX_INFO angelegt.Dazu gehört auch ein Applikations Prozess mit dem Zündpunkt "On Load: Before Header".
begin select count(*)into :FXXX_INFO from informationen where app_id = :APP_ID and status = 'A' and id not in (select info_id from information_read where app_user = :APP_USER);end;
Jetzt der zentrale Punkt: wann und wie zeige ich das modale Fenster an!
Dazu wird auf der Seite 0 eine "Dynamic Action" mit folgenden Einstellungen angelegt.
When: Event = Page Load Condition = No ConditionAdvanced: Event Scope = onceCondition: Type = PL/SQL Expression Expression1 = NVL(:FXXX_HIDE,'F') != 'TRUE' and :FXXX_INFO > 0 and :APP_PAGE_ID not in (101,X)
Es müssen Loginseite und die Seite die als Popup erscheint ausgeschlossen werden.
TRUE ACTION: Execute Java-ScriptCode (In diesem Beispiel wird in der Applikation 100 die Seite 7 als modales Popup aufgerufen)
var ev = this.browserEvent;ev.preventDefault;var horizontalPadding = 20;var verticalPadding = 20;$('<iframe id="modalDialog" src="f?p=100:7:&APP_SESSION.::NO::" />').dialog( {title: "APEX System Info", autoOpen: true, width: 700, hight: 350, modal: true, close: function(event, ui) { $(this).remove();}, overlay: {opacity: 0.5, background: "black"} } ).width(700 - horizontalPadding).height(350 - verticalPadding);return false;
Der Anwender bekommt "neue Informationen" auch während einer laufenden Session sofort angezeigt und er muss aktiv werden und die Meldungen bestätigen, um sie dauerhaft auszublenden.
Achtung! Ab der APEX Version 4.1 sind aus Sicherheitsgründen Frames per default nicht erlaubt. Damit dieses Beispiel funktioniert muss in den Security Attributen "Embed in Frames" auf "Allow from same origin" umgestellt werden.
Weitere Informationen und Tipps zur Entwicklung mit APEX bekommen Sie auch in unseren Schulungen Entwicklung mit Application Express.
Seit APEX Version 5.1 können ja nun zusätzliche Standard-Prüfungen für die Items durchgeführt werden. Diese sind:
Wenn das aber alles nicht passt, können wir uns eine eigene Validation schreiben:
DECLAREstmt VARCHAR2(32000);v_sqlerrm varchar2(32000);BEGINFOR c IN (SELECT PAGE_ID, PAGE_NAME, ITEM_NAMEFROM APEX_APPLICATION_PAGE_ITEMSWHERE application_id=:APP_ID and page_id=:APP_PAGE_ID ) LOOP stmt:=q'!BEGIN IF instr(v('!'||c.item_name||q'!'),'<')>0 OR instr(v('!'||c.item_name||q'!'),'>')>0 OR instr(v('!'||c.item_name||q'!'),'^')>0 OR instr(v('!'||c.item_name||q'!'),'&')>0 OR instr(v('!'||c.item_name||q'!'),'"')>0 OR instr(v('!'||c.item_name||q'!'),chr(39))>0 THEN RAISE_APPLICATION_ERROR(-20500,'Ungültige Zeichen verwendet (^<>&")'); END IF; EXCEPTION WHEN OTHERS THEN IF sqlcode=-20500 then raise; end if; END; !';commit; EXECUTE IMMEDIATE stmt;
END LOOP; RETURN true;EXCEPTION WHEN OTHERS THEN v_sqlerrm:=sqlerrm; RETURN false;END;
Wenn jetzt jemand in irgendein Item eines der Zeichen <>'" &^ einträgt, wird diese Eingabe abgewiesen.
Wer mit APEX und ORDS zusammenarbeitet ist immer froh, wenn er eine Übersicht über die aktuellen ORDS Parameter findet.Anbei haben wir einige zusammengestellt:Sie erhalten eine Komplett-Übersicht aller Oracle ORDS Parameter für die Oracle Version 19.4 hier.Aktuell ist derzeit die Oracle ORDS Version 19.4.6 (1.6.2020)Parameter in der Datei defaults.xml können manuell mit einem Texteditor geändert werden, oder auch durch:
Die folgenden Parameter betreffen die Datenbank
oder bei einem Failover Eintrag
<entry key="db.connectionType">customurl</entry>
<entry key="db.customURL">jdbc:oracle:thin:@(DESCRIPTION=(FAILOVER=ON)(ADDRESS_LIST=
(LOAD_BALANCE=ON)(ADDRESS=(PROTOCOL=TCP)(HOST=muniqsoft-training.de)(PORT=1521)))
(CONNECT_DATA=(SERVICE_NAME=ISPRD)))|</entry>
Wenn es Probleme beim Verbinden gibt (z.B. Could not map a database) sollte versucht werden, eine Verbindung der Datenbank von der Shell/DOS direkt zur Datenbank durchzuführen mit:
Die folgenden 4 Parameter sind verantwortlich für das Debugging und LoggingHinweiß: Für Produktivmaschinen sollte Debuggung auf "false" stehen !
Wenn Sie eine eigene Datei in einem selbst gewählten Pfad für die Fehlermeldungen verwenden möchten:
<entry key="error.externalPath">/opt/tomcat/latest/logs</entry>
Diese Datei muss das Format {servererrorcode}.html besitzenalso z.B 404.html oder 500.htmlDie nächsten 4 Parameter kümmern sich um die Konfiguration der internen Java Parameter und spielen für die Performance des REST Service eine wichtige Rolle:
{servererrorcode}.html besitzen
also z.B 404.html oder 500.html
Maximale Anzahl der Zeilen definieren,die bei einer Abfrage zurückommen dürfen (Default: 500)
REST Enables SQL freischalten:
Datenbank API via REST freischalten:
database.api.enabled
oder auf der Kommandozeile:
Pluggable Database API abschalten (ab 19.2):
database.api.management.services.disabled
oder wieder auf der Kommandozeile:
java -jar ords.war set-property database.api.management.services.disabled true
Oracle APEX 20.1 ist gerade mal 4 Wochen heraus und schon gibt es den ersten Patch, der ein paar praktische Bugfixes mitbringt (u.A. die falsche Timeout Warnung wird behoben)Sie können den Patch von Oracles Support Seite herunterladen und in einer Minute installieren.Vorgehensweise:1. Webserver stoppen1 a, Sie haben das EPG im Einsatz:
Wenn ein Port <>0 zurückommt, dann haben Sie das EPG im Einsatz. Dann merken Sie sich den Port bitte.
1 b, Sie haben den TomCat im Einsatz
1 c, Sie haben TomCat und Apache als Reverse Proxy im Einsatz:
2. Patch einspielen (z.B. in den Ordner /u01/software)
3. Image Ordner aktualisieren3 a. bei EPG (hier werden die Bilder in der datenbank gespeichert)
3 b, bei TomCat (ohne Apache)Prüfen Sie bitte zuerst, ob das Verzeichnis dort existiert (kann je nach Installation auch auf einem anderem Pfad liegen)
3 c, Bei TomCat (mit Apache)
4. Webserver wieder starten4 a. Bei EPG:
4 b, Tomcat ohne Apache
4 c, Sie haben TomCat und Apache als Reverse Proxy im Einsatz:
5. Schlußprüfungen: 5 a. Patch installiert:
SELECT patch_version, installed_onFROM apex_patchesWHERE patch_number = 30990551;
Gibt es ungültige Objekte?
Dies und noch mehr lernen Sie bei einem unserer fünf verschiedenen APEX-Kurse, die wir seit 2005 unterrichten!
Mit dem Datum 21.10.2020 kam die Oracle APEX 20.2 Version nun doch sehr überrraschend frühzeitig heraus (im Vergleich zu den letzten Jahren). Aber gute Nachrichten kann man in den aktuell schweren Zeiten ja immer gebrauchen ... :-). Wir haben uns natürlich gleich am Tag 1 der Veröffentlichung um eine Migration unserer APPs auf das neue Release gekümmert.
APEX 20.2 Download
wir haben mal das relativ neue Installationsskript apexsilentins.sql für die Installation verwendet.Es ersetzt die folgenden Skripte:
Ausserdem erstellt es eine neue ACL (power_users.xml) und der Benutzer APEX_PUBLIC_USER wird automatisch entsperrt (endlich!)Dadurch benötigt es jedoch auch mehr Parameter als das alte apexins.sql Skript. Der Aufruf lautet hier:
Parameter 1: Name des Tablespace für den Application Express Application Benutzer (APEX_200200)Parameter 2: Name des Tablespace für den Application Express files user (FLOWS_FILES)Parameter 3: Name des temporären Tablespace (bzw. Tablespace Gruppe) für Sortierungen / Indexerstellung / Sort Merge Joins u.v.w.Parameter 4: Virtuelles Verzeichnis für APEX Bilder/CSS/Javascript DateienParameter 5: Passwort für APEX_PUBLIC_USERParameter 6: Passwort für APEX_LISTENERParameter 7: Passwort für APEX_REST_PUBLIC_USERParameter 8: Passwort für Workspace Internal APEX internal ADMIN user (Achtung, Sie müssen sich hier an strenge Passwort-Richtlinien erhalten, also bitte nicht APEX123 verwenden :-) )Also als Beispiel:
Die Installationszeit betrug auf unserem Server: 15 minWenn Sie einen Webserver verwenden z.B. Apache TomCat Version 9.x, dann kopieren Sie bitte den images Ordner aus dem Apex Zip File aufWindows: C:\Program Files\Apache Software Foundation\Tomcat 9.0\webappsLinux: /opt/tomcat/latest/webappsals Ordner i !, bzw. den Namen, den Sie bei der Installation als Parameter 4 angegeben haben. Wenn es dort schon einen Ordner gibt, bietet es sich an, den erstmal nur umzubennen und nicht gleich zu löschen!
Wenn Sie das interne EPG verwenden (also keinen externen Werserver), muss noch zusätzlich das folgende Skript gestartet werden:@apex_epg_config.sql <Pfad zu den Images>Achten Sie aber darauf, den Ordner-Namen apex nicht mit im Pfad anzugeben, weil das Skript ihn selbst dazufügt, also wenn die Bilder unter (Windows: c:\temp\apex oder Linux: /tmp/apex) liegen, lautet der Aufruf:
In vielen Datenmodellen werden Schalter für die Aktivierung oder Gültigkeit von Datensätzen verwendet. Hier kann zum Beispiel eine Spalte mit 0/1 oder Y/N belegt werden, um damit zu steuern, welchen Status ein Datensatz haben soll.
Im Normalfall hinterlegen wir so eine Spalte in einem Formular mit einer Selectlist, in der "Ja" oder "Nein" oder ähnliches ausgewählt werden kann. Wie wäre es aber, wenn wir den Anwendern die Möglichkeit geben würden diesen Schalter direkt im Report zu ändern? Er könnte mehrere Datensätze hintereinander verändern ohne die Seite neu laden zu müssen.
Gehen wir einmal von folgender Tabelle aus.
CREATE TABLE "EMP" ( "EMPNO" NUMBER(4,0) NOT NULL, "ENAME" VARCHAR2(10), "JOB" VARCHAR2(9), "MGR" NUMBER(4,0), "HIREDATE" DATE, "SAL" NUMBER(7,2), "COMM" NUMBER(7,2), "DEPTNO" NUMBER(2,0), "ACTIVE" VARCHAR2(1), PRIMARY KEY ("EMPNO"))/
Es handelt sich dabei um die bekannte EMP-Tabelle, ergänzt um die Spalte "ACTIVE", die mit "Y" oder "N" befüllt werden soll. Idealerweise verwenden Sie eine bereits bestehende EMP-Tabelle und erweitern sie um die neue Spalte.
Um einen Default-Wert für den Status der Mitarbeiter zu setzen, feuern wir einmalig noch ein Update-Statement, um alle Mitarbeiter auf aktiv zu setzen.
update EMP set ACTIVE = 'Y';
In APEX erstellen wir einen klassischen Report über alle Spalten der EMP Tabelle.
Nun ist es unsere Idee, auf das "Y" zu klicken und ein "N" daraus zu machen, und natürlich auch anders herum.
Um auf den Mausklick eines Anwenders reagieren zu können müssen wir einen Eventhandler aktivieren, der auf das anzuklickende Objekt "horcht" und dann bei "Klick" eine Aktion ausführt.
Im APEX-Umfeld haben wir die Möglichkeiten dies mit den Dynamic Actions umzusetzen. Das Problem dabei ist, dass wir die Spalte eines Reports nicht als "Selection Type", als Ziel eines "Klicks", auswählen können.
Also müssen wir uns mit der HTML-Struktur der Tabelle auseinandersetzen. Diese kann je nach gewählten Theme unterschiedlich sein. In unserem Beispiel handelt es sich um das Theme 25 in der APEX Version 4.2.6.
Eine Analyse des von APEX erzeugten HTML-Codes erfolgt am besten mit den Entwicklertools der aktuellen Browsergenerationen. Die Browser Firefox und Chrome bringen ausgereifte und mit vielen Funktionen versehene Oberflächen mit. Um sie zu aktivieren genügt es, mit der rechten Maustaste auf das zu untersuchende Objekt auf der Webseite zu klicken und "Element untersuchen" auszuwählen.
Es öffnet sich in der Regel am unteren Bildschirmrand ein zweigeteilter Bereich, in dem links der HTML-Code und rechts die CSS-Befehle angezeigt werden, die auf das angeklickte HTML-Tag wirken.
Bewegt man die Maus über den Quellcode wird der Bereich der Webseite markiert, der durch diesen Code definiert wird.
So erhalten wir die Information, dass die Ausgabe von "Y" oder "N" in einem "td" erfolgt, das mit dem Parameter "headers" und dem Wert "ACTIVE" versehen wird. Es handelt sich dabei um die von uns gewählte Überschrift der Spalte. Das gilt für alle Zeilen unseres Reports.
Mit dieser Information ausgerüstet können wir einen jQuery Selektor definieren, den wir in der Dynamic Action verwenden können.
Die Java Script-Bibliothek bietet sich an, da es sich zu einem "Quasi-Standard" im Internet etabliert hat und auch von APEX selbst verwendet wird. Mit einer leicht zu erlernenden Notation können wir einen Bereich innerhalb des HTML Codes definieren, der als Anker oder Startpunkt für unsere gewünschten Aktionen dienen kann.
In diesem konkreten Fall möchten wir gerne auf einen "td" klicken können, der den "Header" "ACTIVE" besitzt. Also definieren wir den Selektor für jQuery folgendermaßen:
td[headers="ACTIVE"]
Erstellen wir also nun eine neue Dynamic Action und verpassen ihr einen sprechenden Namen.
Sobald der Event "Click" auftritt auf dem gewählten jQuery Selector soll ...
... die Action "Java script" ausgeführt werden. Um unsere Eventhandler zu testen geben wir zuerst nur einen Alert aus der bei Klick angezeigt werden soll.
alert('ok');
Den Haken bei "Fire On Page Load" deaktivieren wir, da wir nicht möchten, dass die Aktion beim Laden der Seite gefeuert wird.
Da wir alle Aktionen mit JavaScript ausführen werden, benötigen wir im nächsten Schritt kein Element, das benutzt werden soll und wählen hier nichts aus und schließen die Erstellung der Dynamischen Aktion ab.
Wir haben den Test bestanden, wenn wir nun im Report auf das "Y" klicken können und eine Alert-Box erscheint. Ein Klick auf einen anderen Bereich der Webseite sollte dagegen den Event nicht auslösen.
Jetzt haben wir zwar den Klick auf "Y" mit dem Eventhandler abgefangen, wir wissen aber noch nicht, auf welches "Y", sprich welche Zeile angeklickt wurde. Wir müssen ja in der Lage sein, ein Update-Statement an die Datenbank zu senden, um den angeklickten Datensatz zu verändern. Dazu benötigen wir den Primary Key des Datensatzes.
In unserem Fall müssen wir die "EMPNO" der angeklickten Zeile ermitteln. Wir können das auf eine einfache aber "gefährliche" Art und Weise mit jQuery erreichen, da die Empno in diesem Fall mit im Report angezeigt wird.
Wenn wir uns im Browser noch einmal den Quellcode anzeigen lassen, entdecken wir den von uns gesuchten Wert in dem ersten "td" einer jeden Zeile.
Hinweis: Sollten Sie einen Report mit Editiermöglichkeit gewählt haben, könnte es sich bei der Empno-Spalte auch um das zweite "td" handeln. Das ist für die weitere Vorgehensweise sehr wichtig. Aus diesem Grund sollten Sie unbedingt unsere weiterführenden Tipps beachten, darin verwenden wir eine Möglichkeit, die von der Reihenfolge der Spalten unabhängig ist.
Die Idee ist nun, ausgehend von dem angeklickten "td", den ersten "td" der Zeile ("tr") zu ermitteln. Zurück in der von uns angelegten Dynamic Action ersetzen wir unsere Debug-Ausgabe mit folgendem jQuery-Selector.
alert( $(this.triggeringElement).parent().children().html());
Das Dollarzeichen ($) ist die Kurzform der Java script-Funktion, mit der wir jQuery aufrufen können. Dieser Funktion geben wir das von APEX befüllte Object "this.triggeringElement" als Selector mit. Dann ermitteln wir mit der Funktion "parent" das Elternelement unseres angeklickten "td"s. Es handelt sich dabei um das übergeordnete "tr". Von dort springen mit der Funktion "children" wieder zum ersten Kind-Element zurück. Von diesem geben wir mit der Funktion "html" den HTML-Inhalt aus.
Wenn es sich bei der Empno-Spalte um das zweite "td" handelt können wir folgenden Selektor verwenden.
alert( $(this.triggeringElement).parent().children().next().html());
Hier wird mit ".next()" auf das zweite Kind-Element gezeigt.
Wer sich ein bisschen mit jQuery beschäftigt hat, wird sicherlich wissen, dass es noch einundreißig weitere Wege gegeben hätte, sich mit jQuery in der HTML-Struktur zu bewegen. So hätten wir mit Kombinationen der Funktionen "first", "next" oder "prev" auf dasselbe Ergebnis kommen können. Auch der Einsatz des bereits verwendeten aber leicht abgewandelten "td[headers='EMPNO']" wäre möglich gewesen. Dabei ist aber zu beachten, dass alle Bewegungen in der Struktur immer ausgehend vom angeklickten Element starten müssen.
Nun haben wir also erreicht, dass bei Klick in der Alert-Box die Empno der angeklickten Zeile ausgegeben wird. Wir benötigen diese Information aber in einem von APEX verwendbaren Element, um es an die Datenbank senden zu können.
Dazu bietet sich ein Hidden-Element an, das wir mit JavaScript befüllen und dann mit PL/SQL auslesen und unseren Update formulieren.
Erster Schritt dazu ist das Anlegen eines Page Items im Format Hidden. Da wir in diesem Element den Wert der Empno zwischenspeichern wollen und wir uns mit unserem Report auf der Seite 5 befinde, nennen wir das Hidden Element "P5_EMPNO_CACHE".
Nach einer kurzen Analyse des HTML-Outputs unserer Seite erkennen wir, dass das von uns erzeugte Element von APEX mit dem Parameter ID versehen wurde, mit dem von uns vergebenen Namen.
Damit haben wir alle Informationen um dem Hidden-Item den Wert mit JavaScript zu übergeben. Wir ersetzen also in der Dynamic Action den JavaScript-Code mit folgendem Inhalt:
$('#P5_EMPNO_CACHE').val( $(this.triggeringElement).parent().children().html());
Hier kommt wieder ein jQuery Selektor zum Einsatz. Das Dollarzeichen ist die jQuery-Funktion selbst. Als Parameter übergeben wir in Hochkommas die Information, dass es sich um eine ID handelt - mit der Raute (#) und den Namen der ID "P5_EMPNO_CACHE". Dann setzen wir mit der Funktion "val" die "Value" des schon vorher ermittelten Wertes.
Um das Ganze zu debuggen geben wir noch zusätzlich den folgenden Code in den JavaScript-Bereich:
console.log( "EMPNO: " + $('#P5_EMPNO_CACHE').val());
Mit dem Befehl "console.log" können wir Ausgaben in die JavaScript-Konsole der Entwicklungsumgebung veranlassen. Das ist in der Regel angenehmer als die Ausgabe über den Alert Befehl.
Aufrufen können wir die Console über die rechte Maustaste und "Element untersuchen", danach klicken wir im Menü der Entwicklungsumgebung auf den Punkt "Console".
Dort sehen wir nach einem Klick auf ein "Y" die Ausgabe unseres Log-Befehls. Da wir damit sichergestellt haben, dass das Hidden Element die richtige Empno enthält, müssen wir jetzt den nächsten Schritt gehen.
Übergabe des Hidden-Wertes zur Datenbank. Natürlich könnten wir einfach einen "Submit" ausführen und der Wert wäre der Datenbank bekannt. Wir möchten aber gerne ohne Neuladen der Webseite auskommen. Daher erzeugen wir eine weitere "True Action" in unserer bestehenden Dynamic Action.
Diesmal möchten wir PL/SQL-Code ausführen. Bei den Optionen lassen wir "Fire On Page Load" deaktiviert. Die Optionen "Stop Execution On Error" und "Wait For Result" lassen wir ebenfalls auf dem Default-Wert (angehakt). Vor allem letztere ist wichtig, da erst der PL/SQL-Teil abgearbeitet werden soll und dann der nächste Schritt ausgeführt werden soll.
Als PL/SQL-Code tragen wir folgendes ein.
update emp set ACTIVE = case when ACTIVE = 'Y' then 'N' when ACTIVE = 'N' then 'Y' endwhere empno = :P5_EMPNO_CACHE;
Damit die Datenbank mit diesem PL/SQL-Code, aber auch auf den Wert in P5_EMPNO_CACHE zugreifen kann, muss das Item noch bei "Page Items to Submit" eingetragen werden. Die Dynamic Action stellt jetzt sicher, dass der Wert auch per AJAX übertragen wird.
Wenn wir jetzt auf ein "Y" oder "N" klicken, wird der Wert in der Datenbank geändert. Wir sehen das Ergebnis aber erst wenn wir den Report neu laden, es fehlt also noch ein automatischer Refresh des Reports.
Dazu legen wir einen eine neue "True Action" in unserer Dynamic Action an, diesmal vom Typ "Refresh". Als "Affected Element" wählen wir "Region" und dann die von uns verwendete Region aus.
Beim Test stellen wir fest: es funktioniert. Aber es funktioniert nur einmal. Das liegt daran, dass wir einen Eventhandler für das Abfangen des Klicks aufbauen, dieser aber beim Refresh des Reports "zerstört" wird. Daher müssen wir in unserer Dynamic Action unter "Advanced" den "Event Scope" auf "Dynamic" setzen, dann klappt das Verändern des Status auch mehrere Male hintereinander.
Hinweis:Sollte der Refresh überhaupt nicht funktionieren kann es sein, dass im Report unter "Report Attributes" im Bereich "Layout and Pagination" der Schalter "Enable Partial Page Refresh" auf "Nein" steht. Das sollte man dann ändern. :)
In den weiterführenden Tipps erfahren Sie, wie Sie ein HTML-Attribut setzen können, um der Reihenfolgenproblematik zu entkommen. Oder aber Sie verbessern die Darstellung mit Icons aus einem Web-Font.
In unseren APEX-Schulungen und Workshops erfahren Sie weitere Möglichkeiten, um benutzerfreundliche APEX Anwendungen zu erstellen.
Ich habe schon oft versucht Dynamic Actions Vorlagen für APEX im Internet zu finden. Aber es gibt nur sehr wenige und viele sind nicht für den Anwendungsfall passend oder zu kompliziert. Ziel dieses Artikels ist es, einfache Dynamic Action in Oracle APEX als Vorlagen für den täglichen Hausgebrauch zur Verfügung zu stellen.
Fangen wir an...
1.Ein Item soll nach der Eingabe, sofort wieder mit dem Session State synchronisiert werden.Das bedeutet der Inhalt des Items wird sofort wieder mit der Datenbank, Tabelle wwv_flow_data synchronisiert. Das hat den Vorteil, von einem anderen Item wieder auf den Inhalt des Items über die Notation :Px_ITEM zugreifen zu können.Voraussetzungen. Ein Text Item (P1_TEXT) existiert in einer Region.
Fertig. Sobald Sie das Item ändern und verlassen, steht es sofort im Session State zur Verfügung. 2. Ein Zweites Item soll erst dann auf der Seite erscheinen, wenn das erste Item mit Inhalt gefüllt wurde:Wir brauchen dazu ein zweites Textfeld (P1_NAME).
Wenn man es noch schöner haben möchte legt man eine weitere True Bedingung fest, die den Cursor in das nächste/richtige Item setzt.
3. Sie geben im ersten Item eine Mitarbeiternummer ein und bekommen in einem anderenItem den Namen des dazugehörigen Mitarbeiters zurück:
4. Beim Klick in eine Textbox, sollen in zwei andere Textboxen neue Werte (mit/ohne Datenbankbezug) eingetragen werden.Wir brauchen dazu die Textboxen P1_TEXT, P1_NAME und P1_GEHALT
5. Modales Fenster gibt Wert an Hauptfenster zurück:Wir brauchen dazu eine normale Seite (Seite 1) mit einer Textbox (P1_TEXT)und einem Button (Modal_Fenster)
Ausserdem eine Modale Seite (Seite 2) mit einer Selectliste (P2_EMPS)und einem Button (Zurueck)
Der Button Modal_Fenster macht einen Redirect auf Seite 2Auf den Button legen wir eine Dynamic Action
6. Bei einem Doppelklick auf die Textbox P1_ENAME soll der Inhalt dieser Textboxsofort in die Datenbank zurückgeschrieben werden.
Wir brauchen dazu eine Normale Seite mit zwei Items:P1_EMPNO vom Typ HiddenP1_ENAME vom Typ Text Field
7. Textbox Eingabe in Großbuchstaben umwandeln:
In der Textbox eintragen unterAdvanced / Custom Attributes: style='text-transform:uppercase' Trotzdem muss das Item auch nach dem Verlassen in Großbuchstaben gewandelt werden!
8. Beim Klick auf ein Button sollen zwei Textfelder geleert werden:
Wir brauchen dazu:Button ("Clear")Text Feld P1_NAME und P1_TEXT
Damit das nun nicht aus Versehen ausgewählt wird, bauen wir eine Sicherheitsabfrage ein Dazu muss eine weitere True Action erzeugt werden mit einer niedrigeren Sequenz Nummer (z.B. 5)
Zum Schluß noch ein paar praktische Javascript Snippets: Abfrage mit YES/NO und dem Text "Mitarbeiter löschen?". Bei YES wird REQUEST = DELETE gesendet apex.confirm( "Mitarbeiter löschen?", 'DELETE' ); Abfrage mit YES/NO und dem Text "Mitarbeiter löschen?". Bei YES wird REQUEST = DEL gesendet und die Items P1_DEPTNO = 10 und P1_EMPNO=7788 gesetzt. apex.confirm( "Mitarbeiter löschen?", { request: "DEL", set: { "P1_DEPTNO": 10, "P1_EMPNO": 7788 }} );
Submit ausführen mit REQUEST=GO apex.submit( "GO" );
9. In einem Tabular Form soll in einer neu hinzugefügten Zeile in einer Spalte immer bereits ein Defaultwert stehen.
Gehen Sie in die Eigenschaften der gewünschten Spalte (bei uns im Beispiel DEPTNO) in den Bereich Advanced / CSS Classes und tragen dort ein:
mydeptno
Der Defaultwert soll aus einem Item stammen mit Namen :P1_DEPTNO
Legen Sie nun eine Dynamic Action auf den "ADD" Button in der Seite, der bei einem Click reagiert:
10. In einem Autocomplete Item soll ein Wert eingesetzt werden, der dazu führt das eine Select Liste sich eine neue Query ausführt mit dem Autocomplete Wert als Filter.
Legen Sie dazu ein Autocomplete Item (P1_DEPT) und eine Select Liste an (P1_EMPS)
Die Query für P1_DEPT:
Die Query für P1_EMPS:
Legen Sie nun eine Dynamic Action auf P1_DEPT:
11. Ein Zweites Item soll mit dem ersten Item synchronisiert werden:Wir brauchen dazu zwei Textfelder (P1_NAME und P1_NAME2).Rechte Maus auf P1_NAME / Create Dynamic Action
12. Automatische Erzeugung eines Primärschlüssels in einem interactiven GridSehr häufig benötigt man eine automatische Generierung eines Primary Schlüssels (Primary Keys) in einer TabelleFolgende Möglichkeiten bieten sich hier an:Tabelle hat einen Before Row Insert Trigger mit einer SequenzTabelle hat eine Identity Spalte (ab 12.1)PK wird durch APEX mit Hilfe einer Sequenz gefülltWir wollen uns den letzten Fall ansehena., Erstellen Sie einen interactiven Grid auf Ihrer Tabelle (bei uns die EMP Tabelle)b, Erstellen Sie eine Sequenz:
c, Erstellen Sie auf der Spalte EMPNO im Grid (rechte Maustaste, Create Dynamic Action) eine neue Dynamic Action
Nun passiert folgendes:Bei jeder neu eingefügten Zeile im Grid wird kurz der Spaltenschutz aufgehoben,dann wird aus der Sequenznummer eine neue Nummer in die Zeile eingetragen,danach wird die Spalte wieder gegenüber Änderungen geschützt.
Für einige der Universal Theme-Templates in APEX 5.0 sind die Template Substitutions besonders interessant - deswegen wollen wir diese Variablenart einmal genauer unter die Lupe nehmen...
In APEX lassen sich Variablen auf fünf verschiedene Arten referenzieren:
Für einige der Universal Theme-Templates in APEX 5.0 sind die Template Substitutions besonders interessant - deswegen wollen wir diese Variablenart einmal genauer unter die Lupe nehmen.
Wichtig ist dabei, dass die gewünschten Template Substitutions im aktuellen Template Ihrer Seite, Region, Liste, etc. enthalten sind, um sie in der Applikation definieren und nutzen zu können!
Im Shared Components Menü "Application Definition Attributes" lässt sich so beispielsweise der Substitution String #GLOBAL_NOTIFICATION# im Seiten-Template füllen. Der dort eingefügte Text wird nun automatisch auf allen Seiten Ihrer Applikation angezeigt.
Auch sogenannte Favicons (das sind die kleinen Symbole in Ihrem Webbrowser-Tab oder der Adresszeile) können Sie an dieser Stelle ganz einfach für Ihre gesamte Applikation festlegen: Geben Sie als Substitution String "APP_FAVICONS" und den dazugehörigen Bildwert, verpackt in einem Link-Tag, an.
Voraussetzung ist hier der String #FAVICONS# im Seiten-Template!
Das Universal Theme in APEX 5.0 bietet uns einige neue Report-Templates - und auch hier kommen Substitution Strings zum Einsatz!
Klären wir zunächst noch, was genau mit "Report-Templates" gemeint ist: Im Gegensatz zu Region-Templates werden Report-Templates im "Attributes"-Bereich einer Report-Region definiert.
In diesem Tipp zeigen wir die Nutzung von Report-Templates unter Verwendung von Substitution Strings am Beispiel des Templates "Timeline".
TEMPLATE ERKUNDENEin Blick in das entsprechende Template (Shared Components -> Templates -> Report Timeline) verrät, welche Substitution Strings grundsätzlich verfügbar sind und durch einen Report gefüllt werden können.
Die Strings in schwarzer Farbe stehen für Daten, die später im Report sichtbar dargestellt werden. In unserem Beispiel: #USER_AVATAR#, #USER_NAME#, #EVENT_DATE#, #EVENT_TYPE#, #EVENT_TITLE#, #EVENT_DESC#.
Substitution Strings in roter Farbe dagegen sind Teil von HTML Klassen und können zur HTML- und CSS Bearbeitung genutzt werden: #EVENT_MODIFIERS#, #USER_COLOR#, #EVENT_STATUS#, #EVENT_ICON#.
Erstellt man einen Bericht mit dem Report-Template "Timeline" und der simplen SQL Query:
select 1 from dual
so werden auch in der laufenden Applikation die im Template definierbaren Substitution Strings angezeigt:
In der Report-Query können diese Substitution Strings nun als Spaltenaliasse verwendet und dadurch gefüllt werden:
select
'IQ' as USER_AVATAR,
'Muniqsoft' as USER_NAME,
'07.11.2016' as EVENT_DATE,
'Kurs' as EVENT_TYPE,
'APEX I' as EVENT_TITLE,
'Grundlagen der Anwendungsentwicklung mit APEX'
as EVENT_DESC,
'user_blue' as USER_COLOR,
'kurs_status' as EVENT_STATUS,
'fa-book' as EVENT_ICON
from dual;
Jetzt fehlt nur noch die Definition der CSS Klassenselektoren, die sich auf die HTML/CSS Substitution Strings #USER_COLOR# und #EVENT_STATUS# beziehen. Diese kann beispielsweise im Custom CSS Bereich des Theme Rollers oder in den Seiten-Eigenschaften unter CSS/Inline erfolgen:
.user_blue { background-color: #58D3F7;}.kurs_status { background-color: #82FA58;}
Und hier ist er, unser "Timeline"-Report:
Anhand dieser Vorgehensweise können Sie natürlich auch alle anderen Report-Templates wie "Badge List", "Cards", "Comments" oder "Search Results" in Ihrer Applikation nutzen!
Weitere Erklärungen zu Substitutions Strings und Templates sowie Tipps und Tricks rund um APEX erhalten Sie in unseren APEX-Schulungen (Grundlagen / Fortschritt / Neuerungen in APEX 5.x/18x)!
Schauen Sie doch einfach mal vorbei!
Nachdem wir in den letzten Jahren schon viele Male den Ords installiert haben und in diverse Probleme gelaufen sind, wird es Zeit hier mal etwas Licht ins Dunkel zu bekommen... :-)
1. Wie installiert man die Java-Applikation "ords.war"?
Zuerst muss wie immer die neueste Version heruntergeladen werden.
Idealerweise hat man bereits eine JDK Version 1.8 (wir hatten mit 1.9 und ords 18.1 ein paar Probleme...) installiert.
Vorbereitung: Wir richten ein config-Verzeichnis für die folgende Installation ein:
Windows: java -jar ords.war configdir c:\app\oracle
Linux:
java -jar ords.war configdir /opt/oracle
Achtung: Dann wird dort bei der Installation ein Verzeichnis "ords/" angelegt mit folgendem Inhalt:
Die Datei "defaults.xml" besteht z.B. aus folgenden Zeilen:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>Saved on Thu Jul 05 06:20:04 CEST 2018</comment> <entry key="cache.caching">false</entry> <entry key="cache.directory">/tmp/apex/cache</entry> <entry key="cache.duration">days</entry> <entry key="cache.expiration">7</entry> <entry key="cache.maxEntries">500</entry> <entry key="cache.monitorInterval">60</entry> <entry key="cache.procedureNameList"/> <entry key="cache.type">lru</entry> <entry key="db.hostname">localhost</entry> <entry key="db.port">1521</entry> <entry key="db.servicename">o12c2</entry> <entry key="debug.debugger">false</entry> <entry key="debug.printDebugToScreen">false</entry> <entry key="error.keepErrorMessages">true</entry> <entry key="error.maxEntries">50</entry> <entry key="jdbc.DriverType">thin</entry> <entry key="jdbc.InactivityTimeout">1800</entry> <entry key="jdbc.InitialLimit">3</entry> <entry key="jdbc.MaxConnectionReuseCount">1000</entry> <entry key="jdbc.MaxLimit">10</entry> <entry key="jdbc.MaxStatementsLimit">10</entry> <entry key="jdbc.MinLimit">1</entry> <entry key="jdbc.statementTimeout">900</entry> <entry key="log.logging">false</entry> <entry key="log.maxEntries">50</entry> <entry key="misc.compress"/> <entry key="misc.defaultPage">apex</entry> <entry key="security.disableDefaultExclusionList">false</entry> <entry key="security.maxEntries">2000</entry> <entry key="security.requestValidationFunction">wwv_flow_epg_include_modules.authorize</entry> <entry key="security.validationFunctionType">plsql</entry> </properties>
Falls Sie https einsetzen und beim Aufruf einer Seite in Google Chrome erhalten Sie die Fehlermeldung:
The Request cannot be processed because this resource doest not support Cross Origin Sharing request...
Dafür gibt es auch ein MOS Doc:
403 Forbidden Error" When Trying To Access The Apex Application Configured with ORDS 3.0.4 Or Higher Using the Google Chrome Browser (Doc ID 2139195.1)
dann sollten Sie als Lösung zusätzlich noch folgenden Parameter in die Datei defaults.xml eintragen:
<entry key="security.forceHTTPS">true</entry>
Interessant sind in der Datei die folgenden Parameter für das Debugging (bitte ggf. von "false" auf "true" setzen):
<entry key="debug.debugger">true</entry> <entry key="debug.printDebugToScreen">true</entry>
Mögliche Parameter (Auswahl) beim Aufruf von "ords.war":
Hilfe ausgeben:
java -jar ords.war help
Config Verzeichnis vorab angeben:
java -jar ords.war configdir <path>
Oracle Rest Data Service installieren:
java -jar ords.war install
Hinweis: Wenn Sie schon ein erfolglose Installation hinter sich haben, oder eine neue ORDS Version installieren, empfihelt es sich unserer Erfahrung nach, zuvor die alte Version zu deinstallieren:
java -jar ords.war uninstall
Datenbank Verbinding einrichten:
java -jar ords.war setup
ORDS_METADATA,, Proxy Benutzer und zugehörige Objekte wieder deinstallieren:
ORDS Konfiguration prüfen:
java -jar ords.war validate
Kommen wir zur Installation von ORDS:
Folgende Vorüberlegungen / Vorbereitungen sollten Sie machen:
1. Welche Datenbank soll am Applicationserver (Tomcat) angebunden werden (Hostname/IP, Portnummer, Instanzname)? 2. Welche Passwörter möchten Sie verwenden für die Benutzer APEX_PUBLIC_USER, APEX LISTENER, APEX_REST_PUBLIC_USER)?
Hinweis: Ein bereits vorhandener APEX_PUBLIC_USER berkommt nur ein neues Passwort, wird aber nicht automatisch entsperrt!
java -jar ords.war Name des Datenbankservers eingeben [localhost]: Listener-Port der Datenbank eingeben [1521]: 1 eingeben, um den Servicenamen der Datenbank anzugeben, oder 2, um die Datenbank-SID anzugeben [1]: Datenbankservicename eingeben:o12c2 Datenbankkennwort für ORDS_PUBLIC_USER eingeben:*** Kennwort bestätigen:*** Erfordert SYS AS SYSDBA, um das Oracle REST Data Services-Schema zu verifizieren. Datenbankkennwort für SYS AS SYSDBA eingeben:*** Kennwort bestätigen:*** Informationen werden abgerufen. Geben Sie 1 ein, wenn Sie das PL/SQL-Gateway verwenden möchten, oder 2, um diesen Schritt zu überspringen. Wenn Sie Oracle Application Express verwenden oder eine Migration von mod_plsql durchführen, müssen Sie 1 eingeben [1]: Datenbankkennwort für APEX_PUBLIC_USER eingeben:*** Kennwort bestätigen:*** Geben Sie 1 ein, um Kennwörter für Application Express RESTful Services-Datenbankbenutzer anzugeben (APEX_LISTENER, APEX_REST_PUBLIC_USER), oder 2, um diesen Schritt zu überspringen [1]: Datenbankkennwort für APEX_LISTENER eingeben:*** Kennwort bestätigen:*** Datenbankkennwort für APEX_REST_PUBLIC_USER eingeben:*** Kennwort bestätigen:*** Jul 05, 2018 6:20:04 AM INFORMATION: Updated configurations: defaults, apex, apex_pu, apex_al, apex_rt Oracle REST Data Services Version 18.2.0.r1831332 wird installiert ... Logdatei in C:\Users\vaiomarco\ords_install_core_2018-07-05_062004_00605.log geschrieben ... Datenbankvoraussetzungen wurden verifiziert ... Oracle REST Data Services-Schema wurde erstellt ... Oracle REST Data Services-Proxybenutzer wurde erstellt ... Berechtigungen für Oracle REST Data Services wurden erteilt ... Oracle REST Data Services-Datenbankobjekte wurden erstellt ... Logdatei in C:\Users\vaiomarco\ords_install_datamodel_2018-07-05_062017_00179.log geschrieben ... Logdatei in C:\Users\vaiomarco\ords_install_apex_2018-07-05_062019_00485.log geschrieben Installation für Oracle REST Data Services Version 18.2.0.r1831332 wurde abgeschlossen. Verstrichene Zeit: 00:00:17.460
Nun wurde die "ords.war" Datei konfiguriert und muss MANUELL in folgendes Verzeichnis kopiert werden:
Windows: C:\Program Files\Apache Software Foundation\Tomcat 9.0\webapps
Linux: /opt/tomcat*/webapps
Wenn Sie den Applicationserver (Tomcat) durchgestartet haben, sollte er aus dem "ords.war" einen Ordner "ords" mit einigen Unterordnern angelegt haben.
2. Troubleshooting / Fehlerbehebung von ORDS-Problemen:
Der Klassiker ... ein "404 not Found"-Fehler. Wir schalten mal das Debugging ein (siehe oben) und starten Tomcat durch.
Na, das ist doch gleich viel besser :-) "Could not find any dispatcher to handle request..." heisst also u.a. APEX_PUBLIC_USER Account ist nicht offen:
Wir prüfen das Mal:
SELECTusername,account_status,lock_date from dba_users WHERE username like 'APEX%' OR username like 'ORDS%' OR username like 'FLOWS%' OR username ='ANONYMOUS' order by 1;
Na da haben wir ja den Schuldigen: APEX_PUBLIC_USER ist gesperrt.
ALTER USER APEX_PUBLIC_USER ACCOUNT UNLOCK;
Vergessen Sie nicht nach jeder Änderung, den Applicationserver (Tomcat) durchzustarten!
2. Problem: Die Bilder-/ CSS-/ Java-Script-Dateien fehlen, oder liegen im falschen Verzeichnis.
Prüfen Sie bitte, ob ein Ordner mit Namen "i" im Verzeichnis .. tomcat/WebApps/ROOT liegt, ansonsten könnte die Seite (weil die CSS-Dateien nicht geladen werden) so aussehen:
Wenn dann aber die Bilder-/ CSS-/ Java-Script-Dateien an richtiger Stelle liegen, haben wir zur Belohnung die Anmeldemaske:
3. Es kommt die Fehlermeldung, dass die Version der Bilder, nicht zur Version von APEX passt.
Da muss einfach der Browser Cache geleert werden.
4. Die "ords.war"-Datei funktioniert in Verbindung mit Tomcat einfach nicht:
Prüfen Sie die Konsistenz der Datei mit:
Dann sollte folgende Ausgabe erscheinen:
Name des Datenbankservers eingeben [localhost]: Listener-Port der Datenbank eingeben [1521]: Datenbankservicename eingeben [o12c2]: Erfordert SYS AS SYSDBA, um das Oracle REST Data Services-Schema zu verifizieren. Datenbankkennwort für SYS AS SYSDBA eingeben: Kennwort bestätigen: Informationen werden abgerufen. Retrieving information. Oracle REST Data Services will be validated. Validating Oracle REST Data Services schema version 18.4.0.r3541002 ... Log file written to /root/ords_validate_core_2019-01-16_133103_00877.log Completed validating Oracle REST Data Services version 18.4.0.r3541002. Elapsed time: 00:00:04.798
Sie können natürlich auch noch die dazugehörige Log-Datei analysieren. Da sollte dann z.B. u.a. folgendes zu finden sein:
INFO: 08:27:22 Validating objects for Oracle REST Data Services. VALIDATION: 08:27:22 Starting validation for schema: ORDS_METADATA VALIDATION: 08:27:22 Validating objects VALIDATION: 08:27:23 Validating ORDS Public Synonyms VALIDATION: 08:27:24 Total objects: 259, invalid objects: 0 VALIDATION: 08:27:24 72 INDEX VALIDATION: 08:27:24 1 JOB VALIDATION: 08:27:24 11 PACKAGE VALIDATION: 08:27:24 11 PACKAGE BODY VALIDATION: 08:27:24 43 PUBLIC SYNONYM VALIDATION: 08:27:24 1 SEQUENCE VALIDATION: 08:27:24 14 SYNONYM VALIDATION: 08:27:24 27 TABLE VALIDATION: 08:27:24 26 TRIGGER VALIDATION: 08:27:24 19 TYPE VALIDATION: 08:27:24 6 TYPE BODY VALIDATION: 08:27:24 28 VIEW VALIDATION: 08:27:24 Validation completed. INFO: 08:27:24 Completed validating objects for Oracle REST Data Services.
Zu guter letzt: Ein Problem, was mir vier Wochen Suche beschert hat. Wir hatten bei der Installation von ORDS immer das Problem, dass sich die Installation an einer Stelle aufgehängt hatte. Sie hing ca. 15 min und stüzte dann ab mit " IO Error: Connection reset by Peer". Das Problem war, dass Java auf unserem System (CentOS 7) mit "/dev/random" nicht genügend viele Zufallszahlen berechnen konnte und stattdessen "/dev/urandom" nehmen musste.
Dazu müssen Sie bei der Installation folgendes zuätzlich angeben:
java -Djava.security.egd=file:///dev/urandom -jar ords.war
Allerdings kann man auch dem Pool der Zufallszahlen von "/dev/random" etwas mehr Entropie verleihen und daher weiterhin "/dev/random" nutzen. Dazu installiert man sich ein entsprechendes Tool:
yum install haveged systemctl enable haveged; systemctl start haveged;
5. Eine ominöse CSS Datei wird nicht gefunden z.B. 56437564376.css
Hier war eine fehlerhafte ords Installation Schuld, es fehlte die Datei apex_rt.xml
Prüfen Sie nach der Installation, ob die folgenden Dateien im angegebenen Config Verzeichnis liegen:
drwxr-xr-x 2 tomcat tomcat 4096 Jan 16 13:16 conf -rw-r--r-- 1 tomcat tomcat 478 Jan 16 13:16 defaults.xml
und im conf Unterordner:
-rw-r--r-- 1 tomcat tomcat 357 Jan 16 13:16 apex_al.xml -rw-r--r-- 1 tomcat tomcat 360 Jan 16 13:16 apex_pu.xml -rw-r--r-- 1 tomcat tomcat 365 Jan 16 13:16 apex_rt.xml -rw-r--r-- 1 tomcat tomcat 360 Jan 16 13:16 apex.xml
Die apex_rt.xml datei sieht z.B. so aus:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>Saved on Wed Jan 16 09:37:29 CET 2019</comment> <entry key="db.password">@0529A217A76655C4328127B3215A50F0D1EF46AB65FEB176BE9E0220</entry> <entry key="db.username">APEX_REST_PUBLIC_USER</entry> </properties>
Fehlerhafte / fehlende Dateien weden auch in der log Datei catalina.out angezeigt:
Caused by: oracle.dbtools.url.mapping.TargetNotAvailableException: The connection pool named: apex_rt does not exist at oracle.dbtools.url.mapping.db.PoolInjector.inject(PoolInjector.java:60) at oracle.dbtools.url.mapping.db.DatabaseURLMappingImpl.addServices(DatabaseURLMappingImpl.java:311) at oracle.dbtools.url.mapping.URLMappingBase.doFilter(URLMappingBase.java:80)
Kürzlich hatten wir einen neuen Fehler, der stellte sich wie folgt da: Eine CSS Datei des Theme Rollers konnte auf einem Server teilweise nicht mehr gefunden werden. Teilweise ist immer spannend ... Ein Blick in die catalina.out brachte etwas Licht ins Dunkel: Einige ORDS_METADATA Views waren invalid- Bei genauerer Betrachtung der Views, stellte sich heraus, dass die dazu passenden Tabellen gar nicht (mehr) da waren. Nur wo werden diese angelegt. Nach einiger Suche habe ich beim Auspacken des ords.war Files die Datei ords_database.objects.sql im Ordner scripts/install/core gefunden. Nachdem das Skript nochmal installiert wurde (bitte im Schema ORDS_METADATA) lief wieder alles perfekt. Sicherheitshalber kann man natürlich einen Zusatzcheck durchführen (hoer mir ORDS Version 19.2 (Stand 26.09.2019))
select object_type,count(valid),count(invalid) from ( select object_type, CASE WHEN status='VALID' THEN 1 END as valid, CASE WHEN status<>'VALID' THEN 1 END as invalid from dba_objects where owner='ORDS_METADATA') group by Object_type order by 1;
Das Ergebnis sollte dann so aussehen:
So, das war es mit einer Kurzübersicht :-) zur Installation und Troubleshooting. Weitere Tipps erhalten Sie in einem unserer beliebten APEX-Kurse.
Ist es Ihnen schon passiert, dass Sie in Application Express ein Schema einem Workspace zuordnen wollten, aber dieses Schema wurde Ihnen nicht angeboten? Und wenn Sie den Schemanamen trotzdem manuell eingetragen haben, wurde der Versuch mit folgender Fehlermeldung quittiert: "The requested schema is reserved or is restricted and the site administrator does not have the privilege to assign restricted schemas to workspaces.".
Das liegt daran, dass standardmäßig alle vordefinierten Schemata (z.B. SYSTEM, SCOTT, RMAN, HR, SH ....) für den Zugriff über Application Express gesperrt sind. Die Liste aller gesperrten Schemata erhalten Sie mit folgendem Select:
SELECT schema FROM APEX_180200.WWV_FLOW_RESTRICTED_SCHEMAS;
Anmerkung: Hier wie im folgenden wird von der Application Express Version 2.0 ausgegangen. Bei anderen Versionen muss der Schemaname entsprechend angepasst werden.
Schemanamen der Unterschiedlichen Apex Versionen:
Über das Package APEX_180200.APEX_INSTANCE_ADMIN.UNRESTRICT_SCHEMA kann ein Datenbankadministrator Schemata freigeben oder sperren.
Es beinhaltet folgende Prozeduren:
UNRESTRICT_SCHEMA: Dadurch wird ein Schema generell freigegeben für die Verwendung.
RESTRICT_SCHEMA: Dadurch wird ein Schema generell gesperrt für die Verwendung.
CREATE_EXCEPTION: Dadurch wird ein an sich gesperrtes Schema für einen bestimmten Workspace freigegeben.
REMOVE_EXCEPTION: Dadurch wird eine solche Freigabe für einen bestimmten Workspace wieder aufgehoben.
REMOVE_SCHEMA_EXCEPTIONS: Dadurch werden alle über CREATE_EXCEPTION gemachte Freigaben für ein bestimmtes Schema zurückgenommen.
REMOVE_WORKSPACE_EXCEPTIONS: Dadurch werden alle über CREATE_EXCEPTION gemachte Freigaben für einen bestimmten Workspace zurückgenommen.
Alle Freigaben und Sperren über das Package müssen mit COMMIT abgeschlossen werden, um in Kraft zu treten. Wird ein Schema gesperrt, so sind bereits getroffene Workspace-Zuordnungen davon nicht betroffen. Generell freigegebene Schemata verschwinden aus WWW_FLOW_RESTRICTED_SCHEMAS, begrenzt freigegebene jedoch nicht. Mit CREATE_EXCEPTION erzeugte Ausnahmen sind in WWV_FLOW_RSCHEMA_EXCEPTIONS zu finden:
SELECT schema_id, workspace_name FROM APEX_180200.WWV_FLOW_RSCHEMA_EXCEPTIONS;
Die Prozedur REPORT erzeugt nur einen SELECT-Befehl, der die beiden Tabellen verknüpft und gibt diesen SELECT-Befehl über DBMS_OUTPUT aus, nicht jedoch dessen Ergebnis. Der ausgegebene Select lautet (unabhängig vom angemeldeten User):
SELECT a.schema "SCHEMA", b.workspace_name "WORKSPACE"FROM WWV_FLOW_RESTRICTED_SCHEMAS a, WWV_FLOW_RSCHEMA_EXCEPTIONS bWHERE b.schema_id(+) = a.id;
Beispiele:
BEGIN FLOWS_020000.HTMLDB_SITE_ADMIN_PRIVS.UNRESTRICT_SCHEMA(p_schema => 'SCOTT'); COMMIT;END;/
BEGIN FLOWS_020000.HTMLDB_SITE_ADMIN_PRIVS.RESTRICT_SCHEMA(p_schema => 'HAS'); COMMIT;END;/
BEGIN FLOWS_020000.HTMLDB_SITE_ADMIN_PRIVS.CREATE_EXCEPTION (p_schema => 'HAS', p_workspace => 'SCHULUNG'); COMMIT;END;/
BEGIN FLOWS_020000.HTMLDB_SITE_ADMIN_PRIVS.REMOVE_EXCEPTION (p_schema => 'HAS', p_workspace =>'SCHULUNG'); -- oder: FLOWS_020000.HTMLDB_SITE_ADMIN_PRIVS.REMOVE_WORKSPACE_EXCEPTIONS (p_workspace => 'SCHULUNG'); -- oder: FLOWS_020000.HTMLDB_SITE_ADMIN_PRIVS.REMOVE_SCHEMA_EXCEPTIONS (p_schema => 'HAS'); COMMIT;END;/
Diesmal soll es vor allem um einfache Anwendungsbeispiele für die Funktionen REGEXP_LIKE, REGEXP_SUBSTR und REGEXP_REPLACE gehen.
Wenn man sich mit der gewöhnungsbedürftigen Syntax (einen Überblick finden Sie am Schluss) erst einmal vertraut gemacht hat, können reguläre Ausdrücke beim Formatieren und Bereinigen von Tabelleninhalten, bei der Formulierung von komplizierten Check-Constraints u.a sehr gute Dienste leisten.
Ausgangspunkt für die Beispiele ist die folgende Tabelle (s. Anhang), die mit den regexp-Funktionen überprüft, bereinigt und ggf. vor falschen Eingaben geschützt werden sollte:
NAME TELEFON EMAIL PLZ STRASSE Maier +49/012-345678-012 johann.maier@chaos.de 00000 24 a, Langstr. meyer 012-345678-013 peter.meyer@chaos.de a0674 1a,Langstr. G Mayerhöfer 012-345678-014 frank.mayerhoefer@chaos.de 00345 10-11, Langstr. MEYR 012-345678-015 tomas.meyr@chaos.de 19387 16b, Waldgasse Mayer 012-345678016 richard.mayer@chaos.de 11028 22, Richterstr. Müller 012-345678-017 martin.mueller@chaos.de - 235b, Langstr. Mair 012-345678-018 wilhelmine.mair@chaos.de 12345 35a, Langstr. meir 0049/012-345678-019 sabine.meir@chaos.de 12345 101, Langstr. myers 0049-12-345678-029 jeff.myers@chaos.de 03927 10, Schlossallee müller D012-345678-021 kurt.müller2@chaos.de 12098 10 c, Langstr. Hintermeier 012-345678-022 hansi.hintermeier@chaos.de 11937 180, Holzweg MEIER #012-345678023 eva.meier@chaos.de 12346 301, Langstr. mAYR ?49-12-345678-024 klaus.mayr@chaos.de 19207 5d, Gärtnerplatz MILLER 345678025 oscar.miller@chaos.de 1525 10 a, Langstr.
1. Prüfung auf unerwünschte Zeichen mit REGEXP_LIKE
REGEXP_LIKE vergleicht den Suchstring mit einem Muster und gibt true oder false zurück.
REGEXP_LIKE(Suchstring, Muster, Match-Parameter)
Die Angabe des Match-Parameters (siehe Anhang) ist optional.
Fangen wir mit der PLZ-Spalte an, in der nur 5 Ziffern stehen sollen und nichts anderes (wenn die PLZ mit einer 0 anfängt, darf an der 2. Stelle keine stehen):
SELECT name, plz, strasse FROM firma WHERE NOT REGEXP_LIKE(plz, '^0[1-9][0-9]{3}$|^[1-9][0-9]{4}$');
NAME PLZ STRASSE Maier 00000 24 a, Langstr. meyer 0674 1a,Langstr. Mayerhöfer 00345 10-11, Langstr. Müller - 235b, Langstr. meir 12345 101, Langstr. müller 12098 10 c, Langstr. Hintermeier 11937 180, Holzweg mAYR 19207 5d, Gärtnerplatz MILLER 1525 10 a, Langstr.
Erläuterungen:
eckige Klammern schließen eine Auswahl von Zeichen ein, [0-9] steht für die Ziffern von 0 bis 9, (alternative Formulierungen sind \d (ab 10g2) oder [[:digit:]]). Die Zahlen in geschweiften Klammern geben die Anzahl der Wiederholungen an, [0-9]{3} steht für 3 Ziffern. ^ und $ stehen für Anfang und Ende eines Ausdrucks. ^0 passt auf alle Muster, die mit einer 0 anfangen,[0-9]{3}$ auf alle, die mit 3 Ziffern aufhören. Vorsicht: Das Caret-Zeichen ^ hat diese Bedeutung nur, wenn es außerhalb von eckigen Klammern steht. Die Postleitzahlen mit einer Null am Anfang passen auf das Muster ^0[1-9][0-9]{3}$ (hier darf an der 2. Stelle keine 0 vorkommen), alle anderen auf ^[1-9][0-9]{4}$. Die beiden alternativen Muster werden durch das Oder-Zeichen | getrennt.
2. Beseitigung von unerwünschten Zeichen mit REGEXP_REPLACE
Die Oracle-Funktion REGEXP_REPLACE ersetzt das Muster im Suchstring durch den Ersatzstring.
REGEXP_REPLACE(Suchstring, Muster, Ersatzstring, Position, Vorkommen, Match-Parameter)
Die Angabe von Position, Vorkommen und Match-Parameter ist optional.
Die störenden Leerzeichen und Buchstaben in der PLZ-Spalte kann man mittels REGEXP_REPLACE in einem Rutsch entfernen. (Wenn der Ersatzstring leer bleibt, kann man ihn auch weglassen):
UPDATE firma SET plz = REGEXP_REPLACE(plz, '[^0-9]','') WHERE NOT REGEXP_LIKE(plz, '^0[1-9][0-9]{3}$|^[1-9][0-9]{4}$'); 9 Zeilen wurden aktualisiert.
Ein Caret-Zeichen innerhalb eines Klammerausdrucks kehrt die Zeichenauswahl um, [^0-9] steht also für alle Zeichen außer Ziffern, statt [^0-9] kann man auch \D oder [^[:digit:]] schreiben (s. Anhang).
Kontrolle:
SELECT name, plz, strasse FROM firma WHERE not REGEXP_LIKE(plz, '^0[1-9][0-9]{3}$|^[1-9][0-9]{4}$')OR plz IS NULL;
NAME PLZ STRASSE Maier 00000 24 a, Langstr. meyer 0674 1a,Langstr. Mayerhöfer 00345 10-11, Langstr. Müller 235b, Langstr. MILLER 1525 10 a, Langstr.
Diese 5 Felder muss man von Hand korrigieren, bevor man einen Check-Constraint einrichten kann:
UPDATE firma SET plz = ... WHERE name = ...
3. Verwendung von REGEXP_LIKE in Check-Constraints
Nach der Korrektur lässt sich durch Hinzufügen eines check-Constraints sicherstellen, dass in Zukunft keine Buchstaben, Sonder- oder Leerzeichen eingegeben werden:
ALTER TABLE firma ADD CONSTRAINT firma_plz_check CHECK (REGEXP_LIKE(plz, '^0[1-9][0-9]{3}$|^[1-9][0-9]{4}$'));
Ähnlich funktioniert die Einrichtung eines Check-Constraints der e-mail-Adressen, z.B.:
ALTER TABLE firma ADD CONSTRAINT firma_mail_check CHECK(REGEXP_LIKE(email, '^\w+\.\w+@\w+\.de$'));
\w (ab 10g2) steht für alle alphanumerischen Zeichen inklusive "_", + für eine beliebige Anzahl davon. Oracle akzeptiert \w nicht innerhalb der Zeichenlisten in eckigen Klammern. Der Punkt muss durch einen Backslash maskiert werden, weil er sonst als beliebiges Zeichen interpretiert würde. (Nur innerhalb von eckigen Klammern muss man die Metazeichen wie Punkt, Stern und Plus etc. nicht maskieren). Das @ steht für sich selbst. Statt de könnte man auch eine Auswahl angeben: [de|com|org] oder dem User mit \d{2,4} noch freiere Wahl lassen.
Wenn man auch Bindestriche oder ähnliches in den e-mail-Adressen zulassen will, muss man das Muster anders formulieren (dafür kann man Name und Vorname in einem Klammerausdruck unterbringen), z. B.:
^[-._0-9a-zA-Z]+@[-_0-9a-zA-Z]+\.[A-Za-z]{2,4}$'
4. Einfache Extraktion von Teilstrings mit REGEXP_SUBSTR
REGEXP_SUBSTR gibt einem dem Muster entsprechenden Teilstring des Suchstrings aus.
Was vor 10g mitunter komplizierte Kombinationen der Funktionen instr, SUBSTR und length erforderte, läßt sich mit REGEXP_SUBSTR in sehr kurzen Ausdrücken bewerkstelligen.
REGEXP_SUBSTR(Suchstring, Muster, Position, Vorkommen, Match-Parameter)
Die Angabe von Position, Vorkommen und Match-Parameter ist wiederum optional.
Die Sekretärin möchte eine Adressenliste der Mitarbeiter als View erstellen, die folgende Informationen enthalten soll: Vorname, Nachname, PLZ, Straße und Hausnummer.
Die Vornamen kann man aus den e-mail-Adressen extrahieren und mit den Nachnamen verknüpfen:
SELECT INITCAP(REGEXP_SUBSTR(email, '[^.]+')||' '||name) AS Name FROM firma;
Aus johann.maier@chaos.de wird somit Johann Maier u.s.w. ...
[^.] steht für alle Zeichen außer dem Punkt (innerhalb der Klammer steht der Punkt für sich selbst), per default wird der erste Teilstring ausgegeben, der dem Muster entspricht (vorkommen = 1). Wollte man den Nachnamen aus der Adresse holen, so müsste man REGEXP_SUBSTR(email, '[^.@]+',1,2) schreiben, (Position = 1, Vorkommen =2) REGEXP_SUBSTR(email, '[^.@]+',2) dagegen gibt den Vornamen ab dem 2. Zeichen aus (Position = 2, Vorkommen = default =1). Die Oracle-Funktion INITCAP sorgt für Großbuchstaben am Anfang und Kleinschreibung für den Rest.
5. Drehung am Komma mit REGEXP_REPLACE
Die umgedrehte Reihenfolge von Hausnummer und Strasse im amerikanischen Stil läßt sich durch mittels REGEXP_REPLACE umkehren:
SELECT LTRIM(REGEXP_REPLACE(strasse, '([^,]+),([^,]+)','\2 \1')) AS strasse FROM firma;
Langstr. 24 a Langstr. 1a Langstr. 10-11 ......
Das Komma teilt den String in 2 Hälften, die runden Klammern dienen der Gruppierung. [^,]+ steht für ein bis beliebig viele Zeichen mit Ausnahme des Kommas. Durch die negative Formulierung läuft man nicht Gefahr, eine Art von Zeichen zu vergessen, zudem kann man sie für beide Seiten verwenden. Positiv formuliert müsste man das Muster z.B. so schreiben: '([- 0-9a-z]+),([a-zA-Z. ]+)' \1 und \2 sind sogenannte Rückwärtsreferenzen (back references), die sich auf die Gruppierungen im Suchstring beziehen. Der Ausdruck '\2 \1' zieht aus dem Muster die Gruppen 1 und 2 heraus (ohne das Komma), dreht sie um und fügt zwischen beiden ein Leerzeichen ein. Die Oracle-Funktion LTRIM entfernt führende Leerzeichen.
Jetzt können wir die View erstellen:
CREATE OR REPLACE VIEW adressen AS SELECT INITCAP(REGEXP_SUBSTR(email, '[^.]+')||' '||name) AS Name, plz, LTRIM(REGEXP_REPLACE(strasse, '([^,]+),([^,]+)','\2 \1')) AS strasse FROM firma;
SELECT * FROM adressen; NAME PLZ STRASSE Johann Maier 12345 Langstr. 24 a Peter Meyer 12345 Langstr. 1a Frank Mayerhöfer 12345 Langstr. 10-11 .......
6. Aufteilung von Strings in 2 Spalten mit REGEXP_SUBSTR
Die folgende View stellt alle Informationen in getrennten Spalten dar:
CREATE OR REPLACE VIEW adressen AS SELECT INITCAP(REGEXP_SUBSTR(email, '[^.]+')) AS Vorname, INITCAP(name) as Nachname, plz, LTRIM(REGEXP_SUBSTR(strasse, '([^,]+)',1,2)) AS strasse, LTRIM(REGEXP_SUBSTR(strasse, '([^,]+)')) AS Nr FROM firma;
Aus einem String wie z.B. '24 a, Langstr.' extrahiert
REGEXP_SUBSTR(strasse, '([^,]+)',1,2))das 2. Vorkommen des Musters (Strasse), und REGEXP_SUBSTR(strasse, '([^,]+)',1,1)) das 1. Vorkommen (Hausnummer, die beiden Einser können hier auch wegfallen, weil sie der Default sind):
SELECT * FROM adressen; VORNAME NAME PLZ STRASSE NR Johann Maier 12345 Langstr. 24 a Peter Meyer 12345 Langstr. 1a Frank Mayerhöfer 12345 Langstr. 10-11 ....
7. Sortierung von alphanumerischen Einträgen mit REGEXP_SUBSTR
Alle Angestellten, die in der Langstrasse wohnen, möchten eine Fahrgemeinschaft bilden. Der Fahrer hätte gern eine nach Hausnummern geordnete Liste der Namen. Wegen der Buchstaben und Leerzeichen etc. funktioniert der direkte Ansatz nicht, auch wenn man die vorangehenden Leerzeichen mit LTRIM eliminiert:
SELECT name, strasse FROM firma WHERE strasse LIKE '%Lang%' ORDER BY LTRIM(strasse); NAME STRASSE meyer 1a,Langstr. MILLER 10 a, Langstr. müller 10 c, Langstr. meir 101, Langstr. Mayerhöfer 10-11, Langstr. ....
Eine Kombination dieser alphabetischen Sortierung mit der Sortierung nach dem Zahlenteilstring bringt dagegen das erwünschte Ergebnis:
SELECT INITCAP(name) Name, LTRIM(REGEXP_SUBSTR(strasse,'[^,]+')) Nr FROM firma WHERE strasse LIKE '%Lang%' ORDER BY TO_NUMBER(REGEXP_SUBSTR(strasse, '[0-9]+')), LTRIM (strasse);
NAME NR Meyer 1a Miller 10 a Müller 10 c Mayerhöfer 10-11 ....
REGEXP_SUBSTR(strasse, '[0-9]+') extrahiert die erste zusammenhängende Zahl aus dem String,(z.B. 10-11 ' 10) was die Umwandlung mit TO_NUMBER und damit die richtige Sortierung ermöglicht.
8. Entfernung von doppelten Leerzeichen mit REGEXP_REPLACE
Die Ausgabe kann man noch etwas verschönern, indem man die doppelten Leerzeichen in der Hausnummern-Spalte entfernt:
SELECT INITCAP(name) Name, LTRIM(REGEXP_REPLACE(REGEXP_SUBSTR(strasse,'[^,]+'),'( ){2,}', ' ')) Nr FROM firma WHERE strasse LIKE '%Lang%' ORDER BY TO_NUMBER(REGEXP_SUBSTR(strasse, '[0-9]+')), LTRIM (strasse);
NAME NR Meyer 1a Miller 10 a Müller 10 c ....
'( ){2,}' findet Gruppen von mindestens 2 Leerzeichen und ersetzt sie durch eins: ' '. Die runden Klammern dienen nur der Übersichtlichkeit.
9. Formatierung von Ausdrücken mit REGEXP_REPLACE
Die Telefonnummern sollen von Leer-, Sonderzeichen u. ä. befreit werden und folgendes Format erhalten: (+49-12)345-6789-029. Die zu bereinigenden Einträge findet man mit:
SELECT telefon FROM firma WHERE REGEXP_LIKE(telefon, '[^-0-9]');
TELEFON +49/012-345678-012 0049/012-345678-019 0049-12-345678-029 D012-345678-021 012-345678-022 #012-345678023 ?49-12-345678-024
[^-0-9] steht für alles außer Bindestrich und Ziffern. Mit REGEXP_REPLACE kann man so alle Zeichen außer den Ziffern entfernen, indem man den Ersatzstring einfach wegläßt.:
UPDATE firma SET telefon = REGEXP_REPLACE(telefon, '[^0-9]'); 14 Zeilen wurden aktualisiert
Für die Formatierung gibt es 2 Möglichkeiten:
a) Verwendung der Oracle-SUBSTR-Funktion (weil sich nur die Durchwahl ändert):
UPDATE firma SET telefon = '(+49-12)345-678-' || SUBSTR(telefon,-3);
SUBSTR(telefon,-3) startet beim dritten Zeichen von hinten und gibt den Rest aus.
b) Verwendung von REGEXP_REPLACE, komplizierter, aber allgemeingültiger:
UPDATE firma SET telefon = REGEXP_REPLACE(telefon, '(0*49)?(0?12)?(\d{3})(\d{3})(\d{3})', '(+49-12)\3-\4-\5'); Gruppe: 1 2 3 4 5
Hier werden wieder Backreferences verwendet. Die Gruppen von Zeichen, die man umformatieren will, werden durch runde Klammern gekennzeichnet.
Die Gruppen 1 (beliebig viele Nullen gefolgt von 49) und 2 (eine oder keine Null gefolgt von 12) die jeweils ein oder kein Mal vorkommen, werden durch (+49-12) ersetzt, die folgenden 3 Gruppen 3 - 5 mit Bindestrich aneinandergehängt.
Hinweis; Oraclle unterstützt maximal 9 Gruppen (1-9)
Die Säuberung und Formatierung kann man mit einem geschachtelten REGEXP_REPLACE auch in einem Zug erledigen:
ROLLBACK; UPDATE firma SET telefon = REGEXP_REPLACE(REGEXP_REPLACE(telefon,'[^0-9]'), '(0*49)?(0?12)?(\d{3})(\d{3})(\d{3})','(+49-12)\3-\4-\5'); SELECT telefon FROM FIRMA; TELEFON (+49-12)345-678-012 (+49-12)345-678-013 (+49-12)345-678-014 (+49-12)345-678-015
10. Suche nach Wörtern mit verschiedener Schreibweise über REGEXP_LIKE:
Angenommen, die Tabelle hätte 100000 Datensätze und wir wollen alle Angestellten suchen, die Maier oder so ähnlich heißen, unabhängig von Groß- und Kleinschreibung und Schreibweise:
SELECT name FROM firma WHERE REGEXP_LIKE (name, '^m[ae][yi].?r$','i');
Hier wird nach einem m am Anfang, gefolgt von a oder e, gefolgt von y oder i gefolgt von 0-1 weiteren Buchstaben und einem r am Schluss gesucht. Der Parameter 'i' steht für case insensitive.
Zusammenfassung der wichtigsten Metazeichen und ihrer Bedeutung:
Der Punkt steht für ein beliebiges Zeichen (ausser einen Zeilenumbruch). eckige Klammern stehen für eine Auswahl von Zeichen, [g-l] z. B. für g, h, i, j, k oder l [0-9A-G] für eine beliebige Ziffer oder einen Großbuchstaben von A bis G . Statt die Zeichenauswahl explizit anzugeben, kann man mit den sog. Charakterklassen arbeiten. Die wichtigsten sind: [:alnum:] alle alphanumerischen Zeichen, [[:alnum:]] entspricht also [0-9A-Za-z] \w alle alphanumerischen Zeichen und der Unterstrich "_" [:alpha:] alle Buchstaben, [[:alpha:]] entspricht [A-Za-z] [:digit:] bzw. \d alle Ziffern, [[:digit:]] entspricht [0-9] [:space:] bzw. \s alle Zeichen, die man nicht sieht, Leerzeichen, Tabzeichen, Enter... \W, \D und S\ sind die Umkehrungen von \w, \d und \s Die Abkürzungen \d, \w etc. stehen seit Version 10.2 zur Verfügung. Das pipe-Symbol | bedeutet "oder", z.B. [ae|ä], [Otto|Emma], etc. Das Dollarzeichen $ verankert das vorausgehende Zeichen am Ende einer Zeile bzw. des Suchstrings, 'r$' passt z.B. auf 'Müller' oder 'Herr', aber nicht zu 'rau' oder 'Karren' Das Caret-Zeichen ^ hat je nachdem, wo es steht, unterschiedliche Bedeutungen ein Caret-Zeichen außerhalb eckiger Klammern verankert das nachfolgende Zeichen am Beginn einer Zeile bzw. des Suchstrings ('^z.*' passt auf 'ziel', 'zeichen' etc, aber nicht auf 'platz', 'setzen') ein Caret-Zeichen innerhalb eckiger Klammern schließt die nachfolgenden Zeichen aus. dementsprechend bedeutet: ^[:alnum:]] alle nicht-alphanumerischen Zeichen (Sonderzeichen, Leerzeichen...) [^0-9] alles ausser Ziffern Der Stern * steht für keine oder beliebig viele Wiederholungen des vorausgehenden Elements (Zeichen oder Gruppe), '.*' passt also auf jeden String Das Fragezeichen ? steht für keine oder eine Wiederholung Das Pluszeichen + steht für eine oder beliebig viele Wiederholungen {n} steht für n Wiederholungen {min,max} steht für min bis max Wiederholungen des Elements , {3,6} z. B für 3 bis 6, {3,} für mindestens 3
Außerhalb von eckigen Klammern bzw. in Kombinationen mit Charakterklassen muss man den Metazeichen einen Backslash voranstellen, wenn man explizit nach ihnen sucht,
z.B. \+, \?, \* etc.
Match-Parameter für die Oracle-REGEXP-Funktionen:
i (case insensitive) Groß- und Kleinschreibung wird nicht berücksichtigt c (case sensitive) Groß- und Kleinschreibung wird berücksichtigt n (newline) Der Punkt kann in diesem Fall auch für einen Zeilenumbruch stehen. m (multiline) Die Zeichenkette wird als mehrzeilige Eingabe betrachtet.^und $ können dann auf jede Zeile angewandt werden und nicht nur für Anfang und Ende des Strings.
Mit dem folgenden SQL-Code können Sie sich die Übungstabelle selbst erstellen:
DROP TABLE firma; CREATE TABLE firma( name VARCHAR2(20), telefon VARCHAR2(20), email VARCHAR2(30), plz VARCHAR2(10), strasse VARCHAR2(50)); INSERT INTO firma VALUES ('Maier','+49/012-345678-012','johann.maier@chaos.de','00000','24 a,Langstr.'); INSERT INTO firma VALUES ('meyer','012-345678-013','peter.meyer@chaos.de','a0674','1a,Langstr. '); INSERT INTO firma VALUES ('Mayerhöfer','012-345678-014','frank.mayerhoefer@chaos.de','00345','10-11,Langstr.'); INSERT INTO firma VALUES ('MEYR','012-345678-015','tomas.meyr@chaos.de','19387','16b,Waldgasse'); INSERT INTO firma VALUES ('Mayer','012-345678016','richard.mayer@chaos.de','11028',' 22,Richterstr.'); INSERT INTO firma VALUES ('Müller','012-345678-017','martin.mueller@chaos.de','-','235b,Langstr.'); INSERT INTO firma VALUES ('Mair','012-345678-018','wilhelmine.mair@chaos.de','12345',' 35a,Langstr.'); INSERT INTO firma VALUES ('meir','0049/012-345678-019','sabine.meir@chaos.de',' 12345','101,Langstr.'); INSERT INTO firma VALUES ('myers','0049-12-345678-029 ','jeff.myers@chaos.de','03927','10,Schlossallee'); INSERT INTO firma VALUES ('müller','D012-345678-021','kurt.müller2@chaos.de','12098 ','10 c,Langstr.'); INSERT INTO firma VALUES ('Hintermeier',' 012-345678-022','hansi.hintermeier@chaos.de',' 11937','180,Holzweg '); INSERT INTO firma VALUES ('MEIER','#012-345678023','eva.meier@chaos.de','12346','301,Langstr.'); INSERT INTO firma VALUES ('mAYR','?49-12-345678-024','klaus.mayr@chaos.de',' 19207','5d,Gärtnerplatz ');
Das neue Oracle APEX 20.1 hat uns ja wieder mit vielen neuen Funktionen überrascht. Eines davon ist die autoamtische Backup-Funktionalität.Nur leider ist diese sehr wenig konfigurierbar.Sie können einstellen, wieviele Backups pro APP behalten werden sollen.Der Default sind 25 Backups pro App
=>25Ändern können Sie die Anzahl mittels:
Eine Übersicht der bereits existierenden Backups erhalten Sie durch:
Für die nächtlichen Backup verantwortlich, ist der Job mit Namen wwv_flow_backup.main:
Dieser läuft jede Nacht um 02:00 UhrSie können jedich auch manuell ein Backup erstellen durch:
Auch können Backup manuell gelöscht werden (Hier die Appliaktionen 11000 und 11020:
Oder alternativ löschen wir alle APEX Backups, die älter als 100 Tage sind:
Weitere Tipps und Tricks zu APEX 20.1 und APEX 20.2 erhalten Sie natürlich in einen unserer 6 verschiedenen APEX-Kurse... Online oder bei uns Vorort
Nachdem das Thema REST immer mehr an Schwung gewinnt, wird es Zeit darüber einen Tipp zu schreiben.Wir haben aus eigener Erfahrung lange im Internet gesucht und nur selten etwas gefunden.Deswegen haben wir ein paar Beispiele gesammelt:Der Einfachheit halber, wird mit nicht mit SSL Verschlüsselung gearbeitet, ansonsten muss noch ein Wallet eingerichtet werden1. CLOB Übertragen (upload)
l_clob:=APEX_WEB_SERVICE.MAKE_REST_REQUEST( p_url=>'http://www.muniqsoft-training.de/ords/my_rest/muso/putCLOB', p_http_method =>'PUT', p_transfer_timeout =>720, p_username =>'rest_user', p_password =>'rest_password' p_body =>text_lob, --CLOB Datentyp übertragen );
Auf dem Zielserver dann einen Rest-Service anlegen (Typ PUT):
BEGIN my_proc(:body_text);END;
Die Procedure my_proc könnte dann wie folgt aussehen:
CREATE OR REPLACE PROCEDURE my_proc (p_clob IN CLOB)IS...BEGIN...END;
2. BLOB übertragen (upload)
l_clob:=APEX_WEB_SERVICE.MAKE_REST_REQUEST( p_url=>'http://www.muniqsoft-training.de/ords/my_rest/muso/putBLOB', p_http_method =>'PUT', p_transfer_timeout =>720, p_username =>'rest_user', p_password =>'rest_password' p_body_blob =>pdf_lob, --BLOB Datentyp übertragen );
BEGINmy_proc(:body);END;
CREATE OR REPLACE PROCEDURE my_proc (p_blob IN BLOB)IS...BEGIN...END;
3. Zwei Parameter übertragen (Upload)
DECLAREl_clob CLOB;BEGIN apex_web_service.g_request_headers.delete(); apex_web_service.g_request_headers(1).name := 'Content-Type'; apex_web_service.g_request_headers(1).value := 'application/octet-stream'; --'application/x-www-form-urlencoded'; apex_web_service.g_request_headers(2).name := 'PARAMETER_A'; apex_web_service.g_request_headers(2).value := '12345'; apex_web_service.g_request_headers(3).name := 'PARAMETER_B'; apex_web_service.g_request_headers(3).value := to_char(sysdate,'DD.MM.YYYY');l_clob:=APEX_WEB_SERVICE.MAKE_REST_REQUEST( p_url=>'http://www.muniqsoft-training.de/ords/my_rest/muso/putDATA', p_http_method =>'PUT', p_transfer_timeout =>180, p_username =>'rest_user', p_password =>'rest_passwort', p_body =>my_clob_text); if apex_web_service.g_status_code = 200 then dbms_output.put_line('Übertragung erfolgreich abgeschlossen.'); else dbms_output.put_line('Fehler aufgetreten: ' || apex_web_service.g_status_code); end if;END;
Auf dem Zielserver dann wieder ein REST Service anlegen (TYP: PUT)
BEGIN:status:=my_func(p_parameter1=>:PARAMETER_A,p_parameter1=>:PARAMETER_A,p_clob=>:BODY_TEXT);END;
REST Parameter:
Die Funktion könnte dann wie folgt aussehen:
CREATE OR REPLACE FUNCTION my_func(p_parameter1 IN VARCHAR2,p_parameter2 IN VARCHAR2,p_clob IN CLOB) RETURN VARCHAR2ISBEGIN...RETURN 200;EXCEPTION WHEN OTHERS THEN RETURN 500;END;
Manchmal ist es sehr nützlich, herauszufinden auf welchem Server man gerade arbeitet. Dann kann man z.B. auf einem Testserver eine andere Seiten-Region ausgeben, als auf dem Produktivserver.Leider funktioniert der Tipp nur innerhalb von APEX und nicht via SQL*Plus, SQL Developer oder anderen Tools:
Gehen Sie daher in APEX und erstellen Sie eine Dynamische PL/SQL Content Region in APEX und legen Sie dort folgenden Code ab:
Nun wird beim Aufbau der Seite z.B. folgende Ausgabe erscheinen:
REMOTE_IDENT =REMOTE_USER = APEX_PUBLIC_USERhost = 172.30.30.230:8080user-agent = Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0accept = text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8accept-language = de,en-US;q=0.7,en;q=0.3accept-encoding = gzip, deflatereferer = http://172.30.30.230:8080/connection = keep-alivecookie =upgrade-insecure-requests = 1APEX_LISTENER_VERSION = 21.4.1.r0250904DAD_NAME =DOC_ACCESS_PATH =DOCUMENT_TABLE =GATEWAY_IVERSION = 3GATEWAY_INTERFACE = CGI/1.1HTTP_ACCEPT = text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8HTTP_ACCEPT_ENCODING = gzip, deflateHTTP_ACCEPT_LANGUAGE = de,en-US;q=0.7,en;q=0.3HTTP_ACCEPT_CHARSET =HTTP_IF_MODIFIED_SINCE =HTTP_IF_NONE_MATCH =HTTP_HOST = 172.30.30.230:8080HTTP_ORACLE_ECID =HTTP_PORT = 8080HTTP_REFERER = http://172.30.30.230:8080/HTTP_USER_AGENT = Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0PATH_ALIAS =PATH_INFO = /rest-template-erstellungPLSQL_GATEWAY = WebDbQUERY_STRING = session=1647342785893REMOTE_ADDR = 172.30.30.30REQUEST_CHARSET = AL32UTF8REQUEST_IANA_CHARSET = UTF-8REQUEST_METHOD = GETREQUEST_PROTOCOL = httpREQUEST_SCHEME = httpSCRIPT_NAME = /ords/scott/r/oracle-restSCRIPT_PREFIX =SERVER_NAME = 172.30.30.230SERVER_PORT = 8080SERVER_PROTOCOL = HTTP/1.1SERVER_SOFTWARE = Mod-ApexWEB_AUTHENT_PREFIX =X-APEX-METHOD = GETX-APEX-BASE = http://172.30.30.230:8080/ords/scott/X-APEX-PATH = r/oracle-rest/rest-template-erstellung?session=1647342785893X-APEX-REMOTE-ADDRESS = 172.30.30.30X-APEX-CHARSET = UTF-8HTTP_COOKIE =
Damit kann man nun in einer Condition wunderbar arbeiten, z.B. mit einer Exists SQL Query
Weitere Tipps und Tricks erfahren Sie in einem unserer APEX Kurse in Unterhaching bei München.
Wenn Sie sich mal im Internal Workspace ausgetobt haben und dabei einige Parameter so verstellt worden sind, dass man sich nicht mehr anmelden kann, hilft Ihnen evtl. der folgende Tipp.
Auch lassen sich viele schöne APEX Einstellungen über ein kleines Skript schneller umsetzen, als die jeweilige Option wieder grafisch in einem der Untermenues zu finden.
Die Quelle alle internen Parameter ist die Tabelle wwv_platform_prefs;
Wir wollen mal zwei interessante Parameter herausgreifen:Der erste verhindert ein anmelden am INTERNAL Workspace:
Der zweite stellt die Idle Time auf 4800 Sekunden um:
Mit folgenden Select können Sie für einen Parameter den aktuellen Inhalt hoch offiziell auslesen:
Viel Spass beim Ausprobieren und ich hoffe wir sehen uns in einem unserer schönen APEX Kurse:-)
Im heutigen Tipp beschäftigen wir uns mit der Installation von ORDS 18.4 unter Windows 10.
Folgende Schritte werden zur Installation durchgeführt:
1. Herunterladen der aktuellen Version (Download vom Oracle Server)2. Auspacken in den Ordner c:\oracle\ords (oder einen beliebig anderen)3. Sehen Sie sich die Oracle Datenbank Parameter db_domain,service_names,instance_name an:
show parameter db_domainshow parameter service_namesshow parameter instance_name
4. Lassen Sie sich die Listener-Daten der Oracle Datenbank anzeigen:
lsnrctl status
5. Laden Sie sich eine aktuelle Java Version runter (Wir verwenden aus Protest zur neuen Lizenzbestimmung von Oracle das Open JDK:Download)
6. Besorgen Sie sich den images Ordner aus einer APEX Installation
7. Nun wird die Installation gestartet und interaktiv ausgeführt:
C:\Oracle\ords>C:\Oracle\Java\jdk-11.0.2\bin\java -jar ords.war
Diese Oracle REST Data Services-Instanz wurde noch nicht konfiguriert.
Nehmen Sie an den folgenden Prompts die entsprechenden Einstellungen vor
Geben Sie den Speicherort für Konfigurationsdaten ein:c:\oracle\ords_conf
Name des Datenbankservers eingeben [localhost]:myserver
Listener-Port der Datenbank eingeben [1521]:
1 eingeben, um den Servicenamen der Datenbank anzugeben, oder 2, um die Datenbank-SID anzugeben [1]:
Datenbankservicename eingeben:XE
Datenbankkennwort für ORDS_PUBLIC_USER eingeben:
Kennwort bestätigen:
Geben Sie 1 ein, wenn Sie das PL/SQL-Gateway verwenden möchten, oder 2, um diesen Schritt zu überspringen.
Wenn Sie Oracle Application Express verwenden oder eine Migration von mod_plsql durchführen, müssen Sie 1 eingeben [1]:
Datenbankkennwort für APEX_PUBLIC_USER eingeben:
Geben Sie 1 ein, um Kennwörter für Application Express RESTful Services-Datenbankbenutzer anzugeben (APEX_LISTENER, APEX_REST_PUBLIC_USER), oder 2, um diesen Schritt zu überspringen [1]:
Datenbankkennwort für APEX_LISTENER eingeben:
Datenbankkennwort für APEX_REST_PUBLIC_USER eingeben:
Feb. 28, 2019 7:53:53 VORM.
INFO: reloaded pools: []
Geben Sie 1 ein, wenn Sie im Modus "Standalone" starten möchten, oder 2 zum Beenden [1]:
Geben Sie das Speicherot der statischen APEX-Ressourcen ein:C:\Oracle\ords\images
Geben Sie 1 ein, wenn Sie HTTP verwenden, oder 2, wenn Sie HTTPS verwenden [1]:2
Geben Sie den HTTPS-Port ein [8443]:
Geben Sie den SSL-Hostnamen ein:dozent4
Geben Sie 1 ein, um das selbstsignierte Zertifikat zu verwenden, oder 2, wenn Sie das SSL-Zertifikat angeben [1]:
Danach sollte der ORDS Listener starten und kann mit CTRL-Z abgebrochen werden. Achtung das Beenden des DOS Fenster stoppt auch den ORDS Listener!
Bei Problemen:
Man sollte zwei Parameter in die Datei defaults.xl (im ords_conf Ordner) einsetzen und durchstarten
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"><properties><comment>Saved on Thu Feb 28 07:53:53 CET 2019</comment><entry key="db.hostname">DOZENT4</entry><entry key="db.port">1521</entry><entry key="db.servicename">XE.ad.muniqsoft-training.de</entry><entry key="security.requestValidationFunction">wwv_flow_epg_include_modules.authorize</entry><entry key="security.validationFunctionType">plsql</entry><entry key="debug.debugger">true</entry><entry key="debug.printDebugToScreen">true</entry><entry key="error.keepErrorMessages">true</entry><entry key="error.maxEntries">100</entry></properties>
Weitere Tipps erhalten Sie in unserem APEX II Kurs.
Haben Sie sich auch schon mal gefragt, wie man seine schönen APEX Applikationen sichert?
Ja natürlich, Sie können das über die grafische Oberflächen machen. Aber zeitgesteuert, nachts um 3.00 Uhr zusammen mit der Datenbank?Na, dann stellen Sie mal den Wecker... oder verwenden Sie den folgenden Tipp:
Erst schauen wir mal, welche schönen APEX Applikationen wir haben:
Als ersten Schritt, können wir eine Applikation über deren Nummer in ein Directory exportieren. APEX liefert schon über eine Routine die komplette App als CLOB zurück. Jetzt musste nur noch ein Package her, welches CLOB´s direkt in das Betriebssystem schreibt. Fündig geworden bin ich im Package DBMS_XSLPROCESSOR.CLOB2FILE.Das spart einem viele lästige Schritte :-)
Wir verwenden hier das DATA_PUMP_DIR Directory zum Schreiben, weil das meistens schon vorhanden ist. Sie können jedoch auch jedes andere Verzeichnis benutzen.Vergeben Sie das Schreibrecht am Directory an den Benutzer, der den Export ausführt (dem sollte auch die APEX Applikation gehören).
APEX App exportieren:
Im zweiten Beispiel werden alle APEX Apps gesichert, die sich in den letzten 24 Stunden geändert haben. Führen Sie den Export z. B. als System durch (NICHT als SYS):
Nun wollen wir Seiten einzeln sichern, aber erst schauen wir mal, wann es Änderungen in den Seiten gab:
Nun können wir prüfen, welche Seiten in den letzten 30 Tage geändert wurden:
Zu guter Letzt ein Beispiel als automatischer Export aller Seiten, die sich in den letzten 30 Tagen geändert haben:
Wenn Sie APEX nicht durch mühsames Probieren selbst erlernen wollen, kommen Sie doch in eine unserer beiden 5 Tages-Schulungen.
Bei manchen (äh fast allen) Applikationen gibt es die geliebten ReadMe (RTFM) Dateien. Jeder von uns liest diese Dateien natürlich ordnungsgemäß komplett von vorne bis hinten durch. :-)
Sollten durch die Installation einer Applikation diverse Initialisierungsparameter auf bestimmte Werte gesetzt werden müssen, könnte man dem Benutzer folgenden kleinen SQL-Befehl (natürlich angepasst an Ihre Wünsche) mitgeben:
Beispielempfehlung für die Installation von Apex 5.1/18.x mit dem EPG Gateway auf Oracle 12.x/18.x Datenbanken:
SELECT * FROM ( SELECT name, nvl(display_value,'NULL') as Wert, CASE WHEN name='db_create_file_dest' THEN (select substr(name,1,instr(name,'\',-1)-1) FROM v$datafile where rownum=1) WHEN name='shared_servers' THEN '>=10 bei EPG' WHEN name='max_shared_servers' THEN '>=20 bei EPG' WHEN name='job_queue_processes' THEN '>=10' WHEN name='session_cached_cursors' THEN '>=100' WHEN name='sga_max_size' THEN '>=550M' WHEN name='sga_target' THEN '>=550M' WHEN name='dispatchers' THEN (select'(PROTOCOL=TCP) (SERVICE='||value ||'XDB) (DISPATCHERS=3)' from v$parameter where name='instance_name') WHEN name='audit_trail' THEN 'db,extended oder xml,extended' END as empfehlung FROM v$parameter) WHERE empfehlung IS NOT NULL;
Ausgabe:
NAME Wert EMPFEHLUNG---------------------- ------ ----------------------------------------sga_max_size 440M >=350Msga_target 440M >=350Mdb_create_file_dest NULL C:\ORACLE\PRODUCT\10.2.0\ORADATA\O10Gdispatchers NULL (PROTOCOL=TCP)(SERVICE=o10gXDB) (DISPATCHERS=3)shared_servers 0 >=5 max_shared_servers NULL >=20 session_cached_cursors 20 >=50 job_queue_processes 10 >5audit_trail NONE db,extended oder xml,extended
Oder Sie basteln dem Benutzer ein Skript, das die Parameter gleich selber umsetzt:
SELECT * FROM ( SELECT CASE WHEN name='db_create_file_dest' THEN (select 'ALTER SYSTEM SET db_create_file_dest=' ||substr(name,1,decode(instr(name,'\'),0, instr(name,'/',-,2),instr(name,'\',-1,2))-1) ||';' from v$datafile where rownum=1) WHEN name='shared_servers' THEN 'ALTER SYSTEM SET shared_servers=5;' WHEN name='max_shared_servers' THEN 'ALTER SYSTEM SET max_shared_servers=20;' WHEN name='job_queue_processes' THEN 'ALTER SYSTEM SET job_queue_processes=10;' WHEN name='session_cached_cursors' THEN 'ALTER SYSTEM SET session_cached_cursors=50;' WHEN name='sga_max_size' THEN 'ALTER SYSTEM SET sga_max_size=350M SCOPE=SPFILE;' WHEN name='sga_target' THEN 'ALTER SYSTEM SET sga_target=350M SCOPE=SPFILE;' WHEN name='dispatchers' THEN (select 'ALTER SYSTEM SET dispatchers= (PROTOCOL=TCP)(SERVICE='|| value || 'XDB) (DISPATCHERS=3) scope=spfile;' from v$parameter where name='instance_name') WHEN name='audit_trail' THEN 'ALTER SYSTEM SET audit_trail='||chr(39)|| 'db,extended'||chr(39)||'scope=spfile;' END as empfehlung FROM v$parameter) WHERE empfehlung IS NOT NULL;
ALTER SYSTEM SET sga_max_size=350M SCOPE=SPFILE;ALTER SYSTEM SET sga_target=350M SCOPE=SPFILE;ALTER SYSTEM SET db_create_file_dest=/opt/oracle/oradata;ALTER SYSTEM SET dispatchers=(PROTOCOL=TCP) (SERVICE=orclXDB) (DISPATCHERS=3) scope=spfile;ALTER SYSTEM SET shared_servers=5;ALTER SYSTEM SET max_shared_servers=20;ALTER SYSTEM SET session_cached_cursors=50;ALTER SYSTEM SET job_queue_processes=10;ALTER SYSTEM SET audit_trail='db,extended' scope=spfile;
Natürlich können Sie die Parameterempfehlungen mit Ihren eigenen Wünschen optimieren.
Auch ganz praktisch ist Netzwerk und Konfig Check, der (fast) alles beinhaltet:SELECT * FROM (SELECT 1,'Username' as Info1, 'Account Status' as Info2,'Lock Date' as Info3, 'Expirary Date' as Info4 FROM dualUNION ALLSELECT 2,'------------','---------------','--------------','------------------' FROM dualUNION ALLSELECT 3,u.username,u.account_status,to_char(u.lock_date,'DD.MM.YY HH24:MI'),to_char(u.EXPIRY_DATE,'DD.MM.YY HH24:MI')FROM dba_users uWHERE (u.username IN ('ANONYMOUS','FLOWS_FILES')OR u.username LIKE 'APEX%'OR u.username LIKE 'ORDS%') AND u.username<>'ORDSYS'UNION ALLSELECT 4,'#################','#############','#############','#################' FROM dualUNION ALLSELECT 5,'COMPO_NAME','VERSION','Status','Modified' FROM dualUNION ALLSELECT 6,'------------','---------------','--------------','------------------' FROM dualUNION ALLSELECT 7,replace(comp_name,'Oracle ',''),version,status,modifiedFROM dba_registryWHERE comp_id='APEX'UNION ALLSELECT 8,'#################','#############','#############','#################' FROM dualUNION ALLSELECT 9,'HTTP Port','FTP Port','Image Count','Allow Anonymus Repo Access'FROM dualUNION ALLSELECT 10,'------------','---------------','--------------','------------------' FROM dualUNION ALLSELECT 11,to_char(dbms_xdb.gethttpport ),to_char(dbms_xdb.getftpport),(SELECT count(*)||' ' FROM PATH_VIEWWHERE UNDER_PATH(res, '/images/',1)>0),(select extractValue(dbms_xdb.cfg_get(), '/xdbconfig/sysconfig/protocolconfig/httpconfig/allow-repository-anonymous-access') from dual) FROM dualUNION ALLSELECT 12,'#################','#############','#############','#################' FROM dualUNION ALLSELECT 14,'Workspace','Username','Admin/Dev','Account Locked' FROM dualUNION ALLSELECT 15,'#################','#############','#############','#################' FROM dualUNION ALLSELECT 16,workspace_display_name,user_name,is_admin||'/'||is_application_developer,account_lockedFROM apex_workspace_developersUNION ALLSELECT 17,'Parameter','Value','--------------','------------------' FROM dualUNION ALLSELECT 18,'------------','---------------','--------------','------------------' FROM dualUNION ALLSELECT 19,name,value,null,null from v$parameter where name in ('local_listener','session_cached_cursors')UNION ALLSELECT 20,'#################','#############','#############','#################' FROM dualUNION ALLSELECT 21,'DAD Names','-----------','--------------','------------------' FROM dualUNION ALLSELECT 22,'------------','---------------','--------------','------------------' FROM dualUNION ALLSELECT 23, u.dad ,null,null,null FROM XMLTable(XMLNAMESPACES (DEFAULT 'http://xmlns.oracle.com/xdb/xdbconfig.xsd' ),'//servlet-list/*[servlet-language="PL/SQL"]' PASSING DBMS_XDB.CFG_GET()COLUMNS DAD varchar2(15) PATH '/servlet/servlet-name/text()') u)ORDER BY 1,2;
Diese und noch viele weitere Tricks lernen Sie in einem unserer schönen APEX Kurse!
Wenn Sie die APEX Version 19.2 (Stand November 2020) in die kostenlose Oracle XE Datenbank Version 18c installieren möchten, gehen Sie bitte wie folgt vor:
Laden Sie sich zuerst APEX und die Oracle Expres (XE) Version 18c herunter.
Für LINUX verwenden wir den Installationspfad /u01/software. Dort sollte dann die APEX Zipdatei ausgepackt liegen
Für die Installation APEX starten Sie:
Sie können für APEX bei Bedarf einen eigenen Tablespace anlegen, oder den SYSAUX Tablespace verwenden.
Nun starten wir das APEX Installations-Hauptskript:
oder der bereits vorhandene SYSAUX Tablespace kommt zum Einsatz:
Wenn Die Datenbank als Webserver Ersatz verwendet werden soll, starten Sie bitte folgendes Skript:Hinweis: Der Schritt ist nicht nötig, wenn mit dem ORDS (Apache TomCat, Glassfish, Bea Weblogic oder ORDS Standalone gearbeitet wird)
Dies legt einen DAD an und lädt alle Bilder/CSS und JS Dateien in die Datenbank (in die Tabelle xdb$resource)
dann wird noch der Datenbank Benutzer ANONYMOUS entsperrt:
Hinweis: Der Schritt ist nicht nötig, wenn mit dem ORDS (TomCat, Glassfish, Bea Weblogic oder ORDS Standalone gearbeitet wird)
Wenn Sie einen speziellen Port für den HTTP Zugriff benötigen, können Sie das auch noch ändern:
Das letzte Skript setzt das Passwort für INTERNAL Workspace ADMIN Benutzer fest.
Sie werden 3 Parameter gefragt:
Das letzte Problem (Passwortkomplexität) kann man aber umgehen, wenn man zuvor den folgenden Befehl laufen lässt:
Zusätzlich wird die REST Schnittstelle benötigt, die man für alle REST Aufgaben uns auch die Application und Workspace Files benötigt:
Nun können Sie sich anmelden:
Legen Sie sich zuerst einen Workspace mit einem Administrationsbenutzer an.Hinweis: Seit April 2020 ist die Version 20.1 bereits verfügbar.
Zu einem guten APEX-Projekt gehört auch ein gutes Backup-Konzept. Sie möchten ja keine Ihrer wichtigen Projektänderungen verlieren oder?
Schön wäre es, wenn dies auch noch automatisch erfolgen würde, also legen wir gleich mal los:
Voraussetzungen:
1. Sie haben ein Oracle Directory angelegt (wir nehmen hier mal das Directory DATA_PUMP_DIR, das ist meistens schon vorhanden)Sonst legen Sie ein neues Directory an mittels:
2. Der Benutzer, der den Export durchführt, hat mindestens Schreibrechte auf dem Directory. Sonst vergeben Sie ihm die Rechte bitte durch:
Beispiel 1: Sicherung aller Apps mit ID<3000, die sich in den letzten 24 Stunden geändert haben
Weitere interessante Parameter des Packages wwv_flow_utilities.export_application_to_clob:
Beispiel 2: Einzelne APEX Seite exportieren:
Beispiel 3: Alle Seiten exportieren, die sich in den letzten 24 Stunden geändert haben:
Beispiel 4: Workspace Export (Achtung, der exportiert keine APEX Apps)
Beispiel 5: Workspace Dateien exportieren:
Für weitere Tipps & Tricks besuchen Sie doch einen unserer APEX Kurse (APEX I, APEX II, APEX Security, APEX für Admins oder Neuerungen in 19.x/20x) .
In Oracle Application Express (APEX) kann man BLOBs über „Formulare“ in die Datenbank abspeichern oder über „Reporte“ aus der Datenbank herausladen und Bilder anzeigen lassen.
Hier wird erklärt, wie man vorgehen könnte.
Voraussetzung:
Zuerst wird in APEX eine leere Seite vom Type „Report“ mit der Vorlage „Report with Form on Table“ erstellt:
Dann werden für den Report von der Tabelle LOAD_BLOB die Spalten BLOB_ID, ATTACH_FILENAME und DOCUMENT (Blob) ausgesucht.
Nach dem Next werden für das Formular „Select Primary Key“ (BLOB_ID) und alle Spalten gewählt. Außerdem benötigt man die „Existing Sequence“ SQ_LOAD_BLOB.
Weil die BLOB-Attribute Mime-Type, Filename, Last Updated und Character-Set im Hintergrund mit abgespeichert werden, werden die Items, die beim Erstellen des Formulars angelegt wurden und die diese Attribute beinhalten sollen, auf „Display Only“ gesetzt, so dass man sieht, was abgespeichert wird:
(Bitte passen Sie P58, das hier für Seite 58 steht, entsprechend an.)
P58_ATTACH_FILENAME: Type: Display OnlyP58_ATTACH_MIMETYPE: Type: Display OnlyP58_ATTACH_LAST_UPDATE: Type: Display OnlyP58_ATTACH_CHARSET: Type: Display Only
Das Item P58_DOCUMENT ist vom Type “File Browse...“, so dass man darüber die entsprechende Datei, die ins BLOB geladen werden soll, auswählen kann.
Folgende Settings sind für dieses Item noch notwendig:
Automatisch werden vom Assistent der Pre-Rendering-Prozess “Fetch Row from LOAD_BLOB”, sowie die Prozesse „Process Row of LOAD_BLOB“, “Get PK” und “reset page” angelegt.
Nun wird die SQL-Query vom Source im Report angepasst:
Bei diesem Statement wird ein Bild vom Type „image“, wie z. B. bei einer png- oder jpg-Datei, als Bild im Report dargestellt. Dagegen werden Dokumente wie pdf-, powerpoint-, word- oder excel-Dateien mit einem eigenen Bild abgebildet. Diese Dateien (application-pdf.png, PowerPoint.ico, docx.png, Excel.ico, zip-icon.png) werden vorher in „Shared Components“ über „Static Application Files“ in Apex hochgeladen und so der Anwendung zur Verfügung gestellt
Wichtig ist außerdem, dass man bei der Spalte Application in Security die „Escape special characters“ auf „No“ setzt, da man sonst nur HTML und nicht die Bilder sieht.
Die Spalte DOCUMENT ist vom Type „Download BLOB“ und man kann über diesen Download-Link in der Spalte die jeweilige Datei aus dem BLOB-Feld herausladen.
Die „BLOB_ID“-Spalte im Report könnte man „Hidden“ stellen.
Über das Pencil-Icon im Report kann man nun im Formular den zugehörigen Datensatz sehen bzw. löschen. Der „Create“-Button im Report leert das Formular, so dass man dort einen neuen Datensatz mit einer Datei im BLOB-Feld anlegen kann.
Hinweis:
Wenn man einen Datensatz in der Form-Region löscht, kann es passieren, dass die Session die BLOB_ID weiterhin speichert, obwohl der Datensatz nicht mehr existiert, dadurch kann es zu einem ORA-1403 „No Data found“ kommen.
Deshalb ist es ratsam, einen Pre-Rendering-Prozess vom Type „Clear Session State“, Point: „Before Header“ anzulegen, um alle Items auf der Seite zu löschen.
Viele weitere Informationen, Erklärungen und Beispiele erhalten Sie in unseren APEX Kursen! Schauen Sie doch einfach mal vorbei!
Es war ein schönes Weihnachtsgeschenk der Oracle APEX-Entwickler: Die heiß ersehnte Application Express Version 5.1 wurde am 21. Dezember 2016 veröffentlicht.
APEX 5.1 bietet u. a. diese neuen Features:
Nun geht es natürlich darum, sich mit den Neuerungen und erweiterten Funktionen vertraut zu machen und diese in der eigenen Umgebung einzusetzen und zu testen. In diesem Artikel stellen wir einige der wichtigsten Verbesserungen vor.
Um einen ersten Überblick über die neuen Features von APEX 5.1 zu erhalten, lohnt es sich, die neuen sowie überarbeiteten Packaged Apps – in der APEX-Installation enthaltene Beispiel-Anwendungen – zu installieren.
Neu sind die Beispiel-Applikationen "Sample REST Services", "REST Client Assistant" und "Sample Interactive Grids", wobei Letztere das wohl wichtigste Feature der Version 5.1 vorstellt: Die sogenannten Interactive Grids.
Hinter diesem Begriff versteckt sich ein neuer Report-Typ, dessen einzelne Felder ähnlich wie in Excel bearbeitet und modifiziert werden können. Dabei vereint das Interactive Grid die Anpassungsmöglichkeiten des Interactive Reports mit den Optionen der Tabular Form (nun veraltet), in der man Daten direkt auf der Report-Seite hinzufügen, bearbeiten oder löschen kann.
Für Interactive Grids mit Bearbeitungsfunktion können bereits in der Report-Query bestimmte Zeilen der Tabelle geschützt werden: So wird genau festgelegt, auf welchen Datensätzen welche DML-Operationen ("U", "D", "UD") durchgeführt werden dürfen. Geschützte Zeilen werden im Bearbeitungsmodus ausgegraut.
Der Benutzer hat im Interactive Grid nun auch die Möglichkeit, den Report durch Drag & Drop individuell zu gestalten und so beispielsweise die Spaltenreihenfolge und -breite nach Belieben zu definieren. Über das Menü der Spaltenüberschriften kann die Option "Freeze" angewählt werden: Damit fixiert der Benutzer einzelne Spalten rechts im Report, die auch während horizontalen Scrollens immer angezeigt werden.
Für die Definition einer Spalte stehen im Interactive Grid nun übrigens alle Item-Typen (Ausnahme: Rich Text Editor) sowie Item-Plugins zur Verfügung. Mehrere Report-Spalten lassen sich zudem deklarativ in einer Spalten-Gruppe zusammenfassen. Der Benutzer erhält auf diese Weise einen besseren Überblick über die Daten.
Das Interactive Grid bietet unterschiedliche Varianten der Report-Pagination, wobei hier insbesondere die Scroll Pagination, auch "Infinite Scrolling" genannt, als neues Features hervorsticht. Während des Scroll-Prozesses werden dabei immer nur die für den Benutzer aktuell sichtbaren Datensets geladen, um so eine bestmögliche Performance bei konstanter Benutzerfreundlichkeit zu gewährleisten.
In den bisherigen APEX-Versionen konnte lediglich eine Master-Detail-Beziehung pro Seite abgebildet werden. Das Interactive Grid bringt auch in diesem Punkt eine Erweiterung mit sich: Es lassen sich nun beliebig viele Master-Detail-Beziehungen über beliebig viele Ebenen hinweg darstellen.
Neu im Bereich Dynamic Actions ist der Auswahltyp "Columns", der sowohl in einem Event, als auch in einer bestimmten Aktion genutzt werden kann. Ändert der Benutzer beispielsweise einen Spaltenwert im Interactive Grid, kann jetzt mit einer Dynamic Action entsprechend darauf reagiert werden.
Die Packaged App "Sample Chart" ist zwar schon aus früheren APEX-Versionen bekannt, wurde jedoch für das neue Release erweitert und dient nun der Vorstellung eines weiteren APEX 5.1 Features: Oracle JET Charts.
Dem APEX-Entwickler stehen nun verschiedene neue Diagrammtypen wie beispielsweise Polar, Funnel oder Radar zur Verfügung. Alle grafischen Darstellungen erscheinen im modernen HTML5-Design, können in den Einstellungen oder auch über Java-Script APIs individuell angepasst werden und reagieren responsiv auf Änderungen der Displaygröße oder weitere Eigenheiten des jeweiligen Endgeräts.
Ermöglicht wird das durch eine neue Chart-Engine, die auf Komponenten der Oracle Java-Script Extension Toolkit (JET) Data Visualizations, einem Open Source Java-Script Framework, basiert. AnyChart-Diagramme aus älteren APEX-Versionen können über einen Migrations-Wizard in JET Charts umgewandelt werden (Ausnahme: MapCharts).
Die Packaged App "Universal Theme" wurde komplett überarbeitet und präsentiert nun im neuen Design die diversen Erweiterungen des Universal Themes unter APEX 5.1.
Interessant ist dabei vor allem die neue Font APEX Icon-Bibliothek, die den früheren Font Awesome um viele Symbole (u.a. zu den Themen Datenbank, Diagramme, Webgestaltung, Barrierefreiheit und Emojis) ergänzt.
Das Icon-Präfix "fa" wurde beibehalten, um den Umstieg auf Font APEX zu erleichtern. Die neuen Icons besitzen verschiedenste Anpassungsmöglichkeiten und können beispielsweise animiert, beliebig gedreht bzw. gespiegelt oder durch zusätzliche kleine Icons ergänzt werden.
Außerdem bietet das Universal Theme sogenannte Live Template Options, die über die Entwickler-Toolbar Option "Quick Edit" erreichbar sind. Damit können durch eine dem Theme Roller ähnliche Vorgehensweise die Template Options des gewünschten Elements zur Laufzeit geändert werden - das umständliche Hin- und Herschalten zwischen Page Designer und laufender Applikation fällt damit weg.
Auch der Page Designer hält einige Neuerungen für APEX-Entwickler bereit: Zunächst wurde die frühere Seitenbearbeitungsansicht "Component View" in den Layout Editor des Page Designers integriert. Damit können Entwickler ihre gewohnte Bearbeitungsansicht, gleichzeitig aber auch die Vorteile des Page Designers nutzen.
Die Darstellung des Page Designers kann zudem beliebig angepasst werden: Zur Auswahl steht hier nicht nur die Anzeige von drei bzw. nur zwei Ausschnitten (Layout und Property Editor), die einzelnen Menü-Tabs im Page Designer können auch per Drag & Drop an einen anderen Bereich geheftet werden.
Praktisch ist auch, dass konditionierte Seitenelemente in APEX 5.1 deutlich mit einem lila Punkt gekennzeichnet werden, was dem Entwickler einen schnelleren Überblick ermöglicht.
Viele weitere Informationen, Erklärungen und Beispiele zu den neuen Features der Version 5.1 erhalten Sie in unserem APEX 5.x/18.1 Kurs Grundlegendes Wissen zur Anwendungsentwicklung mit Oracle Application Express bieten Ihnen außerdem unsere APEX-Schulungen.
Schauen Sie doch einfach mal vorbei! Inwischen sind wir schon bei der APEX Version 20.2 angekommen, auch da gibt es viele neue spannende Features.
Tooltipps sind eine schöne Gestaltungsmöglichkeit, um Texte an verschiedenen Stellen in einer Webseite einzubauen.
Der HTML Befehl dazu lautet:
<span TITLE="Hier zum Beispiel">Stellen</span>
Wie sieht das Ganze in APEX aus? Wenn Sie den Tooltipp in einem Report verwenden möchten, können Sie aus mehreren Varianten wählen:
Im SELECT Statement:
SELECT ename,job,sal,'<span TITLE="Abteilung:'||d.dname||'">'||e.deptno||'</span>' FROM emp e, dept d WHERE e.deptno=d.deptno;
Oder in der jeweiligen Spaltenformatierung:
--> Bereich (APEX 5.x!): Column Formating / HTML Expression
Wenn der Tooltipp statisch sein soll lautet die Syntax:
<span TITLE="Hier könnte Ihr Tooltipp stehen">#ENAME#</span>
Wenn man eine andere Spalte im Tooltipp darstellen möchte, referenziert man sie einfach mit #SPALTENNAME#:
<span TITLE="Verdienst:#SAL#">#ENAME#</span>
Wenn der Tooltipp in der Spaltenüberschrift stehen soll:
Gehen Sie auf den Tree-Punkt Attributes (dieser hängt im Report unter dem Punkt Columns).Dort im Bereich Heading kann der Type auf "PL/SQL Function Body" gesetzt werden.
Danach gibt man als PL/SQL Function Body an:
wenn es statisch sein soll:
RETURN'<span TITLE="Hier steht der Nachname">ENAME</span>:<span TITLE="Hier steht der Beruf">JOB</span>:<span TITLE="Hier steht das Gehalt">SAL</span>:<span TITLE="Hier steht die Abt.Nr.">DEPTNO</span>';
wenn Sie es lieber dynamisch haben möchten (mit nur einem Tooltipp auf einer Spaltenüberschrift):
DECLAREs CLOB;BEGINSELECT listagg(dname,',') within group (order by dname) INTO s FROM dept;s:='ENAME:JOB:SAL:<span TITLE="Abts:'||s||'">DEPTNO</span>';RETURN s;END;
Hinweis: Der Select des Reports lautete dazu:
SELECT ename,job,sal,deptno FROM emp;
Das Feature war lange überfällig und wurde nun ab APEX 20.1 endlich implementiert: Friendly URL.Ich vermute ja, dass die URL hauptsächlich freundlicher gestaltet wurde um die "bösen" SEO Geister der Google Suchmaschine zu besänftigen...Mit der alten Session Notation konnte Google nämlich nichts anfangen und hat bei jedem "spidern" eine neue Session ID bekommen, die Seite dann intern gespeichertund mit den bereits beim letzten Mal gespiderten Seiten verglichen um dann festzustellen, dass die Seite "in einer anderen Version" schon gibt.Das führt dann gnadenlos zum Downgrade (bei uns 20 Plätze) mit der Begründung: Kanonische Seiten !Zurück zur URL:Altes APEX URL Format (bis 19.2):
Neue Oracle APEX URL Format (ab 20.1):
Erklärung der URL Parameter:
Hinweis: Die Rehenfolge der Parameter von Position 5 bis 8 ist austauschbar, nur beginnt der erste Parameter mit ?xxxund die folgenden werden mittels &yyy drangehängt. Achten Sie bitte darauf, dass bei der Itemersetzung im HTML Kontexweiterhin die Syntax &ITEM. (Betonung auf dem Punkt!) lautet.Sie sollten die Seiten URL weiterhin erzeugen durch das Package: APEX_PAGE.GET_URL!Die Syntax lautet:
Beispiel:
Weitere spannende Themen erwarten Sie in einem unserer APEX Kurse.Fun Fakt: Wir haben vermutlich weltweit die meisten verschiedenen APEX Kurse im Program (APEX Kompakt, APEX I, APEX II, APEX New Features, APEX Security, APEX im Internet)macht 6 Stück, wer bietet mehr ? Unser Dozent arbeitet schon seit 1997 mit APEX Techniken (ja da gab es APEX noch gar nicht ...)
Hinweis: Bei unseren Test mit APEX 21.1 haben einige "Kleinigkeiten" nicht funktioniert, evtl sollten Sie noch warten bis der erste Patch rauskommt (Update: es gibt den ersten Patch 32598392):Wenn Sie die APEX Version 21.1 (Stand 12. Mai 2021) in die kostenlose Oracle XE Datenbank Version 18c installieren möchten, gehen Sie bitte wie folgt vor:
Laden Sie sich zuerst APEX und die Oracle Expres (XE) Version 18c herunter. Wir installieren immer die NON-CDB Variante (so lange es noch geht :-) )Update vom 2.4.2022: Ab Version 21c XE ist nun nur noch eine Pluggable Database Installation möglich!
Für LINUX verwenden wir den Installationspfad: /u01/software. Dort sollte dann die APEX Zipdatei ausgepackt liegen
Nun gehen wir in das Installtionsverzeichnis und starten wir das APEX Installations-Hauptskript:
oder der bereits vorhandene interne SYSAUX Tablespace soll zum Einsatz kommen:
Kopieren Sie die Bilder in den entsprechenden Webserver Ordner:
Das letzte Skript setzt das Passwort für INTERNAL Workspace ADMIN Benutzer fest.Wenn Sie migrieren von einer niedrigeren Version von APEX (19.x oder 20.x), ist dieser Schritt nicht notwendig.
Zusätzlich wird die REST Schnittstelle benötigt, die man für alle REST Aufgaben uns auch die Application und Workspace Files benötigt.Wenn Sie von einer niedrigeren Version von APEX (19.x oder 20.x) migrieren, ist dieser Schritt nicht notwendig.
Legen Sie sich zuerst einen Workspace mit einem Administrationsbenutzer an.
Alle hatten noch mit einer Oracle Express Edition 20c im Jahre 2020 gerechnet, nur nachdem es kein OnPremise Release von Oracle im Jahre 2020 gegeben hat, wurde natürlich auch kein neues Express Edition Release veröffentlicht. Unsere Hoffnung ist, das im Sommer eine Oracle XE 21c Edition verfügbar ist. In der Zwischenzeit nehmen wir die Oracle XE 18c Edition füt unsere APEX Installation.Wenn Sie die APEX Version 20.2 (Stand Dezember 2020) in die kostenlose Oracle XE Datenbank Version 18c installieren möchten, gehen Sie bitte wie folgt vor:
Hinweis: Der nächste Schritt installiert die notwenifen Einstllungen für den REST Betrieb (APEX verwendet den z.B. für die Application oder Workspace Images)
Das heutige Thema beschäftigt mit häufigen ORDS Problemen und Fehlern. Da ich schon mehrere Stunden/Tage auf der Suche nach Fehlern mit der Oracle ORDS Schnittstelle verbracht habe, möchte ich versuchen etwas zu den möglichen Lösungen beizutragen... Übersicht: 0. Debugging einschalten 1. Datenbankbenutzer prüfen 2. Problem: Die Bilder-/ CSS-/ Java-Script-Dateien fehlen, oder liegen im falschen Verzeichnis. 3. Es kommt die Fehlermeldung, dass die Version der Bilder, nicht zur Version von APEX passt. 4. Die "ords.war"-Datei funktioniert in Verbindung mit Tomcat einfach nicht: 5. Eine ominöse CSS Datei wird nicht gefunden z.B. 56437564376.css 6. Mehrere Webserver belegen den gleichen Port 7. Ein oder mehrere Benutzer sind gesperrt oder das Passwort ist abgelaufen 8. defaults.xml Datei nicht lesbar/vorhanden 9. ORDS komplett neu aufsetzen 10. Fehler 404 The request could not be mapped to any database 11. 404 Not Found Die Anforderung konnte keiner Datenbank zugeordnet werden 12. Fehler 503 Service Unavailable 13. Internal Server Error 500 0. Debugging einschalten Es hat sich bewährt, bei Problemen rund um APEX, REST oder dem Webserver zuerst mal Debugging einzuschalten: Gehen Sie dazu in die Datei defaults.xml (im Ordner den sie bei der ersten Frage der Installation von ords.war angegeben haben), dort stehen u.a. evtl folgende Zeilen:
<entry key="db.connectionType">basic</entry> <entry key="db.hostname">my_db_server</entry> <entry key="db.port">1521</entry> <entry key="db.sid">o23c</entry>
Wir ergänzen die folgenden Zeilen, bzw. editieren sie, falls bereits vorhanden.
<entry key="debug.debugger">true</entry> <entry key="debug.printDebugToScreen">true</entry> <entry key="log.logging">true</entry> <entry key="log.maxEntries">500</entry>
Wenn Sie Tests machen möchten, ob die Verbindung funktioniert, können sie auch das Kommandozeilen Tool curl verwenden:
curl http://myserver:8080/ords
1. Datenbankbenutzer prüfen
Prüfen Sie die Verfügbarkeit der DB-Benutzer mit folgenden SELECT:
SELECT username, lock_date, expiry_date, account_status FROM dba_users WHERE username IN ( 'ANONYMOUS', 'APEX_PUBLIC_USER', 'APEX_LISTNER', 'APEX_REST_PUBLIC_USER', 'ORDS_METADATA', 'ORDS_PUBLIC_USER' ) ORDER BY 1;
Da sollte dann z.B. folgendes als Rückgabe erscheinen:
USERNAME
LOCK_DATE
EXPIRY_DATE
ACCOUNT_STATUS
ANONYMOUS
28.04.2023
OPEN
APEX_PUBLIC_USER
30.04.2023
APEX_REST_PUBLIC_USER
ORDS_METADATA
ORDS_PUBLIC_USER
Erklärung: Wenn Sie das interne Gateway (Oracle EPG) via Oracle Listener ohne Webserver verwenden, muss der Benutzer ANONYMOUS den Status OPEN besitzen. Wenn ein Webserver verwendet wird, kann der Benutzer ANONYMOUS gesperrt sein (LOCKED), jedoch muss der Benutzer APEX_PUBLIC_USER auf OPEN stehen. Wenn Sie eine höhere APEX Version besitzen (5.1) werden viele interne Funktionen (auch das Bereitstellen von Bildern, CSS und Javascript z.B. bei den Application Files) via REST Schnittstellen zur Verfügung gestellt. Hier muss auch der Benutzer APEX_REST_PUBLIC_USER entsperrt sein. Sollte die Spalte LOCK_DATE bereits ein Datum besitzen, muss der Benutzer entsperrt werden.
ALTER USER <user> ACCOUNT UNLOCK;
Sollte die Spalte EXPIRY_DATE schon in der baldigen Zukunft liegen, sollte die Account-Lebensdauer auch gleich verlängert werden: a, Sollte das gleiche Passwort verwendet werden, hier am Beispiel mit Benutzer ANONYMOUS:
Führen Sie das zurückgegebene Statement aus, dann wird die Lebensdauer des Accounts verlängert. b, wenn Sie das Passwort ändern möchten (Achtung dann muss es auch in einer ORDS XML Datei synchron geändert werden!
Die Fehlermeldung lautet dann z.B. There is a problem with your enviroment because the Application Files have not been loaded. Prüfen Sie bitte, ob ein Ordner mit Namen "i" im Verzeichnis .. tomcat/WebApps/ROOT liegt, ansonsten könnte die Seite (weil die CSS-Dateien nicht geladen werden) defekt aussehen. Wenn Sie zusätzlich den Apache als ReverseProxy einsetzen, müssen die Dateien im Apache docRoot Verzeichnis liegen (bei uns z.B. in /var/www/html)
Da muss einfach der Browser Cache geleert werden. Oder Sie haben die Bilder beim Patchen nicht richtig mit den restlichen Dateien zusammenkopiert Hinweis: Für Apex 21.2.6 sollten 16.730 Dateien im Bild-Ordner (i) liegen In Version 22.2 sind es 15731 Dateien und 1332 Ordner = 17.063 Dateien
Prüfen Sie die Konsistenz der ords.war Datei mit:
java -jar ords.war validate oder java -jar ords.war validate --database o21c
Name des Datenbankservers eingeben [localhost]: Listener-Port der Datenbank eingeben [1521]: Datenbankservicename eingeben [o21c]: Erfordert SYS AS SYSDBA, um das Oracle REST Data Services-Schema zu verifizieren. Datenbankkennwort für SYS AS SYSDBA eingeben: Kennwort bestätigen: Informationen werden abgerufen.
Retrieving information. Oracle REST Data Services will be validated. Validating Oracle REST Data Services schema version 21.1.0.r3541002 ... Log file written to /root/ords_validate_core_2021-01-16_133103_00877.log Completed validating Oracle REST Data Services version 21.1.0.r3541002. Elapsed time: 00:00:04.798
Ein Problem, was mir vier Wochen Suche beschert hat. Wir hatten bei der Installation von ORDS immer das Problem, dass sich die Installation an einer Stelle aufgehängt hatte. Sie hing ca. 15 min und stüzte dann ab mit " IO Error: Connection reset by Peer". Das Problem war, dass Java auf unserem System (CentOS 7) mit "/dev/random" nicht genügend viele Zufallszahlen berechnen konnte und stattdessen "/dev/urandom" nehmen musste.
Hier war eine fehlerhafte ords Installation schuld, es fehlte die Datei apex_rt.xml
Die Dateien sehen wie folgt aus (und können auch manuell erstellt werden):
apex.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>Saved on Sat Oct 22 11:54:56 CEST 2022</comment> <entry key="db.password">@05939D2C32A74181B5BCBA375C0794A111</entry> <entry key="db.username">APEX_PUBLIC_USER</entry> </properties>
apex_al.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>Saved on Sat Oct 22 11:54:56 CEST 2022</comment> <entry key="db.password">@05B2B32CE300417F3AE4BAD1112826CB84E</entry> <entry key="db.username">APEX_LISTENER</entry> </properties>
apex_rt.xml:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>Saved on Sat Oct 22 11:54:56 CEST 2022</comment> <entry key="db.password">@0577928598D4BAB7423441C0D8DF0855F</entry> <entry key="db.username">APEX_REST_PUBLIC_USER</entry> </properties>
apex_pu.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>Saved on Sat Oct 22 11:54:56 CEST 2022</comment> <entry key="db.password">@05651DD1203D235C56A0585BC871A336A2</entry> <entry key="db.username">ORDS_PUBLIC_USER</entry> </properties> Fehlerhafte / fehlende Dateien weden auch in der log Datei catalina.out angezeigt:
<entry key="db.password">!Suchmich2023##</entry>
<entry key="db.username">APEX_REST_PUBLIC_USER</entry>
Eine CSS Datei des Theme Rollers konnte auf einem Server teilweise nicht mehr gefunden werden. Teilweise ist immer spannend ... Ein Blick in die catalina.out brachte etwas Licht ins Dunkel: Einige ORDS_METADATA Views waren invalid- Bei genauerer Betrachtung der Views, stellte sich heraus, dass die dazu passenden Tabellen gar nicht (mehr) da waren. Nur wo werden diese angelegt? Nach einiger Suche habe ich beim Auspacken des ords.war Files die Datei ords_database.objects.sql im Ordner scripts/install/core gefunden. Nachdem das Skript nochmal installiert wurde (bitte im Schema ORDS_METADATA) lief wieder alles perfekt. Sicherheitshalber kann man natürlich einen Zusatzcheck durchführen (hier mir ORDS Version 19.4 (Stand 15.03.2020))
SELECT object_type, COUNT(valid), COUNT(invalid) FROM ( SELECT object_type, CASE WHEN status = 'VALID' THEN 1 END AS valid, CASE WHEN status <> 'VALID' THEN 1 END AS invalid FROM dba_objects WHERE owner = 'ORDS_METADATA' ) GROUP BY object_type ORDER BY 1;
Das Ergebnis sollte in 19.4 (für 21.2 in Klammern) dann so aussehen:
OBJECT_TYPE VALID INVALID INDEX 75 (86) 0 JOB 1 (1) 0 LOB 3 (3) 0 PACKAGE 12 (20)0 PACKAGE BODY 12 (19)0 PROCEDURE 1 (1)0 SEQUENCE1 (1)0 SYNONYM 14 0 TABLE 27 (30)0 TRIGGER 27 (30)0 TYPE 20 (20)0 TYPE BODY 6 (6)0 VIEW28 (34)0
6. Mehrere Webserver belegen den gleichen Port
Prüfen Sie, ob das Oracle EPG evtl. den gleichen Port, wie Ihr Webserver belegt:
SELECT dbms_xdb.gethttport FROM dual;
Falls es der gleiche Port wie im Webserver ist, können Sie ihn wechseln:
EXEC dbms_xdb.sethttpport(0); -- Ausschalten des Datenbank Ports EXEC dbms_xdb.sethttpport(9090); -- Anderer Port
oder unter Linux auf OS Ebene:
netstat -tulpn | grep 8080
7. Ein oder mehrere Benutzer sind gesperrt oder das Passwort ist falsch bzw. abgelaufen:
Benutzer APEX_PUBLIC_USER Webserver Fehler: 503 Service Unavailable Wenn Debugging eingeschalten ist, dann auch noch: Der Verbindungspool namens |apex|rt| ist aufgrund der folgenden Fehler nicht korrekt konfiguriert: ORA-28000: Account ist gesperrt. Witzigerweise kann die Fehlermeldung auch erscheinen, wenn das Passwort falsch ist! Wenn Debugging ausgeschalten ist, bekommen Sie den Fehlertext: Benutzer oder Kennwort für den Verbindungspool namens |apex|| ist ungültig oder abgelaufen, oder der Account wurde gesperrt Lösung:
ALTER USER apex_public_user [IDENTIFIED BY meinpasswort] ACCOUNT UNLOCK;
Wenn Sie das Passwort auf dem Oracle Server geändert haben, muss es natürlich auch auf dem Oracle Client ( dem Webserver) geändert werden. Dass Passwort steht in Datei mit Namen apex.xml (im Ordner den sie bei der ersten Frage der Installation von ords.war angegeben haben) In der Datei sind u.a. folgende Zeilen:
Setzen Sie das geänderte Passwort unverschlüsselt mit vorangestellten ! in die Datei ein (nur bis ords 21.3.4 !!):
Das Passwort wird beim Neustart des Webservers automatisch verschlüsselt. Benutzer: APEX_PUBLIC_REST_USER Symptome: Static und Workspace Files werden nicht mehr angezeigt Webserver Fehler: 503 Service Unavailable Wenn Debugging eingeschalten ist, dann auch noch : Der Verbindungspool namens |apex|rt| ist aufgrund der folgenden Fehler nicht korrekt konfiguriert: ORA-28000: Account ist gesperrt. Witzigerweise kann die Fehlermeldung auch erscheinen, wenn das Passwort falsch ist! Wenn Debugging ausgeschalten ist, bekommen Sie den Fehlertext: Benutzer oder Kennwort für den Verbindungspool namens |apex|| ist ungültig oder abgelaufen, oder der Account wurde gesperrt Lösung:
Dass Passwort steht in Datei mit Namen apex_rt.xml (auch hier im Ordner den sie bei der ersten Frage der Installation von ords.war angegeben haben) In der Datei sind u.a. folgende Zeilen:
<entry key="db.password">@0574B6939D4387C95AD95DA10B99690D65</entry> <entry key="db.username">APEX_REST_PUBLIC_USER</entry>
Setzen Sie das geänderte Passwort unverschlüsselt mit vorangestellten ! in die Datei ein:
<entry key="db.password">!meinpasswort</entry>
Das Passwort wird beim Neustart des Webservers automatisch verschlüsselt. 8. defaults.xml Datei nicht lesbar/vorhanden
Prüfen Sie, ob die Konfigdatei defaults.xml lesbar und für den Webserver (z.B. TomCat) lesbar und auch im richtigen Ordner zur Verfügung steht. Fehler: 404 Not Found Die Anforderung konnte keiner Datenbank zugeordnet werden. Stellen Sie sicher, dass die Anforderungs-URL richtig ist und dass Zuordnungen zwischen URL und Datenbank korrekt konfiguriert wurden. Lösung: Stellen Sie sicher, das der Webserver (z.B. TomCat) auf die Datei zugreifen kann. Einfacher Trick: Benennen Sie die Datei um und starten Sie den Webserver durch. Er legt selbst eine neue Datei an. Falls nicht, gibt es evtl im Verzeichnis ein Rechteproblem. Wenn Sie nicht wissen, in welchen Verzeichnis die Datei liegt: im Webserver liegt im ords/WEB-INF Ordner eine Datei mit Namen web.xml. Dort steht u.a.
<param-name>config.dir</param-name> <!-- Enter the location where configuration settings should be stored --> <param-value>c:\oracle\ords_conf</param-value>
Bei uns hatte sich ein weiterer Fehler in einem Server eingeschlichen: Die SQL*Plus Datei pupbld.sql Datei wurde bei der Installation einer neuen Datenbank nicht installiert. Das hatte zur Folge, dass bei jeder Anmeldung eines Benutzers an der Datenbank eine Fehlermeldung:
Kennwort eingeben: ERROR: ORA-00942: Tabelle oder View nicht vorhanden Fehler bei Zugriff auf PRODUCT_USER_PROFILE Warnung: Daten zu der Tabelle Product User Profile sind nicht geladen PUPBLD.SQL sollte als SYSTEM gestartet werden Letzte erfolgreiche Anmeldezeit: Mi Mrz 25 2020 14:02:32 +01:00 Verbunden mit: Oracle Database 18c Express Edition Release 18.0.0.0.0 - Production Version 18.4.0.0.0
Nachdem wir die Datei (@?/sqlplus/admin/pupbld.sql) installiert hatten, funktionierte das Ganze nach einem Neustart des Webservers wieder. Sie sollten bei 404 Problemen generell die Hauptverdächtigen Benutzer ( APEX_PUBLIC_USER, ORDS_PUBLIC_USER und APEX_REST_PUBLIC_USER) mal manuell an die Datenbank anmelden. Wenn es da Probleme gibt, sollte diese zuerst gelöst werden!
9. ORDS komplett neu aufsetzen:
a, Benutzer löschen
SQL> DROP USER apex_listener CASCADE; SQL> DROP USER apex_rest_public_user CASCADE;
b, Webserver beenden
systemctl stop tomcat
b, ORDS deinstallieren:
c, ords Configurations Verzeichnis finden und löschen Anzeige mittels:
java -jar ords.war configdir
Rückgabe: Mar 17, 2020 9:33:17 AM INFO: The config.dir value is /u01/software/oracle/ords/config d, Löschen des Verzeichnis:
rm -rf /u01/software/oracle/ords/config
Es sollte auch der ords.war und das Verzeichnis ords im Webserver (z.B. in /opt/tomcat/latest/webapps) gelöscht werden e, APEX_REST_CONFIG Skript als SYS neu starten
SQL>@apex_rest_config.sql
f, den Oracle ORDS neu konfigurieren: Hinweis: Packen Sie die datei ords.war immer neu aus dem Zip-Verzeichnis aus. Es könnten von der letzten Konfiguration sich fehler eingeschlichen haben.
java -jar ords.war
mv ords.war /opt/tomcat/webaps
h, Webserver (z.B. TomCat) wieder starten
systemctl start tomcat
und testen ob es nun funktioniert! 10.The request could not be mapped to any database Der Fehler lautet: URLMappingNotFoundException [statusCode=404, reasons=[The request could not be mapped to any database. Check the request URL is correct] Hier war der Rest-Service ausgeschalten. Sie können ihn einschalten mittels:
EXEC apex_instance_admin.set_parameter('RESTFUL_SERVICES_ENABLED','Y');
Der Fehler tritt derzeit in Apex 20.1 bis 22.2 auf. Lösung laut Metalink Doc: ID 2685135.1: Schalten Sie die Option Friendly URL aus (Shared Components / Application Defintion Attributes) [Update vom 6.6.2021) Fehler 404 bei Rest Service Diese Mal war das Kennwort des ORDS_PUBLIC_USER abgelaufen.
select username,account_status,lock_date,expiry_date from dba_users u where username in ('APEX_PUBLIC_USER','ORDS_PUBLIC_USER','APEX_LISTENER'); USERNAME ACCOUNT_STATUS LOCK_DATE EXPIRY_DATE ----------------- --------------- ---------- -------------------- APEX_LISTENER OPEN 10.11.2022 11:40:31 APEX_PUBLIC_USER OPEN 10.11.2022 12:12:53 ORDS_PUBLIC_USER OPEN 10.11.2022 12:13:07
12. Fehler 503 Service Unavailable
Der Datenbankbenutzer für den Verbindungspool |apex|pu| kann das Schema SCOTT nicht als Proxy verwenden. Möglicherweise ist eine Einschränkung der maximalen Anzahl an Datenbanksessions konfiguriert, oder ein Autorisierungsfehler liegt vor. Die Lösung war bei uns:
alter user scott grant connect through ords_public_user;
Ein ähnlicher Fehler war 13. 500 Internal Server Error
Ein unerwarteter Fehler mit der folgenden Fehlermeldung ist aufgetreten: InternalServerException [statusCode=500, logLevel=SEVERE, reasons=[]] Caused by: java.sql.SQLException: ORA-00604: Fehler auf rekursiver SQL-Ebene 1 ORA-01031: Nicht ausreichende Berechtigungen ... Caused by: Error : 604, Position : 0, Sql = select nvl(h.items_per_page,m.items_per_page) items_per_page, t.etag_type, t.etag_query, h.source_type, m.origins_allowed, cursor (select p.name, p.bind_variable_name, p.source_type,p.access_method, p.param_type from user_ords_parameters p where p.handler_id = h.id) parameters, h.source from user_ords_modules m, user_ords_t
In einem meiner letzten APEX Kurse kam die Frage auf, wie kann man ermitteln, welche der Regionen duch den Region Display Selector ausgewählt wurde. Das ist zum Glück sehr leicht:
$('.apex-rds').data('onRegionChange', function(mode, activeTab) {apex.item( "P1_REGION_ID" ).setValue( activeTab.href, null, true )});
Wenn mann nun wissen möchte welche Region ausgewählt wurde, sieht man nach der Auswahl die Nummer im Textfeld. Die kann man sich notieren und ggf eine Aktion damit verbinden.Bei uns kamen z.B. folgende Werte raus:
Natürlich können Sie, wenn die Nummern bekannt sind, das Text-Feld in Hidden umändern...
Wenn man in seiner Oracle Datenbank Trigger zu Audit-Zwecken verwendet, ist man erstaunt, das als Apex Benutzer nicht der Anmeldebenutzer sondern ANONYMOUS oder APEX_PUBLIC_USER erscheint.Das Problem kann man natürlich mit ein paar PL/SQL Objekten lösen.:-)
Etwas unbekannt ist das Oracle Objekt Context, mit dem die Funktion sys_context erweitert werden kann.Die Funktion sys_context besteht aus zwei Parametern:Parameter 1: userenvParameter 2: ca 60 Stück u.a. OS_OSER, SESSION_USER, ...Wir können die Funktionen nun erweitern, indem wir den ersten Parameter ändern auf apex_env
Die Context Funktion benötigt zum Auffruf immer ein Package, das wir hiermit anlegen:
Führen wir einen Testcase durch und setzen den Context manuell:
Nun können wir den Context wieder auslesen:
Jetzt erstellen wir uns eine Audit-Tabelle, in der stehen soll, welcher APEX Benutzer auf welcher Seite, in welcher APP mit welcher Session IDdie Änderung durchgeführt hat.
und der passende Trigger dazu:
Jetzt brauchen wir nur noch den kleinen Testblock in unsere APEX-App einbauen:Gehen Sie dazu auf: Edit Application Properties / Security und dort auf Database Session.Im Bereich "Initialization PL/SQL Code" geben Sie dort ein:
Weitere Tipps und Tricks erfahren Sie in einem unserer APEX oder PL/SQL Kurse (auch als Video-Streaming)
Lange haben wir darauf gewartet, nun ist es endlich verfügbar. Seit November 2023 kann man Oracle APEX 23.2 herunterladen. Im folgenden Tipp beschreiben wir kurz, wie es installiert wird.Sie können APEX in jede Oracle Personal, Standard, Enterprise oder Express Edition (XE oder FREE) Datenbank installieren ab Version 18c0. Erstellen Sie ein funktionierendes Backupo des Workspace, der Workspace Files und aller APEX Applikationen.Das haben wir bereits in einem anderen Tipp thematisiert.1. Herunterladen des Zip FilesDownload Oracle APEX 23.22. Auspacken des Zip Files
3. Neue Bilderverzeichnisse vorbereiten und evtl an den tomcat Benutzer anpassen (teilweise wird auch www-data verwendet)
4. Webserver oder EPG stoppen (als root oder sudo)
5. In den ausgepackten Installationsordner gehen und die Installation via sql*plus starten:
6. Während das Skript läuft (bei unseren Maschinen ca 30 Min) kann der Bilderordener gewechselt werden
7. Nachdem das APEX 20.1 Installationsskript fertig ist, die REST Schnittstelle aktualisieren.Sie sollten dazu die Passwörter der Benutzer APEX_LISTENER und APEX_REST_PUBLIC_USER zu Hand haben :-)
8. Webserver oder EPG starten (als root oder sudo)
9. Passwort für den Internal Workspace Admin Nutzer ändern
Sie werden die folgenden Parameter gefragt:Benutzername: [Schlau ist, ihn nicht ADMIN zu nennen !]Email: [Ihre Email Adresse angeben ]Passwort: [Nur einmal !, also bitte nicht vertippen :-) ]Vergessen Sie zum Abschluß nicht, den Browser Cache zu leeren!Neuerung für die Neuinstallation:Es gibt ein neues Universalskript mit Namen: apxsilentins.sqlEs übernimmt automatisch die folgenden Schritte:a, Installation von APEX (Skript apexins.sql)b, Erstellung oder Upgrade des Instanz-Admin-Accounts (Skript: apxchpwd.sql)c, APEX_PUBLIC_USER konigurierend, Anpassung der Network ACLse, Static File Support mittels REST (Skript: apex_rest_config.sqlAufruf-Syntax:
apxsilentins.sql
Parametererklärung:
Beispielaufruf:
Alternative für Produktiv-Umgebungen (mit absoluter Downtime von unter 1 Minute!):1-3 siehe oben4. Webserver nicht beenden !5. Variablen für die Parameter vorbereiten
Wenn nur die Runtime Version installiert werden soll:
In den 4 Minuten, wo das Skript läuft haben Sie Zeit die Bilder/CSS/Javascript Dateien in das passende Webserver Verzeichnis zu kopieren.Nur überschreiben Sie damit ja das alte Image Verzeichnis und dass muss ja noch 5 Minuten leben
Trick: Kopieren Sie die Bilder in ein Verzeichnis i2
Bei Apache Tomcat wäre das (bei uns):
/opt/tomcat/latest/webapps
Wenn der Apache Webserver als Reverse Proxy davor geschalten ist:
/var/www/html
Prüfen Sie ob die Dateien gelesen werden können (Rechte und Eigentümer beachten!)
https://ihr_server/i/apex_version.txt
Sollte zurückliefern:
Denken Sie nun daran die Bilverzeichnisse zu tauschen, also z.B.
# mv i i_old # mv i2 i
BONUSTIPP:Prüfen Sie, ob ACLS für die alte APEX Installation vorhanden sind, die gelöscht werden sollten:Oracle APEX 23.2 migriert sogar die alten ACLS !!! Super !
Wenn Sie mit den Tests! erfolgreich durch sind, können Sie den alten Oracle APEX Benutzer löschen
Und nun viel Spaß mit der schönen neuen APEX 23.2 Version.
PS: Wir schulen Seit November 2023 schon mit der neuen Oracle APEX Version 23.2
Wenn man seine APEX Anwendung am ersten Tag im Internet frei verfügbar macht, wird man sich gleich über den großen Traffic auf dem Server freuen.Nur, wenn man nachdenkt, fällt einem beim Betrachten der Logfiles schnell auf, dass die meisten Zugriffe Hackerangriffe sind.Hier ein paar Auszüge aus unserem Apache Log-File
Schmunzeln mussten wir schon, wie 90% der Angriffe ablaufen. Ein großer Teil sind versucht php Attacken (1), die bei einer reinen APEX-Installation ins Leere laufen.Die Angriffsgruppe (2) versucht mit SQL-Injection einen Fuß in die (Datenbank-) Türe zu bekommen.Beim Angriff (3) waren wir auch verwundert, was die Funktion name_const denn bei Oracle macht. Relativ schnell stellte sich heraus, das ist gar keine Oracle Funktion, sondern gehört zu einer MySQL Datenbank und läuft damit ins leere... :-)Da sich die Angriffe sehr oft wiederholen (von anderen IP Adressen) gehen wir davon aus, dass es fertige Hacker-Kits gibt, die hier zum Einsatz kommen.So was können wir tun gegen diese Angriffe?1. Seine Hausaufgaben machen und alle Variablen/Items immer lieber einaml zu oft prüfen auf Länge, Datentyp und Logic.2. Prüfsummen in der URL aktivieren3. Apache/Nginx Logfiles regelmäßig auswerten4. Apache mod_security installieren5. Unseren APEX Security Kurs besuchen. Wir haben ihn um die Kapitel Apache und Nginx Security erweitertWir haben uns noch eine weitere Abwehrroutine überlegt, ein Shell Script mit Namen blockip.Es hat die Aufruf-Parameter:
Es kann IP-Adressen blocken/entblocken manuell oder autmatisch, wenn es im Apache Logfile verdächtige Aktionen bemerkt. Bei uns läuft es via Crontab regelmäßig und sperrt die Hacker für 1 -x Stunden aus.Alle unsere APEX Schulungteilnehmer erhalten das Shell-Script von uns kostenlos auf Anfrage.
Wollten Sie auch schon mal in einer APEX Kalender Region auch das Jahr und den Monat auswählen,und nicht mit dem Vor und Zurück Buttons 68 Monate wechseln?Hier werden Sie geholfen :-)Wir legen uns zwei Select List Items, eines für den Monat (:P1_MONAT) eines für die Jahresauswahl (:P1_JAHR):P1_MONAT SQL Query
:P1_JAHR Query für aktuelles Jahr und die letzen 5 Jahre
Unter Kalender Attribute:Calender Views: [ ] Navigation abwählenDas ist kein Muss, aber die Benutzer könnten mit den Vor und Zurück Buttons auch Navigieren und dann müsste man auch die Anzeige der beiden Select Listen aktualisieren!Unter Advanced / JavaScript Initialization Code
Ich habe mich ja lange Zeit geweigert, die Pluggable Database einzusetzen und wenn es nach mir ginge ....Trotzdem sollte man sich der Zukunft nicht verschliessen, denn es wird ab 21c (incl) keine NON CDB Datenbanken mehr geben.Installation einer Apex Version 21.2 in Oracle XE 21c (geht aber auch in einer Enterprise Edition oder Standard Edition):Gehen wir zuerst mal in den Hauptcontainer und schauen uns um
Mich stört der Default Container, also löschen ich ihn und lege einen anderen an (ist natürlich optional, und wenn das schon eteas drinliegt, besser vorher migrieren...)
Wo liegen denn die Datendateien ?
Diesen Hauptpfad tragen wir im nächsten Kommando ein (bei uns C:\Oracle\Product\Base21\oradata)
Der Container wird geöffnet, automatisch beim Start der DB mitgestartet und wir gehen in den Container
Nun installieren wir in den neu erstellen Container unsere APEX Version.Das APEX Download haben wir unter c:\temp ausgepackt
Wir entsperren das schema SCOTT und schalten die starke interne Passwort-Prüfung aus (optional) Der Vorteil ist, dass man sich die ganzen Passwort-Parameter wie gewünscht selbst einstellen kann.
Nun wird das Passwort für den Internal Workspace gesetzt (Sie werden gefragt nach:Admin-name:Admin-User Email:Admin-Passwort:
Und weil wir schon hundert Mal vergessen haben, nach spätestens 187 Tagen vom APEX Benutzer und seiner ganzen "Verwandschaft" zu ändern,erstellen wir ein eigenes Profil für die Truppe:-)Die Passwörter passen Sie bitte Ihren Wünschen an
In einem der nächsten Artikel schauen wir uns die dazu passende ORDS Konfiguration an.Viel Spass bei der Benutzung von APEX und wenn Sie mal eine gute Schulung brauchen, denken Sie an uns ...*zwinker*
In unserem heutigen Beitrag wollen wir uns mit dem Thema beschäftigen, wie man aus einem JSON String wieder die Daten extrahieren kann.Diesen Anwendungsfall hatte ich die letzten 24 Monat sehr häufig, deswegen wurde es mal wieder Zeit sich mit dem Thema JSON in Oracle zu beschäftigen.Wir fangen mit einer kleinen Test-Tabelle basiernd auf den Emp und Dept Daten des Benutzers SCOTT an:Die Besonderheit / Schwierigkeit besteht darin, dass die Mitarbeiter in einem Array eingetragen werden (["CLARK","KING","MILLER"]
Als Bonustrack legen wir einen Oracle Text-Index auf die JSON Spalte:
Wir können dann mit der Funktion JSON_TEXTCONTAINS im JSON String suchen.
Das Ergebnis sieht dann so aus:
Wenn man die Daten der JSON Tabelle wieder extrahieren (und weiterverarbeiten) möchte:
Wenn man mal einen unbekannten JSON String auswerten möchte stellt Oracle dafür auch ein Package zur Verfügung:
Die Ausgabe sieht dann so aus:
}Und nun viel Spaß mit der Auswertung von Daten aus JSON-Ausdrücken. Bei uns wird das Thema ausführlich behandelt in den Kursen Oracle PL/SQL II, Oracle REST und Oracle Dev New Features 12c - 21c.
In vielen unserer Kurse ist JSON ein Thema (z.B. im APEX oder ORDS oder PL/SQL II Kurs). Da die Syntax gewöhnungsbedürftig ist, haben wir mal ein paar Beispiele generiert um die syntax besser zu verstehen.Ausgangslage ist ein JSON String, der in ein relationales Modell überführt werden soll.Übersicht der Beispiele:Beispiel 1, mit 3 WerteBeispiel 2, Verschiedene Datentypen in JSONBeispiel 3, mit Geschachtelten ArraysBeispiel 4, mit 3 Zeilen mit 2 FeldernBeispiel 5, mit 3 Zeilen mit 2 Feldern und einem Root Eintrag (var)Beispiel 6, mit 2 Feldern und 3 ZeilenBeispiel 7, mit Sub-Sub FeldernBeispiel 8, nur einen Wert extrahierenBeispiel 9, Wieviele Elemente hat das Array?Beispiel 10, Sub-Arrays (Darstellungsvariante 1)Beispiel 11, Sub-Arrays (Darstellungsvariante 2) Beispiel 12, Tabelle die von Oracle mit Auto-Rest zurückkommt zerlegenBeispiel 13: JSON String gefiltertBeispiel 1, mit 3 Werte
Ergebnis:
Beispiel 2, Verschiedene Datentypen in JSON:
Hinweis: Die Stunden / Minuten / Sekunden verschwinden hier. Alternative: Datum als Text parsen und mittels to_date in Datum umwandeln.Beispiel 3, mit Geschachtelten Arrays
Beispiel 4, mit 3 Zeilen mit 2 Feldern
Ergebnis
Beispiel 5, mit 3 Zeilen mit 2 Feldern und einem Root Eintrag (var)
Beispiel 6, mit 2 Feldern und 3 Zeilen
Beispiel 7, mit Sub-Sub Feldern
oder
Beispiel 8, nur einen Wert extrahieren
Beispiel 9, Wieviele Elemente hat das Array?
=>4oder
=>[1,3,1]Beispiel 10: Sub-Arrays (Darstellungsvariante 1)
Beispiel 11: Sub-Arrays (Darstellungsvariante 2
Beispiel 12, Tabelle die von Oracle mit Auto-Rest zurückkommt zerlegen
oder ausführlicher (aber nur für eine Ergebnis-Zeile zur Vereinfachung):
Seit Mai 2022 ist eine neue ORDS Version veröffentlicht worden, die eine andere Installation benötigt.Wir wollen hier die wichtigsten Punkte erklären:1. Es werden nur hoch die Java Versionen 11 und 17 unterstützt (und KEIN JAVA 8)Prüfen Sie bitte zuerst welche Java Version sie haben:Achtung: Bei uns machte auch die OpenJDK Version Probleme und endete mit einem Webserver Fehler 500 und Fehlertext NULL!Für Windows:
Installation unter Windows:
Nun wird die ords.war Datei in das TomCat Verzeichnis kopiert/verschoben (z.B. C:\Program Files\Apache Software Foundation\Tomcat 9.0\webapps)oder unter Linux: /opt/tomcat/latest/webappsTomCat sollte dann innerhalb von 5 Sekunden einen Ordner ords dort anlegen!Ein umbenennen des ORDS ist derzeit zu keiner Phase der Installation unterstützt (Stand Nov. 2022)Denken Sie daran, dass Sie ggf auch in diesen Ordner die APEX Bilder (Ordner images) in den Ordner "i" kopieren !Nun kommt der spannendste Teil (weil nur zum Teil in der Doku :-) aber dafür gibt es ja Kurse bei Muniqsoft Training ....Wenn Sie bei TomCat die msi Variante installiert haben, gibt es in er Taskleiste ein TomCat Icon (Feder mit roten oder grünem Punkt)Rot bedeutet= TomCat nicht gestartetGrün bedeutet = TomCat gestartet
Dort tragen Sie im Reiter Java unter Java Options ein:
Wenn das nicht oder falsch konfiguriert wurde, quittiert Tomcat einen APEX Aufruf mit einem 404 Fehler.Sollten Sie TomCat lieber über die Kommandozeile starten, sollte bitte zuerst folgender Parameter im DOS Fenster gesetzt worden sein:
Sie können das auch unter Systemsteuerungen/System/Erweiterte Systemeigenschaften/Umgebungsvariablen unter SYSTEMVARIABLEN (unten) setzen:Wichtig. Unter Windows muss der TomCat Dienst in der Lage sein, die Config-Datei (bzw. den ganzen Ordner lesen zu können)Prüfen Sie bitte auf dem Ordner ob der "Lokale Dienst" Leserechte auf dem Ordner hat. Wenn nicht, vergeben Sie die Rechte durch:Rechte Maus auf den Ordner / Eigenschaften / Sicherheit : Bearbeiten / Hinzufügen "Lokaler Dienst " eingeben / OK / OKAuf dem Reiter Sicherheit / Erweitert (ganz unten) [x] Alle Berechtigungen für untergeordnete Objekte .. anwählen / OKWarnung ignorieren und Fertig !Den Fehler sonst zu suchen, macht wirklich [keinen] Spass !