This is the guide for creating a new backend to query with go-mysql-server.
To create your own data source implementation you need to implement the following interfaces:
sql.DatabaseProvider. This interface allows the engine to find available databases. You can also unlock addtional functionality by optionally implementing additional interfaces:sql.MutableDatabaseProviderto support creating and dropping databases.sql.CollatedDatabaseProviderto support database-level collations.
sql.Database. These are returned by yoursql.DatabaseProvider. The main job ofsql.Databaseis to provide tables from your data source. You can also implement other interfaces on your database to unlock additional functionality:sql.TableCreatorto support creating new tablessql.TableDropperto support dropping tablessql.TableRenamerto support renaming tablessql.ViewCreatorto support creating persisted views on your tablessql.ViewDropperto support dropping persisted views
sql.Table. This interface will provide rows of values from your data source. You can also implement other interfaces on your table to unlock additional functionality:sql.InsertableTableto allow your data source to be updated withINSERTstatements.sql.UpdateableTableto allow your data source to be updated withUPDATEstatements.sql.DeletableTableto allow your data source to be updated withDELETEstatements.sql.ReplaceableTableto allow your data source to be updated withREPLACEstatements.sql.AlterableTableto allow your data source to have its schema modified by adding, dropping, and altering columns.sql.IndexedTableto declare your table's native indexes to speed up query execution.sql.IndexAlterableTableto accept the creation of new native indexes.sql.ForeignKeyAlterableTableto signal your support of foreign key constraints in your table's schema and data.sql.ProjectedTableto return rows that only contain a subset of the columns in the table. This can make query execution faster.sql.FilteredTableto filter the rows returned by your table to those matching a given expression. This can make query execution faster (if your table implementation can filter rows more efficiently than checking an expression on every row in a table).
This is not a complete list, but should be enough to get you started
on a full backend implementation. For an example of implementing these
interfaces, see the memory package.
Many backend implementations will be able to re-use the
sql.BaseSession object for sessioned access to databases. This
should be the case for all read-only database implementations.
However, some backends may need to store session information
particular to that backend, e.g. open data files that have yet to be
written. Such integrators should implement their own sql.Session
implementation, and probably should embed sql.BaseSession in it to
make that easier.
Backends that want transactional semantics for their queries must also
implement sql.TransactionSession in their session object and provide
a corresponding sql.Transaction implementation. The details of doing
so are necessarily very specific to a particular backend and are
beyond the scope of this guide.
Tables can declare that they support native indexes. The memory
package contains an example of this behavior, but please note that it
is only for example purposes and doesn't actually make queries faster
(although we could change this in the future).
Integrators should implement the sql.IndexedTable interface to
declare which indexes their tables support and provide a means of
returning a subset of the rows. The job of your sql.Index
implementation is to accept or reject combinations of sql.Range
expressions that it can support, which will be used by the engine to
construct a sql.IndexLookup struct to provide to your
sql.IndexedTable implementation.
Index drivers are separate backends for storing and querying indexes, without the need for a table to store and query its own native indexes. To implement a custom index driver you need to implement a few things:
sql.IndexDriverinterface, which will be the driver itself. Not that your driver must return an unique ID in theIDmethod. This ID is unique for your driver and should not clash with any other registered driver. It's the driver's responsibility to be fault tolerant and be able to automatically detect and recover from corruption in indexes.sql.Indexinterface, returned by your driver when an index is loaded or created.sql.IndexValueIterinterface, which will be returned by yoursql.IndexLookupand should return the values of the index.- Don't forget to register the index driver in your
sql.Contextusingcontext.RegisterIndexDriver(mydriver)to be able to use it.
To create indexes using your custom index driver you need to use
extension syntax USING driverid on the index creation statement. For
example:
CREATE INDEX foo ON table USING driverid (col1, col2)go-mysql-server does not provide a production index driver implementation. We previously provided a pilosa implementation, but removed it due to the difficulty of supporting it on all platforms (pilosa doesn't work on Windows).
You can see an example of a driver implementation in the memory package.
go-mysql-server provides a suite of engine tests that you can use
to validate that your implementation works as expected. See the
enginetest package for details and examples.
It's also possible and encouraged to write engine tests that are specific to your backend. This is especially important when implementing transactions, which the in-memory backend doesn't support.