Skip to content

feat(vfs): add FileControl support for PRAGMA handling - #17

Closed
corylanou wants to merge 5 commits into
psanford:mainfrom
corylanou:vfs-time-travel-pragma
Closed

feat(vfs): add FileControl support for PRAGMA handling#17
corylanou wants to merge 5 commits into
psanford:mainfrom
corylanou:vfs-time-travel-pragma

Conversation

@corylanou

Copy link
Copy Markdown
Contributor

Summary

  • Add FileController interface for handling file control operations
  • Implement SQLITE_FCNTL_PRAGMA support to enable custom PRAGMA commands
  • Bridge C file control callbacks to Go implementations
  • Add tests for PRAGMA set and query operations

Context

This change addresses the need for custom PRAGMA support in Go-based SQLite VFS implementations, as discussed in benbjohnson/litestream#849.

When implementing time travel queries for Litestream, @asg017 suggested using custom PRAGMAs (e.g., PRAGMA litestream_time = '[date]') instead of SQL functions. This approach is cleaner and more suitable for read-only environments like Datasette. However, implementing custom PRAGMAs requires FileControl support in the VFS layer, which was previously unavailable.

Changes

  1. New FileController interface (file.go): Optional interface that File implementations can implement to handle file control operations, specifically SQLITE_FCNTL_PRAGMA.

  2. C bridge update (sqlite3vfs.c): s3vfsFileControl now delegates to the Go implementation instead of returning SQLITE_NOTFOUND.

  3. Go implementation (sqlite3vfscgo.go): goVFSFileControl handles PRAGMA operations by:

    • Extracting pragma name and optional value from SQLite's argument array
    • Calling the FileController interface if implemented by the file
    • Returning results back to SQLite
  4. Tests (sqlite3vfs_test.go, tmpvfs_test.go): Verify PRAGMA set and query operations work correctly.

Usage

VFS implementers can now handle custom PRAGMAs by implementing the FileController interface:

func (f *MyFile) FileControl(op int, pragmaName string, pragmaValue *string) (*string, error) {
    if pragmaName == "my_custom_pragma" {
        if pragmaValue != nil {
            // Set operation: PRAGMA my_custom_pragma = 'value'
            return nil, f.setCustomValue(*pragmaValue)
        }
        // Query operation: PRAGMA my_custom_pragma
        result := f.getCustomValue()
        return &result, nil
    }
    return nil, nil // Unknown pragma, let SQLite handle it
}

Happy to adjust the approach or implementation if you have any preferred direction - just let us know!

corylanou and others added 4 commits November 24, 2025 12:25
Add xFileControl implementation to enable SQLite PRAGMA commands to be
handled by VFS implementations. This allows VFS files to respond to
custom PRAGMA statements, enabling features like time travel without
using SELECT-based state changes.

Changes:
- Add FileController optional interface in file.go
- Implement goVFSFileControl CGO bridge with PRAGMA argument parsing
- Update s3vfsFileControl to call Go layer instead of returning NOTFOUND
- Handle char** array parsing for pragma name and value
- Support result string return via azArg[0]

This provides a more semantically correct approach for VFS state
management compared to custom SQL functions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Verify that the FileController interface works correctly by testing
custom PRAGMA set and query operations.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Reverts the module path change to keep compatibility with upstream.
@psanford

Copy link
Copy Markdown
Owner

Thanks for the pr! This seems like a reasonable improvement.

It looks like the tests are not passing right now though.

SQLite expects memory returned from FCNTL_PRAGMA to be allocated
with sqlite3_malloc so it can be freed with sqlite3_free. Using
C.CString (which uses malloc) caused a crash on Linux.
@corylanou

Copy link
Copy Markdown
Contributor Author

@psanford whooops! Missed that somehow. Should be fixed. Let me know if you need anything else.

@psanford psanford closed this in 4e34e03 Nov 27, 2025
@psanford

Copy link
Copy Markdown
Owner

I cleaned up the git history and merged it. Thank you for the PR!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants