Skip to content

gilzoide/sqlite-vfs-cpp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SQLiteVfs.hpp

Single header with classes for easily implementing SQLite VFS shims in C++11.

Features

  • Single header: copy SQLiteVfs.hpp to your project, #include <SQLiteVfs.hpp> and that's it
  • Supports C++11 and above
  • Subclass sqlite3vfs::SQLiteVfsImpl<> to override any VFS methods
    • Default implementations forward execution to the default VFS. This makes it easy to implement VFS shims.
  • Subclass sqlite3vfs::SQLiteFileImpl to override any File methods
    • Default implementations forward execution to the File opened by SQLiteVfsImpl::xOpen. This makes it easy to implement File shims.

Usage example

This sample code shows how to create a SQLite extension DLL that registers a simple VFS shim + File shim that logs read/write operations:

// 1. Include <SQLiteVfs.hpp> header
// If you are building an extension DLL, make sure to include
// <sqlite3ext.h> and call SQLITE_EXTENSION_INIT1 first.
#include <sqlite3ext.h>
SQLITE_EXTENSION_INIT1
#include <SQLiteVfs.hpp>

#include <iostream>

using namespace sqlitevfs;
using namespace std;

// 2. Implement your own `SQLiteFileImpl` subclass.
// Override any IO methods necessary. Reference: https://www.sqlite.org/c3ref/io_methods.html
// Default implementation will forward execution to the `original_file` opened by `SQLiteVfsImpl::xOpen`.
// Default constructor will be called before `SQLiteVfsImpl::xOpen`.
// Destructor will be called right after `xClose`, or after a failed `SQLiteVfsImpl::xOpen`.
struct LogIOFileShim : public SQLiteFileImpl {
	LogIOFileShim() {
		cout << "> Constructing file!" << endl;
	}
	int xRead(void *p, int iAmt, sqlite3_int64 iOfst) override {
		cout << "> READ " << iAmt << " bytes starting at " << iOfst << endl;
		return SQLiteFileImpl::xRead(p, iAmt, iOfst);
	}
	int xWrite(const void *p, int iAmt, sqlite3_int64 iOfst) override {
		cout << "> WRITE " << iAmt << " bytes starting at " << iOfst << endl;
		return SQLiteFileImpl::xWrite(p, iAmt, iOfst);
	}
	int xClose() override {
		cout << "> CLOSE" << endl;
		return SQLiteFileImpl::xClose();
	}
	~LogIOFileShim() {
		cout << "> Destroying file!" << endl;
	}
};

// 3. Implement your own `SQLiteVfsImpl<>` subclass.
// Pass your SQLiteFileImpl subclass as template parameter.
// Override any methods necessary. Reference: https://www.sqlite.org/c3ref/vfs.html
// Default implementation will forward execution to the `original_vfs` passed in `SQLiteVfs` construtor.
// Notice that `xOpen` receives a `SQLiteFile<LogIOFileImpl> *` instead of `sqlite3_file`.
// `file` is guaranteed to be fully constructed before this method is called.
struct LogIOVfsShim : public SQLiteVfsImpl<LogIOFileShim> {
	int xOpen(sqlite3_filename zName, SQLiteFile<LogIOFileShim> *file, int flags, int *pOutFlags) override {
		int result = SQLiteVfsImpl::xOpen(zName, file, flags, pOutFlags);
		if (result == SQLITE_OK) {
			cout << "> OPENED '" << zName << "'" << endl;
		}
		else {
			cout << "> ERROR OPENING '" << zName << "': " << sqlite3_errstr(result) << endl;
		}
		return result;
	}
};

// If implementing an extension DLL, export the function as SQLite expects
extern "C" int sqlite3_logiovfs_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi) {
	SQLITE_EXTENSION_INIT2(pApi);

	// 4. Create a `SQLiteVfs<>`.
	// Pass your `SQLiteVfsImpl<>` subclass as template parameter.
	static SQLiteVfs<LogIOVfsShim> logiovfs("logiovfs");
	
	// 5. Register your newly created VFS.
	// Optionally make it the default VFS.
	int rc = logiovfs.register_vfs(false);
	if (rc == SQLITE_OK) {
		rc = SQLITE_OK_LOAD_PERMANENTLY;
	}
	return rc;
}

// 6. (optional) Unregister your VFS using `my_vfs.unregister_vfs()`

Samples

  • logiovfs: shows how to create a SQLite extension DLL that registers a simple VFS shim + File shim that logs read/write operations

Building and running samples:

# build
mkdir build
cd build
cmake ..
make

# run from build folder
samples/logiovfs-sample