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