SQL Funktionen in SQLite als BeanShell-Scripts

vorhergehende Artikel in: Java Komponenten sQLshell
23.06.2024

Ich habe bereits hin und wieder über Erweiterungen der sQLshell berichtet, die bestimmte spezifische, proprietäre Features des jeweiligen DBMS in der sQLshell verfügbar machen.

Man kann sehr einfach Funktionen zu SQLite hinzufügen. Dabei handelt es sich um Funktionen, die einen skalaren Rückgabewert haben - für Table-valued Funktionen gilt das hier gesagte noch nicht.

Meine Idee war, in der sQLshell das neue Feature der Startup-Scripte zu benutzen, um der jeweiligen Datenbank neue Funktionen hinzuzufügen. In der API existiert ein sehr einfaches Beispiel:

Class.forName("org.sqlite.JDBC");
Connection conn = DriverManager.getConnection("jdbc:sqlite:");

Function.create(conn, "myFunc", new Function() { protected void xFunc() { System.out.println("myFunc called!"); } });

Mit den entsprechenden Anpassungen an die sQLshell wird daraus folgendes Skript:

conn=sQLshellAPI.getCurrentlyVisibleShell().getConnection();

specs=sQLshellAPI.getCurrentlyVisibleShell().getDBMSInterface().getDatabaseSpecifics().orElse(null);

if(specs!=null) { myFunc=new org.sqlite.Function() { protected void xFunc() { System.out.println("myFunc called!"); } };

specs.create("myFunc", myFunc); }

Dieser Code funktioniert auch, allerdings sollte es schon möglich sein, Funktionen mittels Parametern zu konfigurieren und Ergebnisse zurückzugeben. Dazu existieren Methoden in der Klasse org.sqlite.Function - diese lassen sich aber aus der Implementierung der Funktion xFunc im obigen Beispiel nicht aufrufen: Geskriptete Objekte sind in BeanShell nur als Implementierungen von Interfaces gedacht - nicht um wie oben dargestellt anonyme Klassen abzuleiten.

Daher musste ich zu einer List greifen: Ich definierte ein neues Interface:

public interface Function
{
    void xFunc() throws java.sql.SQLException;
}

und schrieb eine Klasse, um die bestehende SQLite API und die sQLshell zu verbinden:

public class Bridge extends org.sqlite.Function
{
    private final Function function;

public Bridge(Function function) { super(); this.function = function; }

@Override protected void xFunc() throws java.sql.SQLException { function.xFunc(); } /** * Returns the number of arguments passed to the function. Can only be called from * <tt>xFunc()</tt>. */ public int iargs() throws java.sql.SQLException { return super.args(); } /** * Called by <tt>xFunc</tt> to return a value. * * @param value */ public void iresult(byte[] value) throws java.sql.SQLException { super.result(value); }

/** * Called by <tt>xFunc</tt> to return a value. * * @param value */ public void iresult(double value) throws java.sql.SQLException { super.result(value); }

/** * Called by <tt>xFunc</tt> to return a value. * * @param value */ public void iresult(int value) throws java.sql.SQLException { super.result(value); }

/** * Called by <tt>xFunc</tt> to return a value. * * @param value */ public void iresult(long value) throws java.sql.SQLException { super.result(value); }

/** Called by <tt>xFunc</tt> to return a value. */ public void iresult() throws java.sql.SQLException { super.result(); }

/** * Called by <tt>xFunc</tt> to return a value. * * @param value */ public void iresult(String value) throws java.sql.SQLException { super.result(value); }

/** * Called by <tt>xFunc</tt> to throw an error. * * @param err */ public void ierror(String err) throws java.sql.SQLException { super.error(err); }

/** * Called by <tt>xFunc</tt> to access the value of an argument. * * @param arg */ public String ivalue_text(int arg) throws java.sql.SQLException { return super.value_text(arg); }

/** * Called by <tt>xFunc</tt> to access the value of an argument. * * @param arg */ public byte[] ivalue_blob(int arg) throws java.sql.SQLException { return super.value_blob(arg); }

/** * Called by <tt>xFunc</tt> to access the value of an argument. * * @param arg */ public double ivalue_double(int arg) throws java.sql.SQLException { return super.value_double(arg); }

/** * Called by <tt>xFunc</tt> to access the value of an argument. * * @param arg */ public int ivalue_int(int arg) throws java.sql.SQLException { return super.value_int(arg); }

/** * Called by <tt>xFunc</tt> to access the value of an argument. * * @param arg */ public long ivalue_long(int arg) throws java.sql.SQLException { return super.value_long(arg); }

/** * Called by <tt>xFunc</tt> to access the value of an argument. * * @param arg */ public int ivalue_type(int arg) throws java.sql.SQLException { return super.value_type(arg); } }

Mit diesen Hilfsmitteln ausgestattet kann man nun in der sQLshell per BeanShell beliebige SQL-Funktionen schreiben:

conn=sQLshellAPI.getCurrentlyVisibleShell().getConnection();

specs=sQLshellAPI.getCurrentlyVisibleShell().getDBMSInterface().getDatabaseSpecifics().orElse(null);

if(specs!=null) { myFunc=new de.elbosso.db.spi.impl.sqlite.Function() { protected void xFunc() { func.iresult(func.iargs()>0?func.ivalue_text(0):null); } }; func=new de.elbosso.db.spi.impl.sqlite.Bridge(myFunc);

specs.create("myFunc", func); }

Auf die Idee kam ich auf der Suche nach Möglichkeiten, UUIDs in SQLite zu benutzen. Hier einige meiner Suchergebnisse dazu:

Leider funktioniert das nur für normale Funktionen - für Aggregatfunktionen musste ich weit tiefer in die Trickkiste greifen...

Artikel, die hierher verlinken

SQL-Aggregatfunktionen in SQLite als BeanShell-Scripts

30.06.2024

Ich habe neulich über eine Möglichkeit berichtet, SQLite mittels der sQLshell und Beanshell-Skripten um SQL-Funktionen zu erweitern. In diesem Artikel versprach ich auch, über eine solche Möglichkeit für Aggregatfunktionen zu berichten.

Alle Artikel rss Wochenübersicht Monatsübersicht Github Repositories Gitlab Repositories Mastodon Über mich home xmpp


Vor 5 Jahren hier im Blog

  • CI/CD mit shellcheck

    13.10.2019

    Ich habe mich entschlossen, in meinen diversen Shell-Projekten shellcheck als Mittel zur Qualitätssicherung einzusetzen.

    Weiterlesen...

Neueste Artikel

  • Linux-System SBOM visualisiert als Graph

    In meinem $dayjob kam neulich die Frage auf, ob es möglich wäre, die aktuelle Softwareinstallation eines Linux-Systems als Software Bill of Materials (SBOM) zu exportieren.

    Weiterlesen...
  • Visualisierung von Datenmodellen als gerichtete Graphen

    Ich habe - motiviert durch meine Experimente zur Visualisierung von Paketabhängigkeiten in Linux-Installationen als interaktive Graphen - versucht, relationale Datenmodelle in ähnlicher Form zu visualisieren und dazu zwei Plugins für die sQLshell geschrieben.

    Weiterlesen...
  • Carl Sagan - Christmas Lectures at the Royal Institution

    Die Royal Institution hat in ihren Schätzen gegraben und die Christmas Lectures von Carl Sagan auf Youtube nochmals veröffentlicht. Meiner Ansicht nach unbedingt lohnenswert für alle, die Englisch verstehen!

    Weiterlesen...

Manche nennen es Blog, manche Web-Seite - ich schreibe hier hin und wieder über meine Erlebnisse, Rückschläge und Erleuchtungen bei meinen Hobbies.

Wer daran teilhaben und eventuell sogar davon profitieren möchte, muß damit leben, daß ich hin und wieder kleine Ausflüge in Bereiche mache, die nichts mit IT, Administration oder Softwareentwicklung zu tun haben.

Ich wünsche allen Lesern viel Spaß und hin und wieder einen kleinen AHA!-Effekt...

PS: Meine öffentlichen GitHub-Repositories findet man hier - meine öffentlichen GitLab-Repositories finden sich dagegen hier.