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

  • Fährnisse des Buildprozesses unter Windows

    17.07.2019

    Nachdem ich begonnen hatte, mich mit der Beschleunigung der Berechnung des Mandelbrot-Fraktals unter Zuhilfenahme der Shadereinheiten in Graphikkarten zu beschäftigen und erste Erfolge feiern konnte, wollte ich das mal auf einer richtigen Graphikkarte ausprobieren...

    Weiterlesen...

Neueste Artikel

  • Datenvalidierung UTF8 mit BiDi-Steuerzeichen (TrojanSource 2.0)

    Ich bin heute nochmal inspiriert worden, weiter über die Trojan Source Vulnerability nachzudenken. Meiner Meinung nach bestehen hier noch Probleme - speziell bei Nutzereingaben oder Daten, die über externe Schnittstellen ampfangen werden.

    Weiterlesen...
  • OpenStreetMap Navi als Docker-Container

    Ich habe die auf OpenStreetMap basierende OpenSource Navigationslösung Graphhopper in einen Docker-Container gepackt und als neuestes Mitglied in meinem Docker-Zoo willkommen geheißen.

    Weiterlesen...
  • SQL-Aggregatfunktionen in SQLite als BeanShell-Scripts

    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.

    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.