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...
Wer kennt es nicht, immer wenn man mal listagg benötigt, reciht der Speicherplatz nicht, weil listagg maximal 32767 Bytes zurückgeben kann.Mit einem kleinen Trick klappt es auch mit CLOB als Rückggaabetyp. Dazu verwenden wir die XML Funktion XMLELEMENT.Keine Angst, sie müssen kein XML dazu beherschen:-)Wir haben das ganze in eine WITH Funktion gekappselt, für den Fall, dass Sie kein CREATE PROCEDURE RECHT haben.Die Funktion hat bis zu 3 Parameter,column_name ist der Name der Spalte, die zusammengefasst werden solltable_name ist der Name der Tabelle, in der die Spalte enthalten istwhere_cond ist Optional und beinhaltet eine Filterklausel Default 1=1 also alles)order_by Optional kann auch ein Sortierreihenfolge bei der Ausgabe definiert werden (Default: Sortiert nach der Ausgabespalte)delimiter ist auch Optional und gibt das Trennzeichen zwischen der Ausgabe der Spaltenwerte an (Default ',' )
Wenn Sie das Ganze als eigenständige Funktion anlegen möchten:
Testcases:
Damit können Sie nun (fast) unbegrenzt die Werte einer Spalte zusammenfassen und weiterverarbeiten.
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)
Nachdem ich schon mehere Tage mit der Suche nach Fehlern im Oracle ORDS mit APEX verbracht habe, war es mal Zeit ein Prüf-Skript zu schreiben.Das Prüfskript prüft einige der gängigsten Probleme die einen Web Fehler 404 erzeugen.Das Skript fragt Sie die folgenden Parameter:Pfad des webapss Ordner (meist /opt/tomcat*[/latest] )Name des ORDS meist "ords". Das ist der Name, der in der Datei ords.war verwendet wird.Zusätzlich werden die Passwörter für die Accounts APEX_PUBLIC_USER, ORDS_PUBLIC_USER, APEX_REST_PUBLIC_USERgefragt und eine Anmeldung an der Datenbank durchgeführt. Fehler, wie Account Locked oder Passwort falsch werden dadurch gefunden.
Der letzte Check-Teil prüft die 4 XML Config-Dateien. Diese waren bei unseren Installationen teilweise nicht vollständig angelegt worden.
Ich hoffe Sie können damit zukünftig Ihre Oracle ORDS Fehler finden ...
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
Postgres hat ja nun seit der Version 10 auch Partitionierung bei Tabellen im Einsatz und das natürlich wie immer kostenlos.Derzeit werden die folgenden Partitionierungen unterstützt:
Beispiel zu Range Partitionierung (ohne Primary Key):
Wenn Die Tabelle einen Primary beinhalten soll, muss die Partitionierungspalte im Key enthalten sein, sonst erhält man den Fehler:FEHLER: insufficient columns in PRIMARY KEY constraint definitionDETAIL: PRIMARY KEY constraint on table "emp" lacks column "hiredate" which is part of the partition key.
Beispiel zu LIst Partitionierung:
In der optionalen Default Partition landen alle Einträge, die sonst in keine Partition passen.Wenn Sie keine Default Partition besitzen und der Datensatz kann ich zugeordnet werden, bekommen Sie den Fehler:FEHLER: keine Partition von Relation »dept« für die Zeile gefundenDETAIL: Partitionierungsschlüssel der fehlgeschlagenen Zeile enthält (deptno) = (50).Partitionen löschen:
Hash PartitionierungBei der Hash Partitionierung übernimmt Postgres die richtige Verteilung der Daten auf die Partitionen:
Bei Postgres wird im Gegensatz zu Oracle die Aufgabe in zwei Teile zerlegt:1. Eine Funktion, die das Doing übernimmt2. Einen Trigger, der bei einem Event die Funktion aufruft.
Beispiel: Insert, Update, Delete, Truncate Before Row Trigger
Beispiel: Insert, Update, Delete, Truncate Instead of Row Trigger (zündet nur bei Änderungen an einer View)
Beispiel für die Funktion, die der Trigger dann aufruft:
Welche Trigger gibt es in der DB?
oder für eine spezielle Tabelle:
Trigger bei Bedarf wieder löschen:
Nach 4 Monatiger Verspätung gegenüber der Linux Version war es am 20.2.2019 endlich so weit, das neue Oracle XE Release ist zum Download verfügbar.
Folgende Limitierungen weist die Version 18c XE auf:
Leider kann man bei der Erstinstallation nur die Pluggable Database Version installieren.
Es gibt aber einen Trick, das wieder rückgängig zu machen:
1. man installiert die Version laut den Default Vorgaben
a, Auspacken der Datei OracleXE184_Win64.zip in einen eigenen Ordner.b, Starten der Datei setup.exec, Weiter klickend, Ich stimme zu ... klickene, Pfad ändern oder weiter klickenf, Passwort für Benutzer SYS zweimal angebeng, Installieren klickenh, Bei der Rückfrage der Firewall die Kommunikation gestatten "Zugriff zulassen"i, ca. 20 Min später .. "Fertigstellen"Update vom 12.06.2019:Wenn Sie schnell sind (sie haben ca. 2 Minuten Zeit) können Sie die Installation der CDB Datenbank mit einem Trick abbrechen lassen. Gehen Sie dazu wie folgt vor:Bei Schritt (g) legt der Installer tausende Dateien ins Zielverzeichnis.Gehen Sie (sobald vorhanden) in die Datei <ORACLE_HOME>\dbhomeXE\assistants\dbca\templates\XE_Datbase.dbcErsetzen Sie dort in Zeile 49 die Zeile
<SourceDBName cdb="true">xe</SourceDBName>
durch
<SourceDBName cdb="false">xe</SourceDBName>
der Installer bricht dann nach ca 3,3 Minuten ab und Sie können dann direkt eine NON-CDB Datenbank mittels dbca installieren. Sie sparen dadurch ca 20 Minuten ein!Alternative: Silent InstallationBei der Oracle Silent Installation können Sie alle relevanten Parameter bereits in einer Datei hinterlegen, die Installation kommt dann ohne weitere Interaktion aus.
Die Datei heisst XEInstall.rsp und wird im Zip File mitgeliefert.Die Datei könnte dann z.B so editiert werden:
#c:\temp\OracleXE184_Win64\setup.exe /s /v"RSP_FILE=c:\temp\OracleXE184_Win64\XEInstall.rsp" /v"/L*v c:\temp\OracleXE184_Win64\setup.log" /v"/qn"#Do not leave any parameter with empty value#Install Directory location, username can be replaced with current userINSTALLDIR=C:\oracle\product\18.0.0\#Database password, All users are set with this password, Remove the value once installation is completePASSWORD=sys2019##If listener port is set to 0, available port will be allocated starting from 1521 automaticallyLISTENER_PORT=0#If EM express port is set to 0, available port will be used starting from 5550 automaticallyEMEXPRESS_PORT=0#Specify char set of the databaseCHAR_SET=AL32UTF8
Der Aufruf lautet dann in einem DOS-Fenster (mit Administrationsrechten)
SET ORA_INSTALL_TMP=c:\temp\OracleXE184_Win64
%ORA_INSTALL_TMP%\setup.exe /s /v"RSP_FILE=%ORA_INSTALL_TMP%\XEInstall.rsp" /v"/L*v %ORA_INSTALL_TMP%\setup.log" /v"/qn"
Achtung Sie bekommen den Prompt sofort zurück und man denkt die Installation hat nicht geklappt. Jedoch können Sie im Logfile den Installations Fortschritt der Oracle XE 18c Datenbank schön beobachten:-)
In einer der letzten Zeilen im Logfile sieht man dann den Aufruf des DBCA :
INFO: cmd.exe /c "c:\oracle\product\18.0.0\dbhomeXE\bin\dbca.bat -silent -createDatabase -gdbName XE -templateName XE_Database.dbc -characterSet AL32UTF8 -createAsContainerDatabase true -numberOfPDBs 1 -pdbName XEPDB1 -sid XE -emConfiguration DBEXPRESS -emExpressPort 5500 -sampleSchema true -initParams sga_target=1536M,pga_aggregate_target=512M -customScripts c:\oracle\product\18.0.0\dbhomeXE\assistants\dbca\postdb_creation.sql -oui_internal -maskPasswords FALSE"
Die Vorlagen-Datei XE_DB_Muso.dbc sieht dabei so aus:
<?xml version = '1.0'?><DatabaseTemplate name="XE DB Muniqsoft 2020" description=" " version="18.0.0.0.0"> <CommonAttributes> <option name="OMS" value="true" includeInPDBs="true"/> <option name="JSERVER" value="true" includeInPDBs="true"/> <option name="SPATIAL" value="false" includeInPDBs="true"/> <option name="IMEDIA" value="false" includeInPDBs="true"/> <option name="ORACLE_TEXT" value="true" includeInPDBs="true"> <tablespace id="SYSAUX"/> </option> <option name="SAMPLE_SCHEMA" value="false" includeInPDBs="false"/> <option name="CWMLITE" value="true" includeInPDBs="true"> <tablespace id="SYSAUX"/> </option> <option name="APEX" value="false" includeInPDBs="false"/> <option name="DV" value="true" includeInPDBs="true"/> <option name="NET_EXTENSIONS" value="true" includeInPDBs="true"/> </CommonAttributes> <Variables/> <CustomScripts Execute="false"/> <InitParamAttributes> <InitParams> <initParam name="db_name" value="xe"/> <initParam name="dispatchers" value="(PROTOCOL=TCP) (SERVICE={SID}XDB)"/> <initParam name="audit_file_dest" value="{ORACLE_BASE}\admin\{DB_UNIQUE_NAME}\adump"/> <initParam name="compatible" value="18.0.0"/> <initParam name="remote_login_passwordfile" value="EXCLUSIVE"/> <initParam name="undo_tablespace" value="UNDOTBS1"/> <initParam name="control_files" value="("{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\control01.ctl", "{ORACLE_BASE}\fast_recovery_area\{DB_UNIQUE_NAME}\control02.ctl")"/> <initParam name="diagnostic_dest" value="{ORACLE_BASE}"/> <initParam name="audit_trail" value="db"/> <initParam name="db_block_size" value="8" unit="KB"/> <initParam name="open_cursors" value="600"/> </InitParams> <MiscParams> <databaseType>MULTIPURPOSE</databaseType> <maxUserConn>20</maxUserConn> <percentageMemTOSGA>40</percentageMemTOSGA> <customSGA>true</customSGA> <dataVaultEnabled>false</dataVaultEnabled> <archiveLogMode>true</archiveLogMode> <initParamFileName>{ORACLE_BASE}\admin\{DB_UNIQUE_NAME}\pfile\init.ora</initParamFileName> </MiscParams> <SPfile useSPFile="true">{ORACLE_HOME}\database\spfile{SID}.ora</SPfile> </InitParamAttributes> <StorageAttributes> <DataFiles> <Location>{ORACLE_HOME}\assistants\dbca\templates\XE_Seed_Database.dfb</Location> <SourceDBName cdb="false">xe</SourceDBName> <Name id="3" Tablespace="SYSAUX" Contents="PERMANENT" Size="400" autoextend="true" blocksize="8192" con_id="1">{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\XE_SYSAUX01.DBF</Name> <Name id="1" Tablespace="SYSTEM" Contents="PERMANENT" Size="820" autoextend="true" blocksize="8192" con_id="1">{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\XE_SYSTEM01.DBF</Name> <Name id="4" Tablespace="UNDOTBS1" Contents="UNDO" Size="25" autoextend="true" blocksize="8192" con_id="1">{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\XE_UNDOTBS01.DBF</Name> <Name id="7" Tablespace="USERS" Contents="PERMANENT" Size="5" autoextend="true" blocksize="8192" con_id="1">{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\XE_USERS01.DBF</Name> </DataFiles> <TempFiles> <Name id="1" Tablespace="TEMP" Contents="TEMPORARY" Size="20" con_id="1">{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\TEMP01.DBF</Name> </TempFiles> <ControlfileAttributes id="Controlfile"> <maxDatafiles>100</maxDatafiles> <maxLogfiles>16</maxLogfiles> <maxLogMembers>3</maxLogMembers> <maxLogHistory>1</maxLogHistory> <maxInstances>8</maxInstances> <image name="control01.ctl" filepath="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\"/> <image name="control02.ctl" filepath="{ORACLE_BASE}\fast_recovery_area\{DB_UNIQUE_NAME}\"/> </ControlfileAttributes> <RedoLogGroupAttributes id="1"> <reuse>false</reuse> <fileSize unit="MB">256</fileSize> <Thread>1</Thread> <member ordinal="0" memberName="xe_redo01.log" filepath="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\"/> </RedoLogGroupAttributes> <RedoLogGroupAttributes id="2"> <reuse>false</reuse> <fileSize unit="MB">256</fileSize> <Thread>1</Thread> <member ordinal="0" memberName="xe_redo02.log" filepath="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\"/> </RedoLogGroupAttributes> <RedoLogGroupAttributes id="3"> <reuse>false</reuse> <fileSize unit="MB">256</fileSize> <Thread>1</Thread> <member ordinal="0" memberName="xe_redo03.log" filepath="{ORACLE_BASE}\oradata\{DB_UNIQUE_NAME}\"/> </RedoLogGroupAttributes> </StorageAttributes></DatabaseTemplate>
2. nun startet man den DBCA als Administrator! und löscht die installierte Datenbank Version XEa, "Datenbank löschen"b, Kennwort für SYS eintragen und "Weiter"c, "Weiter"d, "Fertig stellen"e, "Ja"3. Danach kann man die XE Version erneut installieren (als NON CDB)Update vom 12.6.2019. Seit neuestem, wird nur noch ein CDB Template mit ausgeliefert. Wir konnten durch kopieren des Templates in den Template Ordner weiterhineine NON CDB Datenbank erstellen.a, "Datenbank erstellen"b, Globaler Datenbankname: XE[ ] Als Containerdatenbank erstellen ABWÄHLEN.Beachten Sie aber, dass die Speichergrößen von PGA und SGA 2 GB nicht übersteigen dürfen. Der Installer prüft das nicht und fällt erst bei 70% der Installation auf die Nase und man kann von vorne beginnen. Deswegen nehmen wir die "Erweiterte Konfiguration" "Weiter"c, Weiterd, Globaler Datenbankname: XE.<ihre-Domain>SID: XEe, Weiterf, Fast Recovery Area Größe nach eigenen Wünschen anpassen (Min 8GB)[x] Archivierung aktiviereng, Listenerauswahl Weiterh, Database Vault und Label Security nicht anwählen => Weiteri, SGA 1500MB, PGA 500MB, Prozesse auf 200 setzenj, EM "Weiter"k, Passwörter eintragen und Weiterl, Datenbank erstellen und/oder ein Skript zur Erstellung erzeugen. "Fertigstellen"
Hier wäre unsere Vorlage, das ganze ein Template einzuspielen:
<?xml version = '1.0'?><DatabaseTemplate name="XE 18C NONCDB" description="XE 18c ohne Container Datenbank" version="18.0.0.0.0"> <CommonAttributes> <option name="OMS" value="true" includeInPDBs="true"/> <option name="JSERVER" value="true" includeInPDBs="true"/> <option name="SPATIAL" value="true" includeInPDBs="true"/> <option name="IMEDIA" value="true" includeInPDBs="true"/> <option name="ORACLE_TEXT" value="true" includeInPDBs="true"> <tablespace id="SYSAUX"/> </option> <option name="SAMPLE_SCHEMA" value="false" includeInPDBs="false"/> <option name="CWMLITE" value="true" includeInPDBs="true"> <tablespace id="SYSAUX"/> </option> <option name="APEX" value="false" includeInPDBs="false"/> <option name="DV" value="true" includeInPDBs="true"/> <option name="NET_EXTENSIONS" value="true" includeInPDBs="true"/> </CommonAttributes> <Variables/> <CustomScripts Execute="false"/> <InitParamAttributes> <InitParams> <initParam name="db_name" value="xe"/> <initParam name="db_domain" value="ad.muniqsoft-training.de"/> <initParam name="dispatchers" value="(PROTOCOL=TCP) (SERVICE=xeXDB)"/> <initParam name="audit_file_dest" value="c:\oracle\product\18.0.0\admin\xe\adump"/> <initParam name="compatible" value="18.0.0"/> <initParam name="remote_login_passwordfile" value="EXCLUSIVE"/> <initParam name="sga_target" value="1500" unit="MB"/> <initParam name="processes" value="640"/> <initParam name="local_listener" value="LISTENER_XE"/> <initParam name="undo_tablespace" value="UNDOTBS1"/> <initParam name="control_files" value="("c:\oracle\product\18.0.0\oradata\XE\control01.ctl", "c:\oracle\product\18.0.0\fast_recovery_area\XE\control02.ctl")"/> <initParam name="diagnostic_dest" value="c:\oracle\product\18.0.0"/> <initParam name="db_recovery_file_dest" value="c:\oracle\product\18.0.0\fast_recovery_area\XE"/> <initParam name="audit_trail" value="db"/> <initParam name="log_archive_format" value="%t_%s_%r.dbf"/> <initParam name="nls_territory" value="GERMANY"/> <initParam name="db_block_size" value="8192"/> <initParam name="open_cursors" value="300"/> <initParam name="nls_language" value="GERMAN"/> <initParam name="db_recovery_file_dest_size" value="8576" unit="MB"/> <initParam name="pga_aggregate_target" value="500" unit="MB"/> </InitParams> <MiscParams> <databaseType>MULTIPURPOSE</databaseType> <maxUserConn>20</maxUserConn> <percentageMemTOSGA>40</percentageMemTOSGA> <customSGA>false</customSGA> <dataVaultEnabled>false</dataVaultEnabled> <characterSet>AL32UTF8</characterSet> <nationalCharacterSet>AL16UTF16</nationalCharacterSet> <archiveLogMode>true</archiveLogMode> <initParamFileName>{ORACLE_BASE}\admin\{DB_UNIQUE_NAME}\pfile\init.ora</initParamFileName> </MiscParams> <SPfile useSPFile="true">{ORACLE_HOME}\database\spfile{SID}.ora</SPfile> </InitParamAttributes> <StorageAttributes> <DataFiles> <Location>{ORACLE_HOME}\assistants\dbca\templates\XE_Seed_Database.dfb</Location> <SourceDBName cdb="true">xe</SourceDBName> <Name id="3" Tablespace="SYSAUX" Contents="PERMANENT" Size="400" autoextend="true" blocksize="8192" con_id="1">c:\oracle\product\18.0.0\oradata\XE\SYSAUX01.DBF</Name> <Name id="1" Tablespace="SYSTEM" Contents="PERMANENT" Size="820" autoextend="true" blocksize="8192" con_id="1">c:\oracle\product\18.0.0\oradata\XE\SYSTEM01.DBF</Name> <Name id="4" Tablespace="UNDOTBS1" Contents="UNDO" Size="25" autoextend="true" blocksize="8192" con_id="1">c:\oracle\product\18.0.0\oradata\XE\UNDOTBS01.DBF</Name> <Name id="7" Tablespace="USERS" Contents="PERMANENT" Size="5" autoextend="true" blocksize="8192" con_id="1">c:\oracle\product\18.0.0\oradata\XE\USERS01.DBF</Name> </DataFiles> <TempFiles> <Name id="1" Tablespace="TEMP" Contents="TEMPORARY" Size="20" con_id="1">c:\oracle\product\18.0.0\oradata\XE\TEMP01.DBF</Name> </TempFiles> <ControlfileAttributes id="Controlfile"> <maxDatafiles>100</maxDatafiles> <maxLogfiles>16</maxLogfiles> <maxLogMembers>3</maxLogMembers> <maxLogHistory>1</maxLogHistory> <maxInstances>8</maxInstances> <image name="control01.ctl" filepath="c:\oracle\product\18.0.0\oradata\XE\"/> <image name="control02.ctl" filepath="c:\oracle\product\18.0.0\fast_recovery_area\XE\"/> </ControlfileAttributes> <RedoLogGroupAttributes id="1"> <reuse>false</reuse> <fileSize unit="KB">204800</fileSize> <Thread>1</Thread> <member ordinal="0" memberName="redo01.log" filepath="c:\oracle\product\18.0.0\oradata\XE\"/> </RedoLogGroupAttributes> <RedoLogGroupAttributes id="2"> <reuse>false</reuse> <fileSize unit="KB">204800</fileSize> <Thread>1</Thread> <member ordinal="0" memberName="redo02.log" filepath="c:\oracle\product\18.0.0\oradata\XE\"/> </RedoLogGroupAttributes> <RedoLogGroupAttributes id="3"> <reuse>false</reuse> <fileSize unit="KB">204800</fileSize> <Thread>1</Thread> <member ordinal="0" memberName="redo03.log" filepath="c:\oracle\product\18.0.0\oradata\XE\"/> </RedoLogGroupAttributes> </StorageAttributes></DatabaseTemplate>
Geschafft !
Jetzt schauen wir mal, welche Version installiert wurde :-) ?
select comp_name,version_full,status from dba_registry;
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
In Vorbereitung für unseren neuen zweitägigen Kurs Oracle auf Postgres Migration, den wir ab Juli 2021 anbieten werden, ist mir aufgefallen, dass es weltweit wenige Beispiele zu Postgres utl_file Implementierung gibt.Zeit, das jetzt und hier nachzuholen ...:-)Vorbereitungen:Das "Package" (Postgres hat eigentlich gar keine Packages) utl_file ist leider nicht im Standardumfang einer Postgres Installation enthalten, man benötigt dazu die Extension ORAFCE,für das bereits viele Installationsanleitungen und eine gute Doku gibt.Nachdem also erfolgreich der nachfolgende Befehl (nach der Installation aller notwendigen Packages in Linux) in psql oder pgadmin ausgeführt wurde, können wir loslegen...
Wir brauchen ein Verzeichnis mit dem wir arbeiten möchten. In unserem Beispiel verwenden wir das Verzeichnis /tmp. Dieses Arbeits-Verzeichnis tragen wir in eine Tabelle ein:Hinweis: Postgres hat keinen Directory Typ
Einfaches Beispiel (eine Zeile wird geschrieben):
Tabelle in Datei schreiben
Daten aus Datei lesen
Seit August 2021 ist nun Oracle 21c verfügbar. Im folgenden möchten wir kurz die Installation erläutern.Durchgeführt wird das ganze auf einem Oracle Linux 8.4 Server.Zuerst aktualisieren wir die Paketquellen:
Danach sollte geprüft werden ob der Server einen gültigen FQDN Eintrag in der Hosts File (/etc/hosts) besitzt
Als Beispiel der Eintrag auf unserem Server
Natürlich muss auch der korrekte Hostname in der Datei /etc/hostnames gesetzt sein.
Der nächste wichtige Schritt wäre das Ändern von SELinux Flags auf permissive. Ändern Sie also unter /etc/selinux/configfolgendes ab:
auf
Jetzt starten Sie entweder den Server neu oder setzen es mittels
für den Livebetrieb auf Permissive.Nachdem dies erfolgreich abgeschlossen wurde, installieren wir folgendes Package:mittels dnf:
oder mittels yum:
Dies installiert für uns alle Packages die für eine reibungslose Installation einer Oracle 21c Datenbank benötigt werden.Nachdem wir das Package erfolgreich installiert haben, müssen wir nun das RPM Filefür die Datenbank noch auf den Server herunterladen oder kopieren.Das geht einfach über die Oracle Download Seite.Dort findet man unter Oracle Database 21c, den Punkt "RPM".Wenn man die Datei auf den Server kopiert bzw. heruntergeladen hat, muss man sieeigentlich nur noch mit dem Paketmanager seiner Wahl installieren.Dazu führen Sie folgenden Befehl aus:
Der letzte Schritt ist das konfigurieren der DatenbankDazu rufen Sie folgendes Skript auf:
Nun ist die Datenbank fertig installiert.Man sollte nun noch eine .bash_profile mit folgendem Inhalt für den Nutzer oracle anlegen:
Wenn man sich nun erneut mit dem Oracle Nutzer anmeldet oder mittels
die Datei neu lädt kann man sich auch mit dem Befehl "sqlplus / as sysdba" direkt an der Datenbank anmelden.
Leider hat Postgres keine eingebaute Flashback Funktion. Für Flashback Database könnte man sich als Alternative ein Komplettbackup der DB erstellen (z.B. mittels pg_basebackup)Im Fehlerfall würde man dann mit einem zeitbasierten Recovery wieder auf den gewünschten Zeitpunkt zuückstellen.Wir möchten uns heute jedoch eine Alternative für Flashback Transaktion mittels eines Update und Delete Trigger basteln:Beispieltabelle erstellen:
Für die Flashbacktabelle werden drei weitere Spalten hinzugefügt
Ein Trigger in Postgres verwendet immer eine seperate Procedure oder Function:
Nun wird der Trigger erstellt:
Hinweis: Wenn Sie einen Trigger wieder löschen möchten, verwendet man folgende Syntax:
Beispieltransaktion:
Prüfen der Flashback-Tabelle:
Jetzt kommt der spannende Teil: Welchen Wert hatt eine Gehalt zu einem bestimmten Zeitpunkt in der Vergangenheit mittels unserer selbst gebauten Flashback Funktion:
Wenn Sie die Flashback Funktion für Ihre Umgebung nachbauen möchten, müssen Sie hier den Primärschlüssel empno durch Ihren Primärschlüssel austauschen.Weitere tolle Tipps erhalten Sie in einem von unseren Postgres Kursen.
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:
java -versionjava -versionjava version "17.0.4.1" 2022-08-18 LTSJava(TM) SE Runtime Environment (build 17.0.4.1+1-LTS-2)Java HotSpot(TM) 64-Bit Server VM (build 17.0.4.1+1-LTS-2, mixed mode, sharing)=> So is es gut :-)
Installation unter Windows:
ords.exe --config c:\oracle\ords installORDS: Release 22.2 Produktion am Di. Sept. 06 09:49:12 2022Copyright (c) 2010, 2022, Oracle.Konfiguration:
/C:/oracle/ords/Der Konfigurationsordner C:\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]: 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]: 1 Geben Sie den Hostnamen der Datenbank ein [localhost]: 127.0.0.1 Listener-Port der Datenbank eingeben [1521]: Datenbankservicename eingeben [orcl]: apex221 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:@//127.0.0.1:1521/apex221 wird hergestelltInformationen werden abgerufen.Verbindung zu Datenbankbenutzer: ORDS_PUBLIC_USER URL: jdbc:oracle:thin:@//127.0.0.1:1521/apex221 wird hergestellt 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]: 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]: 2Die Einstellung db.connectionType wurde auf basic in Konfiguration default gesetztDie Einstellung db.hostname wurde auf 127.0.0.1 in Konfiguration default gesetztDie Einstellung db.port wurde auf 1521 in Konfiguration default gesetztDie Einstellung db.servicename wurde auf apex221 in Konfiguration default gesetztDie Einstellung plsql.gateway.mode wurde auf proxied in Konfiguration default gesetztDie Einstellung db.username wurde auf ORDS_PUBLIC_USER in Konfiguration default gesetztDie Einstellung db.password wurde auf ****** in Konfiguration default gesetztDie Einstellung feature.sdw wurde auf true in Konfiguration default gesetztDie globale Einstellung database.api.enabled wurde auf true gesetztDie Einstellung restEnabledSql.active wurde auf true in Konfiguration default gesetztDie Einstellung security.requestValidationFunction wurde auf wwv_flow_epg_include_modules.authorize in Konfiguration default gesetzt....INFO: 11:51:30 Validating objects for Oracle REST Data Services.VALIDATION: 11:51:30 Starting validation for schema: ORDS_METADATAVALIDATION: 11:51:30 Validating objectsVALIDATION: 11:51:33 Validating roles granted to ORDS_METADATA andORDS_PUBLIC_USERVALIDATION: 11:51:33 Validating ORDS Public SynonymsVALIDATION: 11:51:34 Total objects: 312, invalid objects: 0, missing objects: 0VALIDATION: 11:51:34 88 INDEXVALIDATION: 11:51:34 1 JOBVALIDATION: 11:51:34 3 LOBVALIDATION: 11:51:34 20 PACKAGEVALIDATION: 11:51:34 19 PACKAGE BODYVALIDATION: 11:51:34 1 PROCEDUREVALIDATION: 11:51:34 56 PUBLIC SYNONYMVALIDATION: 11:51:34 1 SEQUENCEVALIDATION: 11:51:34 31 TABLEVALIDATION: 11:51:34 31 TRIGGERVALIDATION: 11:51:34 20 TYPEVALIDATION: 11:51:34 6 TYPE BODYVALIDATION: 11:51:34 35 VIEWVALIDATION: 11:51:34 Validation completed.INFO: 11:51:34 Completed validating objects for Oracle REST Data Services.PL/SQL-Prozedur erfolgreich abgeschlossen.Commit abgeschlossen.[*** script: ords_alter_session_script.sql]PL/SQL-Prozedur erfolgreich abgeschlossen.2022-09-06T09:51:34.159Z INFO Upgrade f³r Oracle REST Data Services Version 22.2.1.r2021302 wurde abgeschlossen. Verstrichene Zeit: 00:00:22.914[*** Informationen: Upgrade complete][*** Informationen: Upgrade f├╝r Oracle REST Data Services Version 22.2.1.r2021302 wurde abgeschlossen. Verstrichene Zeit: 00:00:22.914]------------------------------------------------------------Containername: APEX221------------------------------------------------------------[*** script: ords_configure_gateway.sql]Configured PL/SQL Gateway user APEX_PUBLIC_USER to be proxiable fromORDS_PUBLIC_USERPL/SQL-Prozedur erfolgreich abgeschlossen.2022-09-06T09:51:34.244Z INFO Konfiguration von PL/SQL-Gatewaybenutzer f³r Oracle REST Data Services Version 22.2.1.r2021302 wurde abgeschlossen. Verstrichene Zeit: 00:00:00.852022-09-06T09:51:34.244Z INFO Datenbankkennwort f³r ORDS_PUBLIC_USER in APEX221 wird aktualisiert[*** Informationen: Konfiguration von PL/SQL-Gatewaybenutzer f├╝r Oracle REST Data Services Version 22.2.1.r2021302 wurde abgeschlossen. Verstrichene Zeit: 00:00:00.85][*** script: ords_change_password.sql]PL/SQL-Prozedur erfolgreich abgeschlossen.2022-09-06T09:51:34.359Z INFO Aktualisieren von Datenbankkennwort f³r ORDS_PUBLIC_USER wurde abgeschlossen. Verstrichene Zeit: 00:00:00.100[*** Informationen: Aktualisieren von Datenbankkennwort f├╝r ORDS_PUBLIC_USER wurde abgeschlossen. Verstrichene Zeit: 00:00:00.100]
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:
-Dconfig.url=C:\oracle\ords
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:
_JAVA_OPTIONS=-Dconfig.url=c:\oracle\ords
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 !
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..
oder etwas ausführlicher:
SELECT oc.id, oc.name, oc.client_id, oc.client_secret,ocr.role_name,ocp.name,oc.created_by FROM user_ords_clients oc,user_ords_client_roles ocr,user_ords_client_privileges ocp where oc.id=ocr.client_id(+) and oc.id=ocp.client_priv_client_id;
Zwischenschritt: Wir testen, ob OAUTH2 uns ein Ticket zurückbringt (sonst sind vermutlich client_id oder client_secret nicht korrekt:
WITH FUNCTION oauth2 RETURN VARCHAR2 IS BEGIN apex_web_service.oauth_authenticate( p_token_url => 'https://www.muniqsoft-training.de/ords/muso/oauth/token', p_client_id => 'xx..', p_client_secret => 'yy..', p_wallet_path => 'file:///opt/oracle/admin/FREE/https_wallet'); RETURN apex_web_service.oauth_get_last_token; END; SELECT oauth2 from dual; =>J5C4eT6W8k0rkj5yeVwxg2
Wir hatten aber noch ein anderes Problem zu lösen: Unser Tomcat ist hinter einem httpd (Apache) Server als Reverse Proxy geschaltet.
Nur leider gibt per Default httpd an den TomCat die daten per http weiter, das mag aber oauth2 nicht. Obwohl wir in der pool.xml (ords config Ordner/database) den Wert
<entry key="security.verifySSL">false</entry>
eingetragen hatten, bekamen wir trotzdem immer die Fehlermeldungen:
TomCat Logfile: java.lang.IllegalArgumentException: Invalid character found in method name [0x050x010x00...]. HTTP method names must be tokens.
Die Lösung bei uns war folgende Zeilen in die httpd.conf Datei einzutragen:
SSLProxyEngine on SSLProxyVerify none SSLProxyCheckPeerCN off SSLProxyCheckPeerName off SSLProxyCheckPeerExpire off RequestHeader set Front-End-Https "On" ProxyPreserveHost on ProxyPass /ords https://127.0.0.1:8443/ords timeout=500 ProxyPassReverse /ords https://127.0.0.1.8443/ords RequestHeader set X-Forwarded-Proto "https" RequestHeader set X-Forwarded-Port "443"
Zusätzlich muss für den TomCat noch ein SSL Self Certificate erstellt werden!
Zurück zum Thema:Die beiden Informationen (client_id + client_secret) 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;
Im heutigen Tipp widmen wir uns ein paar Praxisbeispielen zu Regulär Expression (Reguläre Ausdrücke) in Oracle.
Beispiel 1: Kreditkartennummern haben meist das Format 1234-1234-1234-1234Wir suchen in einem String zwei 4er Blöcke mit Zahlen un einem Minus dazwischen und ersetzen jeden Block durch xxxx-xxxx:
select regexp_replace( '1234-5678-1111-2222', '[[:digit:]]{4}-[[:digit:]]{4}','xxxx-xxxx') from dual;
Ergebnis: xxxx-xxxx-xxxx-xxxx
Oder wir suchen vier 4er Blöcke mit Zahlen und ersetzen das mit XXXX:
select regexp_replace( '1234-5678-1111-2222', '[[:digit:]]{4}','xxxx') from dual;
Nur der letzte 4er Block soll ausgegeben werden
select regexp_replace( '1234-5678-1111-2222', '([[:digit:]]{4})(-)([[:digit:]]{4})(-)([[:digit:]]{4})(-)([[:digit:]]{4})','XXXX-XXXX-XXXX-\7') from dual;
XXXX-XXXX-XXXX-2222
Alternativ können sie anstatt [[:digit:]] durch \d ersetzen
select regexp_replace( '1234-5678-1111-2222', '\d{4}','x') from dual;
Ergebnis: x-x-x-x
Beispiel 2: Wir löschen einige HTML Tags in einem String:
select regexp_replace( '<div>Hallo</div><strong> Kurs</strong>', '(<\/?div>|<\/?p>|<\/?strong>)','') from dual;
oder wir löschen alle HTML Tags im String
select regexp_replace( '<div>Hallo</div><strong> Kurs</strong>', '<\/?[^>]*>,'') from dual;
Das war eine kleine Beispielauswahl, die von uns ständig erweitert wird. Oder Sie kommen z.B. in den PL/SQL oder PL/SQL II Kurs, da werden diese Themen auch ausführlich besprochen.
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 23ai 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 23ai herunterladen:
wget https://yum.oracle.com/repo/OracleLinux/OL8/appstream/x86_64/getPackage/oracle-database-preinstall-23ai-1.0-2.el8.x86_64.rpm
2. FREE Edition herunterladenwget https://download.oracle.com/otn-pub/otn_software/db-free/oracle-database-free-23ai-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 23.2 (oder neuer) herunter:https://download.oracle.com/otn_software/apex/apex_23.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.2024) nicht von ORDS unterstützt:https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.93/bin/apache-tomcat-9.0.93.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-23ai-1.0-0.5.el8.x86_64.rpm wget https://download.oracle.com/otn-pub/otn_software/db-free/oracle-database-free-23ai-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_23.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.89.zip
Nun kann mit der Installation der in SES_2 heruntergeladenen Programme begonnen werden
Session SES_1:
dnf -y install oracle-database-preinstall-23ai* dnf -y localinstall oracle-database-free-23ai* export DB_PASSWORD=mein_password_fuer_2023 (echo "${DB_PASSWORD}"; echo "${DB_PASSWORD}";) | /etc/init.d/oracle-free-23ai configure
In der Datei /etc/oratab die Datenbank auf Autostart (N durch Y in der letzten Zeile am Ende ersetzen)
FREE:/opt/oracle/product/23ai/dbhomeFree:Y
Wenn die Oracle Datenbank Instanz und der Oracle Listener beim Start des Betriebssystem mitstarten sollen:
systemctl enable oracle-free-23ai
Wenn Oracle DB + Listener manuell gestoppt und gestartet werden sollen:
systemctl stop oracle-free-23ai systemctl start oracle-free-23ai
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-23ai in die Datei oracle um:
cp /etc/rc.d/init.d/oracle-free-23ai /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.89.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/23ai/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/23ai/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:http://172.30.30.99:8080/ords
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 :-)
Ab der Version Oracle 21c wird zusätzlich zum alert.log noch eine neue Datei ausgeliefert: das Attention.log. Hier sollen wichtige Information als Zusammenfassung der Alert.log stehen.
Naja, ich hoffe das wird nicht etwas verbessert, aber trotzdem wäre es praktisch die Datei mit einem Select auszulesen. Ich hatte gehofft, jemand hat sich die Arbeit schon gemacht (Google wo bist Du, wenn man Dich braucht…), aber leider habe ich nichts gefunden.
Ok, dann mach ich es halt …
Wir geben die Objekte dem Benuter system, sie können aber natürlich auch einen anderen Benutzer dafür einrichten.
ALTER SESSION SET current_schema=system; col adir new_value adir col afile new_value afile with diag as (select sys_context('userenv','PLATFORM_SLASH') as ps,value from v$diag_info where name='Attention Log') select substr(value,1,instr(value,ps,-1)-1) as adir, substr(value,instr(value,ps,-1)+1) as afile from diag;
CREATE OR REPLACE DIRECTORY attention_dir as '&adir.'; GRANT READ ON DIRECTORY attention_dir to system;
CREATE OR REPLACE TYPE attention_type AS OBJECT ( NOTIFICATION VARCHAR2(4000), ERROR VARCHAR2(4000), URGENCY VARCHAR2(4000), INFO VARCHAR2(4000), CAUSE VARCHAR2(4000), ACTION VARCHAR2(4000), CLASS VARCHAR2(4000), TIME TIMESTAMP WITH TIME ZONE ); /
CREATE OR REPLACE TYPE attention_tab_type AS TABLE OF attention_type; /
CREATE OR REPLACE FUNCTION read_attention_log RETURN attention_tab_type PIPELINED IS f_handle utl_file.file_type:=utl_file.fopen( location=>'ATTENTION_DIR', filename=>'&afile.', open_mode=>'r', max_linesize=>32767); text varchar2(32767); v_a_log attention_type:=attention_type(null,null,null,null,null,null,null,null); v_i INT:=1; BEGIN LOOP BEGIN utl_file.get_line(f_handle,text); -- Neue Zeile lesen IF substr(text,1,16)=' "NOTIFICATION"' THEN v_a_log.NOTIFICATION:=rtrim(rtrim(substr(text,21),','),'"'); END IF; IF substr(text,1,9)=' "ERROR"' THEN v_a_log.ERROR:=rtrim(rtrim(substr(text,21),','),'"'); END IF; IF substr(text,1,11)=' "URGENCY"' THEN v_a_log.URGENCY:=rtrim(rtrim(substr(text,21),','),'"'); END IF; IF substr(text,1,8)=' "INFO"' THEN v_a_log.INFO:=rtrim(rtrim(substr(text,21),','),'"'); END IF; IF substr(text,1,9)=' "CAUSE"' THEN v_a_log.CAUSE:=rtrim(rtrim(substr(text,21),','),'"'); END IF; IF substr(text,1,10)=' "ACTION"' THEN v_a_log.ACTION:=rtrim(rtrim(substr(text,21),','),'"'); END IF; IF substr(text,1,9)=' "CLASS"' THEN v_a_log.CLASS:=rtrim(rtrim(substr(text,21),','),'"'); END IF; IF substr(text,1,8)=' "TIME"' THEN v_a_log.TIME:=to_timestamp_tz(rtrim(substr(text,21),'"'),'YYYY-MM-DD"T"HH24:MI:SS.FFTZH:TZM'); PIPE ROW (v_a_log); v_a_log :=attention_type(null,null,null,null,null,null,null,null); END IF; EXCEPTION WHEN NO_DATA_FOUND THEN EXIT; -- Keine Zeile im Attention.log mehr gefunden oder Fehler=> Schleife verlassen WHEN OTHERS THEN RAISE; END; END LOOP; utl_file.fclose(f_handle); END; /
Un nun können Sie das attention.log via SQL auslesen …
SELECT * FROM table(read_attention_log);
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 !
Alle warten ja gespannt auf die Production Version von Oracle 23ai (formaly known as Oracle 23c). Denn wenn die rauskommt hofft der eine oder andere Windows Benutzer auf eine Windows Portierung.
Wir wollen hier eine Lösung vorstellen die eigentlich ein Kompromiss ist: Oracle 23ai auf Windows in einer Linux Umgebung. Jetzt werden Sie sagen, ja via Virtualisierung geht das ja schon immer… Es gibt aber evtl eine neue Variante, die nicht so bekannt ist: WSL (Windows Subsystem for Linux). Dazu muss nur die CPU auch Virtualisierung unterstützen.Wir arbeiten dann im Windows Terminal (das ab Win 11 vorinstalliert ist)Für Win 10 kann es nachinstalliert werden z.B. mittels:
winget install --id Microsoft.WindowsTerminal -e
Das läuft zwar unter der Haube auch wie eine Virtualisierung, aber der Benutzer sieht nichts davon. Interessant ist, dass Oracle natürlich diese neue Schnittstelle unterstützt (ob sie supported ist, müssten Sie bitte mit Ihrem Support-Techniker klären) Ich würde mal tippen NEIN, aber für die Testzwecke ist die Installation ganz OK. Be uns funktionierte das Ganze sogar innerhalb einer Virtualisierungsmaschine (Nested Virtualization)
Zuerst werden die Windows Features aktiviert (in einem Powershell Fenster als Administrator):
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all
Beachten Sie bitte, dass die Distrubution später auch nur unter diesem Admin Account im Terminal angezeigt wird!
Wir lassen uns anzeigen, welche Distributionen unterstützt werden:
wsl --list --online Die folgende Liste enthält gültige Distributionen, die installiert werden können. Die Standard Distribution ist mit „*“ gekennzeichnet. Installieren sie mit dem Befehl „wsl --install -d <Distro>“. NAME FRIENDLY NAME * Ubuntu Ubuntu Debian Debian GNU/Linux kali-linux Kali Linux Rolling Ubuntu-18.04 Ubuntu 18.04 LTS Ubuntu-20.04 Ubuntu 20.04 LTS Ubuntu-22.04 Ubuntu 22.04 LTS Ubuntu-24.04 Ubuntu 24.04 LTS OracleLinux_7_9 Oracle Linux 7.9 OracleLinux_8_7 Oracle Linux 8.7 OracleLinux_9_1 Oracle Linux 9.1 openSUSE-Leap-15.5 openSUSE Leap 15.5 SUSE-Linux-Enterprise-Server-15-SP4 SUSE Linux Enterprise Server 15 SP4 SUSE-Linux-Enterprise-15-SP5 SUSE Linux Enterprise 15 SP5 openSUSE-Tumbleweed openSUSE Tumbleweed
und siehe da, es werden sogar drei verschiedene Oracle Versionen unterstützt!
Da Oracle 23ai die Version 9 unterstützt, nehmen wir diese natürlich und installieren die Distribution (dauert ca 4 Min.).
wsl --install -d OracleLinux_9_1 --web-download oder manchmal auch nur: wsl --install -d OracleLinux_9_1
Bei einem Fehler: Error: 0x800701bc WSL 2 erfordert ein Update der Kernelkomponente sollte das WSL upgedated werden. z.B. hier.
Wir werden nun nach einen Benutzernamen und einem Passwort für die Distribution gefragt. Wir nehmen Oracle Passwort sys (oder ein besseres natürlich…)
Installing, this may take a few minutes... Please create a default UNIX user account. The username does not need to match your Windows username. For more information visit: https://aka.ms/wslusers Enter new UNIX username: oracle Changing password for user oracle. New password: Retype new password: Windows-Subsystem für Linux ist jetzt im Microsoft Store verfügbar! Sie können ein Upgrade durchführen, indem Sie "wsl.exe --update" ausführen oder https://aka.ms/wslstorepage Durch die Installation von WSL aus dem Microsoft Store erhalten Sie schneller die neuesten WSL-Updates. Weitere Informationen finden Sie unter https://aka.ms/wslstoreinfo
gut ein Update schadet ja selten ..
wsl.exe --update Installation: Windows-Subsystem für Linux Windows-Subsystem für Linux wurde installiert.
Danach sind wir im Terminalfenster bereits in der Unix Maschine angemeldet. Sie können aber natürlich sich auch mittels Putty verbinden.
Nun brauchen wir das Oracle Vorbereitungspackage für die Installation der Datenbank.
sudo dnf install -y oracle-database-preinstall-23ai
Danach laden wird die aktuelle Oracle 23ai Version runter und installieren diese:
wget https://download.oracle.com/otn-pub/otn_software/db-free/oracle-database-free-23ai-1.0-1.el8.x86_64.rpm sudo rpm -ihv oracle-database-free-23ai*
Wenn Sie SYSTEMCTL aktivieren möchten tragen Sie bitte folgendes in die Datei /etc/wsl.conf ein:
[boot] systemd=true
Weitere Parameter finden Sie hier.
Wenn Sie systemd=true gesetzt haben, kann Oracle als Service eingerichtet werden:
cp /etc/initd.d/oracle-free-23ai /etc/init.d/oracle systemctl enable oracle oracle.service is not a native service, redirecting to systemd-sysv-install. Executing: /usr/lib/systemd/systemd-sysv-install enable oracle systemctl start oracle systemctl status oracle ● oracle.service - SYSV: This script is responsible for taking care of configuring the RPM Oracle FREE Database and its> Loaded: loaded (/etc/rc.d/init.d/oracle; generated) Active: active (exited) since Sat 2024-05-18 09:44:49 CEST; 6s ago Docs: man:systemd-sysv-generator(8) Process: 857 ExecStart=/etc/rc.d/init.d/oracle start (code=exited, status=0/SUCCESS) May 18 09:44:48 Schulung133 systemd[1]: Starting SYSV: This script is responsible for taking care of configuring the RP> May 18 09:44:49 Schulung133 oracle[857]: The Oracle Database instance FREE is already started. May 18 09:44:49 Schulung133 systemd[1]: Started SYSV: This script is responsible for taking care of configuring the RPM>
resolv.conf prüfen:
sudo cat /etc/resolv.conf nameserver 172.30.30.6 nameserver 8.8.8.8
Weitere Interessante/praktische Packages für Oracle, die sie nun installieren sollten (ohne hostname klappte unsere Installation auf einigen Rechnern nicht):
OpenSSH
sudo dnf install -y openssh
RLWRAP (History für SQL*Plus und RMAN Eingaben:
sudo dnf install -y https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/Packages/r/rlwrap-0.46.1-1.el9.x86_64.rpm
P7ZIP (Packutility)
sudo dnf install -y https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/Packages/p/p7zip-16.02-21.el9.x86_64.rpm sudo dnf install -y https://dl.fedoraproject.org/pub/epel/9/Everything/x86_64/Packages/p/p7zip-plugins-16.02-21.el9.x86_64.rpm
Firewall
sudo dnf install -y firewall
Hostname
sudo dnf install -y hostname
Wenn auf Ihrer Windows-Maschine bereits eine Oracle Datenbank mit Listener auf Port 1521 läuft, ändern wir den Port für unsere neue DB:
Listener Port ändern in /etc/sysconfig/oracle-free-23ai.conf => 1522
Die Datei hat übrigens folgendes Aussehen (falls Sie vor der Installation noch mehr ändern wollen):
#This is a configuration file to setup the Oracle Database. #It is used when running '/etc/init.d/oracle-free-23ai configure'. # LISTENER PORT used Database listener, Leave empty for automatic port assignment LISTENER_PORT=1522 # Character set of the database CHARSET=AL32UTF8 # Database file directory # If not specified, database files are stored under Oracle base/oradata DBFILE_DEST= # DB Domain name DB_DOMAIN= # Configure TDE CONFIGURE_TDE=false # Encrypt Tablespaces list, Leave empty for user tablespace alone or provide ALL for encrypting all tablespaces # For specific tablespaces use SYSTEM:true,SYSAUX:false ENCRYPT_TABLESPACES= # SKIP Validations, memory, space SKIP_VALIDATIONS=false
Nun starten wir das Oracle Installationsskript:
sudo /etc/init.d/oracle-free-23ai configure ... Database creation complete. For details check the logfiles at: /opt/oracle/cfgtoollogs/dbca/FREE. Database Information: Global Database Name:FREE System Identifier(SID):FREE Look at the log file "/opt/oracle/cfgtoollogs/dbca/FREE/FREE.log" for further details. Connect to Oracle Database using one of the connect strings: Pluggable database: Schulung133:1522/FREEPDB1 Multitenant container database: Schulung133:1522
et voila, die Datenbank ist installiert.
Praktisch ist es jetzt noch, wenn wir uns gleich ein schönes Profil für die neue DB einrichten
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/23ai/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 [x]e_pmon | awk '{print "Oracle-Prozess:" $2}' ps aux | grep [t]ns | awk '{print "Listener-Prozess:" $2}' HISTCONTROL=ignorespace
Na dann testen wir mal:
sqlplus / as sysdba SQL*Plus: Release 23.0.0.0.0 - Production on Mi Mai 15 08:43:05 2024 Version 23.4.0.24.05 Copyright (c) 1982, 2024, Oracle. All rights reserved. Verbunden mit: Oracle Database 23ai Free Release 23.0.0.0.0 - Develop, Learn, and Run for Free Version 23.4.0.24.05
wenn die Instanz gestartet wurde, kann natürlich auch von SQL Developer Windows eine Verbindung zur 23ai aufgebaut werden.
Zum Schluss ein paar Tipps & Tricks , weil die WSL verhält sich nicht ganz Linux-Like … z.B. wird systemctl nicht unterstützt (grmmpf) oder der root account hat kein Passwort und unser Benutzer oracle übernimmt seine Aufgaben mittels sudo …
Instanz und Listener starten:
sudo -s service oracle-free-23ai start oder sudo -s /etc/init.d/oracle-free-23ai start [sudo] password for oracle: Starting Oracle Net Listener. Oracle Net Listener started. Starting Oracle Database instance FREE. Oracle Database instance FREE started.
IP Adresse ändern (Static):
sudo ip address add 172.30.30.233/24 brd + dev eth0
Anmelden an spezieller Distribution mit Benutzer Oracle:
wsl --distribution OracleLinux_9_1 --user oracle
Windows Terminal als Admin starten
Windows Key + X => Windows Terminal (Admin) auswählen
Stoppen der Oracle Linux Disti (shutdown -r now ist hier nicht möglich)
wsl --shutdown OracleLinux_9_1 In Ihrer Linux shell erscheint dann: [Verarbeitung des Prozesses mit Code 1 (0x00000001) beendet] Sie können dieses Terminal jetzt mit STRG+D schließen oder zum Neustart die EINGABETASTE drücken. Nun viel Spass mit Oracle 23ai "unter Windows” und evtl sehen wir uns mal in einem unserer Kurse (live oder per Teams) …
Es gibt ja ca 40.000 Oracle Fehlermeldungen, die vermutlich keiner auswendig kennt. Aber dafür hat ja man die Datenbank, denn die kennt natürlich alle Ihre Fehlertexte.
Die Fehlerfunktion sqlerrm kann mit einem Parameter (der Fehlernummer) aufgerufen werden. Leider klappt das nur in einem PL/SQL Kontext. Aber kein Problem mittels der WITH Klausel kann in SQL auch eine PL/SQL Funktion ausgeführt werden (es ist noch nicht mal das Recht CREATE PROCEDURE) notwendig.
Also wenn man z.B- die ersten 1000 Oracle Fehlertexte ausgeben möchte, kann man folgene SQL Query ausführen.
WITH FUNCTION get_err_text(id IN NUMBER) RETURN VARCHAR2 IS BEGIN return (sqlerrm(id)); END; SELECT get_err_text(-1*rownum) FROM dual CONNECT BY LEVEL<1000;
Alternativ kann auch ein spezieller Bereich (hier von ORA-1000 bis ORA-1100) angezeigt werden:
WITH FUNCTION get_err_text(id IN NUMBER) RETURN VARCHAR2 IS BEGIN return (sqlerrm(id)); END; err_msg as (SELECT rownum as err_id FROM dual CONNECT BY LEVEL<100000) SELECT get_err_text(-1*err_id) FROM err_msg WHERE err_id between 1000 and 1100;
Wer interesse hat,mehr über die Fehlerbehandlung in Oracle zu erfahren, besucht einfach unseren PL/SQL Grundlagen-Kurs
Wir hatten letzte Woche das Problem, dass unsere Oracle 23ai FREE Version an ihr Speicherlimit von 12GB (ORA-12954 The request exceeds the maximum allowed database size of 12 GB.) gekommen ist. Obwohl wir nur Daten mit maximal 1 GB besitzen, wollte die FREE Edition uns partout keinen Speicherplatz mehr gönnen.
Was war passiert ? Der SYSAUX Tablespace hatte in der CDB 3.5 GB und in der PDB bereits 4 GB erreicht. Obwohl in beiden Tablespace mindestens 2GB frei waren!Diesen Speicher zählt Oracle also mit in die 12 GB hinein. Gut kein Problem, dachten wir, dann verkleinern wir den SYSAUX Tablespace halt…
…Honey i shrunk the SYSAUX Tablespace…
Daraus ist dieser BLOG Eintrag entstanden und viiiiiiel internes Fachwissen, welche Objekte mit Samthandschuhen angefasst werden möchten.
Offiziell sind viele dieser Tipps hier auf der Seite “not supported” von Oracle. Das Ganze also bitte nur auf Test-Datenbanken durchführen. Wir haben es zwar auf zwei unserer Produktiv-Datenbanken erfolgreich durchgeführt, trotzdem können wir leider keine Garantie auf die Funktionsweise geben !
Was ist das Problem des SYSAUX Tablespace?
Lösungen:
Wenn Sie vorab wissen möchten welche Verwaltungstabellen welche Anzahl an Zeilen besitzt, können Sie eine Statistik darauf laufen lassen ( Dauerte bei uns ca 8 Min ! )
exec dbms_stats.gather_fixed_objects_stats(degree=>8); exec dbms_stats.gather_dictionary_stats(degree=>8);
PURGE dba_recyclebin;
2. Plugin Violations Tabelle für CDB und alle PDBs leeren
exec DBMS_PDB.CLEAR_PLUGIN_VIOLATIONS (Pdb_name => 'PDB$SEED' ); exec DBMS_PDB.CLEAR_PLUGIN_VIOLATIONS (Pdb_name => 'CDB$ROOT' ); … exec DBMS_PDB.CLEAR_PLUGIN_VIOLATIONS (Pdb_name => 'MY_PDB1' );
3. Kompletten Audit löschen (Achtung vorher evtl. eine Kopie von UNIFIED_AUDIT_TRAIL machen) und den Audit auf anderen Tablespace verschiebenAchtung es dauert einen Tag bis das Wirkung zeigt. Diesen Schritt also evtl. schon einen Tag vorab laufen lassen
BEGIN dbms_audit_mgmt.clean_audit_trail(audit_trail_type=> dbms_audit_mgmt.audit_trail_unified ,use_last_arch_timestamp=>FALSE); END; / BEGIN DBMS_AUDIT_MGMT.ALTER_PARTITION_INTERVAL( interval_number => 1, interval_frequency => 'DAY'); END; / BEGIN DBMS_AUDIT_MGMT.SET_AUDIT_TRAIL_LOCATION( audit_trail_type => DBMS_AUDIT_MGMT.AUDIT_TRAIL_UNIFIED, audit_trail_location_value =>'SYSAUX_SCRATCH'); END; /
4. Alle alten Statistiken löschen (da wird eine Menge Platz wieder frei im SYSAUX Tablespace)
BEGIN dbms_stats.purge_stats(dbms_stats.purge_all); END; / BEGIN dbms_stats.reset_col_usage (null,null); END; /
5. Komplette ADDM Statistiken löschen (damit hat Ihre DB die gleichen “Probleme”, als wenn Sie ganz frisch aufgesetzt wurde (sie hat keine Statistiken)
Sie können natürlich die letzten 2 Snapshots noch behalten (Infos dazu stehen in DBA_HIST_SNAPSHOTS)
REM Note 2660128.1
EXEC dbms_workload_repository.drop_snapshot_range(1,999999999); -- 10min exec prvt_advisor.delete_expired_tasks; WITH FUNCTION do_ddl (cmd IN VARCHAR2) RETURN VARCHAR2 IS PRAGMA AUTONOMOUS_TRANSACTION; -- Damit ist die Funktion eigenständig und beeinflusst niemanden :-) v_cmd VARCHAR2(32000); BEGIN v_cmd:=rtrim(cmd,';'); -- Semmikolon ggf.herausfiltern BEGIN EXECUTE IMMEDIATE v_cmd; -- Befehl ausführen EXCEPTION WHEN OTHERS THEN IF sqlcode=-65040 THEN BEGIN dbms_pdb.exec_as_oracle_script(v_cmd); EXCEPTION WHEN OTHERS THEN RETURN v_cmd||' --'||sqlerrm; END; ELSE RAISE; END IF; END; RETURN v_cmd||'; --OK'; -- Befehl erfolgreich ausgeführt EXCEPTION WHEN OTHERS THEN RETURN v_cmd||' --'||sqlerrm; END; select 'ALTER TABLE WRI$_ADV_OBJECTS MOVE' FROM dual UNION ALL select 'ALTER INDEX WRI$_ADV_OBJECTS_PK REBUILD' FROM dual UNION ALL select 'ALTER INDEX WRI$_ADV_OBJECTS_IDX_01 REBUILD' FROM dual UNION ALL select 'ALTER INDEX WRI$_ADV_OBJECTS_IDX_02 REBUILD' FROM dual /
6. OATS Oracle Active Tracking System (ab 21c):
Ist auch ein großer Platzfresser. Wir räumen (durch Löschen) alles auf. (Wir waren vor Version 21c ja auch glücklich mit unserer DB ohne dieses Feature :-) )
WITH FUNCTION del_oats (del_time date) RETURN varchar2 IS PRAGMA AUTONOMOUS_TRANSACTION; BEGIN IF dbms_activity.delete_snapshots(del_time) THEN RETURN 'OATS deleted'; ELSE RETURN 'OATS not deleted'; END IF; END; SELECT del_oats(sysdate-1/96) FROM dual;
7. Scheduler Logs aufräumen:
exec DBMS_SCHEDULER.PURGE_LOG; exec DBMS_SCHEDULER.PURGE_LOG(0,which_log=>'WINDOW_LOG');
8. Weitere Spezialfälle besprechen wir in unserer Schulung Reorg und Wartung oder im DBA II Kurs :-)
Nun kommen wir zum interessanten Teil: Verschieben der hinteren Objekte in den Scratch Tablespace
Der folgende Select erzeugt Ihnen ein Skript, mit dem sich ca. 95% der Objekte verschieben lassen.
WITH S as (select 1000 as block_id, – Nur Objekte hinter Block Nummer 1000 verschieben 3 as file_id,'SYSAUX_SCRATCH' as scratch_tbs, – Name des Scratch Tablespace für die Objekte 'ONLINE' as on_off_mode – Für SE2 Benutzer bitte Spalte auf ‘’ setzen FROM dual), db as (select count(*) as is_pdb from v$pdbs) SELECT CASE-- ## T A B L E und I N D E X P A R T I T I O N ## WHEN db.is_pdb=1 THEN 'exec dbms_pdb.exec_as_oracle_script(''' END|| CASE WHEN segment_type IN ('INDEX PARTITION','TABLE PARTITION') and e.segment_name not like 'SYS_IL0%' THEN 'ALTER ' || substr(e.segment_type,1,5)||' "' || owner || '"."' || e.segment_name || '"' || CASE segment_type WHEN 'INDEX PARTITION' THEN ' REBUILD PARTITION "' ELSE ' MOVE PARTITION "' END || partition_name|| '" '|| CASE WHEN e.segment_name NOT LIKE 'WRH$%' AND e.segment_name NOT LIKE 'WRM$%' AND e.segment_name NOT IN ('ACTIVITY_TABLE$' ,'WRI$_OPTSTAT_HISTGRM_HISTORY' ,'SCHEDULER$_EVENT_LOG','UMF$_ATSK_HIST_MXDB_MXSN','SCHEDULER$_JOB_RUN_DETAILS') THEN s.on_off_mode END ||' tablespace '||nvl(s.scratch_tbs,e.tablespace_name) WHEN segment_type IN ('TABLE','INDEX') THEN -- ###### T A B L E und I N D E X ###### 'ALTER '||e.segment_type||' "'||owner||'"."'||e.segment_name||'"'|| CASE segment_TYPE WHEN 'TABLE' THEN ' MOVE ' || s.on_off_mode ||' TABLESPACE '||nvl(s.scratch_tbs,e.tablespace_name) ELSE ' REBUILD ' || s.on_off_mode ||' TABLESPACE '||nvl(s.scratch_tbs,e.tablespace_name) END WHEN segment_type IN ('LOBSEGMENT','LOB PARTITION') THEN -- ###### L O B ###### 'ALTER TABLE "'||e.owner||'"."'||(select table_name FROM dba_lobs l where l.segment_name=e.segment_name)||'" MOVE LOB ("'|| (select column_name FROM dba_lobs l where l.segment_name=e.segment_name)||'") STORE AS (tablespace "'|| nvl(s.scratch_tbs,e.tablespace_name) ||'")' END|| CASE WHEN db.is_pdb=1 THEN ''');--' ELSE ';' END as sql_cmd FROM s,db,dba_extents e where e.file_id=s.file_id and e.block_id>s.block_id ORDER BY e.block_id desc;
Da werden jetzt einige Objekte sich beschweren, dass Sie nicht verschiebbar sind (z.B. auch als SYS die Fehlermeldung ORA-01031 Insufficient Privileges)Wir haben eine Lösung dafür gefunden die aber sicher nicht supported ist, weil damit den Schutz auf sensible Spalten in den Tabellen auch ausschalten wird.
Zu guter Letzt, werden noch die Objekte repariert, die den Status INVALID aufweisen:
WITH FUNCTION do_ddl (cmd IN VARCHAR2) RETURN VARCHAR2 IS PRAGMA AUTONOMOUS_TRANSACTION; -- Damit ist die Funktion eigenständig und beeinflusst niemanden :-) v_cmd VARCHAR2(32000); BEGIN v_cmd:=rtrim(cmd,';'); -- Semmikolon ggf.herausfiltern EXECUTE IMMEDIATE v_cmd; -- Befehl ausführen RETURN v_cmd||'; --OK'; -- Befehl erfolgreich ausgeführt EXCEPTION WHEN OTHERS THEN RETURN v_cmd||' --'||sqlerrm; END; SELECT do_ddl('ALTER INDEX "'||owner||'"."'||index_name||'" REBUILD;') FROM dba_indexes i WHERE status='UNUSABLE' UNION ALL SELECT do_ddl('ALTER INDEX "'||index_owner||'"."'||index_name||'" REBUILD PARTITION "'||partition_name||'";') FROM dba_ind_partitions WHERE status='UNUSABLE' UNION ALL select 'ALTER '|| CASE WHEN object_type='PACKAGE BODY' THEN 'PACKAGE' ELSE object_type END ||' "'|| owner ||'"."'|| object_name ||'" COMPILE ' || CASE WHEN object_type='PACKAGE BODY' THEN 'BODY;' ELSE ';' END as sql_stmt from dba_objects where object_type in ('PROCEDURE','FUNCTION','PACKAGE','PACKAGE BODY','VIEW') and status='INVALID';
Mehr Informationen erhalten Sie in einem unserer Oracle Reorg und DBA II Kurse, oder wir kommen zu Ihnen und räumen den SYSAUX Tablespace persönlich auf.Melden Sie sich gerne bei uns und holen Sie ein Angebot ein. Wir freuen uns auf Sie.
Im Gespräch mit einem Oracle Mitarbeiter letztes Jahr kam die Idee auf, warum Oracle keinen Select bietet, um den den Stand des Listeners abzufragen.
Der Mitarbeiter (nennen wir ihn mal Sebastian S. :-) ) wollte die Idee ins Development bringen. Bis das umgesetzt ist, helfen wir uns selbst:
Unter Linux legen wir uns eine kleine Shell Script Datei an
vi /home/oracle/scripts/lsnr_status.sh #!/bin/bash ORACLE_HOME=/opt/oracle/product/23c/dbhomeFree $ORACLE_HOME/bin/lsnrctl status | /usr/bin/awk ' BEGIN { OFS=","; print "LINE"} { print $0 }'
Und geben dieser Datei Ausführungsrechte:
chmod +x /home/oracle/scripts/lsnr_status.sh
Dann brauchen wir ein Datenbank Directory auf diesen Ordner:
CREATE DIRECTORY ext_tab_dir AS '/home/oracle/scripts'; grant read,execute on directory ext_tab_dir to muniq;
Seit Version 19c kann eine External Table ohne ein Create direct “On the Fly” erzeugt werden:
SELECT * FROM EXTERNAL ( ( line varchar2(2000)) TYPE oracle_loader DEFAULT DIRECTORY ext_tab_dir ACCESS PARAMETERS ( RECORDS DELIMITED BY NEWLINE PREPROCESSOR ext_tab_dir:'lsnr_status.sh' FIELDS CSV WITH EMBEDDED TERMINATED BY ';' OPTIONALLY ENCLOSED BY '"' MISSING FIELD VALUES ARE NULL ) LOCATION ('lsnr_status.sh') REJECT LIMIT UNLIMITED ) inline_ext_tab;
Bei älteren Versionen legt man halt zuesrt die Tabelle an:
CREATE TABLE ext_listener_status ( line VARCHAR2(4000) ) ORGANIZATION EXTERNAL ( TYPE ORACLE_LOADER DEFAULT DIRECTORY ext_tab_dir ACCESS PARAMETERS ( RECORDS DELIMITED BY NEWLINE --PREPROCESSOR ext_tab_dir:'lsnr_status.sh' FIELDS TERMINATED BY ',' MISSING FIELD VALUES ARE NULL ( line ) ) LOCATION ('lsnr.info') ); SELECT * FROM ext_listener_status;
Das war es schon, jetzt können Sie den Listener Zustand auch innerhalb der Datenbabnk abfragen (also via SQL*Plus, SQL cl, SQL Developer oder TOAD, oder …)
Wir verwenden für unsere Webseite Oracle 23ai mit APEX 24.1.x (Stand August 2024). Leider funktioniert die Globale Suche dort nicht mehr und die Anfrage stürzt ab mit Webserver Internal Server Fehler 500.
Deswegen haben wir uns eine eigene Suche geschrieben, die kann nur leider nicht direkt auf die Komponente verlinken, aber durchsucht dafür alle APEX Tabellen !
CREATE OR REPLACE TYPE apex_search_type AS OBJECT ( app_id NUMBER, page_id NUMBER, row_text CLOB, tab_name VARCHAR2(128), col_name VARCHAR2(128), row_id VARCHAR2(32)); /
CREATE OR REPLACE FUNCTION muso_apex_search (p_app_id IN NUMBER DEFAULT 0, p_search_string IN VARCHAR2) RETURN apex_search_tab_type PIPELINED IS TYPE ref_curs_type IS REF CURSOR; refc ref_curs_type; str VARCHAR2(2001); ret_rowid ROWID; ret_col CLOB; v_schema VARCHAR2(128); v_flow_id VARCHAR2(64); v_page_id VARCHAR2(128); BEGIN SELECT schema INTO v_schema FROM dba_registry WHERE comp_id='APEX'; FOR rec IN (select table_name,column_name,data_type FROM sys.all_tab_columns dtc, all_objects do WHERE dtc.table_name=do.object_name and do.object_type='TABLE' and dtc.owner=v_schema) LOOP v_flow_Id:=''; v_page_id:=''; FOR c_flow IN (SELECT column_name FROM all_tab_columns WHERE owner=v_schema AND table_name=rec.table_name AND column_name IN('FLOW_ID','PAGE_ID' ) ) LOOP IF c_flow.column_name='FLOW_ID' THEN v_flow_id:=',flow_id'; ELSIF c_flow.column_name='PAGE_ID' THEN v_page_id:=',page_id'; END IF; END LOOP; IF rec.data_type IN( 'CHAR','VARCHAR2','CLOB') THEN str:= 'SELECT rowid,'||rec.column_name||nvl(v_flow_id,',null as flow_id')||nvl(v_page_id,',null as page_id')|| ' FROM '||v_schema||'.'||rec.table_name|| ' WHERE '||rec.column_name||' like '||chr(39)||'%'||p_search_string||'%'||chr(39); BEGIN OPEN refc FOR str; LOOP FETCH refc INTO ret_rowid,ret_col,v_flow_id,v_page_id; EXIT WHEN refc%NOTFOUND; If nvl(p_app_id,v_flow_id)=v_flow_ID THEN PIPE ROW (apex_search_type(v_flow_id,v_page_id,ret_col,v_schema||'.'||rec.table_name,rec.column_name,ret_rowid)); END IF; END LOOP; ret_rowid:=''; ret_col:=''; CLOSE refc; EXCEPTION WHEN OTHERS THEN PIPE ROW (apex_search_type(0,0,'Fehler:'||sqlerrm||' =>'||str,rec.table_name,null,null)); END; END IF; END LOOP; END; /
select * from table(muso_apex_search(11000,'Sitemap') );
Weitere tolle Tipps bekommen Sie in einem von unseren 6 APEX Kursen ! Wir freuen uns auf Sie !
Wollten Sie immer schon mal wissen, welche BIlder in Ihrer Seite vorkommen? Wenn man das über die APEX Tabellen lösen möchte wird es schwierig, denn davon gibt es fast 600.
Wir verwenden deswegen einen anderen Ansatz: Wir rendern die Seite und suchen dann nach Links oder Bildern.
Geben Sie dazu im Kopf des SQL Statements die Werte für die Application ID (hier 100
Bilder in einer Seite finden:
WITH my_app as (select 100 as app_id, 1 as page_id FROM dual) SELECT my_app.app_id,my_app.page_id,replace(column_value,'/','/') img FROM TABLE ( SELECT APEX_STRING.GREP(page, '<img src[^>]*','i')as bilder FROM ( select apex_web_service.make_rest_request( p_url=>'https://www.muniqsoft-training.de/ords/oracle/r/muso_training/schulung/'||page_alias, p_http_method=>'GET', p_wallet_path=>'file:///opt/oracle/admin/FREE/https_wallet' ) as page from apex_application_pages app,my_app where app.application_id=my_app.app_id and app.page_id =my_app.page_id)),my_app /
Links in einer Seite finden:
WITH my_app as (select 100 as app_id, 1 as page_id FROM dual) SELECT my_app.app_id,my_app.page_id,replace(column_value,'/','/') link FROM TABLE ( SELECT APEX_STRING.GREP(page, '<a href=*[^>]*">[[:alnum:] ]{1,}<\/a>' ,'i')as bilder FROM ( select apex_web_service.make_rest_request( p_url=>'https://www.muniqsoft-training.de/ords/oracle/r/muso_training/schulung/'||page_alias, p_http_method=>'GET', p_wallet_path=>'file:///opt/oracle/admin/FREE/https_wallet' ) as page from apex_application_pages app,my_app where app.application_id=my_app.app_id and app.page_id =my_app.page_id)),my_app;
Weitere Tipps erfahren Sie in unserem APEX Kurs
Wie oft habe ich schon nach der Syntax gesucht um nachträglich einen Constraint auf eine Tabelle zu legen. Google ist ja da immer eine gute Hilfe, aber in deutsch gab es bisher wenig.Das ändert sich nun, wir beschätigen uns mit dem Thema Constraints hier nun.Nachträglich einen Not Null Constraints auf eine Tabelle legen:
Constraint wieder löschen:
Nachträglich einen Primärschlüssel anlegen (Achtung es darf keiner bisher existieren):
Nachträglich einen Unique Index anlegen (davon dürfen Sie mehrere auf der gleichen Tabelle besitzen)Hier erlauben wir pro Tag nur einen Mitarbeiter mit gleichem Nachname einzustellen.
Foreign Key Constraint anlegen. (Dieser hat einen Bezug zu einer lokalen Spalte der Tabelle und eine Verbindung zu einer Spalte einer anderen Tabelle)
Der Foreign Key Constraint hat aber noch eine weitere nette Option: On Delete CascadeWenn hier ein Hauptdatensatz (bei uns z.B. die Abteilung) gelöscht wird, werden die Kinddatensätze (hier die Mitarbeiter der Abteilung) auch rekursiv gelöscht
Alternativ kann auch nur die abhängige Spalte auf NULL gesetzt werden
SonderfälleConstraints können auch verzögert geprüft werden. Das ist dann sinvoll, wenn im Datenmodell mit Constraints Änderungen durchgeführt werden sollen, die gegen die Regeln des Constraint verstossen würden.Durch die verzögerte Prüfung erfolgt dies erst beim Commit und nicht schon während der Transaktion.
oder wieder zurück auf Default:
Mit einem ALTER TABLE kann der Zustand der verzögerten Constraints verändert werden:
ENABLE VALIDATE
ENABLE
ENABLE NOVALIDATE
DISABLE NOVALIDATE
DISABLE
DISABLE VALIDATE
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 apex241 secret db.password
Unsere Ordnerstruckur für den Ords sieht wie folgt aus:
Hier war ein falscher Eintrag in der pool.xml Datei (unter Windows z.B. unter c:\oracle\ords\databases) schuld.
Der Parameter plsql.gateway.mode muss auf proxied stehen!
Für Windows:
set ORDS_HOME=c:\oracle\ords set ORDS_CONFIG=c:\oracle\ords %ORDS_HOME%\bin\ords --config %ORDS_CONFIG% config set plsql.gateway.mode proxied
Für Unix
export ORDS_HOME=/opt/oracle/ords export ORDS_CONFIG=/opt/oracle/ords $ORDS_HOME/bin/ords --config $ORDS_CONFIG config set plsql.gateway.mode proxied
Im Logfile des Apache TomCat steht nur:
"GET /ords/wwv_flow.js_messages?p_app_id=4550&p_lang=en&p_version=24.1.5-3518415 HTTP/1.1" 404 451412
Problem war eine falsche Einstellung in der Datei pool.xml (z.B. unter c:\oracle\ords\databases\default):
dort musste
<entry key="plsql.gateway.mode">disabled</entry>
<entry key="plsql.gateway.mode">proxied</entry>
ersetzt werden.
Wir hatten kürzlich das Problem, das keine Applikationen mehr importiert werden konnten. Beim Auswählen der Datei kam im nächsten Schritt die Fehlermeldung, dass keine Datei ausgewählt wurde.
Das Problem war hier, dass beim Benutzer FLOWS_FILES einige Indizes defekt waren. Nach einem Rebuild war ein Import wieder möglich.
Der folgende Select schreibt Ihnen ein Skript, um defekte Indizes zu finden und reparieren.
select 'ALTER INDEX '||owner||'.'||index_name||' REBUILD;' as sql_stmt from dba_indexes where (owner='FLOWS_FILES' or owner=(select schema from dba_registry where comp_id='APEX')) and status='UNUSABLE';
Bei der Migration auf einen anderen Server hatten wir plätzlich beim start des Workspace den Fehler:
Die Anforderung kann nicht verarbeitet werden, da diese Ressource keine Cross Origin Sharing-Anforderungen unterstützt oder da der Anforderungsursprung nicht autorisiert ist, auf diese Ressource zuzugreifen. Wenn ords als Reverse-Proxy verwendet wird, stellen Sie sicher, dass der Frontend-Server den Hostnamen propagiert. Stellen Sie für mod_proxy sicher, dass "ProxyPreserveHost" eingeschaltet ist.
Die Lösung bestand darin in die die Datei /etc/httpd/conf/httpd.conf (bzw. eine Unterdatei z.B. in conf.d) um folgenden Eintrag zu ergänzen:
RequestHeader unset Origin
Mehr Tipps & Tricks erfahren Sie in unserem Oracle ORDS und im APEX II Kurs. Wir freuen uns auf Sie!
Haben Sie sich auch schon darüber geärgert, dass gerade Oracle keine Boolean Datentypen in SQL erlaubt?Wenn Sie also eine PL/SQL Funktion besitzen, die nur TRUE oder FALSE zurückgibt, muss man sich einen Wrapper in PL/SQL schreiben.
Aber in unserem Tipp des Monats, bekommen wir das mit einem Trick auch nur in SQL hin.
Sagen wir mal, wir hätten eine Funktion wie diese hier:
Dann könnten wir mit einer einfachen WITH Klausel das auch in reinem SQL hinbekommen.
Viele weitere Tipps & Tricks bekommen Sie in einem unserer bewährten PL/SQL Kurse (PL/SQL, PL/SQL II, PL/SQL Packages, ...)
Ich liebe das Package dbms_output, wenn es nur nicht ...
hätte.
Aber den letzen Punkt können wir ändern. In diesem Tipp holen wir die Daten, die wir in den Puffer von dbms_output geschrieben haben und legen Sie woanders hin.
##################################################Umleitung von dbms_output zu pipe##################################################
CREATE OR REPLACE PROCEDURE get_dout_from_pipe (pipe_name IN VARCHAR2 DEFAULT 'DBMS_OUTPUT_PIPE')
IS
v_message VARCHAR2(32767);
v_timeout NUMBER:=120;
BEGIN
IF (DBMS_PIPE.receive_message(pipe_name,v_timeout)) <> 0 THEN
RAISE_APPLICATION_ERROR(-20501,'Fehler beim Lesen aus Pipe '||pipe_name||' aufgetreten !');
END IF;
LOOP
EXIT WHEN DBMS_PIPE.NEXT_ITEM_TYPE = 0;
DBMS_PIPE.unpack_message(v_message);
DBMS_OUTPUT.PUT_LINE(v_message);
END LOOP;
END;
/
##################################################Umleitung von dbms_output zu htp##################################################
CREATE OR REPLACE PROCEDURE test_ausgabe IS PROCEDURE dop2htp IS lines dbms_output.chararr; num_lines number:=1000000; BEGIN dbms_output.get_lines(lines, num_lines); FOR i IN 1..num_lines LOOP htp.p(lines(i)||'<BR>'); END LOOP; END; BEGIN dbms_output.enable(null); FOR i IN 1 .. 10 LOOP dbms_output.put_line('Zeile='||i); END LOOP; dop2htp; -- <=######## Umwandelung von dbms_output in htp.p Ausgabe END;
Ich hoffe dies konnte Ihnen weiterhelfen, bei sonstigen Fragen melden sie sich gerne bei uns und oder besuchen sie einen der Kurse. :-)
Firmen, die mit personenbezogenen Daten arbeiten, sind gesetzlich zum Audit verpflichtet. In der Praxis sieht das allerdings häufig so aus, dass man im Vertrauen darauf, dass die Default-Audit Einstellungen von Oracle schon alles Wesentliche abdecken werden, die Inhalte der Audit-Trails eine bestimmte Zeit aufhebt und dann löscht oder irgendwohin exportiert, ohne jemals einen Blick auf den Inhalt geworfen zu haben.
Und wenn ein entnervter DBA unter Oracle 11g kurz nachsehen will, welcher xxxxx an den Datenbankparametern gedreht hat und es wieder mal keiner gewesen sein will, wird er im Audit-Trail der Datenbank vergeblich danach suchen, selbst wenn er den Parameter AUDIT_SYS_OPERATIONS auf TRUE gesetzt hat. Unter Linux müsste er dazu unzählige aud-Files im Betriebssystem und unter Windows das Eventlog durchforsten.
Um wirklich das auditiert zu bekommen, was man gerne hätte und die Auswertung nicht allzu zeitraubend zu gestalten, muss man die Audit-Einstellungen und das Housekeeping der Daten manuell einrichten und testen. Auch die Übertragung eines fertigen 11g-Audit-Konzepts auf Oracle 12c ist eine Menge Arbeit. Dieser Vortrag beschäftigt sich anhand eines fiktiven, aber nicht untypischen Szenarios mit den Schwachstellen der Default-Audit-Konfiguration in Version 11g und 12c und stellt Lösungsansätze für das Audit vor, mit denen man die Erfassung der Daten und die Auswertung vereinfachen kann.
AUSGANGSLAGE FÜR DAS AUDIT-SZENARIODer neue, motivierte und experimentierfreudige DBA einer mittelständischen Firma soll ein neues Audit-Konzept umsetzen. Im Einsatz sind Oracle-Datenbanken der Version 11.2.0.4 (Standard Edition One) auf Linux und auf Windows. Alle Angestellten der Firma loggen sich unter dem selben Account , aber von unterschiedlichen Rechnern aus ein und können entweder direkt (über SQL Developer) oder über ein APEX-Interface auf die Tabellen zugreifen. Der DBA-Kollege nutzt manchmal auch den Enterprise Manager. Die DBAs arbeiten als SYSDBA auf der Instanz, alle anderen haben die Rollen CONNECT und RESOURCE.
Auditiert werden sollen:
Weitere Forderungen
PROBLEME BEI EINRICHTUNG, AUSWERTUNG UND HOUSEKEEPING DES AUDITS UNTER 11G
Gewöhnungsbedürftige Syntax für das Einrichten der Audit-OptionenVon den oben geforderten Audits wird nur ein kleiner Teil über die Default-Einstellungen abgedeckt. Es ist also viel Handarbeit nötig, wobei die Syntax der AUDIT-Anweisung einige Fallstricke enthält.So kann z.B. ein unvorsichtiges SELECT TABLE BY <username> den Audit-Trail exponentiell aufblasen, wenn man ein Tool wie den SQL Developer benutzt.
Überflüssige Informationen im Audit-TrailWenn man den Enterprise Manager konfiguriert hat, der sich im Sekundentakt bei der Datenbank anmeldet, führen die Default-Einstellungen dazu, dass der Audit-Trail größtenteils mit den Logon- und Logoff-Einträgen der User SYSMAN und DBNSMP gefüllt wird. Beim SYS-Auditing werden unter 11g alle Statements aufgezeichnet. Hier muss man den Overhead der Data-Dictionary-Zugriffe (recursive SQL) beim Auswerten herausfiltern. Auch der RMAN erzeugt eine Flut von Einträgen, wenn er sich als SYSDBA anmeldet.
Unterschiedliche Speicherorte der verschiedenen Audit-InformationenConnects als SYSDBA bzw. SYSOPER, Stops und Starts der Datenbank werden per default auditiert (mandatory auditing). Alle weiteren Aktionen des Users SYS können durch Umstellung des Parameters AUDIT_SYS_OPERATIONS auf TRUE auditiert werden. Unter Unix werden die Informationen jedoch in das durch den Parameter audit_file_dest angegebene Verzeichnis geschrieben, unter Windows ins Eventlog. Um dieses Audit auswerten zu können, müsste man die Inhalte der *.aud-Files unter Linux bzw. die Oracle-spezifischen Inhalte des Eventlogs unter Windows parsen und in die Datenbank laden. Beides ist möglich, aber aufwendig.
Unzulänglichkeiten des Packages DBMS_AUDIT_MGMTDas Package DBMS_AUDIT_MGMT ist umständlich zu bedienen, vor allem, wenn man sowohl in der Datenbank als auch im Filesystem aufräumen will. Um die Einträge im Windows Event Log muss man sich selber kümmern.
VORSCHLAG FÜR EIN "UNIFIED AUDITING" ab 11GWenn man den Parameter AUDIT_TRAIL auf XML setzt, werden alle zu auditierenden Statements des Standard, Mandatory, SYS- und Fine Grained Auditing (letzteres natürlich nur in der Enterprise Edition) im AUDIT-FILE-DEST-Verzeichnis als XML-Files gespeichert und können über die View V$XML_AUDIT_TRAIL gemeinsam ausgewertet werden, ähnlich wie die XML-Files des Alert.logs über die View V$DIAG_ALERT_EXT. Die seit der Oracle-Version 10.2 verfügbare View DBA_COMMON_AUDIT_TRAIL vereint diese Einträge mit denen aus DBA_AUDIT_TRAIL und DBA_FGA_AUDIT_TRAIL, so dass auch die Inhalte der Tabellen AUD$ und FGA_LOG$ noch sichtbar bleiben. Diese Lösung kann man durchaus als abgespecktes "Unified Auditing" für 11g bezeichnen. Die Auswertung und das Housekeeping werden dadurch wesentlich erleichtert. Auch die Performance des Audits leidet nicht darunter, dass man die Audit-Files im Betriebssystem speichert , eher im Gegenteil. Wenn man den XML-Audit-Trail vor Zugriffen durch übel gesinnte DBAs schützen will, muss man dafür sorgen, dass die Files in kurzen Abständen auf einen anderen Server außer Reichweite gesichert werden.
Im Vortrag wird gezeigt, wie man die oben genannten Anforderungen an das Audit mit dieser Methode, ein paar Views für die bequeme Auswertung und einem datenbankgesteuerten Housekeeping umsetzen kann.
UND WIE SIEHT'S UNTER 12C AUS ?Unsere mittelständische Firma wächst und gedeiht und denkt an einen Upgrade auf die Version 12c.
Das unter 12c neu eingeführte Unified Auditing soll schneller, leichter einzurichten und zu verwalten und für alle Editions verfügbar sein.Im Prinzip ja, aber ...
Die Standard Edition One (SEO) gibt es nur noch in der Version 12.1.0.1. Hier ist das Feature wegen des Bugs 17466854 (CANNOT SET UNIFIED AUDITING IN STANDARD EDITION) nicht zu aktivieren. Dafür gibt es einen Patch 17466854, den man aber nicht einspielen kann, wenn man seine Datenbank mit dem aktuellen Patchset versorgt hat. Der Bugfix wurde für den Patchset 12.1.0.1.5 (vom 14.10.2014) geschrieben und funktioniert nicht für höhere Levels. Für SEO-Datenbanken unter Windows soll der Bugfix im Patchset 12.1.0.1.18 eingeschlossen sein.
Da die SEO allerdings sowieso ein Auslaufmodell ist, steigt unsere Firma doch lieber auf die Standard Edition 2 (SE2) um. Bei der Version 12.1.0.2 funktioniert der Umstieg auf Unified Auditing problemlos. Es macht sich jedoch deutlich bemerkbar, dass bei jedem Patch diverse Bugs gefixt werden. Man sollte also unbedingt die neuesten Patches einspielen !
Nach der Migration auf die Version 12c ist zunächst der sogenannte Mixed Mode aktiv, unter dem nur die Policies ORA_SECURECONFIG und zusätzlich ORA_LOGON_FAILURES (erst ab 12.1.0.2) aktiviert sind. Diesen beizubehalten, ist keine wirklich gute Option, vor allem hinsichtlich des Housekeepings und der Sicherheit der Audit-Daten gegenüber Manipulation durch den DBA. Zudem gibt es einige wirklich nützliche zusätzliche Features beim neuen Unified Auditing, die man sich nicht entgehen lassen sollte. Dazu zählt vor allem die größere Sicherheit der Audit-Daten.
WAS IST BEIM UMSTIEG AUF UNIFIED AUDITING UNTER ANDEREM ZU BEACHTEN ?
Das sys-Audit ist nicht mehr das, was es einmal warÄnderungen am System, an den Audit-Einstellungen etc. werden im Unified Auditing immer auditiert, egal, ob man sich als SYSTEM oder SYS AS SYSDBA, SYSOPER, SYSDG, SYSBACKUP bzw. SYSKM anmeldet.Ansonsten wird der User SYS aber genauso behandelt wie Hinz und Kunz !!! Auch seine Selects erscheinen nicht mehr im Audit-Trail. Wenn man z.B. mitbekommen will, ob er sich per DML an irgendwelchen User-Tabellen vergreift, muss man dieses Audit explizit in einer Policy einrichten! Der Parameter AUDIT_SYS_OPERATIONS hat keinen Einfluss mehr.
Per Default werden nur failed logins auditiertDass nicht mehr jeder LOGON und LOGOFF registriert wird, macht den Audit-Trail zwar übersichtlicher, aber für Auswertungen des Audit-Trails hinsichtlich der Dauer der Sessions oder der Anzahl nicht korrekt beendeter Session (LOGOFF BY CLEANUP) muss man sich nun eigene Policies schreiben.
Die alten Audit-Optionen sind nicht 1:1 in den neuen Policies abzubildenEin AUDIT PROCEDURE BY consultant;unter 11g wird unter 12c zuCREATE AUDIT POLICY consultant_plsql_polACTIONS CREATE FUNCTION, DROP FUNCTION, CREATE LIBRARY, DROP LIBRARY, CREATE PACKAGE, DROP PACKAGE, CREATE PACKAGE BODY, CREATE PROCEDURE, DROP PROCEDURE;AUDIT POLICY consultant_plsql_pol BY consultant;
Das ist eigentlich ein Vorteil, weil diese Syntax besser verständlich ist, aber die Policies können schnell unübersichtlich werden. Die Anforderungen an das Audit von Seite 1 lassen sich über die beiden Default-Policies und 3 zusätzliche maßgeschneiderte Policies verwirklichen. Zuviel Policies wirken sich eher schädlich auf die Performance aus.
Das neue Audit ist per Default "extended"Während man unter der Version 11g den Parameter audit_trail auf DB, extended oder XML, extended setzen musste, um auch die SQL-Statement und Bindvariablen zu erfassen, ist das in Version 12c per Default der Fall. Das lässt den Audit Trail entsprechend schnell anwachsen, wenn die Statements etwas komplexer werden. Auch das obligatorische RMAN-Audit braucht einiges an Platz. Deshalb ist ein durchdachtes Housekeeping fast noch wichtiger als unter 11g.
Wie der (immer noch motivierte) DBA den Umstieg von der selbstgestrickten Unified Auditing Lösung unter 11g auf die Audit-Konfiguration unter 12c meistert und was ein vernünftig konfiguriertes Audit alles an Verbrechen gegen die Datenbank im allgemeinen und die guten Sitten im besonderen zu Tage fördern kann, erfahren Sie im Vortrag.
Oracle hat das Berechtigungskonzept zu PL/SQL in Hinblick auf zwei gegensätzliche Szenarien in 12c ausgebaut:
Die Änderung zu diesem Szenario (Vergabe von Rollen) betrifft Prozeduren, die mit Invoker Rights arbeiten oder mit dynamischem SQL.
Beiden Neuerungen gemeinsam ist, dass es um die Überprüfung von Rechten zur Laufzeit geht. Auch weiterhin benötigt ein Entwickler alle entsprechenden Berechtigungen selber, um eine Prozedur erfolgreich kompilieren zu können. Dynamisches SQL allerdings wird zur Kompilierzeit nicht ausgewertet.
Hinweis: Hier und im weiteren ist "Prozedur" als Sammelbegriff zu verstehen, der auch Funktionen und Packages mit einschließt.
Hier kommt Szenario 1 ins Spiel:
Angenommen, der User ADMIN hat weitreichende Rechte.
Weiter angenommen, der Programmierer SCOTT hat vergleichsweise wenig Rechte.
Nun schreibt SCOTT eine Prozedur mit Invoker Rights (bei Definer Rights spielt das neue Privileg keine Rolle), die er ADMIN zur Verfügung stellt. Solange es sich um statisches SQL handelt, kann nicht viel passieren, da ja SCOTT's Berechtigungen zur Compile-Zeit überprüft werden.
Nun könnte aber SCOTT bösartigerweise Befehle in dynamisches SQL verpacken, die weit über seine eigenen Berechtigungen hinausgehen (z. B. an sich selbst Admin-Rechte vergeben), nicht jedoch über diejenigen von ADMIN. SCOTT kann so eine Prozedur problemlos erstellen - aber nicht ausführen. ADMIN dagegen kann sie ausführen.
Um einen solchen Missbrauch ggf. unterbinden zu können, wurde mit Version 12c die Berechtigung INHERIT [ANY] PRIVILEGES eingeführt. Das Konzept dabei sieht folgendermaßen aus:
Der Eigentümer der Prozedur (in obigem Szenario SCOTT) braucht, sofern er nicht über das Systemprivileg INHERIT ANY PRIVILEGES verfügt, von dem Benutzer, der die Prozedur später ausführen soll - also hier ADMIN - , das Objektprivileg INHERIT PRIVILEGES. Hat er das nicht, so kann ADMIN später die Prozedur nicht ausführen.
Damit sich das Verhalten zwischen 11g und 12c nicht ändert, erhält PUBLIC automatisch für jeden neu angelegten User dieses Recht. Das können Sie leicht nachprüfen über dba_tab_privs:
Oracle empfiehlt jedoch PUBLIC diese Rechte zu entziehen.
Für das oben beschriebene Szenario bedeutet dies:
Hat PUBLIC das Recht INHERIT PRIVILEGES ON USER ADMIN, wie das dem Default entspricht, so wird ADMIN die Prozedur von SCOTT ausführen können, wie auch schon in 11g. Entzieht ADMIN dieses Recht mit
und vergibt das Recht auch nicht explizit an SCOTT, dann kann er keine Prozedur von SCOTT mehr ausführen, die mit INVOKER RIGHTS angelegt wurde. Beim Versuch erhält er die Fehlermeldung
Szenario 2 sieht so aus:
User SCOTT stellt wiederum Invoker Rights-Prozeduren zur Verfügung, in diesem Fall für den User LEHRLING. Eine der Prozeduren greift auf ein Tabelle im Schema SCOTT zu. SCOTT will aber nicht, dass LEHRLING direkten Zugriff auf diese Tabelle bekommt. Den bräuchte LEHRLING aber bis einschließlich Version 11g, um diese Prozedur ausführen zu können.
SCOTT erstellt z. B. folgende Funktion:
LEHRLING wird diese Funktion bis jetzt nicht erfolgreich ausführen können:
In Version 12c stellt nun ein DB-Administrator SCOTT eine Rolle zur Verfügung:
SCOTT vergibt das benötigte Select-Recht and die Rolle:
Und die Rolle an die Funktion(!):
Nun kann LEHRLING die Funktion erfolgreich ausführen ohne direkten Zugriff auf SCOTT.dept zu erhalten.
An dem Grundprinzip, dass Rollen in PL/SQL unwirksam sind, ändert sich nichts: Eine Prozedur kann auch weiterhin nur dann erfolgreich kompiliert werden, wenn ihr Eigentümer alle dafür erforderlichen Rechte DIREKT gegrantet bekommen hat.
Ein Beispiel zur Anwendung dieses Rollenkonzepts bei Definer Rights und dynamischem SQL hat Tom Kyte in seinem Blog beschrieben.
Letztens bin ich über ein vermeintlich trivales Problem gestolpert: Ich wollte die Größe einer Tabelle berechnen. Nur war die vermeintlich nur sehr klein. Wo lag das Problem?
Wenn man in USER_SEGMENTS oder DBA_SEGMENTS nachschaut, steht dort beim Tabellen (Segment) Namen nur die Größe der Basistabelle (ohne Lob Spalten)
Als Eigentümer des Objekts kann man folgenden Befehl absetzen:Hinweis: Ändern Sie bitte in der ersten Zeile den Namen der Tabelle ab.
Das Ergebnis könnte dann z.B so aussehen:
Wenn man als DBA das Ganze ansehen möchte:
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:
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 Condition Advanced: Event Scope = once Condition: 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.
Ab Version 12c können Spalten ausgeblendet werden, indem man sie als "invisible" deklariert. Das ist sowohl beim Anlegen einer Tabelle oder Spalte möglich als auch nachträglich.Das bedeutet aber nicht, dass auf eine solche Spalte nicht zugegriffen werden kann, sondern nur, dass sie ohne Angabe einer expliziten Spaltenliste nicht berücksichtigt wird:
Solange man die Spalte explizit anspricht, kann man also ganz normal mit ihr arbeiten.
Interessant ist, dass TOAD die Spalte beim DESCRIBE mit angibt - und an welcher Position:
Hier lohnt sich ein Blick ins Data Dictionary:
Die column_id ist also bei unsichtbaren Spalten nicht gefüllt. Interessanter noch ist die etwas weniger bekannte user_tab_cols:
Wenn eine unsichtbare Spalte wieder sichtbar gemacht wird, bekommt sie grundsätzlich die höchste column_id und rückt dementsprechend ans Ende der Spaltenliste:
Auf diese Art könnte man beispielsweise auch eine neu eingefügte Spalte, die ja bis 11g grundsätzlich als letzte Spalte angezeigt wird, in der Spaltenliste weiter nach vorne wandern lassen:
So ganz neu ist das Konzept der unsichtbaren Spalten nicht. Haben Sie sich schon einmal angeschaut, wie eine Spalte vom Typ XMLTYPE intern dargestellt wird?
Hier kann die unsichtbare Spalte SYS_NC00006$ prinzipiell auch direkt angesprochen werden. Da es sich aber bei Speicherung des XMLTYPE als binary xml (dem Default in 12c) um einen BLOB handelt, ist das allerdings nicht sehr sinnvoll. Und bei Speicherung als CLOB (deprecated in 12c) bietet es zumindest keine Vorteile.
Das Prinzip ist also ähnlich, auch wenn es offensichtlich Unterschiede im Detail gibt. Interessierte sollten sich die Spalten column_id (hier gefüllt!), segment_column_id, virtual_column und - in Version 12c neu eingeführt - user_generated in user_tab_cols genauer anschauen.
Sie würden gerne wissen, was ist alles neu in 12c? - dann schauen Sie doch in unserer Oracle Schulung Neuerungen 12c vorbei.
Die Erstellung von Statistiken über Datenbank-Objekte wie Tabellen oder Indizes ist seit der Einführung des kostenbasierenden Optimizers ein absolutes Muss. Die Qualität der Statistiken entscheidet darüber, ob ein SQL-Statement performant in der Datenbank verarbeitet werden kann oder nicht. Mit Hilfe der Statistiken bestimmt die Datenbank, welche Kosten im Sinne von Ressourcen-Nutzung entstehen und welcher Zugriffs-Pfad zu den geringsten Kosten führt.
Der vorliegende Monatstipp hat nicht das Ziel einer detaillierten Beschreibung des kostenbasierenden Optimizers. Dazu wird auf unsere Muniqsoft-Training-Schulungen und auf die einschlägige Literatur verwiesen.
Vielmehr werden folgende Fragestellungen näher betrachtet:
Seit Einführung der RDBMS-Version 10g existiert ein automatischer Statistik-Erstell-Job, der für alle Tabellen, die entweder keine oder veraltete (Stale) Statistiken aufweisen, Statistiken erstellt. Die verwendete Prozedur heißt „DBMS_STATS.GATHER_DATABASE_STATS_JOB_PROC“ und verwendet die gleichen Default-Parameter wie die „DBMS_STATS.GATHER_*_STATS“-Prozedur. Per Default werden die Statistiken aller Tabellen, deren Datensätze sich zu 10% geändert haben, als veraltet (stale) betrachtet und somit neu erstellt. Dieser Wert ist bis Oracle Version 10.2 fest und kann nicht geändert werden. Wenn die Notwendigkeit besteht, Statistiken für eine Tabelle öfters erstellen zu lassen, gibt es ab Version 11.1 die Prozedur „DBMS_STATS.SET_TABLE_PREFS“.
Z.B. kann die Tabelle „SCHULUNG“ des Users „MQS“ bereits bei 5% Änderungen folgendermaßen als veraltet deklariert werden und somit die Erstellung von Statistiken erzwungen werden:
Wenn das automatische Erstellen von Statistiken nicht gewünscht wird, weil z.B. eine andere Prozedur dies bereits erledigt, kann der Automatismus folgendermaßen nur auf Erstellung der Data Dictionary-Tabellen eingeschränkt werden:
Für die manuelle Erstellung von Statistiken ist grundsätzlich das PL/SQL-Package DBMS_STATS und nicht mehr das ANALYZE-Kommando zu verwenden.
Bei der DBMS_STATS-Prozedur sollen die beiden Parameter ESTIMATE_PERCENT und METHOD_OPT näher betrachtet werden:
ESTIMATE_PERCENT gibt den prozentualen Wert an, wieviele Datensätze einer Tabelle als Basis für die Statistikerstellung herangezogen werden. Je höher der Wert, desto genauer die Statistik, aber desto höher auch die Ausführungszeit der Statistikerstellung. Ab 10g hat sich der Default-Wert für estimate_percent von 100% auf AUTO_SAMPLE_SIZE geändert. Hierbei entscheidet die Datenbank selbst über das Verhältnis von untersuchten Datensätzen zur Erzielung brauchbarer Statistiken und der möglichst geringen Systembelastung bedingt durch deren Erstellung. Leider hat sich bei 10g gezeigt, dass die Anzahl der untersuchten Datensätze zu gering war und deswegen ein absoluter Wert für ESTIMATE_PERCENT sinnvoller war.
Mit Version 11g hat Oracle den Algorithmus für AUTO_SAMPLE_SIZE geändert. Der Effekt ist, dass 100% der Datensätze untersucht werden, aber nur eine Systembelastung wie bei einem Sample von ca. 10% zu verzeichnen ist.
Die Empfehlung ist daher bei der Statistik-Erstellung von Tabellen einer 11g-Datenbank für ESTIMATE_PERCENT den AUTO_SAMPLE_SIZE Parameter zu verwenden.
Mit dem Parameter METHOD_OPT kann definiert werden, ob sogenannte Histogramme für Tabellenspalten erzeugt werden. Histogramme teilen dem Oracle Optimizer mit, wie die Werte in den Spalten verteilt sind – z. B. wie oft der Wert „Müller“ in der Spalte „KD_NAME“ enthalten ist. Je öfter der Wert vorhanden ist, desto eher kann sich der Oracle Optimizer dazu entschließen, anstatt einem Direkt-Zugriff über Index alle Datensätze der Tabelle mit einem Full Table Scan zu lesen.
Bei Datenbanken der Version 10g trat bei Verwendung von Histogrammen der sogenannte „Bind-Peeking“-Effekt ein, bei dem Oracle auf Grund des ersten Wertes einer Spalte in der „where“-Klausel einen Ausführungsplan gewählt hat (z.B. ein Full Table Scan, weil der Wert sehr häufig vorkam) und bei der nächsten Ausführung trotz eines Wertes mit geringerer Selektivität (Wert kommt seltener vor) den Ausführungsplan nicht geändert hat.
Um diesen Effekt bei Version 10g zu verhindern gibt es zwei Möglichkeiten:
Wenn in der Applikation aussschließlich Bind-Variablen verwendet werden, sollten die Histogramme gelöscht werden:
Nach Ausführen der folgenden Prozedur erstellen sowohl der automatische Statistik-Erstell-Job als auch die DBMS_STATS.GATHER_*_STATS-Prozeduren keine Histogramme mehr.
Wenn die Applikation auch Literale verwendet, ist das Ausschalten des Bind-Peekings die bessere Methode.
Bitte vor Setzen des sogenanten Underscore-Parameters in MyOracleSupport über mögliche Seiteneffekte informieren oder beim Oracle Support nachfragen.
Mit Version 11g ist das sogenannte „Adaptive Cursor Sharing“ zur Verhinderung des Bind-Peekings eingeführt worden. Vereinfacht gesprochen können bei diesem Konzept mehrere Ausführungspläne für ein SQL-Statement bei Vorlage unterschiedlicher Verteilungen in den Bind-Variablen erstellt werden.
Die Empfehlung bei 11g für den Parameter METHOD_OPT ist der Default-Wert mit Erstellung von Histogrammen.
Eine weitere Option, die beim Erstellen von Statistiken beachtet werden kann, sind „Pending Statistics“. Wenn man vom Default abweichende Angaben bei der Erstellung von Statistiken gemacht hat, können diese innerhalb der eigenen Session ohne Beeinflussung des Gesamtsystems als „nicht zu veröffentlichen“ deklariert werden.
Mit Hilfe des Session-Parameters “OPTIMIZER_USE_PENDING_STATISTICS“ = TRUE werden die erstellten Statistiken innerhalb der Session verwendet. Wenn die Statistiken akzeptiert werden sollen, können sie „veröffentlicht“ werden und gelten damit für das Gesamtsystem.
Die Datenbank erstellt seit Version 10g automatisch im Rahmen eines Maintenance-Windows (werktäglich um 22 Uhr, Samstag und Sonntag um 6 Uhr bei 11g ) Statistiken für alle Tabellen, die keine oder veraltete Statistiken haben.
Wenn der Zeitpunkt nicht erwünscht ist, kann die Statistikerstellung folgendermaßen deaktiviert
oder verschoben werden (z. B. am Montag auf 6 Uhr morgens):
Eine manuelle Erstellung bietet sich dann an, wenn zum Zeitpunkt der automatischen Statistik-Erstellung die Tabelle keine repräsentativen Inhalte für Statistiken besitzt.
Ein Batch-Programm hat um 20 Uhr die Tabelle geleert, der Statistik-Erstell-Job um 22 Uhr ermittelt als Anzahl 0 Datensätze, um 2 Uhr morgens befüllt wiederum ein Batch-Job die Tabelle und um 10 Uhr erfolgt eine Query im Rahmen eines DataWareHouse-Systems. Der Oracle Optimizer ist hierbei nicht in der Lage, einen adäquaten Ausführungsplan zu erzeugen.
In einem solchen Fall ist es besser, den Statistik-Erstell-Job als Bestandteil des Ladeprozesses zu definieren. Der Aufwand für die Erstellung der Statistiken während des Ladeprozesses wird durch eine spürbare Laufzeitverbesserung des SQL-Statements (im DWH-Umfeld kann es sich um Stunden handeln) mehr als ausgeglichen.
Eine Alternative wäre auch, die Statistiken nach Beladung zu sperren oder zu löschen. Aufgrund der Möglichkeit des Optimizers, ein dynamisches Sampling bei Tabellen ohne Statistiken während der Laufzeit durchzuführen (init.ora-Parameter "optimizer_dynamic_sampling" Default=2) kann ein immer noch besserer Ausführungsplan als mit falschen Statistiken erzielt werden.
Für X$-Tabellen verwendet der Optimizer voreingestellte Statistikwerte, die nicht unbedingt ein Abbild der tatsächlichen Beladung darstellen. Da Dynamic Sampling nicht automatisch für diese Tabellen verwendet wird, sollten Statistiken folgendermaßen erzeugt werden:
Die Statistik-Erstellung für Fixed Objects sollte nach Datenbank-Upgrades oder nach Änderungen in der Datenbank-Konfiguration wiederholt werden.
Neben den Objekt-Statistiken benötigt der Oracle Optimizer Informationen über die Kapazität des Systems, auf dem die Datenbank läuft.
Bei der Ausführung der Query „select * from mqs.consulting order by mitarbeiter“ kommen im wesentlichen zwei Ausführungspfade in Betracht:
Wenn das System über schnelle CPUs und langsame Platten verfügt, ist der erste Ausführungspfad günstiger. Bei schnellen Platten und langsameren CPUs ist möglicherweise der zweite Pfad günstiger.
Damit sich die Datenbank einen Überblick über das System verschaffen kann, ist es empfehlenswert, mit folgender Prozedur Systemstatistiken zur Hauptverarbeitungszeit zu erstellen:
Die von Oracle im Intervall von 60 Minuten ermittelten Werte können anschließend der VIEW SYS.AUX_STATS$ entnommen werden.
Fazit
Das Vorhandensein von passenden Objekt-Statistiken ist die unabdingbare Voraussetzung für ein performantes Datenbanksystem und eine hohe Akzeptanz auf Anwenderseite.
Statistiken auf Fixed Tables und auf Systemressourcen verbessern den Durchsatz in der Datenbank, haben aber bei weitem nicht den Effekt wie die Objekt-Statistiken.
Detaillierte Informationen zu Statistiken erhalten Sie in den DB Tuning , SQL Tuning und Optimizer Schulungsangeboten der Muniqsoft GmbH.
Der Workspace Manager dient zur Versionierung von Tabellendaten in verschieden Versionen (Workspaces)Vorteile
Vorbereitungen:
Sie können eine Administrationsrolle mit allen Rechten für die Workspacebearbeitung vergeben:
Folgende Einzelrechte können vergeben werden:
Beispiel:
Folgendes gilt für die Tabellen:
Beispiel:Tabelle für den Workspace Manager aktivieren:
Zwei Workspaces einrichten:
In den ersten Workspace wechseln:
Durchführen von Änderungen in der Tabelle emp im Workspace my_workspace_1:
In den Haupt-Workspace wechseln:
Dort ist die Tabelle in Ihrem Ursprungszustand zu sehen (ohne die 3 DML Änderungen)In welchem Workspace sind wir gerade?
Die Live Tabelle kann nun auf die Workspace Tabellen-Variante refreshed werden:
Oder die Workspace Variante wird auf Live synchronisiert:
Die Tabelle kann wieder aus der Versionsverwaltung herausgenommen werden durch:
Mit der Option FORCE wird das Kommando auch mit geänderten Workspacedaten durchgeführt, sonst erhält man einen Oracle Fehler:
Zum Löschen eines Workspace verwenden Sie:
Weitere Informationen zum Workspace Manager erhalten Sie in unserem PL/SQL II Kurs.
Installation von Oracle 23ai FREE auf Debian
Die folgende Installation wird zwar nicht von Oracle supported, aber das wird die 23ai FREE Edition sowieso nicht, also los geht´s …
Benutzer anlegen (kann man auch durch das Preinstall Skript durchführen lassen), aber hier ist man flexibler…
addgroup --system oinstall addgroup --system dba adduser --system --ingroup oinstall --shell /bin/bash oracle usermod -d /home/oracle oracle chown -R oracle:oinstall /home/oracle adduser -d /home/oracle oracle dba
Ein paar Packages vorinstallieren:
apt-get install alien rlwrap
REM Download der beiden Dateien von der URL: https://www.oracle.com/database/free/download/
Red Hat 8 / Rocky Linux 8 / Alma Linux 8 / Oracle Linux 8 wget https://yum.oracle.com/repo/OracleLinux/OL8/appstream/x86_64/getPackage/oracle-database-preinstall-23ai-1.0-2.el8.x86_64.rpm wget https://download.oracle.com/otn-pub/otn_software/db-free/oracle-database-free-23ai-1.0-1.el8.x86_64.rpm Red Hat 9 / Rocky Linux 9 / Alma Linux 9 / Oracle Linux 9 https://yum.oracle.com/repo/OracleLinux/OL8/appstream/x86_64/getPackage/oracle-database-preinstall-23ai-1.0-2.el9.x86_64.rpm wget https://download.oracle.com/otn-pub/otn_software/db-free/oracle-database-free-23ai-1.0-1.el9.x86_64.rpm
REM Unwandeln der .rpm Dateien in .deb Dateien:
alien --script oracle-database-preinstall*.rpm alien --script oracle-database-free-23ai*.rpm
### Achtung dauert laaaaange #### nicht abbrechen #### bei uns fast 1 Stunde ! zur Überbrückung bekommt man dauernd die Warnung: warning: oracle-database-free-23ai-1.0-1.el8.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID ad986da3: NOKEY oder wenn Sie Langeweile haben, können Sie die Größe des Zielordners "im Auge" behalten:
du -hs oracle-database-free-23ai-1.0
da sollten dann ca. 11 GB rauspurzeln
Sie können während Sie auf die Beendigung der Umwandlung warten schon mal (in einer zweiten Session) die .bash_profile Datei bearbeiten/anpassen:
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/23ai/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 [x]e_pmon | awk '{print "Oracle-Prozess:" $2}' ps aux | grep [t]ns | awk '{print "Listener-Prozess:" $2}' EOF
Wenn der Umwandlungsprozess fertig ist, geht es weiter mit:
apt update apt install libaio* apt install ./oracle-database-preinstall-23ai_1.0-1.5_amd64.deb apt install ./oracle-database-free-23ai_1.0-2_amd64.deb
dann geht es weiter mit:
Hinweis: Bei uns wurde bei der automatischen Installation der Listener Port 1539 verwendet und dann abgebrochen.
Sie können den Port in folgender Datei selber setzen:
vi /etc/sysconfig/oracle-free-23ai.conf LISTENER_PORT=1521
/etc/init.d/oracle-free-23ai configure
zweimal ein schönes langes Passwort eingeben, z.B. "dasistmeinPasswordganzschoenlangoder"
/etc/init.d/oracle-free-23ai configure Oracle Net Listener configured. Specify a password to be used for database accounts. Oracle recommends that the password entered should be at least 8 characters in length, contain at least 1 uppercase character, 1 lower case character and 1 digit [0-9]. Note that the same password will be used for SYS, SYSTEM and PDBADMIN accounts: Confirm the password: Configuring Oracle Listener. Listener configuration succeeded. Configuring Oracle Database FREE. Enter SYS user password: *** Enter SYSTEM user password: **** Enter PDBADMIN User Password: ***** Prepare for db operation 7% complete Copying database files 29% complete Creating and starting Oracle instance 30% complete 33% complete 36% complete 39% complete 43% complete Completing Database Creation 47% complete 49% complete 50% complete Creating Pluggable Databases 54% complete 71% complete Executing Post Configuration Actions 93% complete Running Custom Scripts 100% complete Database creation complete. For details check the logfiles at: /opt/oracle/cfgtoollogs/dbca/FREE. Database Information: Global Database Name:FREE System Identifier(SID):FREE Look at the log file "/opt/oracle/cfgtoollogs/dbca/FREE/FREE.log" for further details. Connect to Oracle Database using one of the connect strings: Pluggable database: pve4/FREEPDB1 Multitenant container database: pve4
Beim ersten Versuch gab es leider kein schöner Abschluss, wir bekommen den Fehler:
Listener configuration failed. Check log '/opt/oracle/cfgtoollogs/netca/netca_configure_out.log' for more details
und da steht drinnen:
The information provided for this listener is currently in use by other software on this computer.
In der listener.ora Datei ($ORACLE_HOME/network/admin) steht ein Port 1539 hmm, kenn ich nicht, Oracle verwendet normalerweise den Port 1521. Oder Sie haben wir oben beschrieben den Port bereits geändert, dann sollte alles durchlaufen.
So jetzt können Sie mit Ihren SQL / DBA /APEX Kenntnissen loslegen… oder doch erst einen Kurs bei uns besuchen ?Kein Problem, bei 44 verschiedenen Kursen ist sicher auch für Sie etwas dabei.
Wollten Sie immer schon mal zu Dokumentationszwecken ihre Shell Skripten in Oracle Tabellen speichern, das Ganze auch noch Clientseitig?
Das Problem sind die vielen Zeilenumbrüche in den Shell Skript Dateien, deswegen wandeln wir die Datei in BASE64 um. Da die Dateien länger als 32767 Zeichen lang werden können und damit die Maximallänge von VARCHAR2 in Tabellen von 4k (bzw. 32K ab 12.1 bei spezieller Einrichtung) übersteigen können,wandeln wir es sicherheitshalber in CLOB um.Leider hat Oracle eine solche Funktion nicht, dewegen schreiben wir sie uns selbst.
1. Funktion anlegen:
CREATE OR REPLACE FUNCTION Decode_Base64( p_base64 IN CLOB ) RETURN CLOB AS v_blob BLOB; v_decoded CLOB; v_length INT; v_warning INT; v_offset INT:= 1; v_context INT:= dbms_lob.default_lang_ctx; BEGIN -- Convert the Base64 CLOB into a BLOB DBMS_LOB.CREATETEMPORARY(v_blob, TRUE); DBMS_LOB.WRITE(v_blob, DBMS_LOB.GETLENGTH(p_base64), 1, UTL_RAW.CAST_TO_RAW(p_base64)); -- Decode the Base64 BLOB v_blob := UTL_ENCODE.BASE64_DECODE(v_blob); -- Determine the length of the decoded text v_length := DBMS_LOB.GETLENGTH(v_blob); -- Convert the BLOB to CLOB DBMS_LOB.CREATETEMPORARY(v_decoded, TRUE); DBMS_LOB.CONVERTTOCLOB( DEST_LOB => v_decoded, SRC_BLOB => v_blob, AMOUNT => v_length, DEST_OFFSET => v_offset, SRC_OFFSET => v_offset, blob_csid => dbms_lob.default_csid, lang_context => v_context, warning => v_warning ); -- Free resources DBMS_LOB.FREETEMPORARY(v_blob); RETURN v_decoded; END Decode_Base64; /
2. Ziel-Tabelle erstellen:
CREATE TABLE script_table ( id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, content CLOB);
3. Auf Shell-Ebene gewünschte Datei (hier: install.sh) in Base64 codieren und in Variable B64 speichern:
export B64=`echo -n \`cat install.sh\` | base64`
4. OS-Variable in Oracle Tabelle eintragen und wieder aus Base64 in CLOB Text konvertieren:
sqlplus scott/TIGER@172.24.114.237:1522/pdb1 <<EOF set echo off termout off DECLARE script_content CLOB := q'^${B64}^'; BEGIN INSERT INTO script_table(content)VALUES(decode_base64(script_content)); COMMIT; END; / EXIT; EOF
So nun steht Ihrer Versionsverwaltung oder dem Audit nichts mehr im Wege…Weitere tolle Tipps erhalten Sie in einem unserer 50 Oracle und Postgres Kurse. Wir freuen uns auf Sie …
Seit 30 Jahren warte ich auf dieses Feature, aber wie sagt man besser spät als nie …
Ab 23ai kann nun endlich ein Tablespace reorganisiert werden. Es gibt da nur ein paar Einschränkungen:
Zuerst prüfen wir mal, welche Tablespaces sich den lohnen bzgl eines Reorg?
set serveroutput on linesize 400 set long 9999999 WITH function analyze_tbs(tbs_name In VARCHAR2) RETURN CLOB IS PRAGMA AUTONOMOUS_TRANSACTION; v_result CLOB:=empty_clob(); BEGIN dbms_output.put_line('### '||tbs_name||' ###:'); DBMS_SPACE.TABLESPACE_SHRINK(tbs_name, SHRINK_MODE => DBMS_SPACE.TS_MODE_ANALYZE, SHRINK_RESULT => v_result); RETURN tbs_name||':'||chr(10)||v_result; END; select analyze_tbs(tablespace_name) from dba_tablespaces where bigfile='YES' and contents='PERMANENT';
Nun können wir einen Tablespace von Oracle shrinken/reorganisieren …
BEGIN DBMS_SPACE.TABLESPACE_SHRINK('SYSAUX', SHRINK_MODE => dbms_space.ts_mode_shrink, target_size => dbms_space.ts_target_max_shrink); END; /
Viel Spaß mit dem neuen gewonnen Speicherplatz. Die Einsparung kann man ja nun in eine Schulung stecken :-)
TomCat Version 10 ist nun einige Jahre auf dem Markt, nur leider unterstützt Oracle diese Version weiterhin nicht. Inwischen gibt es sogar auch schon TomCat 11!Wer doch schon mal auf undokumentierten Pfaden wandeln möchte, bekommt hier die Anleitung dazu.
Packen Sie nun die jakartaee-migration Dateien aus Schritt 3 z.B. in das Temp Verzeichnis aus (c:\temp für Windows oder /tmp für Linux)
Packen Sie auch die ORDS Version aus Schritt 4 im Temp Verzeichnis aus
Kopieren Sie die Datei ords.war in das Verzeichnis C:\Temp\jakartaee-migration-*\lib (Windows) oder /tmp/jakartaee-migration-*/lib (Linux)
Windows: "C:\Program Files\Java\jdk-17\bin\java.exe" -jar jakartaee-migration-1.0.8.jar ords.war ords_neu.war
Linux: java -jar jakartaee-migration-1.0.8.jar ords.war ords_neu.war
Nun wird die ords_neu.war in ords.war umbennant und in das webapps Verzeichnis des TomCat kopiert
Windows: move C:\Temp\jakartaee-migration-1.0.8\lib\ords_neu.war “C:\Program Files\Apache Software Foundation\Tomcat 10.1\webapps\ords.war” bzw. Version 11 Windows: move C:\Temp\jakartaee-migration-1.0.8\lib\ords_neu.war “C:\Program Files\Apache Software Foundation\Tomcat 11.0\webapps\ords.war”
Linux: mv /tmp/jakartaee-migration-1.0.8/lib/ords_neu.war /opt/tomcat/latest/webapss
Ords Einrichtung (Windows)
set JAVA_HOME="C:\Program Files\Java\jdk-17" set PATH=%PATH%;%JAVA_HOME% set ORDS_HOME=c:\oracle\ords set ORDS_CONFIG=c:\oracle\ords set ORDS_LOGS=%ORDS_CONFIG%\logs mkdir %ORDS_CONFIG% mkdir %ORDS_LOGS% dir %JAVA_HOME% set DB_PORT=1521 set DB_SERVICE=apex241 set SYSDBA_USER=SYS set SYSDBA_PASSWORD=sys set ORDS_PASSWORD=ords set ORA_HOST=172.30.30.2 #%ORDS_HOME%\bin\ords --config %ORDS_CONFIG% uninstall %ORDS_HOME%\bin\ords --config %ORDS_CONFIG% install ^ --log-folder %ORDS_LOGS% ^ --admin-user %SYSDBA_USER% ^ --db-hostname %ORA_HOST% ^ --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 Einrichtung (Linux)
export ORDS_HOME=/opt/oracle/ords mkdir -p $ORDS_HOME chown -R tomcat:dba $ORDS_HOME export ORA_HOST=172.30.30.2 export DB_SERVICE=apex241 export ORDS_CONFIG=/opt/oracle/ords cp ords.war $ORDS_HOME cp -R bin $ORDS_HOME cd $ORDS_HOME export SYSDBA_USER=sys export DB_PORT=1521 chmod u+x $ORDS_HOME/bin/ords tnsping $ORA_HOST:$DB_PORT/$DB_SERVICE lsnrctl status | grep $DB_SERVICE # Optional: Deinstallation # systemctl stop tomcat # $ORDS_HOME/bin/ords --config $ORDS_CONFIG uninstall --admin-user $SYSDBA_USER $ORDS_HOME/bin/ords --config $ORDS_CONFIG install \ --log-folder $ORDS_HOME \ --admin-user $SYSDBA_USER \ --db-hostname $ORA_HOST \ --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
Auf jeden Fall immer beachten: Der TomCat muss wissen, wo sein Configfile für den ORDS ist.
Unter Windows trägt man das im Apache Tomcat Config Fenster im Bereich Java ein:
Unter Unix natürlich entsprechend (Datei /etc/systemd/system/tomcat.service):
Environment="JAVA_OPTS=-Djava.security.egd=file:///dev/urandom -Dconfig.url=/opt/oracle/ords"
Danach sollte in der der Catalina*.log etwas stehen wie:
19-May-2025 11:06:32.611 INFORMATION [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.home=C:\Program Files\Apache Software Foundation\Tomcat 9.0 19-May-2025 11:06:32.611 INFORMATION [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dcatalina.base=C:\Program Files\Apache Software Foundation\Tomcat 9.0 19-May-2025 11:06:32.611 INFORMATION [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.io.tmpdir=C:\Program Files\Apache Software Foundation\Tomcat 9.0\temp 19-May-2025 11:06:32.611 INFORMATION [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager 19-May-2025 11:06:32.611 INFORMATION [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Djava.util.logging.config.file=C:\Program Files\Apache Software Foundation\Tomcat 9.0\conf\logging.properties 19-May-2025 11:06:32.611 INFORMATION [main] org.apache.catalina.startup.VersionLoggerListener.log Command line argument: -Dconfig.url=C:\opt\oracle\ords
So, das war es schon. nur immer daran denken, wenn es ein Problem in dieser nicht unterstützen Konfiguartion gibt, müsste das Ganze erst unter TomCat Version 9 reproduziert werden!
Viel Spass und bis Bald in einem unserer APEX Kurse …
Have you always wanted to save your shell scripts in Oracle tables for documentation purposes, even on the client side?
The problem is the many line breaks in the shell script files, so we convert the file to BASE64. Since the files can be longer than 32767 characters and thus exceed the maximum length of VARCHAR2 in tables of 4k (or 32K from 12.1 with special setup),
1. Create Funktion :
2. Target-Tabelle:
3. At shell level, code the desired file (here: install.sh) in Base64 and save it in variable B64:
4. Enter OS variable in Oracle table and convert back from Base64 to CLOB text:
So now nothing stands in the way of your version management or audit...You can get more great tips in one of our 50 Oracle and Postgres courses. We look forward to seeing you ...
I've been waiting 30 years for this feature, but as they say – better late than never…
Starting with Oracle 23ai, it is finally possible to reorganize a tablespace. There are just a few limitations:
It must be a Bigfile Tablespace
It must not contain any exotic or read-only objects such asAUD$UNIFIED
AUD$UNIFIED
First, let's check which tablespaces are actually worth reorganizing.
Now, we are finally able to shrink or reorganize a tablespace in Oracle...
Have fun with the newly reclaimed space. The savings can now be invested in a training course. :-)
The question of how to display a PDF in a page comes up very often in our APEX courses. In our case, the PDF comes from a table in the Oracle database.
Preparation:
CREATE TABLE emp_lob ( EMPNO NUMBER(4,0), ENAME VARCHAR2(10 BYTE), DATEINAME VARCHAR2(512 BYTE), BESCHREIBUNG VARCHAR2(4000 BYTE), DATEITYP VARCHAR2(100 BYTE), L_UPDATE DATE, BILD BLOB)
Create an application process (Shared Components / Application Logic / Application Process) in APEX: Name getPDF and define as Ajax Processes
The process has the following code:
begin for file in (select * from emp_lob where empno = :EMPNO and dateityp='application/pdf') loop sys.htp.init; sys.owa_util.mime_header( file.dateityp, FALSE ); sys.htp.p('Content-length: ' || sys.dbms_lob.getlength( file.bild)); sys.htp.p('Content-Disposition: inline; filename="' || file.fname || '"' ); sys.htp.p('Cache-Control: max-age=3600'); -- tell the browser to cache for one hour, adjust as necessary sys.owa_util.http_header_close; sys.wpg_docload.download_file( file.bild ); apex_application.stop_apex_engine; end loop; end;
<object data="http://127.0.0.1:8080/ords/f?p=100:0:&SESSION.:APPLICATION_PROCESS=getPDF:::EMPNO:&P1_EMPNO." style="width:100%;height:700px"> <a href="http://127.0.0.1:8080/ords/f?p=100:0:&SESSION.:APPLICATION_PROCESS=getPDF:::EMPNO:&P1_EMPNO.">PDF laden</a> </object>
And now have fun displaying all your PDFs. We use it to display our PDF invoices in APEX :-)See you (hopefully) soon in one of our courses ...
In our training sessions, we frequently get interesting questions about the Interactive Grid. Here's a small selection:
Requirements:
There is a grid on the Scott.emp table with the static ID EMP
There is a select list named P1_JOB
2. Only the entries selected using the checkbox (column 1) in the grid should be updated.
3. ou want to handle writing back to the database yourself? No problem. Simply replace the process with:
That was a small excerpt from the many questions we get in our APEX courses. Do you have questions too? Then join one of our courses… we look forward to seeing you!