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() { fun=null; public void setBridge(Object bridge) { fun=bridge; }

protected void xFunc() { fun.iresult(fun.iargs()>0?fun.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

Unterstützung für reguläre Ausdrücke in SQLite

15.03.2025

Ich habe mich unter anderem wegen der Unterstützung von Geo-Daten in der sQLshell auch mit SQLite beschäftigt.

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 Codeberg Repositories Mastodon Über mich home xmpp


Vor 5 Jahren hier im Blog

  • When Someone Requests a Jimi Hendrix Song

    23.08.2020

    Er hier ist mir schon einige Male mit interessanten Videos aufgefallen...

    Weiterlesen

Neueste Artikel

  • Anlehnung an todo.txt für collectedlinks

    Ich habe den Generator für meine Heimatseite im Zwischennetz wieder um ein neues Feture erweitert.

    Weiterlesen
  • NeoVim und ausrangierte Plugins

    Ich habe nun seit geraumer Zeit NeoVim im Einsatz im Produktivbetrieb zum Entwickeln - nicht nur - von Software. Dabei hat sich gezeigt, dass ich meinem Ziel, der Philosophie des Einsatzes möglichst weniger Plugins immer näher komme:

    Weiterlesen
  • Kritzelgenerator

    Ich habe mal wieder etwas im Internet gefunden, das mich herausforderte, eine Fingerübung in Java abzuhalten:

    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, muss 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 Codeberg-Repositories findet man hier.