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


Vor 5 Jahren hier im Blog

  • Multi-User-WebDAV, Docker, GitHub

    17.11.2019

    Nachdem ich mich in letzter Zeit verstärkt mit Docker und dem zugehörigen Ökosystem beschäftige, habe ich begonnen, verschiedenste Dienste in Containern zu testen um zu sehen, ob in manchen Fällen LXC oder KVM nicht doch die bessere Wahl wäre...

    Weiterlesen...

Neueste Artikel

  • Migration der Webseite und aller OpenSource Projekte

    In eigener Sache...

    Weiterlesen...
  • AutoHideToolbar für Java Swing

    Ich habe eine neue Java Swing Komponente erstellt: Es handelt sich um einen Wrapper für von JToolBar abgeleitete Klassen, die die Werkzeugleiste minimieren und sie nur dann einblenden, wenn der Mauszeiger über ihnen schwebt.

    Weiterlesen...
  • Integration von EBMap4D in die sQLshell

    Ich habe bereits in einem früheren Artikel über meine ersten Erfolge berichtet, der sQLshell auf Basis des bestehenden Codes aus dem Projekt EBMap4D eine bessere Integration für Geo-Daten zu spendieren und entsprechende Abfragen, bzw. deren Ergebnisse auf einer Kartenansicht zu visualisieren.

    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.