ora* CODECOP – PLSQL codecop auf GITHUB von yerba1704

Allgemein

Bin durch Zufall auf ein tolles Projekt gestoßen: https://github.com/yerba1704/occ

Die Idee ist recht einfach und die Umsetzung scheint gelungen. Gefällt mir sehr…

Auch und v.a. das Plugin für den SQL Developer 🙂
(zu finden hier https://github.com/yerba1704/occ-sqldeveloper)

SQL Developer – Installation und Konfiguration

Allgemein

Installation

Windows

Einfach die „Windows 64-bit with JDK 8 included“ Version runterladen und installieren.

Linux

Zunächst muss das JDK (“ Java SE Development Kit“) runtergeladen und installiert werden. Download von hier und danach entpacken, z.B: nach /opt/oracle_java/.

Das Einrichten dann in Debian bzw. Debian basierten Distributionen mit (Pfadteil „jdk1.8.0_191“ entsprechend anpassen…):

sudo update-alternatives --set "java" "/opt/oracle_java/jdk1.8.0_191/bin/java"
sudo update-alternatives --set "javac" "/opt/oracle_java/jdk1.8.0_191/bin/javac"
sudo update-alternatives --set "javaws" "/opt/oracle_java/jdk1.8.0_191/bin/javaws"
sudo update-alternatives --set "jar" "/opt/oracle_java/jdk1.8.0_191/bin/jar"

sudo update-alternatives --set "java" "/opt/oracle_java/jdk1.8.0_191/bin/java"
sudo update-alternatives --set "javac" "/opt/oracle_java/jdk1.8.0_191/bin/javac"
sudo update-alternatives --set "javaws" "/opt/oracle_java/jdk1.8.0_191/bin/javaws"
sudo update-alternatives --set "jar" "/opt/oracle_java/jdk1.8.0_191/bin/jar"

Jetzt den SQL Developer runterladen („Other Platforms“) und entpacken, z.B: nach /opt/oracle_sqldeveloper/.

Konfiguration

Meine wichtigsten Anpassungen (Tools > Preferences) kurz und knapp:

  • Code Editor
    • Fonts — Courier New 18 / Consolas 14
    • Format — spaces 2; lower; lower
      • Advanced Format
        • Line Breaks — concatenation no breaks; max line 80; after statement single break
        • White Space — after commas
    • Line Gutter — show line numbers
  • Database — filename for connection startup script mystartup.sql (Inhalt s.u.)
    • Advanced — fetch size 200; null using background color LIGHT_GRAY
    • NLS — date language GERMAN; DD.MM.RR HH24; €; length CHAR
    • PL/SQL Compiler — All Enable
  • Shortcut Keys — upper/lower/initcap ALT+L; convert selection lowercase CTRL+L; toggle line comment CTRL+PERIOD ; run script ALT+SHIFT+ENTER

Inhalt von mystartup.sql

clear screen;
set serveroutput on;

Meine Auswahl an Externsions:

Wenn dem Befehlszeilenaufruf (sqldeveloper.sh bzw. sqldeveloper.exe) ein:
–AddVMOption=-Duser.language=en
mitgegeben wird, so ändert man damit die Sprache der GUI.

Mit dem Zusatz
–AddVMOption=-Dide.user.dir=X:\path\mysettings
können Benutzereinstellungen von einem anderen Ort, z.B. Netzwerkpfad, gezogen werden.

Pimp my Elementary OS 5.0 (Juno)

Bash, ElementaryOS, Fun

Wie man das „alte“ elementary OS 0.4 (Loki) optimal anpasst hatte ich ja bereits hier und hier beschrieben. Seit dem 16.10.2018 ist nun die neue Version von elementary OS für alle verfügbar und damit auch Zeit für mich mein Skript zu aktualisieren…

Eine hervorragende Vorlage für kurze Bash-Skripte habe ich bei github gefunden. Mit „Yet another Bash script template“ (YABST) ging es super einfach.

Genug der langen Vorrede, hier der Code:

#!/bin/bash
##
## Usage: juno_post_install [options]
##
## Improve fresh elementary OS (juno) installation.
## Must be run as root.
##
## Options:
##  -h, --help      Display this message.
##  -v, --version   Display version number.
##
## Example:
## juno_post_install --help
##

#-------------------#
# GLOBAL VARIABLES  #
#-------------------#
VMAJ=1  # major version
VMIN=0  # minor version
VREV=0  # patch version

QTM=0   # quiet mode flag (always off)
#------------------#
# GLOBAL FUNCTIONS #
#------------------#
_config(){
  source "$1"
}
_echo(){
  if [ $QTM -eq 0 ]; then
    echo "$1"
  fi
}
_error(){
  echo "$1"
  exit 1
}
_replace(){
  if [ "$#" -eq 3 ]; then
    if [ -f "$1" ]; then
      sed -i 's/'"${2////\\/}"'/'"${3////\\/}"'/g' "$1"
    else
      _error "'$1' is not a valid file."
    fi
  else
    _error "Function needs 3 parameter (file, search, replace)."
  fi
}
_require(){
  if ! [ -n "$(command -v $1)" ]; then
    _error "The program $1 is required. Please install it first."
  fi
}
_root(){
  if [[ $(whoami) != "root" ]]; then
    _error "This program must be run as root."
  fi
}
_title(){
  if [ $QTM -eq 0 ]; then
    (echo; echo \*\*\* $1 \*\*\*; echo)
  fi
}
_usage(){
  [ "$*" ] && echo "$0: $*"
  sed -n '/^##/,/^$/s/^## \{0,1\}//p' "$0"
  exit 2
}
_version(){
  echo "" && echo "$0 version $VMAJ.$VMIN.$VREV"
  exit 2
}
_write(){
  fname="out.txt"
  if [ ! -z "$2" ]; then
    fname="$2"
  fi

  cat  http://appcenter.elementary.io/
}
configure_vm(){
  _title "Configure virtual machine (if any)"

  vbox=`dmidecode -t system | grep -i 'virtualbox' | wc -l`
  if [ $vbox -gt 0 ]; then
    _echo "Install software and..."
    apt install virtualbox-guest-additions-iso virtualbox-guest-utils
    _echo "...add user to group"
    if [ $SUDO_USER == "" ]; then
      adduser $USER vboxsf
    else
      adduser $SUDO_USER vboxsf
    fi
  fi
}
create_aliases(){
  _title "Create command aliases"

  txt="
alias clear-history='cat /dev/null > ~/.bash_history && history -c'
alias apt-opt='sudo apt update && sudo apt upgrade -y && sudo apt autoremove -y && sudo apt autoclean -y'"

  echo "$txt" >> "/home/$SUDO_USER/.bashrc"
  _echo "2 aliases added."
}
clean_up(){
  _title "Clean up"
  apt update && apt upgrade -y && apt autoremove -y && apt autoclean -y
}
#-----------------------#
# MAIN FUNCTION / START #
#-----------------------#
main() {
  while [ $# -gt 0 ]; do
    case $1 in
    (-h|--help) _usage;;
    (-v|--version) _version;;
    (-q) QTM=1;shift;;
    (--) shift; break;;
    (-*) _usage "$1: unknown option";;
    (*) break;;
    esac
  done
  _root
  # start steps
  full_update
  remove_software
  add_software1
  add_software2
  configure_vm
  create_aliases
  clean_up
}
main "$@"

Viel Spass!

Linux Standardprogramme Teil 2 – IDENTIFY und CONVERT.

Bash, Fun

Hier mal nun wieder einige Beispiele rund ums Bild via Kommandozeile.

# Allgemeine, kurze Infos zu Bild foo.jpg anzeigen
file foo.jpg
# Spezielle, ausführliche Infos zu Bild foo.jpg anzeigen (u.a. EXIF)
identify -verbose foo.jpg
# Alle Bilder im aktuellen Verzeichnis mit PNG Format konvertieren zu JPG (Dateinamen beibehalten, nur Dateiendung anpassen).
for p in *png; do convert "$p" "${p%.png}.jpg"; done
# Alle Bilder im aktuellen Verzeichnis mit PNG Format zu einer Animation mit 120 Millisekunden Pause zwischen den einzelnen Bildern zusammenfügen.
convert -delay 120 -loop 0 *.png animated.gif
# Alle Bilder im aktuellen Verzeichnis mit JPG Format auf 70% verkleinern.
for j in *jpg; do convert "$j" -resize 70% "${j%.jpg}_70.jpg"; done
# Alle Bilder im aktuellen Verzeichnis mit JPG Format auf 1600x900 Pixel skalieren. Die Höhe passt sich dem bestehenden Seitenverhältnis an, kann also größer oder kleiner 900 Pixel sein, die Breite mit 1600 Pixel ist maßgeblich.
for j in *jpg; do convert "$j" -resize '1600x900^' "${j%.jpg}-16_9.jpg"; done
# Alle Bilder im aktuellen Verzeichnis mit JPG Format auf 1600x900 Pixel skalieren. Die Breite passt sich dem bestehenden Seitenverhältnis an, kann also größer oder kleiner 1600 Pixel sein, die Höhe mit 900 Pixel ist maßgeblich.
for j in *jpg; do convert "$j" -resize '1600x900' "${j%.jpg}-16_9.jpg"; done
# Alle Bilder im aktuellen Verzeichnis mit JPG Format auf exakt 1600x900 Pixel skalieren.
for j in *jpg; do convert "$j" -resize '1600x900!' "${j%.jpg}-16_9.jpg"; done
# Vom Bild foo.png einen Bereich von 640x480 Pixel ausschneiden und zwar 50 Pixel von links und 100 von oben.
convert foo.png -crop 640x480+50+100 out.png

ORACLE – Java und C Code in der Datenbank

Fun, Oracle

Heute möchte ich mal zwei Möglichkeiten vorstellen „externen“ Code in der Oracle DB laufen zu lassen. Dabei gibt es diverse Unterschiede und Feinheiten zu beachten, ich versuche es aber einfach zu halten und so wenig wie möglich theoretischen Ballast zu liefern.

Als Beispiel kommen drei Funktionen zum Einsatz welche verschiedene Parameter entgegen nehmen sowie unterschiedliche Rückgabewerte haben.

  1. square_number liefert die Quadratzahl einer ganzzahligen Zahl.
  2. square_root liefert die Quadratwurzel einer beliebigen Zahl.
  3. full_name verbindet den Vor- und Nachnamen zum vollständigen Familiennamen

Java

Bei Java kann man ein Objekt erzeugen welches entweder eine Referenz auf eine Java-Datei ist oder auf den konkreten Code.

Ersteres würde so aussehen:

create java class using bfile (java_dir, 'jex_util.class');

Letzteres so:

create or replace and compile java source named jex_src
as
public class jex_util {

  public static int square_number (int val) {
    return val*val;
  }
  public static double square_root (double val) {
    return java.lang.Math.sqrt(val);
  }
  public static String full_name (String given_name, String family_name) {
    return given_name+" "+family_name;
  }

};
/

Nachdem der Klassencode in der DB ist kann er „angesprochen“ werden. Hier der Code dafür:

create or replace function j_square_number(
    p_val pls_integer)
  return pls_integer authid definer
as
  language java
  name 'jex_util.square_number(int) return int';
/

create or replace function j_square_root(
    p_val number)
  return number authid definer
as
  language java
  name 'jex_util.square_root(double) return double';
/

create or replace function j_full_name(
    p_given_name varchar2,
    p_family_name varchar2)
  return varchar2 authid definer
as
  language java
  name 'jex_util.full_name(java.lang.String, java.lang.String) return java.lang.String';
/

Das reicht um nun endlich auch alles testen zu können:

select
  j_square_number(3),
  j_square_root(9.25),
  j_full_name('foo', 'bar')
from
  dual;

Zum Schluß natürlich das Aufräumen nicht vergessen…

drop function j_square_number;
drop function j_square_root;
drop function j_full_name;
drop java source jex_src;

C

Nun das gleiche in C. Hier muss zunächst eine Bibliothek bzw. „Library“ erstellt werden (Dateiendung *dll* bei Windows und *so* bei Linux). Der Sourcecode ist unabhängig vom Betriebssystem und verwendeten Compiler für die Funktionen zunächst identisch (mal abgesehen vom C Präprozessor der hier im Beispiel für das Erstellen der DLL in Windows mit Visual Studio benötigt wird…).

Die Quellcodedatei cex_util.c könnte etwa so aussehen:

#include
#include
#include

#if defined(_WIN64)
  __declspec(dllexport)
#endif
char* full_name(char* given_name, char* family_name)
{
  char* space = " ";
  char* result = malloc(strlen(given_name) + strlen(space) + strlen(family_name) + 1);
  strcpy(result, given_name);
  strcat(result, space);
  strcat(result, family_name);

  return result;
}

#if defined(_WIN64)
  __declspec(dllexport)
#endif
int square_number(int val)
{
  return val*val;
}

#if defined(_WIN64)
  __declspec(dllexport)
#endif
double square_root(double val)
{
  return sqrt(val);
}

Wenn man unter Windows arbeitet kompiliert man den Code nun z.B. mit Visual Studio. In der „Visual Studio x64 Win64 Command Prompt (2010)“ oder auch „Visual Studio x64 Cross Tools Command Prompt (2010)“ wird dazu zunächst eine Objektdatei erzeugt, um anschließend aus dieser die gewünschte Bibliothek (cex_util.dll) zu erstellen:

cl /LD cex_util.c

Unter Linux kompiliert man am einfachsten mit der GNU Compiler Collection (gcc) die quasi bei jeder Distribution dabei ist. Dazu direkt im Terminal eingeben:

gcc -shared -o libcex_util.so -fPIC cex_util.c

Nun muss die dll bzw. so Datei noch dorthin gelegt werden, wo Oracle Zugriff darauf hat bzw. von wo überhaupt DLLs geladen werden dürfen. Laut der extproc.ora ist der Default Ordner von wo aus immer geladen werden darf $ORACLE_HOME/lib und $ORACLE_HOME/bin. Alternativ kann man auch die exproc.ora editieren und einen speziellen Pfad festlegen. Gehen wir mal von letzterem aus und erzeugen ein Objekt in der Datenbank welches in dieses (fiktive) Verzeichnis auf die entsprechende Bibliothek referenziert. Das sieht z.B. in Windows bei einem (angenommenen) Pfad C:\ora_lib\ so aus:

create or replace library lib_cex
as
'C:\ora_lib\cex_util.dll';

Und bei Linux – die Datei in /opt/ora_lib/ vorausgesetzt – dann so:

create or replace library lib_cex
as
'/opt/ora_lib/cex_util.so';

Nachdem die Referenz auf die Bibliothek erfolgreich erstellt wurde, kann nun der Code „angesprochen“ werden. Das geht so:

create or replace function c_square_number(
    p_val in pls_integer)
  return pls_integer authid definer
as
  language c
  name "square_number"
  library lib_cex;
/

create or replace function c_square_root(
    p_val in double precision)
  return double precision authid definer
as
  language c
  name "square_root"
  library lib_cex;
/

create or replace function c_full_name(
    p_given_name varchar2,
    p_family_name varchar2)
  return varchar2 authid definer
as
  language c
  name "full_name"
  library lib_cex;
/

Nun geht es endlich ans testen:

select
  c_square_number(4),
  c_square_root(20.25),
  c_full_name('hello', 'world')
from
  dual;

Zum Schluß das Aufräumen nicht vergessen:

drop function c_square_number;
drop function c_square_root;
drop function c_full_name;
drop library lib_cex;

Ein Satz noch zu den Typen bzw. Konvertierungen. Oracle nimmt eine Menge implizite Konvertierungen vor (z.B. wird varchar2 zu string und string wiederrum entspricht in C einem char pointer). Man kann aber die Konvertierungen auch explizit mitgeben indem man die „PARAMETERS“ clause hinzufügt.

create or replace function c_square_number(
    p_val in pls_integer)
  return pls_integer authid definer
as
  language c
  name "square_number"
  library lib_cex;
  parameters(p_val int, return int);
/

Eine sehr gute Übersicht über das Hin und Her bei den Datentypen gibt eine etwas ältere (aber scheinbar immer noch aktuelle) Doku von Oracle: [https://docs.oracle.com/cd/B10501_01/appdev.920/a96590/adg11rtn.htm#1005528](https://docs.oracle.com/cd/B10501_01/appdev.920/a96590/adg11rtn.htm#1005528)

Und nun bin ich gespannt aufs Feedback!

Pimp my Elementary OS 0.4 (Loki) – Teil 2

Bash, ElementaryOS, Fun

Hier noch eine verbesserte Form des alten Skriptes:

#!/bin/bash
##
## Usage: loki_post_install [options]
##
## Removes unnecessary and add usefull software to a fresh installed Elementary OS 0.4 (Loki).
## Must be run as root.
##
## Options:
##  -h, --help      Display this message.
##

main() {
while [ $# -gt 0 ]; do
case $1 in
(-h|--help) usage;;
(--) shift; break;;
(*) break;;
esac
done
if [ $(whoami) != "root" ]; then
echo "This program must be run as root."
exit 1
fi
software
}
usage(){
[ "$*" ] && echo "$0: $*"
sed -n '/^##/,/^$/s/^## \{0,1\}//p' "$0"
exit 2
}
msg() {
(echo; echo \*\*\* $1 \*\*\*; echo)
}
software() {
msg "Prepare system"
apt update && apt upgrade -y && apt autoremove -y && apt autoclean -y
msg "Remove software"
apt purge maya-calendar pantheon-mail appcenter simple-scan -y
msg "Install software"
apt install zip unzip rar unrar gnome-disk-utility firefox lilypond fluid-soundfont-gm timidity libav-tools openjdk-8-jdk-headless -y

vbox=`dmidecode -t system | grep -i 'virtualbox' | wc -l`
if [ $vbox -gt 0 ]; then
msg "Install & configure additional software for VirtualBox"
apt install virtualbox-guest-additions-iso virtualbox-guest-utils

if [ $SUDO_USER == "" ]; then
adduser $USER vboxsf
else
adduser $SUDO_USER vboxsf
fi
fi

msg "Clean up"
apt update && apt upgrade -y && apt autoremove -y && apt autoclean -y
}

main "$@"

Feedback welcome!

Linux Standardprogramme Teil 1 – FIND

Bash, Fun

Es gibt ja einige sehr mächtige Standardprogramme bei linux wie awk, sed oder auch find – um nur 3 zu nennen. Letzteres benutzt man gern mal hier und da, vergisst dann aber im Laufe der Zeit wieder wie genau das mit der Syntax war. Daher hier nun einige Beispiele in Verbindung mit dem Programm wc („word count“).

# Im aktuellen Verzeichnis rekursiv absteigend die Anzahl aller Dateien zählen
find . -type f | wc -l
# Im aktuellen Verzeichnis rekursiv absteigend die Anzahl aller Verzeichnisse zählen
find . -type d | wc -l
# Im aktuellen Verzeichnis rekursiv absteigend alle MP3-Dateien zählen
find . -iname '*mp3' | wc -l
# Im aktuellen Verzeichnis rekursiv absteigend alle MP3 oder FLAC-Dateien zählen
find . -iname '*mp3' -o -iname '*flac' | wc -l
# Im aktuellen Verzeichnis (nicht rekursiv absteigend) alle Dateien auflisten
find ./* -maxdepth 0 -type f
# Im aktuellen Verzeichnis (nicht rekursiv absteigend) alle Dateien, auch die versteckten, auflisten
find ./ -maxdepth 1 -type f #This does show hidden files

Pimp my Elementary OS 0.4 (Loki)

Bash, ElementaryOS, Fun

Also das neue schicke Elementary OS ist ja nun verfügbar, jedoch fehlt hier und da das ein oder andere wichtige Tool für mich. Und da ich den Laptop nur als Zweitrechner nutze brauche ich ja kein extra Mailprogramm geschweige denn ein Scanprogramm…

Lange Rede kurzer Sinn: Einiges musste  weg, einiges noch hinzu kommen damit ich mit dem Endergebnis so richtig zufrieden bin…

#!/bin/bash
##
## Usage: loki_post_install [options]
##
## Removes unnecessary and add usefull software to a fresh installed Elementary OS 0.4 (Loki).
## Must be run as root.
##
## Options:
##   -h, --help    Display this message.
##   -d            Display debug information.
##

DBG=0;

main() {
while [ $# -gt 0 ]; do
case $1 in
(-d) DBG=1;shift;;
(-h|--help) usage 2>&1;;
(--) shift; break;;
(-*) usage "$1: unknown option";;
(*) break;;
esac
done
if [[ $(whoami) != "root" ]]; then
echo "This program must be run as root." >&2
exit 1
fi
software
}

usage() {
[ "$*" ] && echo "$0: $*"
sed -n '/^##/,/^$/s/^## \{0,1\}//p' "$0"
exit 2
} 2>/dev/null

msg() {
if [ $DBG -eq 1 ]; then
(echo; echo \*\*\* $1 \*\*\*; echo)
fi
}

software() {
msg "Prepare system"
apt update -y && apt upgrade -y && apt autoremove -y
msg "Remove software"
apt purge maya-calendar pantheon-mail appcenter simple-scan -y
msg "Install software"
apt install zip unzip rar unrar gnome-disk-utility firefox lilypond frescobaldi fluid-soundfont-gm timidity -y
msg "Clean up"
apt update -y && apt upgrade -y && apt autoremove -y
}

main "$@"

 

DEBORA – Erweiterung um Ausführung von Programmen via DBMS_SCHEDULER

Fun, Oracle

Seit Oracle 10 gibt es mit dem Package DBMS_SCHEDULER ein ziemlich mächtiges Werkzeug welches in der Version 11 nochmals erweitert wurde. Mich interessieren tut hier in dem Zusammenhang weniger das Aufsetzen eines Jobs der in einem high sophisticated Zeitintervall läuft (mit Zeitzone, Feiertagskalender und allem drum und dran…), sondern vielmehr der Zugriff aufs darunter liegende Betriebssystem. Warum? Ganz einfach, weil somit augenblicklich alle möglichen (Kommandozeilen-)programme direkt aus Oracle heraus ausführbar werden. Etwa über eine Weboberfläche die mit APEX erstellt wurde!?

Damit das ganze aber reibungslos funktionieren kann, muss zuvor einiges erledigt werden…

1. Einstellungen im Guest bzw. bei DEBORA

Wir beginnen mit der Arbeit in Debian und führen als root folgende Befehle aus:

cd $ORACLE_HOME
chown root:dba bin/extjob
chmod 4750 bin/extjob
touch rdbms/admin/externaljob.ora
chown root:dba rdbms/admin/externaljob.ora
chmod 644 rdbms/admin/externaljob.ora

 

Nun müssen in diese soeben erstellte Datei noch zwei Zeilen mit folgenden Inhalt hinein:

run_user = oracle
run_group = dba

2. Einstellungen in der DB

Als Admin muss man dem User, welcher Programme ausführen dürfen soll, noch bissl Rechte geben – z.B. einen Testuser mit dem Namen „DEBORA“.

CREATE USER DEBORA IDENTIFIED BY DEBORA;
GRANT CONNECT,RESOURCE TO DEBORA;
GRANT CREATE JOB TO DEBORA;
GRANT CREATE EXTERNAL JOB TO DEBORA;

So, und nun können wir (hoffentlich) das Ergebnis bestaunen. Wir erstellen dazu der Einfachheit halber eine leere Datei.

BEGIN
  dbms_scheduler.create_job(
    job_name        => 'EXAMPLE_JOB',
    job_type        => 'EXECUTABLE',
    job_action      => '/bin/touch',
    auto_drop       => true,
    enabled         => false,
    start_date      => systimestamp,
    number_of_arguments => 1
  );
  dbms_scheduler.set_job_argument_value(
    job_name          => 'EXAMPLE_JOB',
    argument_position => 1,
    argument_value    => '/tmp/file_created_by_oracle_db'
  );
  dbms_scheduler.ENABLE('EXAMPLE_JOB');
END;

Viel Spass beim Experimentieren und wie immer ist Feedback willkommen!

P.S. Das erfolgreiche (oder eben auch mal nicht erfolgreiche) Ausführen der Jobs wird protokolliert und leicht abgefragt werden via

SELECT * FROM all_scheduler_job_run_details;