summaryrefslogtreecommitdiff
path: root/doc/vtable.adoc
diff options
context:
space:
mode:
Diffstat (limited to 'doc/vtable.adoc')
-rw-r--r--doc/vtable.adoc167
1 files changed, 0 insertions, 167 deletions
diff --git a/doc/vtable.adoc b/doc/vtable.adoc
deleted file mode 100644
index d759de1..0000000
--- a/doc/vtable.adoc
+++ /dev/null
@@ -1,167 +0,0 @@
-= Virtual tables
-[#vtables]
-
-https://www.sqlite.org/vtab.html[A Virtual Table] is an object that is registered with a <<connection>>.
-It looks like a regular table, but is actually invoking virtual methods internally.
-This allows users to expose functionality from C++ to sqlite through a table interface.
-
-NOTE: The implementation uses abstract base classes to make interfaces easy to implement.
-You can disable the use of virtual by defining `BOOST_SQLITE_VIRTUAL` which will yield linker errors instead.
-
-== Eponymous
-
-And eponymous table is a virtual table the exists without needing to be created from sqlite.
-
-Such a table can either expose global values or can be used to build https://www.sqlite.org/vtab.html#tabfunc2[table-valued functions].
-
-=== Eponymous value table
-
-The easiest example of a data structure to expose to sql, is a simple ordered map:
-
-[source,cpp]
-----
-container::flat_map<std::string, std::string> data;
-----
-
-To create a virtual table it needs to have a cursor first. The cursor is what runs over the table, akin to an iterator.
-
-[source,cpp]
-----
-include::../example/ordered_map.cpp[tag=cursor]
-----
-<1> Declare the value the cursor produces
-<2> The data the cursor operates on
-<3> Advance the cursor by one
-<4> The module is declared without ROW id, see below
-<5> Get the actual column value
-<6> Tell sqlite when the cursor reached its end
-
-The cursor above just runs over the ordered map, returning values.
-However, the map is always ordered, so the cursor can optimize the built-in filter for sqlite.
-That is, sqlite will filter values on its own, but it's more efficient to do that before returning them.
-
-This can be done in the `filter` function, which can be written as follows:
-
-[source,cpp]
-----
-include::../example/ordered_map.cpp[tag=filter]
-----
-<1> If the first idx is not null, it means the order is reversed (see best_index below)
-<2> The equal constraint can be fulfilled by setting the range to enclose the value.
-<3> A greater than/equal constraint can be fulfilled by moving the beginning of the range.
-<4> A lesser than/equal constraint can be fulfilled by moving the end of the range.
-
-NOTE: Constraints of the same can appear multiple times, so the filter must only narrow the range.
-
-After the cursor, the actual table needs to be implemented:
-
-[source,cpp]
-----
-include::../example/ordered_map.cpp[tag=table]
-----
-<1> Declare the table to not be read-only, which adds functions 4-6.
-<2> The declaration is a literal that tells sqlite the shape of the table. It includes `WITHOUT ROWID` as `cursor.row_id()` mustn't be used.
-<3> This function gets called when the table gets scanned, i.e. a cursor gets created.
-<4> Delete value from the table, inherited from `modifiable`.
-<5> Insert a value into the table, inherited from `modifiable`.
-<6> Update a value in the table, inherited from `modifiable`.
-
-Next, there also should be a `best_index` function. This function informs sqlite about the available
-filter features so that sqlite can omit the operations.
-
-[source,cpp]
-----
-include::../example/ordered_map.cpp[tag=best_index]
-----
-<1> The data being passed on as idxStr to `cursor.filter`.
-<2> These are the constraints handled by filter, so only those get encoded.
-<3> filter assumes idx != 0 means descending, i.e. inverted
-<4> Tell sqlite the data is ordered already.
-<5> Set the index information to be passed to filter.
-
-With that all defined, the only thing left is to declare the module & create it.
-
-[source,cpp]
-----
-include::../example/ordered_map.cpp[tag=module]
-----
-
-=== Function table
-
-An eponymous function can be used as a function. For this example, a `query` vtable will be used to
-parse the query part of a url and return it as a table:
-
-[source,sqlite]
-----
-include::../example/url.sql[tag=query]
-----
-
-[cols="1,1,1"]
-|===
-|0|name|boost
-|1|thingy|foo
-|2|name|sqlite
-|3|foo|
-|===
-
-To achieve this a cursor is needed:
-
-[source,cpp]
-----
-include::../example/url.cpp[tag=query_cursor]
-----
-<1> Return the parts of the query view as columns
-<2> Pick the input value here.
-
-This is the module & table declaration;
-
-[source,cpp]
-----
-include::../example/url.cpp[tag=query_boiler_plate]
-----
-<1> The hidden colum to use for the input value.
-<2> Assert only equal is used for input data.
-
-NOTE: See the https://www.sqlite.org/vtab.html#tabfunc2[sqlite documentation here].
-
-== Non-eponymous Tables
-
-A non-eponymous table is a table backed by an actual resource.
-
-The module needs to provide a `create` function in the module,
-in addition to the `connect` one.
-The table is required to have a `destroy` function that removes the resource.
-
-
-[source,cpp]
-----
-struct csv_module final : sqlite::vtab::module<csv_table>
-{
- // create the csv file
- sqlite::result<table_type> create(sqlite::connection /*db*/,
- int argc, const char * const argv[]);
-
- // connect to an existing csv file.
- sqlite::result<table_type> connect(sqlite::connection /*db*/,
- int argc, const char * const argv[]);
-
-};
-----
-
-The virtual table can be created with the special syntax:
-
-[source,cpp]
-----
-CREATE VIRTUAL TABLE csv_example USING csv_file(./csv-example.csv, username, first_name, last_name);
-----
-
-When the above query is executed `csv_module.create()` will be executed with `"./csv-example.csv", "username", "first_name", "last_name".
-
-If the database gets opened with a previously created virtual table,
-`csv_module.connect()` will be called with the same parameters.
-
-Executing `DROP TABLE csv_example` will call `destroy()` on the `csv_table`.
-
-NOTE: The `destroy` function will be invoked when the virtual table gets dropped,
-not when the connection gets closed.
-