distribution/vendor/zombiezen.com/go/sqlite/index_constraint.go

151 lines
4.6 KiB
Go

// 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:]
}
}