You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sqlite3_opt_vtable.go 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. // Copyright (C) 2019 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
  2. //
  3. // Use of this source code is governed by an MIT-style
  4. // license that can be found in the LICENSE file.
  5. // +build sqlite_vtable vtable
  6. package sqlite3
  7. /*
  8. #cgo CFLAGS: -std=gnu99
  9. #cgo CFLAGS: -DSQLITE_ENABLE_RTREE
  10. #cgo CFLAGS: -DSQLITE_THREADSAFE
  11. #cgo CFLAGS: -DSQLITE_ENABLE_FTS3
  12. #cgo CFLAGS: -DSQLITE_ENABLE_FTS3_PARENTHESIS
  13. #cgo CFLAGS: -DSQLITE_ENABLE_FTS4_UNICODE61
  14. #cgo CFLAGS: -DSQLITE_TRACE_SIZE_LIMIT=15
  15. #cgo CFLAGS: -DSQLITE_ENABLE_COLUMN_METADATA=1
  16. #cgo CFLAGS: -Wno-deprecated-declarations
  17. #ifndef USE_LIBSQLITE3
  18. #include <sqlite3-binding.h>
  19. #else
  20. #include <sqlite3.h>
  21. #endif
  22. #include <stdlib.h>
  23. #include <stdint.h>
  24. #include <memory.h>
  25. static inline char *_sqlite3_mprintf(char *zFormat, char *arg) {
  26. return sqlite3_mprintf(zFormat, arg);
  27. }
  28. typedef struct goVTab goVTab;
  29. struct goVTab {
  30. sqlite3_vtab base;
  31. void *vTab;
  32. };
  33. uintptr_t goMInit(void *db, void *pAux, int argc, char **argv, char **pzErr, int isCreate);
  34. static int cXInit(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr, int isCreate) {
  35. void *vTab = (void *)goMInit(db, pAux, argc, (char**)argv, pzErr, isCreate);
  36. if (!vTab || *pzErr) {
  37. return SQLITE_ERROR;
  38. }
  39. goVTab *pvTab = (goVTab *)sqlite3_malloc(sizeof(goVTab));
  40. if (!pvTab) {
  41. *pzErr = sqlite3_mprintf("%s", "Out of memory");
  42. return SQLITE_NOMEM;
  43. }
  44. memset(pvTab, 0, sizeof(goVTab));
  45. pvTab->vTab = vTab;
  46. *ppVTab = (sqlite3_vtab *)pvTab;
  47. *pzErr = 0;
  48. return SQLITE_OK;
  49. }
  50. static inline int cXCreate(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr) {
  51. return cXInit(db, pAux, argc, argv, ppVTab, pzErr, 1);
  52. }
  53. static inline int cXConnect(sqlite3 *db, void *pAux, int argc, const char *const*argv, sqlite3_vtab **ppVTab, char **pzErr) {
  54. return cXInit(db, pAux, argc, argv, ppVTab, pzErr, 0);
  55. }
  56. char* goVBestIndex(void *pVTab, void *icp);
  57. static inline int cXBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *info) {
  58. char *pzErr = goVBestIndex(((goVTab*)pVTab)->vTab, info);
  59. if (pzErr) {
  60. if (pVTab->zErrMsg)
  61. sqlite3_free(pVTab->zErrMsg);
  62. pVTab->zErrMsg = pzErr;
  63. return SQLITE_ERROR;
  64. }
  65. return SQLITE_OK;
  66. }
  67. char* goVRelease(void *pVTab, int isDestroy);
  68. static int cXRelease(sqlite3_vtab *pVTab, int isDestroy) {
  69. char *pzErr = goVRelease(((goVTab*)pVTab)->vTab, isDestroy);
  70. if (pzErr) {
  71. if (pVTab->zErrMsg)
  72. sqlite3_free(pVTab->zErrMsg);
  73. pVTab->zErrMsg = pzErr;
  74. return SQLITE_ERROR;
  75. }
  76. if (pVTab->zErrMsg)
  77. sqlite3_free(pVTab->zErrMsg);
  78. sqlite3_free(pVTab);
  79. return SQLITE_OK;
  80. }
  81. static inline int cXDisconnect(sqlite3_vtab *pVTab) {
  82. return cXRelease(pVTab, 0);
  83. }
  84. static inline int cXDestroy(sqlite3_vtab *pVTab) {
  85. return cXRelease(pVTab, 1);
  86. }
  87. typedef struct goVTabCursor goVTabCursor;
  88. struct goVTabCursor {
  89. sqlite3_vtab_cursor base;
  90. void *vTabCursor;
  91. };
  92. uintptr_t goVOpen(void *pVTab, char **pzErr);
  93. static int cXOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) {
  94. void *vTabCursor = (void *)goVOpen(((goVTab*)pVTab)->vTab, &(pVTab->zErrMsg));
  95. goVTabCursor *pCursor = (goVTabCursor *)sqlite3_malloc(sizeof(goVTabCursor));
  96. if (!pCursor) {
  97. return SQLITE_NOMEM;
  98. }
  99. memset(pCursor, 0, sizeof(goVTabCursor));
  100. pCursor->vTabCursor = vTabCursor;
  101. *ppCursor = (sqlite3_vtab_cursor *)pCursor;
  102. return SQLITE_OK;
  103. }
  104. static int setErrMsg(sqlite3_vtab_cursor *pCursor, char *pzErr) {
  105. if (pCursor->pVtab->zErrMsg)
  106. sqlite3_free(pCursor->pVtab->zErrMsg);
  107. pCursor->pVtab->zErrMsg = pzErr;
  108. return SQLITE_ERROR;
  109. }
  110. char* goVClose(void *pCursor);
  111. static int cXClose(sqlite3_vtab_cursor *pCursor) {
  112. char *pzErr = goVClose(((goVTabCursor*)pCursor)->vTabCursor);
  113. if (pzErr) {
  114. return setErrMsg(pCursor, pzErr);
  115. }
  116. sqlite3_free(pCursor);
  117. return SQLITE_OK;
  118. }
  119. char* goVFilter(void *pCursor, int idxNum, char* idxName, int argc, sqlite3_value **argv);
  120. static int cXFilter(sqlite3_vtab_cursor *pCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) {
  121. char *pzErr = goVFilter(((goVTabCursor*)pCursor)->vTabCursor, idxNum, (char*)idxStr, argc, argv);
  122. if (pzErr) {
  123. return setErrMsg(pCursor, pzErr);
  124. }
  125. return SQLITE_OK;
  126. }
  127. char* goVNext(void *pCursor);
  128. static int cXNext(sqlite3_vtab_cursor *pCursor) {
  129. char *pzErr = goVNext(((goVTabCursor*)pCursor)->vTabCursor);
  130. if (pzErr) {
  131. return setErrMsg(pCursor, pzErr);
  132. }
  133. return SQLITE_OK;
  134. }
  135. int goVEof(void *pCursor);
  136. static inline int cXEof(sqlite3_vtab_cursor *pCursor) {
  137. return goVEof(((goVTabCursor*)pCursor)->vTabCursor);
  138. }
  139. char* goVColumn(void *pCursor, void *cp, int col);
  140. static int cXColumn(sqlite3_vtab_cursor *pCursor, sqlite3_context *ctx, int i) {
  141. char *pzErr = goVColumn(((goVTabCursor*)pCursor)->vTabCursor, ctx, i);
  142. if (pzErr) {
  143. return setErrMsg(pCursor, pzErr);
  144. }
  145. return SQLITE_OK;
  146. }
  147. char* goVRowid(void *pCursor, sqlite3_int64 *pRowid);
  148. static int cXRowid(sqlite3_vtab_cursor *pCursor, sqlite3_int64 *pRowid) {
  149. char *pzErr = goVRowid(((goVTabCursor*)pCursor)->vTabCursor, pRowid);
  150. if (pzErr) {
  151. return setErrMsg(pCursor, pzErr);
  152. }
  153. return SQLITE_OK;
  154. }
  155. char* goVUpdate(void *pVTab, int argc, sqlite3_value **argv, sqlite3_int64 *pRowid);
  156. static int cXUpdate(sqlite3_vtab *pVTab, int argc, sqlite3_value **argv, sqlite3_int64 *pRowid) {
  157. char *pzErr = goVUpdate(((goVTab*)pVTab)->vTab, argc, argv, pRowid);
  158. if (pzErr) {
  159. if (pVTab->zErrMsg)
  160. sqlite3_free(pVTab->zErrMsg);
  161. pVTab->zErrMsg = pzErr;
  162. return SQLITE_ERROR;
  163. }
  164. return SQLITE_OK;
  165. }
  166. static sqlite3_module goModule = {
  167. 0, // iVersion
  168. cXCreate, // xCreate - create a table
  169. cXConnect, // xConnect - connect to an existing table
  170. cXBestIndex, // xBestIndex - Determine search strategy
  171. cXDisconnect, // xDisconnect - Disconnect from a table
  172. cXDestroy, // xDestroy - Drop a table
  173. cXOpen, // xOpen - open a cursor
  174. cXClose, // xClose - close a cursor
  175. cXFilter, // xFilter - configure scan constraints
  176. cXNext, // xNext - advance a cursor
  177. cXEof, // xEof
  178. cXColumn, // xColumn - read data
  179. cXRowid, // xRowid - read data
  180. cXUpdate, // xUpdate - write data
  181. // Not implemented
  182. 0, // xBegin - begin transaction
  183. 0, // xSync - sync transaction
  184. 0, // xCommit - commit transaction
  185. 0, // xRollback - rollback transaction
  186. 0, // xFindFunction - function overloading
  187. 0, // xRename - rename the table
  188. 0, // xSavepoint
  189. 0, // xRelease
  190. 0 // xRollbackTo
  191. };
  192. void goMDestroy(void*);
  193. static int _sqlite3_create_module(sqlite3 *db, const char *zName, uintptr_t pClientData) {
  194. return sqlite3_create_module_v2(db, zName, &goModule, (void*) pClientData, goMDestroy);
  195. }
  196. */
  197. import "C"
  198. import (
  199. "fmt"
  200. "math"
  201. "reflect"
  202. "unsafe"
  203. )
  204. type sqliteModule struct {
  205. c *SQLiteConn
  206. name string
  207. module Module
  208. }
  209. type sqliteVTab struct {
  210. module *sqliteModule
  211. vTab VTab
  212. }
  213. type sqliteVTabCursor struct {
  214. vTab *sqliteVTab
  215. vTabCursor VTabCursor
  216. }
  217. // Op is type of operations.
  218. type Op uint8
  219. // Op mean identity of operations.
  220. const (
  221. OpEQ Op = 2
  222. OpGT = 4
  223. OpLE = 8
  224. OpLT = 16
  225. OpGE = 32
  226. OpMATCH = 64
  227. OpLIKE = 65 /* 3.10.0 and later only */
  228. OpGLOB = 66 /* 3.10.0 and later only */
  229. OpREGEXP = 67 /* 3.10.0 and later only */
  230. OpScanUnique = 1 /* Scan visits at most 1 row */
  231. )
  232. // InfoConstraint give information of constraint.
  233. type InfoConstraint struct {
  234. Column int
  235. Op Op
  236. Usable bool
  237. }
  238. // InfoOrderBy give information of order-by.
  239. type InfoOrderBy struct {
  240. Column int
  241. Desc bool
  242. }
  243. func constraints(info *C.sqlite3_index_info) []InfoConstraint {
  244. l := info.nConstraint
  245. slice := (*[1 << 30]C.struct_sqlite3_index_constraint)(unsafe.Pointer(info.aConstraint))[:l:l]
  246. cst := make([]InfoConstraint, 0, l)
  247. for _, c := range slice {
  248. var usable bool
  249. if c.usable > 0 {
  250. usable = true
  251. }
  252. cst = append(cst, InfoConstraint{
  253. Column: int(c.iColumn),
  254. Op: Op(c.op),
  255. Usable: usable,
  256. })
  257. }
  258. return cst
  259. }
  260. func orderBys(info *C.sqlite3_index_info) []InfoOrderBy {
  261. l := info.nOrderBy
  262. slice := (*[1 << 30]C.struct_sqlite3_index_orderby)(unsafe.Pointer(info.aOrderBy))[:l:l]
  263. ob := make([]InfoOrderBy, 0, l)
  264. for _, c := range slice {
  265. var desc bool
  266. if c.desc > 0 {
  267. desc = true
  268. }
  269. ob = append(ob, InfoOrderBy{
  270. Column: int(c.iColumn),
  271. Desc: desc,
  272. })
  273. }
  274. return ob
  275. }
  276. // IndexResult is a Go struct representation of what eventually ends up in the
  277. // output fields for `sqlite3_index_info`
  278. // See: https://www.sqlite.org/c3ref/index_info.html
  279. type IndexResult struct {
  280. Used []bool // aConstraintUsage
  281. IdxNum int
  282. IdxStr string
  283. AlreadyOrdered bool // orderByConsumed
  284. EstimatedCost float64
  285. EstimatedRows float64
  286. }
  287. // mPrintf is a utility wrapper around sqlite3_mprintf
  288. func mPrintf(format, arg string) *C.char {
  289. cf := C.CString(format)
  290. defer C.free(unsafe.Pointer(cf))
  291. ca := C.CString(arg)
  292. defer C.free(unsafe.Pointer(ca))
  293. return C._sqlite3_mprintf(cf, ca)
  294. }
  295. //export goMInit
  296. func goMInit(db, pClientData unsafe.Pointer, argc C.int, argv **C.char, pzErr **C.char, isCreate C.int) C.uintptr_t {
  297. m := lookupHandle(uintptr(pClientData)).(*sqliteModule)
  298. if m.c.db != (*C.sqlite3)(db) {
  299. *pzErr = mPrintf("%s", "Inconsistent db handles")
  300. return 0
  301. }
  302. args := make([]string, argc)
  303. var A []*C.char
  304. slice := reflect.SliceHeader{Data: uintptr(unsafe.Pointer(argv)), Len: int(argc), Cap: int(argc)}
  305. a := reflect.NewAt(reflect.TypeOf(A), unsafe.Pointer(&slice)).Elem().Interface()
  306. for i, s := range a.([]*C.char) {
  307. args[i] = C.GoString(s)
  308. }
  309. var vTab VTab
  310. var err error
  311. if isCreate == 1 {
  312. vTab, err = m.module.Create(m.c, args)
  313. } else {
  314. vTab, err = m.module.Connect(m.c, args)
  315. }
  316. if err != nil {
  317. *pzErr = mPrintf("%s", err.Error())
  318. return 0
  319. }
  320. vt := sqliteVTab{m, vTab}
  321. *pzErr = nil
  322. return C.uintptr_t(newHandle(m.c, &vt))
  323. }
  324. //export goVRelease
  325. func goVRelease(pVTab unsafe.Pointer, isDestroy C.int) *C.char {
  326. vt := lookupHandle(uintptr(pVTab)).(*sqliteVTab)
  327. var err error
  328. if isDestroy == 1 {
  329. err = vt.vTab.Destroy()
  330. } else {
  331. err = vt.vTab.Disconnect()
  332. }
  333. if err != nil {
  334. return mPrintf("%s", err.Error())
  335. }
  336. return nil
  337. }
  338. //export goVOpen
  339. func goVOpen(pVTab unsafe.Pointer, pzErr **C.char) C.uintptr_t {
  340. vt := lookupHandle(uintptr(pVTab)).(*sqliteVTab)
  341. vTabCursor, err := vt.vTab.Open()
  342. if err != nil {
  343. *pzErr = mPrintf("%s", err.Error())
  344. return 0
  345. }
  346. vtc := sqliteVTabCursor{vt, vTabCursor}
  347. *pzErr = nil
  348. return C.uintptr_t(newHandle(vt.module.c, &vtc))
  349. }
  350. //export goVBestIndex
  351. func goVBestIndex(pVTab unsafe.Pointer, icp unsafe.Pointer) *C.char {
  352. vt := lookupHandle(uintptr(pVTab)).(*sqliteVTab)
  353. info := (*C.sqlite3_index_info)(icp)
  354. csts := constraints(info)
  355. res, err := vt.vTab.BestIndex(csts, orderBys(info))
  356. if err != nil {
  357. return mPrintf("%s", err.Error())
  358. }
  359. if len(res.Used) != len(csts) {
  360. return mPrintf("Result.Used != expected value", "")
  361. }
  362. // Get a pointer to constraint_usage struct so we can update in place.
  363. l := info.nConstraint
  364. s := (*[1 << 30]C.struct_sqlite3_index_constraint_usage)(unsafe.Pointer(info.aConstraintUsage))[:l:l]
  365. index := 1
  366. for i := C.int(0); i < info.nConstraint; i++ {
  367. if res.Used[i] {
  368. s[i].argvIndex = C.int(index)
  369. s[i].omit = C.uchar(1)
  370. index++
  371. }
  372. }
  373. info.idxNum = C.int(res.IdxNum)
  374. idxStr := C.CString(res.IdxStr)
  375. defer C.free(unsafe.Pointer(idxStr))
  376. info.idxStr = idxStr
  377. info.needToFreeIdxStr = C.int(0)
  378. if res.AlreadyOrdered {
  379. info.orderByConsumed = C.int(1)
  380. }
  381. info.estimatedCost = C.double(res.EstimatedCost)
  382. info.estimatedRows = C.sqlite3_int64(res.EstimatedRows)
  383. return nil
  384. }
  385. //export goVClose
  386. func goVClose(pCursor unsafe.Pointer) *C.char {
  387. vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor)
  388. err := vtc.vTabCursor.Close()
  389. if err != nil {
  390. return mPrintf("%s", err.Error())
  391. }
  392. return nil
  393. }
  394. //export goMDestroy
  395. func goMDestroy(pClientData unsafe.Pointer) {
  396. m := lookupHandle(uintptr(pClientData)).(*sqliteModule)
  397. m.module.DestroyModule()
  398. }
  399. //export goVFilter
  400. func goVFilter(pCursor unsafe.Pointer, idxNum C.int, idxName *C.char, argc C.int, argv **C.sqlite3_value) *C.char {
  401. vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor)
  402. args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc]
  403. vals := make([]interface{}, 0, argc)
  404. for _, v := range args {
  405. conv, err := callbackArgGeneric(v)
  406. if err != nil {
  407. return mPrintf("%s", err.Error())
  408. }
  409. vals = append(vals, conv.Interface())
  410. }
  411. err := vtc.vTabCursor.Filter(int(idxNum), C.GoString(idxName), vals)
  412. if err != nil {
  413. return mPrintf("%s", err.Error())
  414. }
  415. return nil
  416. }
  417. //export goVNext
  418. func goVNext(pCursor unsafe.Pointer) *C.char {
  419. vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor)
  420. err := vtc.vTabCursor.Next()
  421. if err != nil {
  422. return mPrintf("%s", err.Error())
  423. }
  424. return nil
  425. }
  426. //export goVEof
  427. func goVEof(pCursor unsafe.Pointer) C.int {
  428. vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor)
  429. err := vtc.vTabCursor.EOF()
  430. if err {
  431. return 1
  432. }
  433. return 0
  434. }
  435. //export goVColumn
  436. func goVColumn(pCursor, cp unsafe.Pointer, col C.int) *C.char {
  437. vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor)
  438. c := (*SQLiteContext)(cp)
  439. err := vtc.vTabCursor.Column(c, int(col))
  440. if err != nil {
  441. return mPrintf("%s", err.Error())
  442. }
  443. return nil
  444. }
  445. //export goVRowid
  446. func goVRowid(pCursor unsafe.Pointer, pRowid *C.sqlite3_int64) *C.char {
  447. vtc := lookupHandle(uintptr(pCursor)).(*sqliteVTabCursor)
  448. rowid, err := vtc.vTabCursor.Rowid()
  449. if err != nil {
  450. return mPrintf("%s", err.Error())
  451. }
  452. *pRowid = C.sqlite3_int64(rowid)
  453. return nil
  454. }
  455. //export goVUpdate
  456. func goVUpdate(pVTab unsafe.Pointer, argc C.int, argv **C.sqlite3_value, pRowid *C.sqlite3_int64) *C.char {
  457. vt := lookupHandle(uintptr(pVTab)).(*sqliteVTab)
  458. var tname string
  459. if n, ok := vt.vTab.(interface {
  460. TableName() string
  461. }); ok {
  462. tname = n.TableName() + " "
  463. }
  464. err := fmt.Errorf("virtual %s table %sis read-only", vt.module.name, tname)
  465. if v, ok := vt.vTab.(VTabUpdater); ok {
  466. // convert argv
  467. args := (*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.sqlite3_value)(nil))]*C.sqlite3_value)(unsafe.Pointer(argv))[:argc:argc]
  468. vals := make([]interface{}, 0, argc)
  469. for _, v := range args {
  470. conv, err := callbackArgGeneric(v)
  471. if err != nil {
  472. return mPrintf("%s", err.Error())
  473. }
  474. // work around for SQLITE_NULL
  475. x := conv.Interface()
  476. if z, ok := x.([]byte); ok && z == nil {
  477. x = nil
  478. }
  479. vals = append(vals, x)
  480. }
  481. switch {
  482. case argc == 1:
  483. err = v.Delete(vals[0])
  484. case argc > 1 && vals[0] == nil:
  485. var id int64
  486. id, err = v.Insert(vals[1], vals[2:])
  487. if err == nil {
  488. *pRowid = C.sqlite3_int64(id)
  489. }
  490. case argc > 1:
  491. err = v.Update(vals[1], vals[2:])
  492. }
  493. }
  494. if err != nil {
  495. return mPrintf("%s", err.Error())
  496. }
  497. return nil
  498. }
  499. // Module is a "virtual table module", it defines the implementation of a
  500. // virtual tables. See: http://sqlite.org/c3ref/module.html
  501. type Module interface {
  502. // http://sqlite.org/vtab.html#xcreate
  503. Create(c *SQLiteConn, args []string) (VTab, error)
  504. // http://sqlite.org/vtab.html#xconnect
  505. Connect(c *SQLiteConn, args []string) (VTab, error)
  506. // http://sqlite.org/c3ref/create_module.html
  507. DestroyModule()
  508. }
  509. // VTab describes a particular instance of the virtual table.
  510. // See: http://sqlite.org/c3ref/vtab.html
  511. type VTab interface {
  512. // http://sqlite.org/vtab.html#xbestindex
  513. BestIndex([]InfoConstraint, []InfoOrderBy) (*IndexResult, error)
  514. // http://sqlite.org/vtab.html#xdisconnect
  515. Disconnect() error
  516. // http://sqlite.org/vtab.html#sqlite3_module.xDestroy
  517. Destroy() error
  518. // http://sqlite.org/vtab.html#xopen
  519. Open() (VTabCursor, error)
  520. }
  521. // VTabUpdater is a type that allows a VTab to be inserted, updated, or
  522. // deleted.
  523. // See: https://sqlite.org/vtab.html#xupdate
  524. type VTabUpdater interface {
  525. Delete(interface{}) error
  526. Insert(interface{}, []interface{}) (int64, error)
  527. Update(interface{}, []interface{}) error
  528. }
  529. // VTabCursor describes cursors that point into the virtual table and are used
  530. // to loop through the virtual table. See: http://sqlite.org/c3ref/vtab_cursor.html
  531. type VTabCursor interface {
  532. // http://sqlite.org/vtab.html#xclose
  533. Close() error
  534. // http://sqlite.org/vtab.html#xfilter
  535. Filter(idxNum int, idxStr string, vals []interface{}) error
  536. // http://sqlite.org/vtab.html#xnext
  537. Next() error
  538. // http://sqlite.org/vtab.html#xeof
  539. EOF() bool
  540. // http://sqlite.org/vtab.html#xcolumn
  541. Column(c *SQLiteContext, col int) error
  542. // http://sqlite.org/vtab.html#xrowid
  543. Rowid() (int64, error)
  544. }
  545. // DeclareVTab declares the Schema of a virtual table.
  546. // See: http://sqlite.org/c3ref/declare_vtab.html
  547. func (c *SQLiteConn) DeclareVTab(sql string) error {
  548. zSQL := C.CString(sql)
  549. defer C.free(unsafe.Pointer(zSQL))
  550. rv := C.sqlite3_declare_vtab(c.db, zSQL)
  551. if rv != C.SQLITE_OK {
  552. return c.lastError()
  553. }
  554. return nil
  555. }
  556. // CreateModule registers a virtual table implementation.
  557. // See: http://sqlite.org/c3ref/create_module.html
  558. func (c *SQLiteConn) CreateModule(moduleName string, module Module) error {
  559. mname := C.CString(moduleName)
  560. defer C.free(unsafe.Pointer(mname))
  561. udm := sqliteModule{c, moduleName, module}
  562. rv := C._sqlite3_create_module(c.db, mname, C.uintptr_t(newHandle(c, &udm)))
  563. if rv != C.SQLITE_OK {
  564. return c.lastError()
  565. }
  566. return nil
  567. }