index_constraint.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // Copyright 2023 Ross Light
  2. // SPDX-License-Identifier: ISC
  3. package sqlite
  4. import (
  5. "fmt"
  6. "unsafe"
  7. "modernc.org/libc"
  8. lib "modernc.org/sqlite/lib"
  9. )
  10. // IndexConstraint is a constraint term in the WHERE clause
  11. // of a query that uses a virtual table.
  12. type IndexConstraint struct {
  13. // Column is the left-hand operand.
  14. // Column indices start at 0.
  15. // -1 indicates the left-hand operand is the rowid.
  16. // Column should be ignored when Op is [IndexConstraintLimit] or [IndexConstraintOffset].
  17. Column int
  18. // Op is the constraint's operator.
  19. Op IndexConstraintOp
  20. // Usable indicates whether [VTable.BestIndex] should consider the constraint.
  21. // Usable may false depending on how tables are ordered in a join.
  22. Usable bool
  23. // Collation is the name of the collating sequence
  24. // that should be used when evaluating the constraint.
  25. Collation string
  26. // RValue is the right-hand operand, if known during statement preparation.
  27. // It's only valid until the end of [VTable.BestIndex].
  28. RValue Value
  29. // RValueKnown indicates whether RValue is set.
  30. RValueKnown bool
  31. }
  32. func (c *IndexConstraint) copyFromC(tls *libc.TLS, infoPtr uintptr, i int32, ppVal uintptr) {
  33. info := (*lib.Sqlite3_index_info)(unsafe.Pointer(infoPtr))
  34. src := (*lib.Sqlite3_index_constraint)(unsafe.Pointer(info.FaConstraint + uintptr(i)*unsafe.Sizeof(lib.Sqlite3_index_constraint{})))
  35. *c = IndexConstraint{
  36. Column: int(src.FiColumn),
  37. Op: IndexConstraintOp(src.Fop),
  38. Usable: src.Fusable != 0,
  39. }
  40. const binaryCollation = "BINARY"
  41. cCollation := lib.Xsqlite3_vtab_collation(tls, infoPtr, int32(i))
  42. if isCStringEqual(cCollation, binaryCollation) {
  43. // BINARY is the most common, so avoid allocations in this case.
  44. c.Collation = binaryCollation
  45. } else {
  46. c.Collation = libc.GoString(cCollation)
  47. }
  48. if ppVal != 0 {
  49. res := ResultCode(lib.Xsqlite3_vtab_rhs_value(tls, infoPtr, int32(i), ppVal))
  50. if res == ResultOK {
  51. c.RValue = Value{
  52. tls: tls,
  53. ptrOrType: *(*uintptr)(unsafe.Pointer(ppVal)),
  54. }
  55. c.RValueKnown = true
  56. }
  57. }
  58. }
  59. // IndexConstraintOp is an enumeration of virtual table constraint operators
  60. // used in [IndexConstraint].
  61. type IndexConstraintOp uint8
  62. const (
  63. IndexConstraintEq IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_EQ
  64. IndexConstraintGT IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_GT
  65. IndexConstraintLE IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_LE
  66. IndexConstraintLT IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_LT
  67. IndexConstraintGE IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_GE
  68. IndexConstraintMatch IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_MATCH
  69. IndexConstraintLike IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_LIKE
  70. IndexConstraintGlob IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_GLOB
  71. IndexConstraintRegexp IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_REGEXP
  72. IndexConstraintNE IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_NE
  73. IndexConstraintIsNot IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_ISNOT
  74. IndexConstraintIsNotNull IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_ISNOTNULL
  75. IndexConstraintIsNull IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_ISNULL
  76. IndexConstraintIs IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_IS
  77. IndexConstraintLimit IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_LIMIT
  78. IndexConstraintOffset IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_OFFSET
  79. )
  80. const indexConstraintFunction IndexConstraintOp = lib.SQLITE_INDEX_CONSTRAINT_FUNCTION
  81. // String returns the operator symbol or keyword.
  82. func (op IndexConstraintOp) String() string {
  83. switch op {
  84. case IndexConstraintEq:
  85. return "="
  86. case IndexConstraintGT:
  87. return ">"
  88. case IndexConstraintLE:
  89. return "<="
  90. case IndexConstraintLT:
  91. return "<"
  92. case IndexConstraintGE:
  93. return ">="
  94. case IndexConstraintMatch:
  95. return "MATCH"
  96. case IndexConstraintLike:
  97. return "LIKE"
  98. case IndexConstraintGlob:
  99. return "GLOB"
  100. case IndexConstraintRegexp:
  101. return "REGEXP"
  102. case IndexConstraintNE:
  103. return "<>"
  104. case IndexConstraintIsNot:
  105. return "IS NOT"
  106. case IndexConstraintIsNotNull:
  107. return "IS NOT NULL"
  108. case IndexConstraintIsNull:
  109. return "IS NULL"
  110. case IndexConstraintIs:
  111. return "IS"
  112. case IndexConstraintLimit:
  113. return "LIMIT"
  114. case IndexConstraintOffset:
  115. return "OFFSET"
  116. default:
  117. if op < indexConstraintFunction {
  118. return fmt.Sprintf("IndexConstraintOp(%d)", uint8(op))
  119. }
  120. return fmt.Sprintf("<function %d>", uint8(op))
  121. }
  122. }
  123. func isCStringEqual(c uintptr, s string) bool {
  124. if c == 0 {
  125. return s == ""
  126. }
  127. for {
  128. cc := *(*byte)(unsafe.Pointer(c))
  129. if cc == 0 {
  130. return len(s) == 0
  131. }
  132. if len(s) == 0 || cc != s[0] {
  133. return false
  134. }
  135. c++
  136. s = s[1:]
  137. }
  138. }