Skip to main content

sqlite3_ext/vtab/
mod.rs

1//! Create virtual tables.
2//!
3//! To create a virtual table, define the virtual table module and then register it on each
4//! connection it will be used from. The [sqlite3_ext_vtab](sqlite3_ext_macro::sqlite3_ext_vtab) macro is used to define the virtual table module. It can be registered using [Connection::create_module].
5//!
6//! There are 3 base types of virtual tables:
7//!
8//! - [StandardModule] is a virtual table which is created using the CREATE VIRTUAL TABLE
9//!   command.
10//! - [EponymousModule] is a virtual table which is available ambiently in the database
11//!   connection without being explicitly created.
12//! - [EponymousOnlyModule] is similar to EponymousModule, but CREATE VIRTUAL TABLE is
13//!   explicitly forbidden for these modules.
14//!
15//! In addition to the base type of virtual table, there are several traits which can be
16//! implemented to add behavior.
17//!
18//! - [VTab] is required to be implemented by all virtual tables.
19//! - [CreateVTab] indicates that the table supports CREATE VIRTUAL TABLE.
20//! - [UpdateVTab] indicates that the table supports INSERT/UPDATE/DELETE.
21//! - [TransactionVTab] indicates that the table supports ROLLBACK.
22//! - [FindFunctionVTab] indicates that the table overrides certain SQL functions when they
23//!   operate on the table.
24//! - [RenameVTab] indicates that the table supports ALTER TABLE RENAME TO.
25
26use super::{
27    ffi, function::ToContextResult, sqlite3_match_version, types::*, value::*, Connection,
28};
29pub use function::*;
30pub use index_info::*;
31pub use module::*;
32use std::{ffi::c_void, ops::Deref, slice};
33
34mod function;
35mod index_info;
36mod module;
37pub(crate) mod stubs;
38
39pub type DisconnectResult<T> = std::result::Result<(), (T, Error)>;
40
41/// A virtual table.
42///
43/// This trait defines functionality required by all virtual tables. A read-only,
44/// eponymous-only virtual table (e.g. a table-valued function) can implement only this trait.
45pub trait VTab<'vtab>: Sized {
46    /// Additional data associated with the virtual table module.
47    ///
48    /// When registering the module with [Connection::create_module], additional data can
49    /// be passed as a parameter. This data will be passed to [connect](VTab::connect) and
50    /// [create](CreateVTab::create). It can be used for any purpose.
51    type Aux: 'vtab;
52
53    /// Cursor implementation for this virtual table.
54    type Cursor: VTabCursor + 'vtab;
55
56    /// Corresponds to xConnect.
57    ///
58    /// This method is called called when connecting to an existing virtual table, either
59    /// because it was previously created with CREATE VIRTUAL TABLE (see
60    /// [CreateVTab::create]), or because it is an eponymous virtual table.
61    ///
62    /// This method must return a valid CREATE TABLE statement as a [String], along with a
63    /// configured table instance. Additionally, all virtual tables are recommended to set
64    /// a risk level using [VTabConnection::set_risk_level].
65    ///
66    /// The virtual table implementation will return an error if any of the arguments
67    /// contain invalid UTF-8.
68    fn connect(
69        db: &'vtab VTabConnection,
70        aux: &'vtab Self::Aux,
71        args: &[&str],
72    ) -> Result<(String, Self)>;
73
74    /// Corrresponds to xBestIndex.
75    ///
76    /// This method is called when SQLite is planning to query a virtual table. See
77    /// [IndexInfo] for details.
78    ///
79    /// If this method returns Err([SQLITE_CONSTRAINT]), that does not indicate an error. Rather,
80    /// it indicates that the particular combination of input parameters specified is insufficient
81    /// for the virtual table to do its job. This is logically the same as setting the
82    /// [estimated_cost](IndexInfo::set_estimated_cost) to infinity. If every call to best_index
83    /// for a particular query plan returns this error, that means there is no way for the virtual
84    /// table to be safely used, and the SQLite call will fail with a "no query solution" error.
85    fn best_index(&'vtab self, index_info: &mut IndexInfo) -> Result<()>;
86
87    /// Create an uninitialized query.
88    fn open(&'vtab self) -> Result<Self::Cursor>;
89
90    /// Corresponds to xDisconnect. This method is called when the database connection is
91    /// being closed. The implementation should not remove the underlying data, but it
92    /// should release any resources associated with the virtual table implementation. This method is the inverse of [Self::connect].
93    ///
94    /// The default implementation of this method simply returns Ok.
95    fn disconnect(self) -> DisconnectResult<Self> {
96        Ok(())
97    }
98}
99
100/// A non-eponymous virtual table that supports CREATE VIRTUAL TABLE.
101pub trait CreateVTab<'vtab>: VTab<'vtab> {
102    /// List of shadow table names.
103    ///
104    /// This can be set by a virtual table implementation to automatically implement the
105    /// xShadowName method. For example, "data" appears in this slice, then SQLite will
106    /// understand that "vtab_data" is a shadow table for a table named "vtab" created with
107    /// this module.
108    ///
109    /// Shadow tables are read-only if the database has SQLITE_DBCONFIG_DEFENSIVE set, and
110    /// SQLite is version 3.26.0 or greater. For more information, see [the SQLite
111    /// documentation](https://www.sqlite.org/vtab.html#the_xshadowname_method).
112    const SHADOW_NAMES: &'static [&'static str] = &[];
113
114    /// Corresponds to xCreate.
115    ///
116    /// This method is invoked when a CREATE VIRTUAL TABLE statement is invoked on the
117    /// module. Future connections to the created table will use [VTab::connect] instead.
118    ///
119    /// This method has the same requirements as [VTab::connect]; see that method
120    /// for more details.
121    fn create(
122        db: &'vtab VTabConnection,
123        aux: &'vtab Self::Aux,
124        args: &[&str],
125    ) -> Result<(String, Self)>;
126
127    /// Corresponds to xDestroy, when DROP TABLE is run on the virtual table. The virtual
128    /// table implementation should destroy any underlying state that was created by
129    /// [Self::create].
130    fn destroy(self) -> DisconnectResult<Self>;
131}
132
133/// A virtual table that supports INSERT/UPDATE/DELETE.
134pub trait UpdateVTab<'vtab>: VTab<'vtab> {
135    /// Modify a single row in the virtual table. The info parameter may be used to
136    /// determine the type of change being performed by this update.
137    ///
138    /// If the change is an INSERT for a table with rowids and the provided rowid was NULL,
139    /// then the virtual table must generate and return a rowid for the inserted row. In
140    /// all other cases, the returned Ok value of this method is ignored.
141    ///
142    /// It isn't possible to provide a mutable reference to the virtual table
143    /// implementation because there may be active cursors affecting the table or even the
144    /// row that is being updated. Use Rust's interior mutability types to properly
145    /// implement this method.
146    fn update(&'vtab self, info: &mut ChangeInfo) -> Result<i64>;
147}
148
149/// A virtual table that supports ROLLBACK.
150///
151/// See [VTabTransaction] for details.
152pub trait TransactionVTab<'vtab>: UpdateVTab<'vtab> {
153    type Transaction: VTabTransaction + 'vtab;
154
155    /// Begin a transaction.
156    fn begin(&'vtab self) -> Result<Self::Transaction>;
157}
158
159/// A virtual table that overloads some functions.
160///
161/// A virtual table implementation may choose to overload certain functions when the first
162/// argument to the function refers to a column in the virtual table. To do this, add a
163/// [VTabFunctionList] to the virtual table struct and return a reference to it from the
164/// [functions][FindFunctionVTab::functions] method. When a function uses a column from this
165/// virtual table as its first argument, the returned list will be checked to see if the
166/// virtual table would like to overload the function.
167///
168/// Overloading additionally allows the virtual table to indicate that the virtual table is
169/// able to exploit the function to speed up a query result. For this to work, the function
170/// must take exactly two arguments and appear as a boolean in the WHERE clause of a query. The
171/// [ConstraintOp] supplied with the function will then be provided as an [IndexInfoConstraint]
172/// to [VTab::best_index]. This feature additionally requires SQLite 3.25.0.
173///
174/// For more details, see [the SQLite documentation](https://www.sqlite.org/vtab.html#the_xfindfunction_method).
175///
176/// # Example
177///
178/// Here is a brief summary of how to use this trait:
179///
180/// ```no_run
181/// # use sqlite3_ext_macro::*;
182/// use sqlite3_ext::{function::*, vtab::*, *};
183///
184/// #[sqlite3_ext_vtab(StandardModule)]
185/// struct MyVTab<'vtab> {
186///     /// Used to store the overloaded functions
187///     functions: VTabFunctionList<'vtab, Self>
188/// }
189/// # sqlite3_ext_doctest_impl!(MyVTab<'vtab>);
190///
191/// impl MyVTab<'_> {
192///     /// Register the overloaded functions. Should be called from connect/create.
193///     fn init_functions(&mut self) {
194///         self.functions.add_method(1, "my_func", None, |vtab, ctx, args| {
195///             println!("my_func was called");
196///             ctx.set_result(&*args[0])
197///         });
198///     }
199/// }
200///
201/// /// Return the owned functions list.
202/// impl<'vtab> FindFunctionVTab<'vtab> for MyVTab<'vtab> {
203///     fn functions(&self) -> &VTabFunctionList<'vtab, Self> {
204///         &self.functions
205///     }
206/// }
207/// ```
208pub trait FindFunctionVTab<'vtab>: VTab<'vtab> {
209    /// Retrieve a reference to the [VTabFunctionList] associated with this virtual table.
210    fn functions(&'vtab self) -> &'vtab VTabFunctionList<'vtab, Self>;
211}
212
213/// A virtual table that supports ALTER TABLE RENAME.
214pub trait RenameVTab<'vtab>: VTab<'vtab> {
215    /// Corresponds to xRename, when ALTER TABLE RENAME is run on the virtual table. If
216    /// this method returns Ok, then SQLite will disconnect this virtual table
217    /// implementation and connect to a new implementation with the updated name.
218    fn rename(&'vtab self, name: &str) -> Result<()>;
219}
220
221/// Implementation of the cursor type for a virtual table.
222pub trait VTabCursor {
223    /// Begin a search of the virtual table. This method is always invoked after creating
224    /// the cursor, before any other methods of this trait. After calling this method, the
225    /// cursor should point to the first row of results (or [eof](VTabCursor::eof) should
226    /// return true to indicate there are no results).
227    ///
228    /// The index_num parameter is an arbitrary value which was passed to
229    /// [IndexInfo::set_index_num]. The index_str parameter is an arbitrary value which was
230    /// passed to [IndexInfo::set_index_str].
231    fn filter(
232        &mut self,
233        index_num: i32,
234        index_str: Option<&str>,
235        args: &mut [&mut ValueRef],
236    ) -> Result<()>;
237
238    /// Move the cursor one row forward.
239    fn next(&mut self) -> Result<()>;
240
241    /// Check if the cursor currently points beyond the end of the valid results.
242    fn eof(&mut self) -> bool;
243
244    /// Fetch the column numbered idx for the current row. The indexes correspond to the order the
245    /// columns were declared by [VTab::connect]. The output value must be assigned to the context
246    /// using [ColumnContext::set_result]. If no result is set, SQL NULL is returned. If this
247    /// method returns an Err value, the SQL statement will fail, even if a result had been set
248    /// before the failure.
249    fn column(&mut self, idx: usize, context: &ColumnContext) -> Result<()>;
250
251    /// Fetch the rowid for the current row.
252    fn rowid(&mut self) -> Result<i64>;
253}
254
255/// Implementation of the transaction type for a virtual table.
256///
257/// Virtual tables which modify resources outside of the database in which they are defined may
258/// require additional work in order to safely implement fallible transactions. If the virtual
259/// table only modifies data inside of the database in which it is defined, then SQLite's
260/// built-in transaction support is sufficient and implementing [TransactionVTab] is not
261/// necessary. The most important methods of this trait are
262/// [rollback](VTabTransaction::rollback) and [rollback_to](VTabTransaction::rollback_to). If
263/// it is not possible to correctly implement these methods for the virtual table, then there
264/// is no need to implement [TransactionVTab] at all.
265///
266/// Virtual table transactions do not nest, so there will never be more than one instance of
267/// this trait per virtual table. Instances are always dropped in a call to either
268/// [commit](VTabTransaction::commit) or [rollback](VTabTransaction::rollback), with one
269/// exception: eponymous tables implementing this trait automatically begin a transaction after
270/// [VTab::connect], but this transaction will be later on dropped without any methods being
271/// called on it. This is harmless, because if an UPDATE occurs for such a table, a new
272/// transaction will be created, dropping the previous one first.
273///
274/// Note that the [savepoint](VTabTransaction::savepoint), [release](VTabTransaction::release),
275/// and [rollback_to](VTabTransaction::rollback_to) methods require SQLite 3.7.7. On previous
276/// versions of SQLite, these methods will not be called, which may result in unsound behavior.
277/// In the following example, the virtual table will incorrectly commit changes which should
278/// have been rolled back.
279///
280/// ```sql
281/// BEGIN;
282/// SAVEPOINT a;
283/// UPDATE my_virtual_table SET foo = 'bar';
284/// ROLLBACK TO a;
285/// COMMIT;
286/// ```
287pub trait VTabTransaction {
288    /// Start a two-phase commit.
289    ///
290    /// This method is only invoked prior to a commit or rollback. In order to implement
291    /// two-phase commit, the sync method on all virtual tables is invoked prior to
292    /// invoking the commit method on any virtual table. If any of the sync methods fail,
293    /// the entire transaction is rolled back.
294    fn sync(&mut self) -> Result<()>;
295
296    /// Finish a commit.
297    ///
298    /// A call to this method always follows a prior call sync.
299    fn commit(self) -> Result<()>;
300
301    /// Roll back a commit.
302    fn rollback(self) -> Result<()>;
303
304    /// Save current state as a save point.
305    ///
306    /// The current state of the virtual table should be saved as savepoint n. There is
307    /// no guarantee that n starts at zero or increases by 1 in between calls.
308    ///
309    /// This method will only be called on SQLite 3.7.7 or later.
310    fn savepoint(&mut self, n: i32) -> Result<()>;
311
312    /// Invalidate previous save points.
313    ///
314    /// All save points numbered >= n should be invalidated. This does not mean the
315    /// changes are ready to be committed, just that there is no need to maintain a record
316    /// of those saved states any more.
317    ///
318    /// Note that there is no guarantee that n will be a value from a previous call to
319    /// [savepoint](VTabTransaction::savepoint).
320    ///
321    /// This method will only be called on SQLite 3.7.7 or later.
322    fn release(&mut self, n: i32) -> Result<()>;
323
324    /// Restore a save point.
325    ///
326    /// The virtual table should revert to the state it had when
327    /// [savepoint](VTabTransaction::savepoint) was called the lowest number >= n. There is
328    /// no guarantee that [savepoint](VTabTransaction::savepoint) was ever called with n
329    /// exactly.
330    ///
331    /// This method will only be called on SQLite 3.7.7 or later.
332    fn rollback_to(&mut self, n: i32) -> Result<()>;
333}
334
335/// A wrapper around [Connection] that supports configuring virtual table implementations.
336#[repr(transparent)]
337pub struct VTabConnection {
338    db: ffi::sqlite3,
339}
340
341impl VTabConnection {
342    unsafe fn from_ptr<'a>(db: *mut ffi::sqlite3) -> &'a Self {
343        &*(db as *mut Self)
344    }
345
346    /// Indicate that this virtual table properly verifies constraints for updates.
347    ///
348    /// If this is enabled, then the virtual table guarantees that if the
349    /// [UpdateVTab::update] method returns Err([SQLITE_CONSTRAINT]), it will do so before
350    /// any modifications to internal or persistent data structures have been made. If the
351    /// ON CONFLICT mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite is able to roll back a
352    /// statement or database transaction, and abandon or continue processing the current
353    /// SQL statement as appropriate. If the ON CONFLICT mode is REPLACE and the update
354    /// method returns SQLITE_CONSTRAINT, SQLite handles this as if the ON CONFLICT mode
355    /// had been ABORT.
356    ///
357    /// Requires SQLite 3.7.7. On earlier versions of SQLite, this is a harmless no-op.
358    pub fn enable_constraints(&self) {
359        sqlite3_match_version! {
360            3_007_007 => unsafe {
361                let guard = self.lock();
362                Error::from_sqlite_desc(ffi::sqlite3_vtab_config()(
363                    guard.as_mut_ptr(),
364                    ffi::SQLITE_VTAB_CONSTRAINT_SUPPORT,
365                    1,
366                ), guard)
367                .unwrap()
368            },
369            _ => (),
370        }
371    }
372
373    /// Set the risk level of this virtual table.
374    ///
375    /// See the [RiskLevel](super::RiskLevel) enum for details about what the individual
376    /// options mean.
377    ///
378    /// Requires SQLite 3.31.0. On earlier versions of SQLite, this is a harmless no-op.
379    pub fn set_risk_level(&self, level: super::RiskLevel) {
380        let _ = level;
381        sqlite3_match_version! {
382            3_031_000 => unsafe {
383                let guard = self.lock();
384                Error::from_sqlite_desc(ffi::sqlite3_vtab_config()(
385                    guard.as_mut_ptr(),
386                    match level {
387                        super::RiskLevel::Innocuous => ffi::SQLITE_VTAB_INNOCUOUS,
388                        super::RiskLevel::DirectOnly => ffi::SQLITE_VTAB_DIRECTONLY,
389                    },
390                ), guard)
391                .unwrap();
392            },
393            _ => (),
394        }
395    }
396}
397
398impl Deref for VTabConnection {
399    type Target = Connection;
400
401    fn deref(&self) -> &Connection {
402        unsafe { Connection::from_ptr(&self.db as *const _ as _) }
403    }
404}
405
406/// Information about an INSERT/UPDATE/DELETE on a virtual table.
407pub struct ChangeInfo {
408    #[cfg_attr(not(modern_sqlite), allow(unused))]
409    db: *mut ffi::sqlite3,
410    argc: usize,
411    argv: *mut *mut ValueRef,
412}
413
414impl ChangeInfo {
415    /// Returns the type of update being performed.
416    pub fn change_type(&self) -> ChangeType {
417        if self.args().len() == 0 {
418            ChangeType::Delete
419        } else if self.rowid().is_null() {
420            ChangeType::Insert
421        } else {
422            ChangeType::Update
423        }
424    }
425
426    /// Returns the rowid (or, for WITHOUT ROWID tables, the PRIMARY KEY column) of the row
427    /// being deleted or updated.
428    ///
429    /// Semantically, an UPDATE to a virtual table is identical to a DELETE followed by an
430    /// INSERT. In that sense, this method returns the rowid or PRIMARY KEY column of the
431    /// row being deleted. The rowid of the row being inserted is available as the first
432    /// element in [args](Self::args).
433    ///
434    /// For the mutable version, see [rowid_mut](Self::rowid_mut).
435    pub fn rowid(&self) -> &ValueRef {
436        debug_assert!(self.argc > 0);
437        unsafe { &**self.argv }
438    }
439
440    /// Mutable version of [rowid](Self::rowid).
441    pub fn rowid_mut(&mut self) -> &mut ValueRef {
442        debug_assert!(self.argc > 0);
443        unsafe { &mut **self.argv }
444    }
445
446    /// Returns the arguments for an INSERT or UPDATE. The meaning of the first element in
447    /// this slice depends on the type of change being performed:
448    ///
449    /// - For an INSERT on a WITHOUT ROWID table, the first element is always NULL. The
450    ///   PRIMARY KEY is listed among the remaining elements.
451    /// - For an INSERT on a regular table, if the first element is NULL, it indicates that
452    ///   a rowid must be generated and returned from [UpdateVTab::update]. Otherwise, the
453    ///   first element is the rowid.
454    /// - For an UPDATE, the first element is the new value for the rowid or PRIMARY KEY
455    ///   column.
456    ///
457    /// In all cases, the second and following elements correspond to the values for all
458    /// columns in the order declared in the virtual table's schema (returned by
459    /// [VTab::connect] / [CreateVTab::create]).
460    ///
461    /// For the mutable version, see [args_mut](Self::args_mut).
462    pub fn args(&self) -> &[&ValueRef] {
463        debug_assert!(self.argc > 0);
464        unsafe { slice::from_raw_parts(self.argv.offset(1) as _, self.argc - 1) }
465    }
466
467    /// Mutable version of [args](Self::args).
468    pub fn args_mut(&mut self) -> &mut [&mut ValueRef] {
469        debug_assert!(self.argc > 0);
470        unsafe { slice::from_raw_parts_mut(self.argv.offset(1) as _, self.argc - 1) }
471    }
472
473    /// Return the ON CONFLICT mode of the current SQL statement. In order for this method
474    /// to be useful, the virtual table needs to have previously enabled ON CONFLICT
475    /// support using [VTabConnection::enable_constraints].
476    ///
477    /// Requires SQLite 3.7.7. On earlier versions, this will always return
478    /// [ConflictMode::Abort].
479    pub fn conflict_mode(&self) -> ConflictMode {
480        sqlite3_match_version! {
481            3_007_007 => {
482                ConflictMode::from_sqlite(unsafe { ffi::sqlite3_vtab_on_conflict(self.db) })
483            }
484            _ => ConflictMode::Abort,
485        }
486    }
487}
488
489impl std::fmt::Debug for ChangeInfo {
490    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
491        f.debug_struct("ChangeInfo")
492            .field("change_type", &self.change_type())
493            .field("rowid", &self.rowid())
494            .field("args", &self.args())
495            .field("conflict_mode", &self.conflict_mode())
496            .finish()
497    }
498}
499
500/// Indicates the type of modification that is being applied to the virtual table.
501#[derive(Debug, Eq, PartialEq, Copy, Clone)]
502pub enum ChangeType {
503    /// Indicates an SQL INSERT.
504    Insert,
505    /// Indicates an SQL DELETE.
506    Delete,
507    /// Indicates an SQL UPDATE.
508    Update,
509}
510
511/// Indicates the ON CONFLICT mode for the SQL statement currently being executed.
512///
513/// An [UpdateVTab] which has used [VTabConnection::enable_constraints] can examine this value
514/// to determine how to handle a conflict during a change.
515///
516/// For details about what each mode means, see [the SQLite documentation](https://www.sqlite.org/lang_conflict.html).
517#[derive(Debug, Eq, PartialEq, Copy, Clone)]
518pub enum ConflictMode {
519    /// Corresponds to ON CONFLICT ROLLBACK.
520    Rollback,
521    /// Corresponds to ON CONFLICT IGNORE.
522    Ignore,
523    /// Corresponds to ON CONFLICT FAIL.
524    Fail,
525    /// Corresponds to ON CONFLICT ABORT.
526    Abort,
527    /// Corresponds to ON CONFLICT REPLACE.
528    Replace,
529}
530
531impl ConflictMode {
532    #[cfg(modern_sqlite)]
533    fn from_sqlite(val: i32) -> Self {
534        match val {
535            1 => ConflictMode::Rollback,
536            2 => ConflictMode::Ignore,
537            3 => ConflictMode::Fail,
538            4 => ConflictMode::Abort,
539            5 => ConflictMode::Replace,
540            _ => panic!("invalid conflict mode"),
541        }
542    }
543}
544
545/// Describes the run-time environment of the [VTabCursor::column] method.
546#[repr(transparent)]
547pub struct ColumnContext {
548    base: ffi::sqlite3_context,
549}
550
551impl ColumnContext {
552    pub(crate) fn as_ptr<'a>(&self) -> *mut ffi::sqlite3_context {
553        &self.base as *const ffi::sqlite3_context as _
554    }
555
556    pub(crate) unsafe fn from_ptr<'a>(base: *mut ffi::sqlite3_context) -> &'a mut Self {
557        &mut *(base as *mut Self)
558    }
559
560    /// Return a handle to the current database.
561    pub fn db(&self) -> &Connection {
562        unsafe { Connection::from_ptr(ffi::sqlite3_context_db_handle(self.as_ptr())) }
563    }
564
565    /// Return true if the column being fetched is part of an UPDATE operation during which
566    /// the column value will not change.
567    ///
568    /// See [ValueRef::nochange] for details and usage.
569    ///
570    /// This method is provided as an optimization. It is permissible for this method to
571    /// return false even if the value is unchanged. The virtual table implementation must
572    /// function correctly even if this method were to always return false.
573    ///
574    /// Requires SQLite 3.22.0. On earlier versions of SQLite, this method always returns
575    /// false.
576    pub fn nochange(&self) -> bool {
577        crate::sqlite3_match_version! {
578            3_022_000 => (unsafe { ffi::sqlite3_vtab_nochange(self.as_ptr()) } != 0),
579            _ => false,
580        }
581    }
582
583    /// Assign the given value to the column. This function always returns Ok.
584    pub fn set_result(&self, val: impl ToContextResult) -> Result<()> {
585        unsafe { val.assign_to(self.as_ptr()) };
586        Ok(())
587    }
588}