27. November 2007

Installierte Oracle Software ermitteln ... doch, das geht mit SQL!

Die Tage hatte ich mit Volker Solinus eine sehr interessante Diskussion. Was dabei herausgekommen ist, ist eine ganz nette Anwendung der XML-Technologie in der Datenbank. Bekanntlich kann der DBA sich mit der View DBA_REGISTRY recht einfach die in der jeweiligen Datenbank konfigurierten Komponenten ansehen. Schwieriger stellt es sich dar, wenn man wissen möchte, welche Software im $ORACLE_HOME des Datenbankservers installiert ist - Da treten schon öfter Fragen auf wie ...
  • Ist die Companion CD installiert oder nicht?
  • Welche Einzelpatches sind eigentlich installiert?
Die Antwort auf diese Fragen lässt sich auch mit SQL ermitteln: Basis dafür ist die Tatsache, dass der Oracle-Installer eine Datei namens comps.xml im Verzeichnis $ORACLE_HOME/inventory/ContentsXML pflegt. In dieser XML-Datei sind alle installierten Softwarekomponenten enthalten - Das OPatch-Werkzeug pflegt auch die installierten Einzelpatches ein.
Und da es eine XML-Datei ist, kann sie mit den hier schon öfter genutzten SQL-Funktionen wie EXTRACTVALUE ausgelesen werden.
Um zu beginnen, erzeugen wir zunächst ein Verzeichnis-Objekt auf besagtes Verzeichnis mit der Datei comps.xml:
create or replace directory COMPSXMLDIR as '/oracle/u01/app/oracle/product/11.1.0/inventory/ContentsXML';
Anschließend kann man sich die Datei im SQL*Plus schonmal ansehen:
select 
  xmltype(
      bfilename('COMPSXMLDIR', 'comps.xml'),
      nls_charset_id('WE8ISO8859P1')
  ).getclobval()
from dual;
Nun geht's aber los: Wir verwenden sie Funktionen EXTRACTVALUE zum Ausschneiden einzelner Tags bzw. Attribute und nutzen das TABLE(XMLSEQUENCE(EXTRACT(...)))-Konstrukt zum "Flachklopfen" der hierarchischen XML-Struktur. Die erste Frage wäre die nach den installierten CD-Sets:
col comp_name format a50
col comp_version format a20

select 
  extractvalue(value(c), '/COMP/EXT_NAME') comp_name,
  extractvalue(value(c), '/COMP/@ACT_INST_VER') comp_version
FROM table(
     XMLSequence(
         extract(
             xmltype(
                 bfilename('COMPSXMLDIR', 'comps.xml'),
                 nls_charset_id('WE8ISO8859P1')
             ), 
             '/PRD_LIST/TL_LIST/COMP'
         )
     )
 ) c
/ 

COMP_NAME                                          COMP_VERSION
-------------------------------------------------- --------------------
Oracle Database 11g                                11.1.0.6.0
Auf einer anderen Datenbank sieht es u.U. so aus:
COMP_NAME                                          COMP_VERSION
-------------------------------------------------- --------------------
Oracle Database 11g                                11.1.0.6.0
Oracle Database 11g Examples                       11.1.0.6.0
Gehen wir ein wenig tiefer hinein: Welche Komponenten machen denn die Oracle Database 11g aus?
select 
  extractvalue(value(c), '/COMP/EXT_NAME') comp_name,
  extractvalue(value(c), '/COMP/@ACT_INST_VER') comp_version
FROM table(
     XMLSequence(
         extract(
             xmltype(
                 bfilename('COMPSXMLDIR', 'comps.xml'),
                 nls_charset_id('WE8ISO8859P1')
             ), 
             '/PRD_LIST/COMP_LIST/COMP'
         )
     )
 ) c
/

COMP_NAME                                          COMP_VERSION
-------------------------------------------------- --------------------
Sun JDK                                            11.1.0.6.0
Installer SDK Component                            11.1.0.6.0
Oracle One-Off Patch Installer                     11.1.0.6.0
Oracle Universal Installer                         11.1.0.6.0
LDAP Required Support Files                        11.1.0.6.0
SSL Required Support Files for InstantClient       11.1.0.6.0
Oracle Net Required Support Files                  11.1.0.6.0
Buildtools Common Files                            11.1.0.6.0
:                                                  :
Und schließlich die Frage nach den installierten Einzelpatches
SELECT to_number(   extractValue(value(oneOffList), '/ONEOFF/@REF_ID')              ) oneoff_id,
       substr   (   extractValue(value(oneOffList), '/ONEOFF/@ACT_INST_VER')  , 1,20) db_version,
       substr   (   extractValue(value(oneOffList), '/ONEOFF/@INSTALL_TIME')  , 1,30) install_time
FROM table(
     XMLSequence(
         extract(
             xmltype(
                 bfilename('COMPSXMLDIR', 'comps.xml'),
                 nls_charset_id('WE8ISO8859P1')
             ), 
             '/PRD_LIST/ONEOFF_LIST/ONEOFF'
         )
     )
 ) oneOffList
/

 ONEOFF_ID DB_VERSION           INSTALL_TIME
---------- -------------------- ------------------------------
   5557962 10.2.0.3.0           2007.Mar.12 14:03:52 CET
   5556081 10.2.0.3.0           2007.Mar.12 14:04:03 CET
   6010833 10.2.0.3.0           2007.Jul.10 11:10:29 CEST
   6069085 10.2.0.3.0           2007.Jul.10 11:16:35 CEST
         : :                    :

Bitte achtet auf den Zeichensatz, den Ihr bei NLS_CHARSET_ID angibt - es sollte der sein, in dem die Datei comps.xml vorliegt - hängt mitunter vom Betriebssystem ab. Nochmals Danke an Volker für die Idee und die Hilfe bei der Umsetzung.

Keine Kommentare:

Beliebte Postings