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