podman

Форк
0
/
sqlite3_opt_vtable.go 
721 строка · 19.9 Кб
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

9
package 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

31
static inline char *_sqlite3_mprintf(char *zFormat, char *arg) {
32
  return sqlite3_mprintf(zFormat, arg);
33
}
34

35
typedef struct goVTab goVTab;
36

37
struct goVTab {
38
	sqlite3_vtab base;
39
	void *vTab;
40
};
41

42
uintptr_t goMInit(void *db, void *pAux, int argc, char **argv, char **pzErr, int isCreate);
43

44
static 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

62
static 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
}
65
static 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

69
char* goVBestIndex(void *pVTab, void *icp);
70

71
static 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

82
char* goVRelease(void *pVTab, int isDestroy);
83

84
static 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

98
static inline int cXDisconnect(sqlite3_vtab *pVTab) {
99
	return cXRelease(pVTab, 0);
100
}
101
static inline int cXDestroy(sqlite3_vtab *pVTab) {
102
	return cXRelease(pVTab, 1);
103
}
104

105
typedef struct goVTabCursor goVTabCursor;
106

107
struct goVTabCursor {
108
	sqlite3_vtab_cursor base;
109
	void *vTabCursor;
110
};
111

112
uintptr_t goVOpen(void *pVTab, char **pzErr);
113

114
static 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

126
static 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

133
char* goVClose(void *pCursor);
134

135
static 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

144
char* goVFilter(void *pCursor, int idxNum, char* idxName, int argc, sqlite3_value **argv);
145

146
static 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

154
char* goVNext(void *pCursor);
155

156
static 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

164
int goVEof(void *pCursor);
165

166
static inline int cXEof(sqlite3_vtab_cursor *pCursor) {
167
	return goVEof(((goVTabCursor*)pCursor)->vTabCursor);
168
}
169

170
char* goVColumn(void *pCursor, void *cp, int col);
171

172
static 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

180
char* goVRowid(void *pCursor, sqlite3_int64 *pRowid);
181

182
static 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

190
char* goVUpdate(void *pVTab, int argc, sqlite3_value **argv, sqlite3_int64 *pRowid);
191

192
static 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

203
static 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
231
static 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

258
void goMDestroy(void*);
259

260
static 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

264
static 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
*/
268
import "C"
269

270
import (
271
	"fmt"
272
	"math"
273
	"reflect"
274
	"unsafe"
275
)
276

277
type sqliteModule struct {
278
	c      *SQLiteConn
279
	name   string
280
	module Module
281
}
282

283
type sqliteVTab struct {
284
	module *sqliteModule
285
	vTab   VTab
286
}
287

288
type sqliteVTabCursor struct {
289
	vTab       *sqliteVTab
290
	vTabCursor VTabCursor
291
}
292

293
// Op is type of operations.
294
type Op uint8
295

296
// Op mean identity of operations.
297
const (
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.
311
type InfoConstraint struct {
312
	Column int
313
	Op     Op
314
	Usable bool
315
}
316

317
// InfoOrderBy give information of order-by.
318
type InfoOrderBy struct {
319
	Column int
320
	Desc   bool
321
}
322

323
func 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

345
func 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
369
type 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
379
func 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
388
func 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
419
func 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
434
func 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
447
func 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
501
func 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
511
func goMDestroy(pClientData unsafe.Pointer) {
512
	m := lookupHandle(pClientData).(*sqliteModule)
513
	m.module.DestroyModule()
514
}
515

516
//export goVFilter
517
func 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
536
func 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
546
func 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
556
func 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
567
func 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
578
func 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
633
type 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
644
type 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
651
type 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
665
type 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
673
type 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
690
func (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
702
func (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
}
722

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.