SQLDatabase sample
We recently got an example project for SQLite with MBS Xojo SQL Plugin and let's explain a bit on how it works.
First you decide which database client library to use. For SQLite this can be a sqlite3.dll/dylib/so library to load or you use the built-in library inside our plugin. The one in InternalSQLiteLibraryMBS module includes various extensions and encryption support, so we can activate it with the Use method.
Create a database connection object with SQLDatabaseMBS class. That is our MBS class subclasses from Database, so it supports the database interface in Xojo. But alternatively we also have the SQLConnectionMBS class, which implements the our own interface and works with Xojo Lite. Which side you use doesn't matter much as both can do about the same things.
Next you need a connection string and potential credentials. For SQLite, the connection string is the path to the database file, usually a native path. For an in-memory database, you can use the path ":memory:" for SQLite. This allows you to have a very fast database, but it is forgotten when the app quits. You can achieve nearly the same with a file based database and setting a huge cache, e.g. "PRAGMA cache_size = 2000000", which is a 2 GB maximum cache size. Then data is preserved and still it mostly operates in memory.
- JSON1, the extension to provide JSON functions
- FTS5, the full text search extension in version 5
- R*Tree index extension
- SOUNDEX function
- SQL math functions
- Geopoly extension
- ICU extension for unicode handling
- The RBU Extension
- SQLite Encryption Extension
- UUID extension
- Base64 extension
- CSV extension
For our plugin which connects to 15 different types of databases, you need to inform the plugin which one you like. Either you set the client property to one of the constants or for SQLDatabaseMBS class, you specify it as a prefix of the connection string. For SQLite we include "SQLite:" as prefix. Then we connect with the Connect Method or function. The method raises an exception while the function returns false on failure and sets ErrorMessage property.
Once connected, we can query the version for SQLite with a SELECT statement. This will give us a record set with one record with one field containing the version number. Which we could also get with InternalSQLiteLibraryMBS' Version function.
Next we can execute a SQL command to create a table. SQLite knows the "IF NOT EXISTS" term, so it doesn't give an error, if we created the table before.
We can insert a record with a SQL statement and put the data in the statement. That is excellent to pre-fill a database with some basic data, that doesn't need to be adjusted.
If data is coming from the user like text fields or external sources, we need to use prepared statements to avoid SQL injections. Otherwise someone may type text in your field and delete your table, e.g.
"; DROP TABLE test_tbl; --
First quote and semicolon end the current command. Then the DROP TABLE command would delete a table. And the two dashes make the rest of the line a comment.
We avoid that all with the prepared statement and pass data to fill parameters in the statements. You can provide types, but otherwise the automatic mode looks on the variant type.
Instead of referring to parameters by ID or index, we can use named parameters which is much more secure. Especially if you later add more parameters, you can't mess up the indexes.
The prepared statement for inserting the record is automatically made for you if you use DatabaseRecord or DatabaseRow classes. We can do both with our plugin. So insert one with DatabaseRecord first:
And the same for the newer DatabaseRow:
Technically both are the same, just different syntax sugar.
Let us query data with the RowSet class and loop over the rows and add them to the listbox:
Do the same with older RecordSet. Yes, it's the old API, but we have still a ton of code with that and so we support it in the plugin.
For SQLDatabaseMBS and SQLConnectionMBS classes, we automatically close the connection when you loose the last reference. But keeping a SQLCommandMBS, RecordSet or RowSet around may delay that. We can only release the connection once the last object is released. You can explicitly close the connection, but then please don't use anything that may try to talk to the database as that may fail with an error or exception.
Enjoy our MBS Xojo SQL Plugin and connect to all the databases.
