-
-
Notifications
You must be signed in to change notification settings - Fork 19
/
index_constraint.go
150 lines (138 loc) · 4.62 KB
/
index_constraint.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Copyright 2023 Roxy 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 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 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:]
}
}