From 464c03efdcf3db169847a2b95ce3f847c561add8 Mon Sep 17 00:00:00 2001 From: Pasquale De Rose Date: Thu, 31 Dec 2020 20:04:07 +0100 Subject: [PATCH] Added support for load dynamic extensions --- samples/extension_load.cr | 24 ++++++++++++++++++++++++ src/sqlite3/connection.cr | 15 +++++++++++++++ src/sqlite3/lib_sqlite3.cr | 24 ++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 samples/extension_load.cr diff --git a/samples/extension_load.cr b/samples/extension_load.cr new file mode 100644 index 0000000..ec16ed6 --- /dev/null +++ b/samples/extension_load.cr @@ -0,0 +1,24 @@ +require "db" +require "../src/sqlite3" + +db = DB.open "sqlite3://%3Amemory%3A" + +db.setup_connection do |connection| + connection.enable_extension_load true + connection.load_extension "/usr/local/lib/mod_spatialite" + connection.enable_extension_load false +end + +INSERT_POINT_QUERY = "insert into contacts values (?, SetSRID(MakePoint(?, ?),2261))" + +db.exec "create table contacts (name text, position)" +db.exec INSERT_POINT_QUERY, "John Doe", 51.5074, 0.1278 +db.exec INSERT_POINT_QUERY, "Mario Rossi", 41.9028, 12.4964 +db.exec INSERT_POINT_QUERY, "Dewayne Abara", 9.7054, 43.6327 +db.exec INSERT_POINT_QUERY, "Toshiro Ito", 35.6762, 139.6503 + +db.query "select a.name, b.name, st_distance(a.position, b.position) from contacts a, contacts b where a.name != b.name" do |rs| + rs.each do + puts "Distance between #{rs.read(String)} and #{rs.read(String)} is #{rs.read(Float)}" + end +end \ No newline at end of file diff --git a/src/sqlite3/connection.cr b/src/sqlite3/connection.cr index ca60043..dfe53ca 100644 --- a/src/sqlite3/connection.cr +++ b/src/sqlite3/connection.cr @@ -85,6 +85,21 @@ class SQLite3::Connection < DB::Connection @db end + # Enable or disable the loading of dynamic extensions in the current SQLite3 Connection + def enable_extension_load(onoff : Bool) + check LibSQLite3.db_config(@db, LibSQLite3::Option::SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, onoff ? 1 : 0, nil) + end + + # Load a dynamic extension from file in the current SQLite3 Connection + def load_extension(filename : String) + pzErrMsg : UInt8** = Pointer( UInt8* ).new( ( Pointer( UInt8 ).malloc( 250 ) ).address ) + code = LibSQLite3.load_extension(@db, filename, nil, pzErrMsg) + if code != LibSQLite3::Code::OKAY + puts String.new(pzErrMsg.value) + raise Exception.new(@db) + end + end + private def check(code) raise Exception.new(self) unless code == 0 end diff --git a/src/sqlite3/lib_sqlite3.cr b/src/sqlite3/lib_sqlite3.cr index 9455f8b..a32eb35 100644 --- a/src/sqlite3/lib_sqlite3.cr +++ b/src/sqlite3/lib_sqlite3.cr @@ -73,11 +73,35 @@ lib LibSQLite3 DONE = 101 end + enum Option + SQLITE_DBCONFIG_MAINDBNAME = 1000 # UInt8* + SQLITE_DBCONFIG_LOOKASIDE = 1001 # void* Int32 Int32 + SQLITE_DBCONFIG_ENABLE_FKEY = 1002 # Int32 Int32* + SQLITE_DBCONFIG_ENABLE_TRIGGER = 1003 # Int32 Int32* + SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER = 1004 # Int32 Int32* + SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION = 1005 # Int32 Int32* + SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE = 1006 # Int32 Int32* + SQLITE_DBCONFIG_ENABLE_QPSG = 1007 # Int32 Int32* + SQLITE_DBCONFIG_TRIGGER_EQP = 1008 # Int32 Int32* + SQLITE_DBCONFIG_RESET_DATABASE = 1009 # Int32 Int32* + SQLITE_DBCONFIG_DEFENSIVE = 1010 # Int32 Int32* + SQLITE_DBCONFIG_WRITABLE_SCHEMA = 1011 # Int32 Int32* + SQLITE_DBCONFIG_LEGACY_ALTER_TABLE = 1012 # Int32 Int32* + SQLITE_DBCONFIG_DQS_DML = 1013 # Int32 Int32* + SQLITE_DBCONFIG_DQS_DDL = 1014 # Int32 Int32* + SQLITE_DBCONFIG_ENABLE_VIEW = 1015 # Int32 Int32* + SQLITE_DBCONFIG_LEGACY_FILE_FORMAT = 1016 # Int32 Int32* + SQLITE_DBCONFIG_TRUSTED_SCHEMA = 1017 # Int32 Int32* + end + alias Callback = (Void*, Int32, UInt8**, UInt8**) -> Int32 alias FuncCallback = (SQLite3Context, Int32, SQLite3Value*) -> Void fun open_v2 = sqlite3_open_v2(filename : UInt8*, db : SQLite3*, flags : ::SQLite3::Flag, zVfs : UInt8*) : Int32 + fun db_config = sqlite3_db_config(db : SQLite3, op : Option, ...) : Int32 + fun load_extension = sqlite3_load_extension(db : SQLite3, zFile : UInt8*, zProc : UInt8*, pzErrMsg : UInt8**) : Code + fun errcode = sqlite3_errcode(SQLite3) : Int32 fun errmsg = sqlite3_errmsg(SQLite3) : UInt8*