| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- // Copyright 2023 Ross Light
- // SPDX-License-Identifier: ISC
- package sqlite
- import (
- "fmt"
- "unsafe"
- "modernc.org/libc"
- lib "modernc.org/sqlite/lib"
- )
- // IndexConstraint is a constraint term in the WHERE clause
- // of a query that uses a virtual table.
- type IndexConstraint struct {
- // Column is the left-hand operand.
- // Column indices start at 0.
- // -1 indicates the left-hand operand is the rowid.
- // Column should be ignored when Op is [IndexConstraintLimit] or [IndexConstraintOffset].
- Column int
- // Op is the constraint's operator.
- Op IndexConstraintOp
- // Usable indicates whether [VTable.BestIndex] should consider the constraint.
- // Usable may false depending on how tables are ordered in a join.
- Usable bool
- // Collation is the name of the collating sequence
- // that should be used when evaluating the constraint.
- Collation string
- // RValue is the right-hand operand, if known during statement preparation.
- // It's only valid until the end of [VTable.BestIndex].
- RValue Value
- // RValueKnown indicates whether RValue is set.
- RValueKnown bool
- }
- func (c *IndexConstraint) copyFromC(tls *libc.TLS, infoPtr uintptr, i int32, ppVal uintptr) {
- info := (*lib.Sqlite3_index_info)(unsafe.Pointer(infoPtr))
- src := (*lib.Sqlite3_index_constraint)(unsafe.Pointer(info.FaConstraint + uintptr(i)*unsafe.Sizeof(lib.Sqlite3_index_constraint{})))
- *c = IndexConstraint{
- Column: int(src.FiColumn),
- Op: IndexConstraintOp(src.Fop),
- Usable: src.Fusable != 0,
- }
- const binaryCollation = "BINARY"
- cCollation := lib.Xsqlite3_vtab_collation(tls, infoPtr, int32(i))
- if isCStringEqual(cCollation, binaryCollation) {
- // BINARY is the most common, so avoid allocations in this case.
- c.Collation = binaryCollation
- } else {
- c.Collation = libc.GoString(cCollation)
- }
- if ppVal != 0 {
- res := ResultCode(lib.Xsqlite3_vtab_rhs_value(tls, infoPtr, int32(i), ppVal))
- if res == ResultOK {
- c.RValue = Value{
- tls: tls,
- ptrOrType: *(*uintptr)(unsafe.Pointer(ppVal)),
- }
- c.RValueKnown = true
- }
- }
- }
- // IndexConstraintOp is an enumeration of virtual table constraint operators
- // used in [IndexConstraint].
- type IndexConstraintOp uint8
- const (
- IndexConstraintEq IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_EQ
- IndexConstraintGT IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_GT
- IndexConstraintLE IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_LE
- IndexConstraintLT IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_LT
- IndexConstraintGE IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_GE
- IndexConstraintMatch IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_MATCH
- IndexConstraintLike IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_LIKE
- IndexConstraintGlob IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_GLOB
- IndexConstraintRegexp IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_REGEXP
- IndexConstraintNE IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_NE
- IndexConstraintIsNot IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_ISNOT
- IndexConstraintIsNotNull IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_ISNOTNULL
- IndexConstraintIsNull IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_ISNULL
- IndexConstraintIs IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_IS
- IndexConstraintLimit IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_LIMIT
- IndexConstraintOffset IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_OFFSET
- )
- const indexConstraintFunction IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_FUNCTION
- // String returns the operator symbol or keyword.
- func (op IndexConstraintOp) String() string {
- switch op {
- case IndexConstraintEq:
- return "="
- case IndexConstraintGT:
- return ">"
- case IndexConstraintLE:
- return "<="
- case IndexConstraintLT:
- return "<"
- case IndexConstraintGE:
- return ">="
- case IndexConstraintMatch:
- return "MATCH"
- case IndexConstraintLike:
- return "LIKE"
- case IndexConstraintGlob:
- return "GLOB"
- case IndexConstraintRegexp:
- return "REGEXP"
- case IndexConstraintNE:
- return "<>"
- case IndexConstraintIsNot:
- return "IS NOT"
- case IndexConstraintIsNotNull:
- return "IS NOT NULL"
- case IndexConstraintIsNull:
- return "IS NULL"
- case IndexConstraintIs:
- return "IS"
- case IndexConstraintLimit:
- return "LIMIT"
- case IndexConstraintOffset:
- return "OFFSET"
- default:
- if op < indexConstraintFunction {
- return fmt.Sprintf("IndexConstraintOp(%d)", uint8(op))
- }
- return fmt.Sprintf("<function %d>", uint8(op))
- }
- }
- func isCStringEqual(c uintptr, s string) bool {
- if c == 0 {
- return s == ""
- }
- for {
- cc := *(*byte)(unsafe.Pointer(c))
- if cc == 0 {
- return len(s) == 0
- }
- if len(s) == 0 || cc != s[0] {
- return false
- }
- c++
- s = s[1:]
- }
- }
|