vtable.go 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965
  1. // Copyright 2023 Ross Light
  2. // SPDX-License-Identifier: ISC
  3. package sqlite
  4. import (
  5. "fmt"
  6. "strings"
  7. "sync"
  8. "unsafe"
  9. "modernc.org/libc"
  10. "modernc.org/libc/sys/types"
  11. lib "modernc.org/sqlite/lib"
  12. )
  13. // A Module declares a [virtual table] that can be registered with a [Conn]
  14. // via [Conn.SetModule].
  15. //
  16. // [virtual table]: https://sqlite.org/vtab.html
  17. type Module struct {
  18. // Connect establishes a connection to an existing virtual table.
  19. // This is the only required field.
  20. Connect VTableConnectFunc
  21. // Create is called to create a new instance of the virtual table
  22. // in response to a [CREATE VIRTUAL TABLE statement].
  23. // If it is nil, then the virtual table is [eponymous].
  24. // UseConnectAsCreate determines whether the virtual table is eponymous-only.
  25. //
  26. // [CREATE VIRTUAL TABLE statement]: https://sqlite.org/lang_createvtab.html
  27. // [eponymous]: https://sqlite.org/vtab.html#epovtab
  28. Create VTableConnectFunc
  29. // If UseConnectAsCreate is true and Create is nil,
  30. // then the virtual table is eponymous, but not eponymous-only.
  31. // This means that the virtual table can still be given a name
  32. // with CREATE VIRTUAL TABLE
  33. // and indicates that the virtual table has no persistent state
  34. // that needs to be created and destroyed.
  35. UseConnectAsCreate bool
  36. }
  37. // VTableConnectFunc is a [Module.Connect] or [Module.Create] callback.
  38. type VTableConnectFunc func(*Conn, *VTableConnectOptions) (VTable, *VTableConfig, error)
  39. // VTableConnectOptions is the set of arguments to a [VTableConnectFunc].
  40. type VTableConnectOptions struct {
  41. // ModuleName is the name of the [Module] being invoked.
  42. ModuleName string
  43. // DatabaseName is the name of the database in which the new virtual table is being created.
  44. // The database name is "main" for the primary database,
  45. // or "temp" for TEMP database,
  46. // or the name given at the end of the ATTACH statement for attached databases.
  47. DatabaseName string
  48. // VTableName is the name of the name of the new virtual table.
  49. // For eponymous virtual tables, this will be the same as ModuleName.
  50. VTableName string
  51. // Arguments passed to the CREATE VIRTUAL TABLE statement.
  52. Args []string
  53. }
  54. // VTableConfig specifies the configuration of a [VTable] returned by [VTableConnectFunc].
  55. // [VTableConfig.Declaration] is the only required field.
  56. type VTableConfig struct {
  57. // Declaration must be a [CREATE TABLE statement]
  58. // that defines the columns in the virtual table and their data type.
  59. // The name of the table in this CREATE TABLE statement is ignored,
  60. // as are all constraints.
  61. //
  62. // [CREATE TABLE statement]: https://sqlite.org/lang_createtable.html
  63. Declaration string
  64. // If ConstraintSupport is true, then the virtual table implementation
  65. // guarantees that if [WritableVTable.Update] or [WritableVTable.DeleteRow]
  66. // returns a [ResultConstraint] error,
  67. // it will do so before any modifications to internal or persistent data structures
  68. // have been made.
  69. ConstraintSupport bool
  70. // If AllowIndirect is false, then the virtual table may only be used from top-level SQL.
  71. // If AllowIndirect is true, then the virtual table can be used in VIEWs, TRIGGERs,
  72. // and schema structures (e.g. CHECK constraints and DEFAULT clauses).
  73. //
  74. // This is the inverse of SQLITE_DIRECTONLY.
  75. // See https://sqlite.org/c3ref/c_vtab_constraint_support.html
  76. // for more details.
  77. // This defaults to false for better security.
  78. AllowIndirect bool
  79. }
  80. // VTable represents a connected [virtual table].
  81. //
  82. // [virtual table]: https://sqlite.org/vtab.html
  83. type VTable interface {
  84. // BestIndex informs SQLite the best way to access the virtual table.
  85. // While compiling a single SQL query,
  86. // the SQLite core might call BestIndex multiple times with different inputs.
  87. // The SQLite core will then select the combination
  88. // that appears to give the best performance.
  89. BestIndex(*IndexInputs) (*IndexOutputs, error)
  90. // Open creates a new cursor.
  91. Open() (VTableCursor, error)
  92. // Disconnect releases any resources associated with the virtual table.
  93. Disconnect() error
  94. // Destroy is called when the table is "DROP"ed
  95. // to tear down any persistent data structures
  96. // and release any resources associated with the virtual table.
  97. Destroy() error
  98. }
  99. // VTableUpdateParams is the set of parameters to the [WritableVTable.Update] method.
  100. type VTableUpdateParams struct {
  101. OldRowID Value
  102. NewRowID Value
  103. Columns []Value
  104. }
  105. // IsInsert reports whether the arguments represent an INSERT.
  106. // If not, then the arguments represent an UPDATE.
  107. func (p VTableUpdateParams) IsInsert() bool {
  108. return p.OldRowID.Type() == TypeNull
  109. }
  110. // A WritableVTable is a [VTable] that supports modifications.
  111. type WritableVTable interface {
  112. VTable
  113. Update(params VTableUpdateParams) (rowID int64, err error)
  114. DeleteRow(rowID Value) error
  115. }
  116. // A TransactionVTable is a [VTable] that supports transactions.
  117. type TransactionVTable interface {
  118. VTable
  119. // Begin begins a transaction on a virtual table.
  120. // Virtual table transactions do not nest,
  121. // so the Begin method will not be invoked more than once
  122. // on a single virtual table
  123. // without an intervening call to either Commit or Rollback.
  124. Begin() error
  125. // Sync signals the start of a two-phase commit on a virtual table.
  126. // This method is only invoked after a call to the Begin method
  127. // and prior to a Commit or Rollback.
  128. Sync() error
  129. // Commit causes a virtual table transaction to commit.
  130. Commit() error
  131. // Rollback causes a virtual table transaction to rollback.
  132. Rollback() error
  133. }
  134. // A SavepointVTable is a [VTable] that supports savepoints.
  135. type SavepointVTable interface {
  136. TransactionVTable
  137. // Savepoint signals that the virtual table
  138. // should save its current state as savepoint N.
  139. Savepoint(n int) error
  140. // Release invalidates all savepoints greater than or equal to n.
  141. Release(n int) error
  142. // RollbackTo signals that the state of the virtual table
  143. // should return to what it was when Savepoint(n) was last called.
  144. // This invalidates all savepoints greater than n.
  145. RollbackTo(n int) error
  146. }
  147. // A RenameVTable is a [VTable] that supports its non-eponymous form being renamed.
  148. type RenameVTable interface {
  149. VTable
  150. Rename(new string) error
  151. }
  152. // IndexInputs is the set of arguments that the SQLite core passes to [VTable.BestIndex].
  153. type IndexInputs struct {
  154. // Constraints corresponds to the WHERE clause.
  155. Constraints []IndexConstraint
  156. // OrderBy corresponds to the ORDER BY clause.
  157. OrderBy []IndexOrderBy
  158. // ColumnsUsed is a bitmask of columns used by the statement.
  159. ColumnsUsed uint64
  160. }
  161. func newIndexInputs(tls *libc.TLS, infoPtr uintptr) *IndexInputs {
  162. info := (*lib.Sqlite3_index_info)(unsafe.Pointer(infoPtr))
  163. inputs := &IndexInputs{
  164. Constraints: make([]IndexConstraint, info.FnConstraint),
  165. OrderBy: make([]IndexOrderBy, info.FnOrderBy),
  166. ColumnsUsed: info.FcolUsed,
  167. }
  168. ppVal := lib.Xsqlite3_malloc(tls, int32(unsafe.Sizeof(uintptr(0))))
  169. if ppVal != 0 {
  170. defer lib.Xsqlite3_free(tls, ppVal)
  171. }
  172. for i := range inputs.Constraints {
  173. inputs.Constraints[i].copyFromC(tls, infoPtr, int32(i), ppVal)
  174. }
  175. aOrderBy := info.FaOrderBy
  176. for i := range inputs.OrderBy {
  177. o := (*lib.Sqlite3_index_orderby)(unsafe.Pointer(aOrderBy))
  178. inputs.OrderBy[i] = IndexOrderBy{
  179. Column: int(o.FiColumn),
  180. Desc: o.Fdesc != 0,
  181. }
  182. aOrderBy += unsafe.Sizeof(lib.Sqlite3_index_orderby{})
  183. }
  184. return inputs
  185. }
  186. // IndexOrderBy is a term in the ORDER BY clause.
  187. type IndexOrderBy struct {
  188. // Column is column index.
  189. // Column indices start at 0.
  190. Column int
  191. // Desc is true if descending or false if ascending.
  192. Desc bool
  193. }
  194. // IndexOutputs is the information that [VTable.BestIndex] returns to the SQLite core.
  195. type IndexOutputs struct {
  196. // ConstraintUsage is a mapping from [IndexInputs.Constraints]
  197. // to [VTableCursor.Filter] arguments.
  198. // The mapping is in the same order as [IndexInputs.Constraints]
  199. // and must not contain more than len(IndexInputs.Constraints) elements.
  200. // If len(ConstraintUsage) < len(IndexInputs.Constraints),
  201. // then ConstraintUsage is treated as if the missing elements have the zero value.
  202. ConstraintUsage []IndexConstraintUsage
  203. // ID is used to identify the index in [VTableCursor.Filter].
  204. ID IndexID
  205. // OrderByConsumed is true if the output is already ordered.
  206. OrderByConsumed bool
  207. // EstimatedCost is an estimate of the cost of a particular strategy.
  208. // A cost of N indicates that the cost of the strategy
  209. // is similar to a linear scan of an SQLite table with N rows.
  210. // A cost of log(N) indicates that the expense of the operation
  211. // is similar to that of a binary search on a unique indexed field
  212. // of an SQLite table with N rows.
  213. // A negative or zero cost uses a large default cost unless UseZeroEstimates is true.
  214. EstimatedCost float64
  215. // EstimatedRows is an estimate of the number of rows
  216. // that will be returned by the strategy.
  217. // A negative or zero estimate uses 25 unless UseZeroEstimates is true.
  218. EstimatedRows int64
  219. // If UseZeroEstimates is true and EstimatedCost or EstimatedRows is zero,
  220. // then the zeroes will be used instead of being interpreted as defaults.
  221. UseZeroEstimates bool
  222. // IndexFlags is a bitmask of other flags about the index.
  223. IndexFlags IndexFlags
  224. }
  225. func (outputs *IndexOutputs) copyToC(tls *libc.TLS, infoPtr uintptr) error {
  226. info := (*lib.Sqlite3_index_info)(unsafe.Pointer(infoPtr))
  227. aConstraintUsage := info.FaConstraintUsage
  228. for _, u := range outputs.ConstraintUsage {
  229. ptr := (*lib.Sqlite3_index_constraint_usage)(unsafe.Pointer(aConstraintUsage))
  230. ptr.FargvIndex = int32(u.ArgvIndex)
  231. if u.Omit {
  232. ptr.Fomit = 1
  233. } else {
  234. ptr.Fomit = 0
  235. }
  236. aConstraintUsage += unsafe.Sizeof(lib.Sqlite3_index_constraint_usage{})
  237. }
  238. info.FidxNum = outputs.ID.Num
  239. if len(outputs.ID.String) == 0 {
  240. info.FidxStr = 0
  241. info.FneedToFreeIdxStr = 0
  242. } else {
  243. var err error
  244. info.FidxStr, err = sqliteCString(tls, outputs.ID.String)
  245. if err != nil {
  246. return err
  247. }
  248. info.FneedToFreeIdxStr = 1
  249. }
  250. if outputs.OrderByConsumed {
  251. info.ForderByConsumed = 1
  252. } else {
  253. info.ForderByConsumed = 0
  254. }
  255. if outputs.EstimatedCost > 0 || outputs.UseZeroEstimates {
  256. info.FestimatedCost = outputs.EstimatedCost
  257. }
  258. if outputs.EstimatedRows > 0 || outputs.UseZeroEstimates {
  259. info.FestimatedRows = outputs.EstimatedRows
  260. }
  261. info.FidxFlags = int32(outputs.IndexFlags)
  262. return nil
  263. }
  264. // IndexConstraintUsage maps a single constraint from [IndexInputs.Constraints]
  265. // to a [VTableCursor.Filter] argument in the [IndexOutputs.ConstraintUsage] list.
  266. type IndexConstraintUsage struct {
  267. // ArgvIndex is the intended [VTableCursor.Filter] argument index plus one.
  268. // If ArgvIndex is zero or negative,
  269. // then the constraint is not passed to [VTableCursor.Filter].
  270. // Within the [IndexOutputs.ConstraintUsage] list,
  271. // there must be exactly one entry with an ArgvIndex of 1,
  272. // another of 2, another of 3, and so forth
  273. // to as many or as few as the [VTable.BestIndex] method wants.
  274. ArgvIndex int
  275. // If Omit is true, then it is a hint to SQLite
  276. // that the virtual table will guarantee that the constraint will always be satisfied.
  277. // SQLite will always double-check that rows satisfy the constraint if Omit is false,
  278. // but may skip this check if Omit is true.
  279. Omit bool
  280. }
  281. // IndexID is a virtual table index identifier.
  282. // The meaning of its fields is defined by the virtual table implementation.
  283. // String cannot contain NUL bytes.
  284. type IndexID struct {
  285. Num int32
  286. String string
  287. }
  288. // IndexFlags is a bitmap of options returned in [IndexOutputs.IndexFlags].
  289. type IndexFlags uint32
  290. const (
  291. // IndexScanUnique indicates that the virtual table
  292. // will only return zero or one rows given the input constraints.
  293. IndexScanUnique IndexFlags = lib.SQLITE_INDEX_SCAN_UNIQUE
  294. )
  295. // VTableCursor is a cursor over a [VTable] used to loop through the table.
  296. type VTableCursor interface {
  297. // Filter begins a search of a virtual table.
  298. // The ID is one that is returned by [VTable.BestIndex].
  299. // The arguments will be populated as specified by [IndexOutputs.ConstraintUsage].
  300. Filter(id IndexID, argv []Value) error
  301. // Next advances the cursor to the next row of a result set
  302. // initiated by [VTableCursor.Filter].
  303. // If the cursor is already pointing at the last row when this routine is called,
  304. // then the cursor no longer points to valid data
  305. // and a subsequent call to the [VTableCursor.EOF] method must return true.
  306. Next() error
  307. // Column returns the value for the i-th column of the current row.
  308. // Column indices start at 0.
  309. //
  310. // If noChange is true, then the column access is part of an UPDATE operation
  311. // during which the column value will not change.
  312. // This can be used as a hint to return [Unchanged] instead of fetching the value:
  313. // [WritableVTable.Update] implementations can check [Value.NoChange] to test for this condition.
  314. Column(i int, noChange bool) (Value, error)
  315. // RowID returns the row ID of the row that the cursor is currently pointing at.
  316. RowID() (int64, error)
  317. // EOF reports if the cursor is not pointing to a valid row of data.
  318. EOF() bool
  319. // Close releases any resources associated with the cursor.
  320. Close() error
  321. }
  322. // SetModule registers or unregisters a virtual table module with the given name.
  323. func (c *Conn) SetModule(name string, module *Module) error {
  324. if c == nil {
  325. return fmt.Errorf("sqlite: set module %q: nil connection", name)
  326. }
  327. cname, err := libc.CString(name)
  328. if err != nil {
  329. return fmt.Errorf("sqlite: set module %q: %v", name, err)
  330. }
  331. defer libc.Xfree(c.tls, cname)
  332. if module == nil {
  333. res := ResultCode(lib.Xsqlite3_create_module_v2(c.tls, c.conn, cname, 0, 0, 0))
  334. if err := res.ToError(); err != nil {
  335. return fmt.Errorf("sqlite: set module %q: %w", name, err)
  336. }
  337. return nil
  338. }
  339. if module.Connect == nil {
  340. return fmt.Errorf("sqlite: set module %q: connect not provided", name)
  341. }
  342. cmod := lib.Xsqlite3_malloc(c.tls, int32(unsafe.Sizeof(lib.Sqlite3_module{})))
  343. if cmod == 0 {
  344. return fmt.Errorf("sqlite: set module %q: %w", name, ResultNoMem.ToError())
  345. }
  346. libc.Xmemset(c.tls, cmod, 0, types.Size_t(unsafe.Sizeof(lib.Sqlite3_module{})))
  347. cmodPtr := (*lib.Sqlite3_module)(unsafe.Pointer(cmod))
  348. cmodPtr.FiVersion = 3
  349. cmodPtr.FxConnect = cFuncPointer(vtabConnectTrampoline)
  350. if module.Create != nil {
  351. cmodPtr.FxCreate = cFuncPointer(vtabCreateTrampoline)
  352. } else if module.UseConnectAsCreate {
  353. cmodPtr.FxCreate = cmodPtr.FxConnect
  354. }
  355. cmodPtr.FxBestIndex = cFuncPointer(vtabBestIndexTrampoline)
  356. cmodPtr.FxDisconnect = cFuncPointer(vtabDisconnect)
  357. cmodPtr.FxDestroy = cFuncPointer(vtabDestroy)
  358. cmodPtr.FxOpen = cFuncPointer(vtabOpenTrampoline)
  359. cmodPtr.FxClose = cFuncPointer(vtabCloseTrampoline)
  360. cmodPtr.FxFilter = cFuncPointer(vtabFilterTrampoline)
  361. cmodPtr.FxNext = cFuncPointer(vtabNextTrampoline)
  362. cmodPtr.FxEof = cFuncPointer(vtabEOFTrampoline)
  363. cmodPtr.FxColumn = cFuncPointer(vtabColumnTrampoline)
  364. cmodPtr.FxRowid = cFuncPointer(vtabRowIDTrampoline)
  365. cmodPtr.FxUpdate = cFuncPointer(vtabUpdateTrampoline)
  366. cmodPtr.FxBegin = cFuncPointer(vtabBeginTrampoline)
  367. cmodPtr.FxSync = cFuncPointer(vtabSyncTrampoline)
  368. cmodPtr.FxCommit = cFuncPointer(vtabCommitTrampoline)
  369. cmodPtr.FxRollback = cFuncPointer(vtabRollbackTrampoline)
  370. cmodPtr.FxRename = cFuncPointer(vtabRenameTrampoline)
  371. cmodPtr.FxSavepoint = cFuncPointer(vtabSavepointTrampoline)
  372. cmodPtr.FxRelease = cFuncPointer(vtabReleaseTrampoline)
  373. cmodPtr.FxRollbackTo = cFuncPointer(vtabRollbackToTrampoline)
  374. xDestroy := cFuncPointer(destroyModule)
  375. xmodules.mu.Lock()
  376. defensiveCopy := new(Module)
  377. *defensiveCopy = *module
  378. // Module pointer address is unique for lifetime of module.
  379. xmodules.m[cmod] = defensiveCopy
  380. xmodules.mu.Unlock()
  381. res := ResultCode(lib.Xsqlite3_create_module_v2(c.tls, c.conn, cname, cmod, cmod, xDestroy))
  382. if err := res.ToError(); err != nil {
  383. return fmt.Errorf("sqlite: set module %q: %w", name, err)
  384. }
  385. return nil
  386. }
  387. func vtabCreateTrampoline(tls *libc.TLS, db uintptr, pAux uintptr, argc int32, argv uintptr, ppVTab uintptr, pzErr uintptr) int32 {
  388. xmodules.mu.RLock()
  389. module := xmodules.m[pAux]
  390. xmodules.mu.RUnlock()
  391. return callConnectFunc(tls, module.Create, db, argc, argv, ppVTab, pzErr)
  392. }
  393. func vtabConnectTrampoline(tls *libc.TLS, db uintptr, pAux uintptr, argc int32, argv uintptr, ppVTab uintptr, pzErr uintptr) int32 {
  394. xmodules.mu.RLock()
  395. module := xmodules.m[pAux]
  396. xmodules.mu.RUnlock()
  397. return callConnectFunc(tls, module.Connect, db, argc, argv, ppVTab, pzErr)
  398. }
  399. func callConnectFunc(tls *libc.TLS, connect VTableConnectFunc, db uintptr, argc int32, argv uintptr, ppVTab uintptr, pzErr uintptr) (retcode int32) {
  400. allConns.mu.RLock()
  401. c := allConns.table[db]
  402. allConns.mu.RUnlock()
  403. options := new(VTableConnectOptions)
  404. if argc > 0 {
  405. options.ModuleName = libc.GoString(*(*uintptr)(unsafe.Pointer(argv)))
  406. argc--
  407. argv += uintptr(ptrSize)
  408. }
  409. if argc > 0 {
  410. options.DatabaseName = libc.GoString(*(*uintptr)(unsafe.Pointer(argv)))
  411. argc--
  412. argv += uintptr(ptrSize)
  413. }
  414. if argc > 0 {
  415. options.VTableName = libc.GoString(*(*uintptr)(unsafe.Pointer(argv)))
  416. argc--
  417. argv += uintptr(ptrSize)
  418. }
  419. if argc > 0 {
  420. options.Args = make([]string, argc)
  421. for i := range options.Args {
  422. options.Args[i] = libc.GoString(*(*uintptr)(unsafe.Pointer(argv)))
  423. argv += uintptr(ptrSize)
  424. }
  425. }
  426. vtab, cfg, err := connect(c, options)
  427. if err != nil {
  428. zerr, _ := sqliteCString(tls, err.Error())
  429. *(*uintptr)(unsafe.Pointer(pzErr)) = zerr
  430. return int32(ErrCode(err))
  431. }
  432. defer func() {
  433. if retcode != lib.SQLITE_OK {
  434. vtab.Disconnect()
  435. }
  436. }()
  437. // Call vtab configuration functions based on result.
  438. cdecl, err := libc.CString(cfg.Declaration)
  439. if err != nil {
  440. return lib.SQLITE_NOMEM
  441. }
  442. defer libc.Xfree(tls, cdecl)
  443. if res := ResultCode(lib.Xsqlite3_declare_vtab(tls, db, cdecl)); !res.IsSuccess() {
  444. return int32(res)
  445. }
  446. if !cfg.AllowIndirect {
  447. lib.Xsqlite3_vtab_config(tls, db, lib.SQLITE_VTAB_DIRECTONLY, 0)
  448. }
  449. if cfg.ConstraintSupport {
  450. vargs := libc.NewVaList(int32(1))
  451. lib.Xsqlite3_vtab_config(tls, db, lib.SQLITE_VTAB_DIRECTONLY, vargs)
  452. libc.Xfree(tls, vargs)
  453. }
  454. vtabWrapperSize := int32(unsafe.Sizeof(vtabWrapper{}))
  455. pvtab := lib.Xsqlite3_malloc(tls, vtabWrapperSize)
  456. *(*uintptr)(unsafe.Pointer(ppVTab)) = pvtab
  457. if pvtab == 0 {
  458. return lib.SQLITE_NOMEM
  459. }
  460. libc.Xmemset(tls, pvtab, 0, types.Size_t(vtabWrapperSize))
  461. avt := assertVTable(vtab)
  462. xvtables.mu.Lock()
  463. id := xvtables.ids.next()
  464. xvtables.m[id] = avt
  465. xvtables.mu.Unlock()
  466. (*vtabWrapper)(unsafe.Pointer(pvtab)).id = id
  467. return lib.SQLITE_OK
  468. }
  469. func vtabDisconnect(tls *libc.TLS, pVTab uintptr) int32 {
  470. id := (*vtabWrapper)(unsafe.Pointer(pVTab)).id
  471. lib.Xsqlite3_free(tls, pVTab)
  472. xvtables.mu.Lock()
  473. xvtables.ids.reclaim(id)
  474. vtab := xvtables.m[id]
  475. delete(xvtables.m, id)
  476. xvtables.mu.Unlock()
  477. return int32(ErrCode(vtab.Disconnect()))
  478. }
  479. func vtabDestroy(tls *libc.TLS, pVTab uintptr) int32 {
  480. id := (*vtabWrapper)(unsafe.Pointer(pVTab)).id
  481. lib.Xsqlite3_free(tls, pVTab)
  482. xvtables.mu.Lock()
  483. xvtables.ids.reclaim(id)
  484. vtab := xvtables.m[id]
  485. delete(xvtables.m, id)
  486. xvtables.mu.Unlock()
  487. return int32(ErrCode(vtab.Destroy()))
  488. }
  489. func vtabBestIndexTrampoline(tls *libc.TLS, pVTab uintptr, infoPtr uintptr) int32 {
  490. vw := (*vtabWrapper)(unsafe.Pointer(pVTab))
  491. info := (*lib.Sqlite3_index_info)(unsafe.Pointer(infoPtr))
  492. xvtables.mu.RLock()
  493. vtab := xvtables.m[vw.id]
  494. xvtables.mu.RUnlock()
  495. outputs, err := vtab.BestIndex(newIndexInputs(tls, infoPtr))
  496. if err != nil {
  497. vw.setErrorMessage(tls, err.Error())
  498. return int32(ErrCode(err))
  499. }
  500. if len(outputs.ConstraintUsage) > int(info.FnConstraint) {
  501. vw.setErrorMessage(tls, fmt.Sprintf("len(ConstraintUsage) = %d (> %d)",
  502. len(outputs.ConstraintUsage), info.FnConstraint))
  503. return int32(ResultMisuse)
  504. }
  505. if err := outputs.copyToC(tls, infoPtr); err != nil {
  506. vw.setErrorMessage(tls, err.Error())
  507. return int32(ErrCode(err))
  508. }
  509. return lib.SQLITE_OK
  510. }
  511. func vtabOpenTrampoline(tls *libc.TLS, pVTab uintptr, ppCursor uintptr) int32 {
  512. vw := (*vtabWrapper)(unsafe.Pointer(pVTab))
  513. vtabID := vw.id
  514. xvtables.mu.RLock()
  515. vtab := xvtables.m[vtabID]
  516. xvtables.mu.RUnlock()
  517. cursor, err := vtab.Open()
  518. if err != nil {
  519. vw.setErrorMessage(tls, err.Error())
  520. return int32(ErrCode(err))
  521. }
  522. cursorWrapperSize := int32(unsafe.Sizeof(vtabWrapper{}))
  523. pcursor := lib.Xsqlite3_malloc(tls, cursorWrapperSize)
  524. *(*uintptr)(unsafe.Pointer(ppCursor)) = pcursor
  525. if pcursor == 0 {
  526. cursor.Close()
  527. vw.setErrorMessage(tls, "no memory for cursor wrapper")
  528. return lib.SQLITE_NOMEM
  529. }
  530. libc.Xmemset(tls, pcursor, 0, types.Size_t(cursorWrapperSize))
  531. xcursors.mu.Lock()
  532. cursorID := xcursors.ids.next()
  533. xcursors.m[cursorID] = cursor
  534. xcursors.mu.Unlock()
  535. (*cursorWrapper)(unsafe.Pointer(pcursor)).id = cursorID
  536. return lib.SQLITE_OK
  537. }
  538. func vtabCloseTrampoline(tls *libc.TLS, pCursor uintptr) int32 {
  539. id := (*cursorWrapper)(unsafe.Pointer(pCursor)).id
  540. pVTab := (*cursorWrapper)(unsafe.Pointer(pCursor)).base.FpVtab
  541. xcursors.mu.Lock()
  542. cur := xcursors.m[id]
  543. delete(xcursors.m, id)
  544. xcursors.ids.reclaim(id)
  545. xcursors.mu.Unlock()
  546. lib.Xsqlite3_free(tls, pCursor)
  547. if err := cur.Close(); err != nil {
  548. (*vtabWrapper)(unsafe.Pointer(pVTab)).setErrorMessage(tls, err.Error())
  549. return int32(ErrCode(err))
  550. }
  551. return lib.SQLITE_OK
  552. }
  553. func vtabFilterTrampoline(tls *libc.TLS, pCursor uintptr, idxNum int32, idxStr uintptr, argc int32, argv uintptr) int32 {
  554. cw := (*cursorWrapper)(unsafe.Pointer(pCursor))
  555. xcursors.mu.RLock()
  556. cur := xcursors.m[cw.id]
  557. xcursors.mu.RUnlock()
  558. idxID := IndexID{
  559. Num: idxNum,
  560. String: libc.GoString(idxStr),
  561. }
  562. goArgv := make([]Value, 0, int(argc))
  563. for ; len(goArgv) < cap(goArgv); argv += uintptr(ptrSize) {
  564. goArgv = append(goArgv, Value{
  565. tls: tls,
  566. ptrOrType: *(*uintptr)(unsafe.Pointer(argv)),
  567. })
  568. }
  569. if err := cur.Filter(idxID, goArgv); err != nil {
  570. cw.setErrorMessage(tls, err.Error())
  571. return int32(ErrCode(err))
  572. }
  573. return lib.SQLITE_OK
  574. }
  575. func vtabNextTrampoline(tls *libc.TLS, pCursor uintptr) int32 {
  576. cw := (*cursorWrapper)(unsafe.Pointer(pCursor))
  577. xcursors.mu.RLock()
  578. cur := xcursors.m[cw.id]
  579. xcursors.mu.RUnlock()
  580. if err := cur.Next(); err != nil {
  581. cw.setErrorMessage(tls, err.Error())
  582. return int32(ErrCode(err))
  583. }
  584. return lib.SQLITE_OK
  585. }
  586. func vtabEOFTrampoline(tls *libc.TLS, pCursor uintptr) int32 {
  587. id := (*cursorWrapper)(unsafe.Pointer(pCursor)).id
  588. xcursors.mu.RLock()
  589. cur := xcursors.m[id]
  590. xcursors.mu.RUnlock()
  591. if cur.EOF() {
  592. return 1
  593. }
  594. return 0
  595. }
  596. func vtabColumnTrampoline(tls *libc.TLS, pCursor uintptr, ctx uintptr, n int32) int32 {
  597. id := (*cursorWrapper)(unsafe.Pointer(pCursor)).id
  598. xcursors.mu.RLock()
  599. cur := xcursors.m[id]
  600. xcursors.mu.RUnlock()
  601. goCtx := Context{tls: tls, ptr: ctx}
  602. noChange := lib.Xsqlite3_vtab_nochange(tls, ctx) != 0
  603. v, err := cur.Column(int(n), noChange)
  604. if err != nil {
  605. goCtx.result(TextValue(err.Error()), nil)
  606. return int32(ErrCode(err))
  607. }
  608. if noChange && v.tls == nil && v.NoChange() {
  609. // Skip calling a result function if the method returns Unchanged.
  610. return lib.SQLITE_OK
  611. }
  612. goCtx.result(v, nil)
  613. return lib.SQLITE_OK
  614. }
  615. func vtabRowIDTrampoline(tls *libc.TLS, pCursor uintptr, pRowid uintptr) int32 {
  616. cw := (*cursorWrapper)(unsafe.Pointer(pCursor))
  617. xcursors.mu.RLock()
  618. cur := xcursors.m[cw.id]
  619. xcursors.mu.RUnlock()
  620. rowID, err := cur.RowID()
  621. if err != nil {
  622. cw.setErrorMessage(tls, err.Error())
  623. return int32(ErrCode(err))
  624. }
  625. *(*int64)(unsafe.Pointer(pRowid)) = rowID
  626. return lib.SQLITE_OK
  627. }
  628. func vtabUpdateTrampoline(tls *libc.TLS, pVTab uintptr, argc int32, argv uintptr, pRowid uintptr) int32 {
  629. vw := (*vtabWrapper)(unsafe.Pointer(pVTab))
  630. xvtables.mu.RLock()
  631. vtab := xvtables.m[vw.id]
  632. xvtables.mu.RUnlock()
  633. if vtab.Write == nil {
  634. vw.setErrorMessage(tls, fmt.Sprintf("%T does not implement WritableVTable", vtab.VTable))
  635. return lib.SQLITE_READONLY
  636. }
  637. if argc < 1 {
  638. panic("SQLite did not give enough arguments to xUpdate")
  639. }
  640. oldRowID := Value{
  641. tls: tls,
  642. ptrOrType: *(*uintptr)(unsafe.Pointer(argv)),
  643. }
  644. if argc == 1 {
  645. if err := vtab.Write.DeleteRow(oldRowID); err != nil {
  646. vw.setErrorMessage(tls, err.Error())
  647. return int32(ErrCode(err))
  648. }
  649. return lib.SQLITE_OK
  650. }
  651. goArgs := VTableUpdateParams{
  652. OldRowID: oldRowID,
  653. }
  654. argv += unsafe.Sizeof(uintptr(0))
  655. goArgs.NewRowID = Value{
  656. tls: tls,
  657. ptrOrType: *(*uintptr)(unsafe.Pointer(argv)),
  658. }
  659. if argc > 2 {
  660. goArgs.Columns = make([]Value, argc-2)
  661. argv += unsafe.Sizeof(uintptr(0))
  662. for i := range goArgs.Columns {
  663. goArgs.Columns[i] = Value{
  664. tls: tls,
  665. ptrOrType: *(*uintptr)(unsafe.Pointer(argv)),
  666. }
  667. argv += unsafe.Sizeof(uintptr(0))
  668. }
  669. }
  670. insertRowID, err := vtab.Write.Update(goArgs)
  671. if err != nil {
  672. vw.setErrorMessage(tls, err.Error())
  673. return int32(ErrCode(err))
  674. }
  675. *(*int64)(unsafe.Pointer(pRowid)) = insertRowID
  676. return lib.SQLITE_OK
  677. }
  678. func vtabBeginTrampoline(tls *libc.TLS, pVTab uintptr) int32 {
  679. vw := (*vtabWrapper)(unsafe.Pointer(pVTab))
  680. xvtables.mu.RLock()
  681. vtab := xvtables.m[vw.id]
  682. xvtables.mu.RUnlock()
  683. if vtab.Transaction != nil {
  684. if err := vtab.Transaction.Begin(); err != nil {
  685. vw.setErrorMessage(tls, err.Error())
  686. return int32(ErrCode(err))
  687. }
  688. }
  689. return lib.SQLITE_OK
  690. }
  691. func vtabSyncTrampoline(tls *libc.TLS, pVTab uintptr) int32 {
  692. vw := (*vtabWrapper)(unsafe.Pointer(pVTab))
  693. xvtables.mu.RLock()
  694. vtab := xvtables.m[vw.id]
  695. xvtables.mu.RUnlock()
  696. if vtab.Transaction != nil {
  697. if err := vtab.Transaction.Sync(); err != nil {
  698. vw.setErrorMessage(tls, err.Error())
  699. return int32(ErrCode(err))
  700. }
  701. }
  702. return lib.SQLITE_OK
  703. }
  704. func vtabCommitTrampoline(tls *libc.TLS, pVTab uintptr) int32 {
  705. vw := (*vtabWrapper)(unsafe.Pointer(pVTab))
  706. xvtables.mu.RLock()
  707. vtab := xvtables.m[vw.id]
  708. xvtables.mu.RUnlock()
  709. if vtab.Transaction != nil {
  710. if err := vtab.Transaction.Commit(); err != nil {
  711. vw.setErrorMessage(tls, err.Error())
  712. return int32(ErrCode(err))
  713. }
  714. }
  715. return lib.SQLITE_OK
  716. }
  717. func vtabRollbackTrampoline(tls *libc.TLS, pVTab uintptr) int32 {
  718. vw := (*vtabWrapper)(unsafe.Pointer(pVTab))
  719. xvtables.mu.RLock()
  720. vtab := xvtables.m[vw.id]
  721. xvtables.mu.RUnlock()
  722. if vtab.Transaction != nil {
  723. if err := vtab.Transaction.Rollback(); err != nil {
  724. vw.setErrorMessage(tls, err.Error())
  725. return int32(ErrCode(err))
  726. }
  727. }
  728. return lib.SQLITE_OK
  729. }
  730. func vtabRenameTrampoline(tls *libc.TLS, pVTab uintptr, zNew uintptr) int32 {
  731. vw := (*vtabWrapper)(unsafe.Pointer(pVTab))
  732. xvtables.mu.RLock()
  733. vtab := xvtables.m[vw.id]
  734. xvtables.mu.RUnlock()
  735. if vtab.Rename == nil {
  736. vw.setErrorMessage(tls, fmt.Sprintf("no Rename method for %T", vtab.VTable))
  737. return lib.SQLITE_READONLY
  738. }
  739. if err := vtab.Rename.Rename(libc.GoString(zNew)); err != nil {
  740. vw.setErrorMessage(tls, err.Error())
  741. return int32(ErrCode(err))
  742. }
  743. return lib.SQLITE_OK
  744. }
  745. func vtabSavepointTrampoline(tls *libc.TLS, pVTab uintptr, n int32) int32 {
  746. vw := (*vtabWrapper)(unsafe.Pointer(pVTab))
  747. xvtables.mu.RLock()
  748. vtab := xvtables.m[vw.id]
  749. xvtables.mu.RUnlock()
  750. if vtab.Savepoint != nil {
  751. if err := vtab.Savepoint.Savepoint(int(n)); err != nil {
  752. vw.setErrorMessage(tls, err.Error())
  753. return int32(ErrCode(err))
  754. }
  755. }
  756. return lib.SQLITE_OK
  757. }
  758. func vtabReleaseTrampoline(tls *libc.TLS, pVTab uintptr, n int32) int32 {
  759. vw := (*vtabWrapper)(unsafe.Pointer(pVTab))
  760. xvtables.mu.RLock()
  761. vtab := xvtables.m[vw.id]
  762. xvtables.mu.RUnlock()
  763. if vtab.Savepoint != nil {
  764. if err := vtab.Savepoint.Release(int(n)); err != nil {
  765. vw.setErrorMessage(tls, err.Error())
  766. return int32(ErrCode(err))
  767. }
  768. }
  769. return lib.SQLITE_OK
  770. }
  771. func vtabRollbackToTrampoline(tls *libc.TLS, pVTab uintptr, n int32) int32 {
  772. vw := (*vtabWrapper)(unsafe.Pointer(pVTab))
  773. xvtables.mu.RLock()
  774. vtab := xvtables.m[vw.id]
  775. xvtables.mu.RUnlock()
  776. if vtab.Savepoint != nil {
  777. if err := vtab.Savepoint.RollbackTo(int(n)); err != nil {
  778. vw.setErrorMessage(tls, err.Error())
  779. return int32(ErrCode(err))
  780. }
  781. }
  782. return lib.SQLITE_OK
  783. }
  784. func destroyModule(tls *libc.TLS, pAux uintptr) {
  785. xmodules.mu.Lock()
  786. delete(xmodules.m, pAux)
  787. xmodules.mu.Unlock()
  788. lib.Xsqlite3_free(tls, pAux)
  789. }
  790. type vtabWrapper struct {
  791. base lib.Sqlite3_vtab
  792. id uintptr
  793. }
  794. func (vw *vtabWrapper) setErrorMessage(tls *libc.TLS, s string) {
  795. if vw.base.FzErrMsg != 0 {
  796. lib.Xsqlite3_free(tls, vw.base.FzErrMsg)
  797. }
  798. vw.base.FzErrMsg, _ = sqliteCString(tls, s)
  799. }
  800. type cursorWrapper struct {
  801. base lib.Sqlite3_vtab_cursor
  802. id uintptr
  803. }
  804. func (cw *cursorWrapper) setErrorMessage(tls *libc.TLS, s string) {
  805. vw := (*vtabWrapper)(unsafe.Pointer(cw.base.FpVtab))
  806. vw.setErrorMessage(tls, s)
  807. }
  808. type assertedVTable struct {
  809. VTable
  810. Write WritableVTable
  811. Transaction TransactionVTable
  812. Savepoint SavepointVTable
  813. Rename RenameVTable
  814. }
  815. func assertVTable(vtab VTable) assertedVTable {
  816. avt := assertedVTable{VTable: vtab}
  817. avt.Write, _ = vtab.(WritableVTable)
  818. avt.Transaction, _ = vtab.(TransactionVTable)
  819. avt.Savepoint, _ = vtab.(SavepointVTable)
  820. avt.Rename, _ = vtab.(RenameVTable)
  821. return avt
  822. }
  823. var (
  824. xmodules = struct {
  825. mu sync.RWMutex
  826. m map[uintptr]*Module
  827. }{
  828. m: make(map[uintptr]*Module),
  829. }
  830. xvtables = struct {
  831. mu sync.RWMutex
  832. m map[uintptr]assertedVTable
  833. ids idGen
  834. }{
  835. m: make(map[uintptr]assertedVTable),
  836. }
  837. xcursors = struct {
  838. mu sync.RWMutex
  839. m map[uintptr]VTableCursor
  840. ids idGen
  841. }{
  842. m: make(map[uintptr]VTableCursor),
  843. }
  844. )
  845. // sqliteCString copies a Go string to SQLite-allocated memory.
  846. func sqliteCString(tls *libc.TLS, s string) (uintptr, error) {
  847. if strings.Contains(s, "\x00") {
  848. return 0, fmt.Errorf("%q contains NUL bytes", s)
  849. }
  850. csize := len(s) + 1
  851. c := lib.Xsqlite3_malloc(tls, int32(csize))
  852. if c == 0 {
  853. return 0, fmt.Errorf("%w: cannot allocate %d bytes", ResultNoMem.ToError(), len(s))
  854. }
  855. cslice := unsafe.Slice((*byte)(unsafe.Pointer(c)), csize)
  856. copy(cslice, s)
  857. cslice[len(s)] = 0
  858. return c, nil
  859. }