Skip to content

Commit

Permalink
Extension loading implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
ugursoy committed Feb 1, 2025
1 parent df6ddcd commit 4c04e22
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 0 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,23 @@ Additionally, a video tutorial by [Mitch McCollum (finepointcgi)](https://github
Backup or restore the current database to/from a path, see [here](https://www.sqlite.org/backup.html). This feature is useful if you are using a database as your save file and you want to easily implement a saving/loading mechanic. Be warned that the original database will be overwritten entirely when restoring.
- int enable_load_extension = **enable_load_extension(** Boolean success **)**
[Extension loading](https://www.sqlite.org/c3ref/load_extension.html) is disabled by default for security reasons. There are two ways to load an extension: C-API and SQL function. This method turns on both options.
SQL function `load_extension()` can only be used after enabling extension loading with this method. Preferably should be disabled after loading the extension to prevent SQL injections. Returns the SQLite return code.
- int load_extension = **load_extension(** String extension_path, String extension_entry_point **)**
Loads the extension in the given path. Does not require [method SQLite.enable_load_extension], as it only enables C-API during the call and disables it right after, utilizing the recommended extension loading method declared by the SQLite documentation ([see](https://www.sqlite.org/c3ref/load_extension.html)). Returns the SQLite return code.
- **extension_path:** the path to the compiled binary of the extension
- **entrypoint:** the extension's entrypoint method (init function). It is defined in the .c file of the extension.
Example for loading the spellfix module:
```gdscript
db.load_extension("res://addons/godot-sqlite/extensions/spellfix.dll", "sqlite3_spellfix_init")
```
## Frequently Asked Questions (FAQ)
### 1. My query fails and returns syntax errors, what should I do?
Expand Down
19 changes: 19 additions & 0 deletions doc_classes/SQLite.xml
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,25 @@
[/codeblock]
</description>
</method>
<method name="enable_load_extension">
<return type="int" />
<description>
[url=https://www.sqlite.org/c3ref/load_extension.html]Extension loading[/url] is disabled by default for security reasons. There are two ways to load an extension: C-API and SQL function. This method turns on both options.
SQL function [code]load_extension()[/code] can only be used after enabling extension loading with this method. Preferably should be disabled after loading the extension to prevent SQL injections. Returns the SQLite return code.
</description>
</method>
<method name="load_extension">
<return type="int" />
<description>
Loads the extension in the given path. Does not require [method SQLite.enable_load_extension], as it only enables C-API during the call and disables it right after, utilizing the recommended extension loading method declared by the SQLite documentation ([url=https://www.sqlite.org/c3ref/load_extension.html]see[/url]). Returns the SQLite return code.
- [b]extension_path:[/b] the path to the compiled binary of the extension
- [b]entrypoint:[/b] the extension's entrypoint method (init function). It is defined in the .c file of the extension.
Example for loading the spellfix module:
[codeblock]
db.load_extension("res://addons/godot-sqlite/extensions/spellfix.dll", "sqlite3_spellfix_init")
[/codeblock]
</description>
</method>
</methods>
<members>
<member name="path" type="String" default="default">
Expand Down
48 changes: 48 additions & 0 deletions src/gdsqlite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ void SQLite::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_autocommit"), &SQLite::get_autocommit);
ClassDB::bind_method(D_METHOD("compileoption_used", "option_name"), &SQLite::compileoption_used);

ClassDB::bind_method(D_METHOD("enable_load_extension", "onoff"), &SQLite::enable_load_extension);
ClassDB::bind_method(D_METHOD("load_extension", "extension_path", "entrypoint"), &SQLite::load_extension, DEFVAL("sqlite3_extension_init"));

// Properties.
ClassDB::bind_method(D_METHOD("set_last_insert_rowid", "last_insert_rowid"), &SQLite::set_last_insert_rowid);
ClassDB::bind_method(D_METHOD("get_last_insert_rowid"), &SQLite::get_last_insert_rowid);
Expand Down Expand Up @@ -1152,3 +1155,48 @@ int SQLite::compileoption_used(const String &option_name) const {
const char *char_name = dummy_name.get_data();
return sqlite3_compileoption_used(char_name);
}

int SQLite::enable_load_extension(const bool &p_onoff) {
int rc;
if (p_onoff == true) {
rc = sqlite3_enable_load_extension(db, 1);
}
else{
rc = sqlite3_enable_load_extension(db, 0);
}
if (rc != SQLITE_OK) {
UtilityFunctions::printerr("GDSQLite Error: Extension loading cannot be enabled/disabled.");
}
return rc;
}

int SQLite::load_extension(const String &p_path, const String &entrypoint) {

int rc;

char *zErrMsg = 0;
String globalized_path = ProjectSettings::get_singleton()->globalize_path(p_path.strip_edges());
const CharString dummy_path = globalized_path.utf8();
const char *char_path = dummy_path.get_data();

const CharString dummy_func_name = entrypoint.utf8();
const char *func_name = dummy_func_name.get_data();

// Enable C-API only
sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, NULL);
// load extension
rc = sqlite3_load_extension(db, char_path, func_name, &zErrMsg);
// Disable C-API
sqlite3_db_config(db, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 0, NULL);

if (rc != SQLITE_OK) {
UtilityFunctions::printerr("GDSQLite Error: Unable to load extension: " + String::utf8(zErrMsg));
sqlite3_free(zErrMsg);
return rc;
}
if (verbosity_level > VerbosityLevel::QUIET) {
UtilityFunctions::print("Loaded extension successfully (" + globalized_path + ")");
}

return rc;
}
3 changes: 3 additions & 0 deletions src/gdsqlite.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ class SQLite : public RefCounted {
int get_autocommit() const;
int compileoption_used(const String &option_name) const;

int load_extension(const String &p_path, const String &p_init_func_name);
int enable_load_extension(const bool &p_onoff);

// Properties.
void set_last_insert_rowid(const int64_t &p_last_insert_rowid);
int64_t get_last_insert_rowid() const;
Expand Down

0 comments on commit 4c04e22

Please sign in to comment.