query.go 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694
  1. package core
  2. import (
  3. "git.ycl.pub/yl32940/TsDB2/DB/core/index"
  4. "git.ycl.pub/yl32940/TsDB2/DB/core/page"
  5. "git.ycl.pub/yl32940/TsDB2/DB/core/types"
  6. "bytes"
  7. "container/heap"
  8. "encoding/binary"
  9. "fmt"
  10. "math/big"
  11. "sort"
  12. )
  13. // Query 查询操作对象
  14. type Query struct {
  15. table *Table
  16. selectCols []string // SELECT 字段列表
  17. whereCond Condition // WHERE 条件
  18. orderBys []SortField // ORDER BY
  19. limit int // LIMIT
  20. offset int // OFFSET
  21. groupBys []string // GROUP BY
  22. havingCond Condition // HAVING
  23. // wantMask 投影掩码 (master 下标 → 是否解码), selectCols 与 orderBys 的并集;
  24. // 排序键从解码后的行里取, ORDER BY 列必须保留在掩码中。nil = 不过滤 (全列)。
  25. wantMask []bool
  26. wantBuilt bool
  27. }
  28. type SortField struct {
  29. Field string
  30. Descending bool
  31. }
  32. // keyRange 索引扫描的单个键区间。
  33. type keyRange struct {
  34. startKey []byte
  35. endKey []byte
  36. startInclusive bool
  37. endInclusive bool
  38. }
  39. // scanPlan 索引扫描计划。
  40. // ranges 通常为单区间; WHERE ... IN (...) 落在可用分量上时展开成多区间
  41. // (每个值一个精确区间), 空切片表示"结果必为空" (如 IN 空集合)。
  42. type scanPlan struct {
  43. meta *IndexMeta
  44. handler index.IndexHandler
  45. ranges []keyRange
  46. rowStore bool // 该索引是否承载行数据 (主键/时序=true)
  47. remainingCond Condition // 需要行级过滤的剩余条件
  48. }
  49. // Query 返回查询操作对象
  50. func (table *Table) Query() *Query {
  51. return &Query{table: table}
  52. }
  53. func (q *Query) Select(cols ...string) *Query {
  54. q.selectCols = cols
  55. q.wantBuilt = false // 投影掩码随 selectCols 失效
  56. return q
  57. }
  58. func (q *Query) Where(cond Condition) *Query { q.whereCond = cond; return q }
  59. func (q *Query) Limit(n int) *Query { q.limit = n; return q }
  60. func (q *Query) Offset(n int) *Query { q.offset = n; return q }
  61. func (q *Query) GroupBy(cols ...string) *Query { q.groupBys = cols; return q }
  62. func (q *Query) Having(cond Condition) *Query { q.havingCond = cond; return q }
  63. func (q *Query) OrderBy(field string, descending ...bool) *Query {
  64. desc := false
  65. if len(descending) > 0 {
  66. desc = descending[0]
  67. }
  68. q.orderBys = append(q.orderBys, SortField{Field: field, Descending: desc})
  69. q.wantBuilt = false // 投影掩码随 orderBys 失效
  70. return q
  71. }
  72. // ======================== 索引键编码 ========================
  73. // encodeIndexKey 将条件值编码为索引键字节。
  74. //
  75. // 编码与行内存储【同源】(都走 types.EncodeValue): 索引的 B+ 树直接按字节序比较键,
  76. // 因此"索引键字节 == 行内字节"是范围扫描正确的前提。这里不再按类型手写分支 ——
  77. // 以前每加一个类型都要在这里补一份, 漏补的后果是索引选出来的行与过滤结果不一致。
  78. //
  79. // param 是列级类型参数: decimal 是小数位数, 字符串家族是行内宽度码。少了它就没法把
  80. // 条件值编成与行内完全一致的字节 —— decimal 会因 scale 不同而长度/系数不一致,
  81. // 字符串则会按错误的宽度截断或越界, 两种都让"索引选出 5 行、过滤后剩 0 行"。
  82. //
  83. // 键长必须等于 FieldSize(ft, param): B+ 树按【定长拼键】比较, 键长与行内宽度不一致
  84. // 就等于拿两种编码去比大小。
  85. func encodeIndexKey(value interface{}, ft types.FieldType, param byte) []byte {
  86. if types.IsDynamic(ft) {
  87. // 动态列不能作为索引分量 (CreateIndex 已拒绝), 这里仅作兜底
  88. if b, ok := value.([]byte); ok {
  89. return b
  90. }
  91. return nil
  92. }
  93. size := types.FieldSize(ft, param)
  94. if size == 0 {
  95. // 未注册类型 / 非法列参数: 交给下面 EncodeValue 报出具体原因 (buf 长度为 0)
  96. panic(fmt.Errorf("%w: 类型 %s 的宽度不可计算 (列级参数 %d)",
  97. types.ErrValueType, types.TypeNameOf(ft), param))
  98. }
  99. buf := make([]byte, size)
  100. if err := types.EncodeValue(ft, param, value, buf); err != nil {
  101. // 沿用既有约定: panic 由 encodeIndexKeySafe* 转成 error。
  102. panic(err)
  103. }
  104. return buf
  105. }
  106. // encodeIndexKeySafe 在 encodeIndexKey 外面包一层 panic 恢复。
  107. // 值类型与列不符时 encodeIndexKey 会 panic, 而公开 API 传进来的值不可信,
  108. // 必须转成 error, 不能把用户输入直接变成崩溃。
  109. func encodeIndexKeySafe(value interface{}, ft types.FieldType) (enc []byte, err error) {
  110. return encodeIndexKeySafeWithParam(value, ft, 0)
  111. }
  112. // encodeIndexKeySafeWithParam 同 encodeIndexKeySafe, 但带上列级类型参数。
  113. // 查询侧拿得到字段元信息时必须走这个版本 (decimal 需要 param 才能编出正确的字节)。
  114. func encodeIndexKeySafeWithParam(value interface{}, ft types.FieldType, param byte) (enc []byte, err error) {
  115. defer func() {
  116. if r := recover(); r != nil {
  117. enc, err = nil, fmt.Errorf("值 %v 与存储类型 %s 不匹配: %v", value, types.TypeNameOf(ft), r)
  118. }
  119. }()
  120. return encodeIndexKey(value, ft, param), nil
  121. }
  122. // ======================== 索引匹配 ========================
  123. // fieldNameFromMeta 获取索引第一个字段的名称
  124. func (q *Query) fieldNameFromMeta(meta *IndexMeta) string {
  125. fieldIdx := int(meta.FieldIDs[0])
  126. if fieldIdx < len(q.table.Field) {
  127. return string(q.table.Field[fieldIdx].FieldName)
  128. }
  129. return ""
  130. }
  131. // ======================== 复合索引键规划 ========================
  132. //
  133. // 索引键 = 各分量字段定长拼接 (编码与 extractIndexKey 完全一致), 因此:
  134. // - 已知前 k 个分量等值 → 键上一段连续区间;
  135. // - 第 k+1 个分量上的范围条件 → 再收窄这段区间;
  136. // - 更靠后的分量索引帮不上忙, 原样留作行级后置过滤。
  137. // 下面的代码把 WHERE 按这个模型折叠成 (startKey, endKey, 残余条件)。
  138. //
  139. // 单列索引是 n == 1 的特例, 行为与旧实现一致。
  140. // indexKeyLayout 索引键各分量的偏移与长度 (定长拼接)
  141. type indexKeyLayout struct {
  142. offsets []int
  143. sizes []int
  144. total int
  145. }
  146. // cmpKind 叶子条件能为键分量提供的边界方向
  147. type cmpKind int
  148. const (
  149. cmpEq cmpKind = iota
  150. cmpGe
  151. cmpGt
  152. cmpLe
  153. cmpLt
  154. )
  155. // keyConstraint 某个键分量上的合并边界 (多个 AND 子条件取交集)
  156. type keyConstraint struct {
  157. lo, hi []byte // 编码后的分量值; nil 表示该侧无约束
  158. loInc, hiInc bool
  159. count int // 落在该分量上的条件个数, 0 = 无约束
  160. }
  161. // add 把一个边界并入本分量; 返回 false 表示条件自相矛盾。
  162. func (kc *keyConstraint) add(kind cmpKind, enc []byte) bool {
  163. switch kind {
  164. case cmpEq:
  165. if !kc.addLower(enc, true) || !kc.addUpper(enc, true) {
  166. return false
  167. }
  168. case cmpGe:
  169. if !kc.addLower(enc, true) {
  170. return false
  171. }
  172. case cmpGt:
  173. if !kc.addLower(enc, false) {
  174. return false
  175. }
  176. case cmpLe:
  177. if !kc.addUpper(enc, true) {
  178. return false
  179. }
  180. case cmpLt:
  181. if !kc.addUpper(enc, false) {
  182. return false
  183. }
  184. }
  185. kc.count++
  186. return true
  187. }
  188. func (kc *keyConstraint) addLower(enc []byte, inclusive bool) bool {
  189. if kc.lo == nil {
  190. kc.lo, kc.loInc = enc, inclusive
  191. return true
  192. }
  193. switch c := bytes.Compare(enc, kc.lo); {
  194. case c > 0: // 取更高的下界
  195. kc.lo, kc.loInc = enc, inclusive
  196. case c == 0: // 同值: 两端都闭才算"含"
  197. kc.loInc = kc.loInc && inclusive
  198. }
  199. return kc.notContradictory()
  200. }
  201. func (kc *keyConstraint) addUpper(enc []byte, inclusive bool) bool {
  202. if kc.hi == nil {
  203. kc.hi, kc.hiInc = enc, inclusive
  204. return true
  205. }
  206. switch c := bytes.Compare(enc, kc.hi); {
  207. case c < 0: // 取更低的上界
  208. kc.hi, kc.hiInc = enc, inclusive
  209. case c == 0:
  210. kc.hiInc = kc.hiInc && inclusive
  211. }
  212. return kc.notContradictory()
  213. }
  214. // notContradictory 判断 [lo, hi] 是否还可能有值。
  215. //
  216. // 注意: 这里按编码字节比较, 而定长整数用的是补码 —— 负数的字节序与数值序相反。
  217. // 所以它只在"字节序下已确定矛盾"时才返回 false, 此时真值也必然为空, 反向不成立。
  218. // 调用方因此只把它当作"放弃使用索引"的依据, 绝不据此断言区间非空。
  219. func (kc *keyConstraint) notContradictory() bool {
  220. if kc.lo == nil || kc.hi == nil {
  221. return true
  222. }
  223. switch c := bytes.Compare(kc.lo, kc.hi); {
  224. case c > 0:
  225. return false
  226. case c == 0:
  227. return kc.loInc && kc.hiInc
  228. }
  229. return true
  230. }
  231. // isEquality 该分量已被钉死为单值 (lo == hi 且两端都闭)
  232. func (kc *keyConstraint) isEquality() bool {
  233. return kc.count > 0 && kc.lo != nil && kc.hi != nil &&
  234. kc.loInc && kc.hiInc && bytes.Equal(kc.lo, kc.hi)
  235. }
  236. // buildKeyLayout 依据索引元信息与表字段类型算出键布局。
  237. // 返回 false 表示该索引当前不可用于查询:
  238. // - 分量列不存在或已被 Drop (新行提不出该分量, 索引里根本没有这批键);
  239. // - 分量是动态列 (行内只存 6B 堆引用, 值 != 引用, 无法按键定位)。
  240. func (q *Query) buildKeyLayout(meta *IndexMeta) (*indexKeyLayout, bool) {
  241. n := int(meta.FieldCnt)
  242. if n <= 0 || n > len(meta.FieldIDs) || n > len(q.table.Field) {
  243. return nil, false
  244. }
  245. lay := &indexKeyLayout{offsets: make([]int, n), sizes: make([]int, n)}
  246. off := 0
  247. for k := 0; k < n; k++ {
  248. fi := int(meta.FieldIDs[k])
  249. if fi >= len(q.table.Field) {
  250. return nil, false
  251. }
  252. if q.table.Field[fi].IsDropped() {
  253. return nil, false
  254. }
  255. ft := q.table.Field[fi].FieldType
  256. if types.IsDynamic(ft) {
  257. return nil, false
  258. }
  259. // 键分量宽度必须与行内宽度同源 (含字符串列的宽度码), 否则索引键的偏移切不出该列
  260. size := int(q.table.Field[fi].Width())
  261. if size <= 0 {
  262. return nil, false
  263. }
  264. lay.offsets[k] = off
  265. lay.sizes[k] = size
  266. off += size
  267. }
  268. lay.total = off
  269. return lay, true
  270. }
  271. // locateComponent 返回字段 master 下标在索引键中的分量位置; -1 表示不属于该索引
  272. func (q *Query) locateComponent(fieldName string, meta *IndexMeta) int {
  273. fi := q.table.findFieldIndex(fieldName)
  274. if fi < 0 {
  275. return -1
  276. }
  277. n := int(meta.FieldCnt)
  278. if n > len(meta.FieldIDs) {
  279. n = len(meta.FieldIDs)
  280. }
  281. for k := 0; k < n; k++ {
  282. if int(meta.FieldIDs[k]) == fi {
  283. return k
  284. }
  285. }
  286. return -1
  287. }
  288. // classifyLeaf 判断一个叶子条件能否成为某个键分量的边界。
  289. // comp < 0 表示与该索引无关 (字段不在索引里, 或该条件类型给不出可比边界)。
  290. func (q *Query) classifyLeaf(c Condition, meta *IndexMeta) (comp int, value interface{}, kind cmpKind) {
  291. switch t := c.(type) {
  292. case EqCondition:
  293. return q.locateComponent(t.Field, meta), t.Value, cmpEq
  294. case GeCondition:
  295. return q.locateComponent(t.Field, meta), t.Value, cmpGe
  296. case GtCondition:
  297. return q.locateComponent(t.Field, meta), t.Value, cmpGt
  298. case LeCondition:
  299. return q.locateComponent(t.Field, meta), t.Value, cmpLe
  300. case LtCondition:
  301. return q.locateComponent(t.Field, meta), t.Value, cmpLt
  302. default:
  303. return -1, nil, cmpEq
  304. }
  305. }
  306. // flattenAnd 把 AND 树展平成叶子条件。
  307. // OR / NOT / LIKE / IN 不是合取项, 整体当叶子返回 —— 它们给不出索引边界,
  308. // 但必须原样保留下来做行级过滤。
  309. func flattenAnd(cond Condition, out *[]Condition) {
  310. if and, ok := cond.(AndCondition); ok {
  311. for _, sub := range and.Conditions {
  312. flattenAnd(sub, out)
  313. }
  314. return
  315. }
  316. *out = append(*out, cond)
  317. }
  318. // incBE 把 buf 当作大端无符号整数加一 (原地)。返回 false 表示溢出 ——
  319. // 此时 buf 之后不再存在任何更大的键。
  320. func incBE(buf []byte) bool {
  321. for i := len(buf) - 1; i >= 0; i-- {
  322. buf[i]++
  323. if buf[i] != 0 {
  324. return true
  325. }
  326. }
  327. return false
  328. }
  329. // fillFF 把 buf[from:] 全置 0xFF (该分量及其后分量的最大值)。
  330. // from 可以是 0 —— 首分量就是范围分量时前缀为空, 此时整个键都无上界。
  331. func fillFF(buf []byte, from int) {
  332. for i := from; i < len(buf); i++ {
  333. buf[i] = 0xFF
  334. }
  335. }
  336. // buildScanPlan 分析 WHERE 条件, 选择最优索引
  337. func (q *Query) buildScanPlan() *scanPlan {
  338. if q.whereCond == nil {
  339. return nil
  340. }
  341. if q.table.indexMeta == nil {
  342. return nil
  343. }
  344. // 先展平成合取项: 索引区间是按"分量"折叠出来的, 只有 AND 语义才可加。
  345. var leaves []Condition
  346. flattenAnd(q.whereCond, &leaves)
  347. var bestPlan *scanPlan
  348. for i := range q.table.indexMeta.metas {
  349. m := &q.table.indexMeta.metas[i]
  350. if m.Flag&0x80 != 0 {
  351. continue
  352. }
  353. // 主键索引直接承载全部行, 但它的 B+ 树叶键是 pkID, 而不是"建在哪一列上"。
  354. // planIndex 会用 meta.FieldIDs 编码出的【字段值】当扫描区间 (见 buildKeyLayout),
  355. // 拿它去比对 pkID 叶键, 语义对不上 —— 只有当该列的值恒等于 pkID 时才偶然正确,
  356. // 否则会静默地只命中/漏掉若干行 (例如 Delete/Update 的条件扫描)。
  357. // 因此主键索引不参与列条件规划, 这类查询退回全表扫描 + 行级过滤 (fullTableScan
  358. // 会施加 whereCond), 结果正确; 按 pkID 的点查/回表仍走 SearchByIndex/ResolveByPK,
  359. // 不经过这里, 不受影响。
  360. if m.IndexType == page.IndexTypePrimary {
  361. continue
  362. }
  363. handler, ok := index.Compose.GetHandler(m.IndexType)
  364. if !ok {
  365. continue
  366. }
  367. plan := q.planIndex(m, handler, leaves)
  368. if plan == nil {
  369. continue // 此索引不匹配
  370. }
  371. // 该索引是否承载行数据: 由处理器自报, 本层不认识索引类型
  372. plan.rowStore = handler.IsRowStore()
  373. if plan.rowStore {
  374. return plan // 行存储索引最优 (免回表), 不再找
  375. }
  376. if bestPlan == nil {
  377. bestPlan = plan
  378. }
  379. }
  380. return bestPlan
  381. }
  382. // planIndex 为一个索引推导扫描区间; 该索引用不上时返回 nil。
  383. func (q *Query) planIndex(m *IndexMeta, handler index.IndexHandler, leaves []Condition) *scanPlan {
  384. lay, ok := q.buildKeyLayout(m)
  385. if !ok {
  386. return nil
  387. }
  388. n := len(lay.sizes)
  389. cons := make([]keyConstraint, n) // 各分量合并后的边界
  390. compCond := make([][]Condition, n) // 各分量上的原始条件 (用于决定哪些能丢)
  391. var rest []Condition // 与索引无关、必须保留的条件
  392. for _, c := range leaves {
  393. k, value, kind := q.classifyLeaf(c, m)
  394. if k < 0 {
  395. rest = append(rest, c)
  396. continue
  397. }
  398. ft := q.table.Field[m.FieldIDs[k]].FieldType
  399. // 用 Safe 版本: 条件的值类型与列存储类型不符时 encodeIndexKey 会 panic,
  400. // 规划阶段不该把用户输入直接变成崩溃 —— 退回行级过滤由 Match 去处理。
  401. // 带上列级 param (decimal 的 scale / 字符串的宽度码): 索引键必须与行内字节完全一致。
  402. enc, err := encodeIndexKeySafeWithParam(value, ft, q.table.fieldParam(int(m.FieldIDs[k])))
  403. if err != nil || len(enc) != lay.sizes[k] {
  404. // 编码失败, 或长度与分量长度不符 (拼进定长键会错位) → 交给行级过滤
  405. rest = append(rest, c)
  406. continue
  407. }
  408. if !cons[k].add(kind, enc) {
  409. // 该分量上的条件互相矛盾 → 结果必为空。
  410. // 这里保守地"放弃索引"而不是返回空区间: 定长补码编码下负数字节序与
  411. // 数值序相反, 用字节比较断定"空"对负数不成立, 退回全表扫描更稳。
  412. return nil
  413. }
  414. compCond[k] = append(compCond[k], c)
  415. }
  416. // 从左往右消费"等值分量"; 之后最多再消费一个范围分量, 更后面的分量帮不上忙。
  417. eqLen := 0
  418. for eqLen < n && cons[eqLen].isEquality() {
  419. eqLen++
  420. }
  421. rangeIdx := -1
  422. if eqLen < n && cons[eqLen].count > 0 {
  423. rangeIdx = eqLen
  424. }
  425. // IN 展开: 只看"等值前缀的下一个分量", 且其上必须还没有任何边界条件
  426. // (有范围/等值条件时让位给常规区间规划, IN 由行级过滤兜底)。
  427. // 每个 IN 值变成该分量取值的精确区间 [前缀||v||00.., 前缀||v||FF..]。
  428. // 多个 IN 只消费第一个适用的, 其余留在行级过滤 (正确性不受影响)。
  429. // 注意本段在 cons[0].count 判定【之前】: 只有 IN 条件时 cons 全空,
  430. // 但它照样能给出一组精确区间。
  431. for _, c := range leaves {
  432. in, ok := c.(InCondition)
  433. if !ok {
  434. continue
  435. }
  436. if eqLen >= n || cons[eqLen].count != 0 {
  437. continue
  438. }
  439. if q.locateComponent(in.Field, m) != eqLen {
  440. continue
  441. }
  442. if plan := q.planInRanges(m, handler, lay, cons, eqLen, rest, compCond, in); plan != nil {
  443. return plan
  444. }
  445. // 返回了 nil = 有值编不出键: 本索引放弃 IN, 让行级过滤兜住正确性,
  446. // 继续走下面的常规区间规划 (等值前缀等条件仍可用)。
  447. break
  448. }
  449. if cons[0].count == 0 {
  450. return nil // 首分量没有边界 → 索引给不出连续区间
  451. }
  452. startKey := make([]byte, lay.total)
  453. endKey := make([]byte, lay.total)
  454. prefix := 0
  455. for j := 0; j < eqLen; j++ {
  456. copy(startKey[prefix:], cons[j].lo)
  457. copy(endKey[prefix:], cons[j].lo)
  458. prefix += len(cons[j].lo)
  459. }
  460. plan := &scanPlan{
  461. meta: m, handler: handler,
  462. ranges: []keyRange{{startKey: startKey, endKey: endKey,
  463. startInclusive: true, endInclusive: true}},
  464. remainingCond: q.remainCond(rest, compCond, eqLen, rangeIdx),
  465. }
  466. // 全部等值 → 精确键 (此时 prefix == total, fillFF 无事可做);
  467. // 只消费了等值前缀 → 该前缀下的全部键: [前缀||00.., 前缀||FF..]。
  468. if eqLen == n || rangeIdx < 0 {
  469. fillFF(endKey, prefix)
  470. return plan
  471. }
  472. rc := &cons[rangeIdx]
  473. size := lay.sizes[rangeIdx]
  474. // 下界: [前缀 || 分量值 || 00..]
  475. if rc.lo != nil {
  476. copy(startKey[prefix:], rc.lo)
  477. if !rc.loInc {
  478. // 严格下界: 要跳过分量 == lo 的全部键, 即把 (前缀||lo) 整体加一
  479. if !incBE(startKey[:prefix+size]) {
  480. return nil // 已经是最大键, 该条件不可能有匹配行
  481. }
  482. }
  483. }
  484. // 上界: [前缀 || 分量值 || FF..]
  485. kr := &plan.ranges[0]
  486. if rc.hi == nil {
  487. fillFF(endKey, prefix)
  488. } else if rc.hiInc {
  489. copy(endKey[prefix:], rc.hi)
  490. fillFF(endKey, prefix+size)
  491. } else {
  492. // 严格上界: 分量 == hi 的键全部排除
  493. copy(endKey[prefix:], rc.hi)
  494. kr.endInclusive = false
  495. }
  496. return plan
  497. }
  498. // planInRanges 把 IN 条件展开成多区间扫描计划。
  499. //
  500. // 返回 nil 表示 IN 无法索引化 (有值编不出键) —— 调用方退回常规规划/全表扫描,
  501. // IN 本身仍在 whereCond 里, 行级过滤保证正确性。
  502. // IN 空集合 → 返回 ranges 为空的计划: 任何区间都不扫, 结果必空 (IN 恒假),
  503. // 与 InCondition.Match 的空集合语义一致。
  504. func (q *Query) planInRanges(m *IndexMeta, handler index.IndexHandler, lay *indexKeyLayout,
  505. cons []keyConstraint, eqLen int, rest []Condition, compCond [][]Condition, in InCondition) *scanPlan {
  506. k := eqLen
  507. size := lay.sizes[k]
  508. fi := int(m.FieldIDs[k])
  509. ft := q.table.Field[fi].FieldType
  510. param := q.table.fieldParam(fi)
  511. // 等值前缀字节 (与常规规划同一编码: cons[j].lo, isEquality 保证两端闭且相等)
  512. prefix := make([]byte, lay.offsets[k])
  513. for j := 0; j < eqLen; j++ {
  514. copy(prefix[lay.offsets[j]:], cons[j].lo)
  515. }
  516. if len(in.Values) == 0 {
  517. // 恒空: 不扫任何区间。remainingCond 保留全部条件 (无行可过滤, 仅为语义完整)。
  518. return &scanPlan{meta: m, handler: handler,
  519. ranges: nil,
  520. remainingCond: q.remainCond(rest, compCond, 0, -1)}
  521. }
  522. ranges := make([]keyRange, 0, len(in.Values))
  523. seen := make(map[string]struct{}, len(in.Values)) // 编码后同键的值只留一个区间
  524. for _, v := range in.Values {
  525. enc, err := encodeIndexKeySafeWithParam(v, ft, param)
  526. if err != nil || len(enc) != size {
  527. return nil // 任一值编不出正确宽度的键 → 整个 IN 退回行级过滤
  528. }
  529. // 该分量取值 v 的全部键: [前缀||v||00.., 前缀||v||FF..] (单列索引即 [v, v])
  530. start := make([]byte, lay.total)
  531. end := make([]byte, lay.total)
  532. copy(start, prefix)
  533. copy(end, prefix)
  534. copy(start[lay.offsets[k]:], enc)
  535. copy(end[lay.offsets[k]:], enc)
  536. fillFF(end, lay.offsets[k]+size)
  537. // 重复值/编码碰撞值去重: 不去重的话, raw 聚合路径 (Count/Sum 的
  538. // scanRaw) 会对同一行重复计数 —— 行交付路径有去重, 聚合没有。
  539. if _, dup := seen[string(start)]; dup {
  540. continue
  541. }
  542. seen[string(start)] = struct{}{}
  543. ranges = append(ranges, keyRange{startKey: start, endKey: end,
  544. startInclusive: true, endInclusive: true})
  545. }
  546. return &scanPlan{meta: m, handler: handler, ranges: ranges,
  547. remainingCond: q.remainCond(rest, compCond, eqLen, -1)}
  548. }
  549. // remainCond 汇总索引区间没能表达、仍需逐行过滤的条件。
  550. // 已被区间精确覆盖的分量 (等值前缀 + 那个范围分量) 上的条件可以安全丢掉。
  551. func (q *Query) remainCond(rest []Condition, compCond [][]Condition, eqLen, rangeIdx int) Condition {
  552. remaining := rest
  553. for j := range compCond {
  554. if j < eqLen || j == rangeIdx {
  555. continue
  556. }
  557. remaining = append(remaining, compCond[j]...)
  558. }
  559. switch len(remaining) {
  560. case 0:
  561. return nil
  562. case 1:
  563. return remaining[0]
  564. default:
  565. return And(remaining...)
  566. }
  567. }
  568. // rowWithPK 把结果行与它的 pkID 绑在一起 —— 排序/翻页会重排结果集, pkID 必须
  569. // 跟着行一起移动, 否则回调会把 A 行的 pkID 配到 B 行的数据上。
  570. type rowWithPK struct {
  571. pkID uint64
  572. row []types.FieldValue
  573. }
  574. // orderKeySpec 预解析的排序键: 排序列不存在于表中时在构建阶段就被丢掉,
  575. // 比较阶段不再做任何字段查找。
  576. type orderKeySpec struct {
  577. field string
  578. ft types.FieldType
  579. desc bool
  580. }
  581. // buildOrderSpecs 把 OrderBy 解析成排序键规格 (字段名 + 列类型 + 方向)。
  582. func (q *Query) buildOrderSpecs() []orderKeySpec {
  583. specs := make([]orderKeySpec, 0, len(q.orderBys))
  584. for _, ob := range q.orderBys {
  585. idx := q.table.findFieldIndex(ob.Field)
  586. if idx < 0 {
  587. continue
  588. }
  589. specs = append(specs, orderKeySpec{
  590. field: ob.Field,
  591. ft: q.table.Field[idx].FieldType,
  592. desc: ob.Descending,
  593. })
  594. }
  595. return specs
  596. }
  597. // compareRowsForOrderBy 按 OrderBy 规则比较两行, 返回 -1/0/1。
  598. // 0 表示"所有排序列都无法区分"(字段缺失), 由调用方用稳定排序保持原顺序。
  599. //
  600. // 保留给外部调用方; 查询内部排序走 sortResults (decoration 每行只提取一次键)。
  601. func (q *Query) compareRowsForOrderBy(a, b []types.FieldValue) int {
  602. return compareRowsBySpecs(a, b, q.buildOrderSpecs())
  603. }
  604. // compareRowsBySpecs 按预解析规格比较两行 (每行先经 findFieldValue 取值)。
  605. func compareRowsBySpecs(a, b []types.FieldValue, specs []orderKeySpec) int {
  606. for _, s := range specs {
  607. vi := findFieldValue(a, s.field)
  608. vj := findFieldValue(b, s.field)
  609. if vi == nil || vj == nil {
  610. continue
  611. }
  612. cmp := compareFieldValues(vi, vj, s.ft)
  613. if cmp == 0 {
  614. continue
  615. }
  616. if s.desc {
  617. return -cmp
  618. }
  619. return cmp
  620. }
  621. return 0
  622. }
  623. // ======================== 核心查询 ========================
  624. // Find 执行查询,返回多行
  625. func (q *Query) Find() ([][]types.FieldValue, error) {
  626. var results [][]types.FieldValue
  627. err := q.scan(func(row []types.FieldValue) bool {
  628. results = append(results, row)
  629. return true
  630. })
  631. if err != nil {
  632. return nil, err
  633. }
  634. // 投影
  635. if len(q.selectCols) > 0 {
  636. results = q.project(results)
  637. }
  638. return results, nil
  639. }
  640. // Scan 流式扫描查询, 回调函数逐行处理数据, 返回 false 提前终止
  641. // 适用于不需要全量收集结果的场景, 内存友好
  642. func (q *Query) Scan(callback func(row []types.FieldValue) bool) error {
  643. return q.scan(callback)
  644. }
  645. // scan 内部流式扫描核心方法
  646. // 自动处理: 索引选择 → 排序 → OFFSET → LIMIT → 回调
  647. func (q *Query) scan(callback func(row []types.FieldValue) bool) error {
  648. return q.scanWithPKID(func(_ uint64, row []types.FieldValue) bool {
  649. return callback(row)
  650. })
  651. }
  652. // ScanWithPKID 流式扫描, 回调同时拿到行主键号 pkID 与列值。
  653. //
  654. // 迁移/导出工具必须用这个而不是 Scan: 行数据里不含 pkID (它是行的 8 字节前缀,
  655. // 不是字段), 只拿字段值就没法还原"这一行的主键号是多少" —— 导出到 SQL 时要么
  656. // 丢掉真实主键, 要么被迫用某个列值冒充 (列值可能是 0、可能被改过)。
  657. func (q *Query) ScanWithPKID(callback func(pkID uint64, row []types.FieldValue) bool) error {
  658. return q.scanWithPKID(callback)
  659. }
  660. // scanWithPKID 与 scan 完全一致, 但额外把每行的真实 pkID 交给回调。
  661. //
  662. // 为什么需要: 行数据里不含 pkID (它是行的 8 字节前缀, 不是字段), 普通 Scan 回调
  663. // 只拿得到字段值。删除/更新必须按真实 pkID 定位行, 旧实现只能退而求其次地
  664. // "取第一个 uint64 类型的字段值当 pkID" —— 主键列不是行内第一个 8 字节列时,
  665. // 它删掉的是另一个主键指向的行, 匹配上的行反而一条都没动, 而且不报错。
  666. func (q *Query) scanWithPKID(callback func(pkID uint64, row []types.FieldValue) bool) error {
  667. plan := q.buildScanPlan()
  668. // 判断是否需要内存排序 (OrderBy 字段与索引不一致时)
  669. needSort := false
  670. if len(q.orderBys) > 0 {
  671. if plan == nil {
  672. needSort = true
  673. } else {
  674. idxField := q.fieldNameFromMeta(plan.meta)
  675. // 免排序只适用于单区间: 多区间 (IN 展开) 的输出是"各区间有序、
  676. // 全局无序"的拼接, 必须交给下面的排序管线。
  677. if !(len(q.orderBys) == 1 && q.orderBys[0].Field == idxField && len(plan.ranges) == 1) {
  678. needSort = true
  679. }
  680. }
  681. }
  682. // 需要排序时, 必须先收集全部再排序, 无法流式 LIMIT
  683. if needSort {
  684. specs := q.buildOrderSpecs()
  685. // ORDER BY + LIMIT: 流式 top-k, 只保留 limit+offset 行的小顶堆,
  686. // 内存 O(k) 且免全量排序 (旧实现物化全部结果再整体排序)。
  687. if q.limit > 0 && len(specs) > 0 {
  688. return q.topKScan(callback, plan, specs)
  689. }
  690. var all []rowWithPK
  691. err := q.executeScan(func(pkID uint64, row []types.FieldValue) bool {
  692. all = append(all, rowWithPK{pkID, row})
  693. return true
  694. }, plan, 0)
  695. if err != nil {
  696. return err
  697. }
  698. // 排序必须连 pkID 一起搬: 只排 []FieldValue 会让回调拿到错位的 pkID。
  699. // decoration: 每行只按名提取一次排序键, 键必须随行进数组 —— 排序会重排
  700. // 切片元素, 平行键数组会因此错位 (索引指向交换后的别的行)。
  701. // 各行列集合可能因 NULL 跳过而不同, 键按名取、缺失用 nil 占位。
  702. if len(specs) > 0 {
  703. dec := make([]struct {
  704. item rowWithPK
  705. keys []interface{}
  706. }, len(all))
  707. for i := range all {
  708. k := make([]interface{}, len(specs))
  709. for j, s := range specs {
  710. k[j] = findFieldValue(all[i].row, s.field)
  711. }
  712. dec[i] = struct {
  713. item rowWithPK
  714. keys []interface{}
  715. }{all[i], k}
  716. }
  717. sort.SliceStable(dec, func(i, j int) bool {
  718. return compareKeys(dec[i].keys, dec[j].keys, specs) < 0
  719. })
  720. all = all[:0]
  721. for i := range dec {
  722. all = append(all, dec[i].item)
  723. }
  724. }
  725. // OFFSET
  726. if q.offset > 0 {
  727. if q.offset >= len(all) {
  728. return nil
  729. }
  730. all = all[q.offset:]
  731. }
  732. // LIMIT
  733. if q.limit > 0 && q.limit < len(all) {
  734. all = all[:q.limit]
  735. }
  736. for _, item := range all {
  737. if !callback(item.pkID, item.row) {
  738. return nil
  739. }
  740. }
  741. return nil
  742. }
  743. // 不需要排序: 直接流式传递 callback, 支持 LIMIT 提前终止。
  744. // 回表预算 = LIMIT+OFFSET: 达到即收工 (OFFSET 行也要交付给下面的跳行逻辑)。
  745. budget := 0
  746. if q.limit > 0 {
  747. budget = q.limit + q.offset
  748. }
  749. seen := 0
  750. return q.executeScan(func(pkID uint64, row []types.FieldValue) bool {
  751. if seen < q.offset {
  752. seen++
  753. return true // 跳过 OFFSET
  754. }
  755. seen++
  756. if !callback(pkID, row) {
  757. return false // 用户要求停止
  758. }
  759. // LIMIT 检查 (0 表示无限制)
  760. if q.limit > 0 && seen-q.offset >= q.limit {
  761. return false // 已满足, 提前终止扫描
  762. }
  763. return true
  764. }, plan, budget)
  765. }
  766. // executeScan 执行索引扫描或全表扫描, 将反序列化后的行传递给回调。
  767. // budget > 0 时最多交付 budget 行 (LIMIT+OFFSET 场景): 二级索引回表据此
  768. // 提前收工, 而不是把命中的上千行全部解出再丢掉 —— Where(hash=重).First()
  769. // 这类点查只允许解 1 行。
  770. func (q *Query) executeScan(callback func(pkID uint64, row []types.FieldValue) bool, plan *scanPlan, budget int) error {
  771. if plan != nil {
  772. return q.indexScan(plan, callback, budget)
  773. }
  774. return q.fullTableScan(callback)
  775. }
  776. // deserialize 行解码入口: 无投影走全列解码; 有投影只解码选中列 (含 ORDER BY 列,
  777. // 排序键要从解码后的行里取)。掩码按 master 下标, 随查询构建器惰性构建一次。
  778. func (q *Query) deserialize(rowData []byte) []types.FieldValue {
  779. if len(q.selectCols) == 0 {
  780. return q.table.deserializeRow(rowData)
  781. }
  782. if !q.wantBuilt {
  783. mask := make([]bool, len(q.table.Field))
  784. mark := func(name string) {
  785. if i := q.table.findFieldIndex(name); i >= 0 {
  786. mask[i] = true
  787. }
  788. }
  789. for _, c := range q.selectCols {
  790. mark(c)
  791. }
  792. for _, ob := range q.orderBys {
  793. mark(ob.Field)
  794. }
  795. q.wantMask = mask
  796. q.wantBuilt = true
  797. }
  798. return q.table.deserializeRowSelect(rowData, q.wantMask)
  799. }
  800. // indexScan 使用索引扫描并按"先物化、后回表"两阶段执行。
  801. //
  802. // 为什么不能像旧实现那样在 RangeScan 回调里直接回表 + 触发用户 callback:
  803. // RangeScan 是沿叶子双向链 (PageHdr.NextPage) 推进的裸游标, 而用户的 Scan 回调
  804. // 常常会对【同一棵索引】做 Update/Delete —— 删旧条目 + 插新条目会触发叶分裂/合并,
  805. // 被合并掉的叶子页会被登记回收, 下一个 Commit/drain 时该页被清零并改写成空闲链节点
  806. // (空闲链同样用 PageHdr.NextPage 串接)。此时游标再读该页的 NextPage, 拿到的就是
  807. // 空闲链指针, 于是跳到一张 type=0 的空页上 (实测 panic: bad page type=0)。
  808. //
  809. // 物化把"遍历"与"修改"彻底分开: 遍历阶段树保持只读, 游标始终有效; 修改发生在
  810. // 遍历结束之后, 不再影响游标。二级索引只物化 pkID(8B/行), 内存开销与结果集成正比
  811. // 且远小于整行物化; rowStore 索引物化的是行的快照 (必须拷贝, 因为它是页内缓冲视图)。
  812. func (q *Query) indexScan(plan *scanPlan, callback func(pkID uint64, row []types.FieldValue) bool, budget int) error {
  813. // 判断 OrderBy 是否需要反向 (只对单区间有定义; 多区间已强制走排序管线)
  814. reverse := false
  815. if len(plan.ranges) == 1 && len(q.orderBys) == 1 {
  816. idxField := q.fieldNameFromMeta(plan.meta)
  817. if q.orderBys[0].Field == idxField && q.orderBys[0].Descending {
  818. reverse = true
  819. }
  820. }
  821. if plan.rowStore {
  822. // 承载行数据的索引: RangeScan 返回 storeRow = [pkID(8B) + rowData]。
  823. // storeRow 指向页缓冲, 遍历结束后页可能被回收改写, 必须拷贝一份快照。
  824. // 多区间 (IN 展开) 时不同值可能编码出重叠区间 → 按 pkID 去重。
  825. var rows [][]byte
  826. var seen map[uint64]struct{}
  827. if len(plan.ranges) > 1 {
  828. seen = make(map[uint64]struct{}, len(plan.ranges)*4)
  829. }
  830. for _, kr := range plan.ranges {
  831. if err := plan.handler.RangeScan(q.table.handle, plan.meta.EntryPage,
  832. kr.startKey, kr.endKey, kr.startInclusive, kr.endInclusive, reverse,
  833. func(row []byte) bool {
  834. if len(row) < 8 {
  835. return true
  836. }
  837. if seen != nil {
  838. pkID := binary.BigEndian.Uint64(row[:8])
  839. if _, dup := seen[pkID]; dup {
  840. return true
  841. }
  842. seen[pkID] = struct{}{}
  843. }
  844. snapshot := make([]byte, len(row))
  845. copy(snapshot, row)
  846. rows = append(rows, snapshot)
  847. return true
  848. }); err != nil {
  849. return err
  850. }
  851. }
  852. for _, row := range rows {
  853. rowData := row[8:]
  854. if plan.remainingCond != nil {
  855. if !plan.remainingCond.Match(rowData, q.table) {
  856. continue
  857. }
  858. }
  859. if !callback(binary.BigEndian.Uint64(row[:8]), q.deserialize(rowData)) {
  860. return nil
  861. }
  862. }
  863. return nil
  864. }
  865. // 二级索引: RangeScan 的输出序即索引键序 (B+ 叶序 / Hash 内部已按键排序),
  866. // 免排序 ORDER BY 路径依赖它 —— 单区间时原样保留; 只有 IN 多区间才排序去重
  867. // (此时顺序本来就交给排序管线, 升序输入也是批量回表游标的要求)。
  868. var pkIDs []uint64
  869. for _, kr := range plan.ranges {
  870. if err := plan.handler.RangeScan(q.table.handle, plan.meta.EntryPage,
  871. kr.startKey, kr.endKey, kr.startInclusive, kr.endInclusive, reverse,
  872. func(row []byte) bool {
  873. if len(row) < 8 {
  874. return true
  875. }
  876. pkIDs = append(pkIDs, binary.BigEndian.Uint64(row[:8]))
  877. return true
  878. }); err != nil {
  879. return err
  880. }
  881. }
  882. if len(plan.ranges) > 1 && len(pkIDs) > 1 {
  883. sort.Slice(pkIDs, func(i, j int) bool { return pkIDs[i] < pkIDs[j] })
  884. // 多区间才可能重复 (同 pkID 命中多个重叠区间); 单区间去重徒增一次扫描
  885. w := 1
  886. for i := 1; i < len(pkIDs); i++ {
  887. if pkIDs[i] != pkIDs[w-1] {
  888. pkIDs[w] = pkIDs[i]
  889. w++
  890. }
  891. }
  892. pkIDs = pkIDs[:w]
  893. }
  894. q.table.indexMeta.BatchResolveByPK(pkIDs, budget, func(pkID uint64, storeRow []byte) bool {
  895. rowData := storeRow[8:]
  896. if plan.remainingCond != nil {
  897. if !plan.remainingCond.Match(rowData, q.table) {
  898. return true
  899. }
  900. }
  901. return callback(pkID, q.deserialize(rowData))
  902. })
  903. return nil
  904. }
  905. // fullTableScan 全表扫描 (流式回调模式)
  906. func (q *Query) fullTableScan(callback func(pkID uint64, row []types.FieldValue) bool) error {
  907. // 找承载行数据的索引 (由处理器自报, 本层不认识索引类型)
  908. primMeta, primHandler, ok := q.table.indexMeta.rowStoreMeta()
  909. if !ok || primMeta == nil || primHandler == nil {
  910. return nil
  911. }
  912. dpIDs := primHandler.GetDataPageIDs(q.table.handle, primMeta.EntryPage)
  913. for _, dpID := range dpIDs {
  914. rows := primHandler.ReadDataPageRows(q.table.handle, dpID)
  915. for _, storeRow := range rows {
  916. if len(storeRow) < 8 {
  917. continue
  918. }
  919. rowData := storeRow[8:]
  920. if q.whereCond != nil {
  921. if !q.whereCond.Match(rowData, q.table) {
  922. continue
  923. }
  924. }
  925. if !callback(binary.BigEndian.Uint64(storeRow[:8]), q.deserialize(rowData)) {
  926. return nil // 回调要求提前终止
  927. }
  928. }
  929. }
  930. return nil
  931. }
  932. // ======================== 裸字节扫描 (聚合专用) ========================
  933. // scanRaw 裸字节版流式扫描: 回调拿 (pkID, 原始行字节), 全程不 deserializeRow。
  934. //
  935. // 背景: Count/Sum/Max/Min 每行只需要"过条件 + 最多一列", 而 scan 管线对每行都
  936. // 分配 []FieldValue 并解码全部活跃列 —— 100 万行的 SUM 里这部分占了绝对大头
  937. // (实测带条件全表扫描每行 ~0.66µs, 整行物化路径 ~1.4µs/行)。
  938. //
  939. // 约束: 只服务内部只读聚合。有 ORDER BY 时排序要比较解码后的列值, 这条路径
  940. // 无能为力 —— 调用方必须先退回整行路径。OFFSET/LIMIT 语义与 scanWithPKID
  941. // 的无排序分支逐行一致。
  942. func (q *Query) scanRaw(callback func(pkID uint64, rowData []byte) bool) error {
  943. plan := q.buildScanPlan()
  944. seen := 0
  945. return q.executeScanRaw(func(pkID uint64, rowData []byte) bool {
  946. if seen < q.offset {
  947. seen++
  948. return true // 跳过 OFFSET
  949. }
  950. seen++
  951. if !callback(pkID, rowData) {
  952. return false // 用户要求停止
  953. }
  954. if q.limit > 0 && seen-q.offset >= q.limit {
  955. return false // 已满足 LIMIT, 提前终止扫描
  956. }
  957. return true
  958. }, plan)
  959. }
  960. func (q *Query) executeScanRaw(callback func(pkID uint64, rowData []byte) bool, plan *scanPlan) error {
  961. if plan != nil {
  962. return q.indexScanRaw(plan, callback)
  963. }
  964. return q.fullTableScanRaw(callback)
  965. }
  966. // indexScanRaw 与 indexScan 走同一执行计划, 但回调拿裸行字节, 且遍历中同步回表。
  967. //
  968. // 为什么可以在 RangeScan 回调里直接回表 (indexScan 却必须"先物化、后回表"):
  969. // 物化两阶段是为"用户回调会在遍历中 Update/Delete 同一棵索引"准备的 —— 叶分裂/
  970. // 合并会让裸游标读到被改写的页。本路径的消费者全是只读聚合, 遍历中不存在任何
  971. // 写操作, 游标必然有效; 于是物化 (含 rowStore 的逐行快照拷贝) 一并省掉。
  972. func (q *Query) indexScanRaw(plan *scanPlan, callback func(pkID uint64, rowData []byte) bool) error {
  973. scanRange := func(kr keyRange) error {
  974. if plan.rowStore {
  975. // 承载行数据的索引: 条目即 storeRow = [pkID(8B) + rowData]
  976. return plan.handler.RangeScan(q.table.handle, plan.meta.EntryPage,
  977. kr.startKey, kr.endKey, kr.startInclusive, kr.endInclusive, false,
  978. func(row []byte) bool {
  979. if len(row) < 8 {
  980. return true
  981. }
  982. rowData := row[8:]
  983. if plan.remainingCond != nil && !plan.remainingCond.Match(rowData, q.table) {
  984. return true
  985. }
  986. return callback(binary.BigEndian.Uint64(row[:8]), rowData)
  987. })
  988. }
  989. // 二级索引: 条目 = pkID(8B BE), 遍历中同步回表 (只读, 不触碰被遍历的索引结构)
  990. return plan.handler.RangeScan(q.table.handle, plan.meta.EntryPage,
  991. kr.startKey, kr.endKey, kr.startInclusive, kr.endInclusive, false,
  992. func(row []byte) bool {
  993. if len(row) < 8 {
  994. return true
  995. }
  996. storeRow, found := q.table.indexMeta.ResolveByPK(binary.BigEndian.Uint64(row[:8]))
  997. if !found {
  998. return true // 行已被删除, 跳过
  999. }
  1000. rowData := storeRow[8:]
  1001. if plan.remainingCond != nil && !plan.remainingCond.Match(rowData, q.table) {
  1002. return true
  1003. }
  1004. return callback(binary.BigEndian.Uint64(row[:8]), rowData)
  1005. })
  1006. }
  1007. for _, kr := range plan.ranges {
  1008. if err := scanRange(kr); err != nil {
  1009. return err
  1010. }
  1011. }
  1012. return nil
  1013. }
  1014. // fullTableScanRaw 与 fullTableScan 同构, 回调拿裸行字节。
  1015. // ReadDataPageRows 返回的行本就是拷贝快照, rowData 跨回调安全。
  1016. func (q *Query) fullTableScanRaw(callback func(pkID uint64, rowData []byte) bool) error {
  1017. primMeta, primHandler, ok := q.table.indexMeta.rowStoreMeta()
  1018. if !ok || primMeta == nil || primHandler == nil {
  1019. return nil
  1020. }
  1021. dpIDs := primHandler.GetDataPageIDs(q.table.handle, primMeta.EntryPage)
  1022. for _, dpID := range dpIDs {
  1023. for _, storeRow := range primHandler.ReadDataPageRows(q.table.handle, dpID) {
  1024. if len(storeRow) < 8 {
  1025. continue
  1026. }
  1027. rowData := storeRow[8:]
  1028. if q.whereCond != nil {
  1029. if !q.whereCond.Match(rowData, q.table) {
  1030. continue
  1031. }
  1032. }
  1033. if !callback(binary.BigEndian.Uint64(storeRow[:8]), rowData) {
  1034. return nil // 回调要求提前终止
  1035. }
  1036. }
  1037. }
  1038. return nil
  1039. }
  1040. // ======================== 排序 ========================
  1041. // sortResults 内存排序: decoration 阶段每行按名提取一次排序键, 键随行进数组
  1042. // (排序会重排元素, 平行键数组会错位), 比较阶段零查找。
  1043. // 行集合可能因 NULL 跳列而宽窄不一, 键按名进行、缺失用 nil 占位,
  1044. // 语义与旧比较器完全一致。
  1045. func (q *Query) sortResults(results [][]types.FieldValue) {
  1046. specs := q.buildOrderSpecs()
  1047. if len(specs) == 0 {
  1048. return
  1049. }
  1050. dec := make([]struct {
  1051. row []types.FieldValue
  1052. keys []interface{}
  1053. }, len(results))
  1054. for i := range results {
  1055. k := make([]interface{}, len(specs))
  1056. for j, s := range specs {
  1057. k[j] = findFieldValue(results[i], s.field)
  1058. }
  1059. dec[i] = struct {
  1060. row []types.FieldValue
  1061. keys []interface{}
  1062. }{results[i], k}
  1063. }
  1064. sort.SliceStable(dec, func(i, j int) bool {
  1065. return compareKeys(dec[i].keys, dec[j].keys, specs) < 0
  1066. })
  1067. for i := range dec {
  1068. results[i] = dec[i].row
  1069. }
  1070. }
  1071. // compareKeys 比较两行预提取的排序键。
  1072. func compareKeys(ka, kb []interface{}, specs []orderKeySpec) int {
  1073. for j, s := range specs {
  1074. vi, vj := ka[j], kb[j]
  1075. if vi == nil || vj == nil {
  1076. continue
  1077. }
  1078. cmp := compareFieldValues(vi, vj, s.ft)
  1079. if cmp == 0 {
  1080. continue
  1081. }
  1082. if s.desc {
  1083. return -cmp
  1084. }
  1085. return cmp
  1086. }
  1087. return 0
  1088. }
  1089. // ======================== 流式 top-k (ORDER BY + LIMIT) ========================
  1090. // topkItem 堆内元素: 行 + 预提取排序键 + 输入序号。
  1091. // 序号做相等键的决胜 —— 弹出顺序与 sort.SliceStable 完全一致 (稳定)。
  1092. type topkItem struct {
  1093. pkID uint64
  1094. row []types.FieldValue
  1095. keys []interface{}
  1096. idx int
  1097. }
  1098. // topkHeap 容量上限 limit+offset 的小顶堆: 超过即弹出当前最小, 堆里始终是
  1099. // 已见行中的前 k 名。heap.Interface。
  1100. type topkHeap struct {
  1101. specs []orderKeySpec
  1102. items []topkItem
  1103. }
  1104. func (h *topkHeap) Len() int { return len(h.items) }
  1105. // Less 定义"输出序的逆序" (大顶堆): 堆顶是【当前集合里最后输出】的元素 ——
  1106. // 容量超限时的淘汰对象。相等键时输入序号大者更靠后、先被淘汰 (稳定)。
  1107. func (h *topkHeap) Less(i, j int) bool {
  1108. c := compareKeys(h.items[i].keys, h.items[j].keys, h.specs)
  1109. if c != 0 {
  1110. return c > 0
  1111. }
  1112. return h.items[i].idx > h.items[j].idx
  1113. }
  1114. func (h *topkHeap) Swap(i, j int) { h.items[i], h.items[j] = h.items[j], h.items[i] }
  1115. func (h *topkHeap) Push(x interface{}) { h.items = append(h.items, x.(topkItem)) }
  1116. func (h *topkHeap) Pop() interface{} {
  1117. old := h.items
  1118. n := len(old)
  1119. it := old[n-1]
  1120. old[n-1] = topkItem{} // 防内存泄漏
  1121. h.items = old[:n-1]
  1122. return it
  1123. }
  1124. // topKScan ORDER BY + LIMIT 的流式执行: 扫描全程只保留 limit+offset 行的小顶堆,
  1125. // 内存 O(k)、免全量排序 (旧实现先物化全部结果再整体排序, 百万行翻页也要全排)。
  1126. // 稳定性: 相等键按输入序号决胜, 输出与 sort.SliceStable 后切片逐字节一致。
  1127. func (q *Query) topKScan(callback func(pkID uint64, row []types.FieldValue) bool,
  1128. plan *scanPlan, specs []orderKeySpec) error {
  1129. cap := q.limit + q.offset
  1130. if cap < q.limit {
  1131. cap = q.limit // 防 offset 溢出 (理论值, int 实际不会)
  1132. }
  1133. h := &topkHeap{specs: specs}
  1134. idx := 0
  1135. err := q.executeScan(func(pkID uint64, row []types.FieldValue) bool {
  1136. keys := make([]interface{}, len(specs))
  1137. for j, s := range specs {
  1138. keys[j] = findFieldValue(row, s.field)
  1139. }
  1140. heap.Push(h, topkItem{pkID: pkID, row: row, keys: keys, idx: idx})
  1141. idx++
  1142. if h.Len() > cap {
  1143. heap.Pop(h)
  1144. }
  1145. return true
  1146. }, plan, 0)
  1147. if err != nil {
  1148. return err
  1149. }
  1150. // 全部弹出: 大顶堆弹出的是"输出序最后"的元素 → items 是输出序的逆序。
  1151. items := make([]topkItem, 0, h.Len())
  1152. for h.Len() > 0 {
  1153. items = append(items, heap.Pop(h).(topkItem))
  1154. }
  1155. if q.offset > 0 {
  1156. if q.offset >= len(items) {
  1157. return nil
  1158. }
  1159. items = items[:len(items)-q.offset] // 弹出序的尾部 = 输出序的头部 → 丢弃
  1160. }
  1161. if q.limit > 0 && len(items) > q.limit {
  1162. items = items[len(items)-q.limit:] // 保留弹出序尾部 = 输出序的前 limit 名
  1163. }
  1164. for i := len(items) - 1; i >= 0; i-- {
  1165. if !callback(items[i].pkID, items[i].row) {
  1166. return nil
  1167. }
  1168. }
  1169. return nil
  1170. }
  1171. func findFieldValue(row []types.FieldValue, field string) interface{} {
  1172. for _, fv := range row {
  1173. if string(fv.FieldName) == field {
  1174. return fv.Value
  1175. }
  1176. }
  1177. return nil
  1178. }
  1179. // cmpInt64 / cmpUint64 把三态比较收敛到一处, 避免每个分支重复写一遍 if 链。
  1180. func cmpInt64(a, b int64) int {
  1181. switch {
  1182. case a < b:
  1183. return -1
  1184. case a > b:
  1185. return 1
  1186. }
  1187. return 0
  1188. }
  1189. func cmpUint64(a, b uint64) int {
  1190. switch {
  1191. case a < b:
  1192. return -1
  1193. case a > b:
  1194. return 1
  1195. }
  1196. return 0
  1197. }
  1198. // compareFieldValues 按【字段类型】比较同一列的两个值, 返回 -1/0/1。
  1199. //
  1200. // 类型必须由调用方传入, 不能只看 Go 值类型: 同一列都可能读成 int16, 但它既可能来自
  1201. // 有符号的 FieldType_Int16 (int16 语义), 也可能来自无符号的 FieldType_Uint16 ——
  1202. // 后者的值是 uint16 的位模式被重解释成 int16, 两者序不同 (位模式 0xFFFF: int16 是 -1,
  1203. // uint16 是 65535)。旧实现只按 Go 值类型分派, 既分不清这两种, 又整个漏掉了 int8/int64。
  1204. //
  1205. // 有符号类型比的是【解码后的值】而不是盘上字节: 盘上是保序编码 (符号位已翻转),
  1206. // 直接比字节也对, 但这里拿到的是已解码的值, 比数值更直白。
  1207. func compareFieldValues(a, b interface{}, ft types.FieldType) int {
  1208. switch ft {
  1209. case types.FieldType_Int8:
  1210. return cmpInt64(int64(a.(int8)), int64(b.(int8)))
  1211. case types.FieldType_Int16:
  1212. return cmpInt64(int64(a.(int16)), int64(b.(int16)))
  1213. case types.FieldType_Int32:
  1214. return cmpInt64(int64(a.(int32)), int64(b.(int32)))
  1215. case types.FieldType_Int64:
  1216. return cmpInt64(a.(int64), b.(int64))
  1217. case types.FieldType_Uint8:
  1218. return cmpUint64(uint64(a.(byte)), uint64(b.(byte)))
  1219. case types.FieldType_Uint16:
  1220. // 无符号: 先把 int16 位模式还原回 uint16 再比, 否则 > 32767 的值会被当成负数
  1221. return cmpUint64(uint64(uint16(a.(int16))), uint64(uint16(b.(int16))))
  1222. case types.FieldType_Uint32:
  1223. return cmpUint64(uint64(uint32(a.(int32))), uint64(uint32(b.(int32))))
  1224. case types.FieldType_Uint64:
  1225. return cmpUint64(a.(uint64), b.(uint64))
  1226. case types.FieldType_Float64:
  1227. // 同一列读出的一定是同一类型, 故 b 也是 float64; 容错地走 toFloat64
  1228. fa, fb := toFloat64(a), toFloat64(b)
  1229. switch {
  1230. case fa < fb:
  1231. return -1
  1232. case fa > fb:
  1233. return 1
  1234. }
  1235. return 0
  1236. case types.FieldType_Float32:
  1237. fa, fb := a.(float32), b.(float32)
  1238. switch {
  1239. case fa < fb:
  1240. return -1
  1241. case fa > fb:
  1242. return 1
  1243. }
  1244. return 0
  1245. case types.FieldType_Bool:
  1246. // false < true (与盘上 0x00 < 0x01 的字节序一致)
  1247. ba, bb := a.(bool), b.(bool)
  1248. switch {
  1249. case ba == bb:
  1250. return 0
  1251. case !ba:
  1252. return -1
  1253. }
  1254. return 1
  1255. case types.FieldType_Year:
  1256. // 同 uint16: 载体是 int16, 但语义是无符号年份
  1257. return cmpUint64(uint64(uint16(a.(int16))), uint64(uint16(b.(int16))))
  1258. case types.FieldType_Decimal:
  1259. // 走数值比较 (自动对齐 scale): 同一列的 scale 必然相同, 但比较函数不该依赖这一点
  1260. return a.(types.Decimal).Cmp(b.(types.Decimal))
  1261. case types.FieldType_Int128:
  1262. na, oka := a.(*big.Int)
  1263. nb, okb := b.(*big.Int)
  1264. if !oka || !okb {
  1265. return 0
  1266. }
  1267. return na.Cmp(nb)
  1268. case types.FieldType_UUID:
  1269. ua, oka := a.(types.UUID)
  1270. ub, okb := b.(types.UUID)
  1271. if !oka || !okb {
  1272. return 0
  1273. }
  1274. return bytes.Compare(ua[:], ub[:])
  1275. }
  1276. // 动态字段与所有定长字符串: 按字节序
  1277. ba, ok := a.([]byte)
  1278. if !ok {
  1279. return 0
  1280. }
  1281. bb, ok := b.([]byte)
  1282. if !ok {
  1283. return 0
  1284. }
  1285. return bytes.Compare(ba, bb)
  1286. }
  1287. // fieldTypeOf 取某列的存储类型, 供按类型比较/聚合使用; 列不存在时返回 0。
  1288. func (q *Query) fieldTypeOf(name string) types.FieldType {
  1289. if i := q.table.findFieldIndex(name); i >= 0 {
  1290. return q.table.Field[i].FieldType
  1291. }
  1292. return 0
  1293. }
  1294. // ======================== 投影 ========================
  1295. func (q *Query) project(results [][]types.FieldValue) [][]types.FieldValue {
  1296. colSet := make(map[string]bool)
  1297. for _, c := range q.selectCols {
  1298. colSet[c] = true
  1299. }
  1300. for i, row := range results {
  1301. var filtered []types.FieldValue
  1302. for _, fv := range row {
  1303. if colSet[string(fv.FieldName)] {
  1304. filtered = append(filtered, fv)
  1305. }
  1306. }
  1307. results[i] = filtered
  1308. }
  1309. return results
  1310. }
  1311. // ======================== 流式聚合 ========================
  1312. // FindOne 流式查询,返回单行 (命中即停,不遍历全表)
  1313. func (q *Query) FindOne() ([]types.FieldValue, error) {
  1314. var result []types.FieldValue
  1315. found := false
  1316. err := q.scan(func(row []types.FieldValue) bool {
  1317. result = row
  1318. found = true
  1319. return false // 找到第一行即停止
  1320. })
  1321. if err != nil {
  1322. return nil, err
  1323. }
  1324. if !found {
  1325. return nil, page.ErrNotFound
  1326. }
  1327. return result, nil
  1328. }
  1329. // Count 流式计数。
  1330. //
  1331. // 三级加速 (每级都严格保持与全量扫描相同的计数语义):
  1332. // 1. 无条件无分页排序 → 逐页数活行 (DataPage::CountLiveRows), 不物化、不解码;
  1333. // 2. WHERE 被索引区间完全消费 (remainingCond == nil) → 直接数索引条目,
  1334. // 不回表、不反序列化 —— 旧实现这里每个命中行都做一次 ResolveByPK +
  1335. // deserializeRow, "用索引 COUNT" 反而比全表扫描更慢 (20k 行 632ms);
  1336. // 3. 其余 → 裸字节扫描计数 (deserializeField 都不需要)。
  1337. // 带 OFFSET/LIMIT/ORDER BY 时保持旧行为 (旧实现的 Count 语义上会先被分页截断)。
  1338. func (q *Query) Count() (int64, error) {
  1339. paged := q.limit > 0 || q.offset > 0 || len(q.orderBys) > 0
  1340. if !paged && q.whereCond == nil {
  1341. return q.countAllLive(), nil
  1342. }
  1343. if !paged {
  1344. if plan := q.buildScanPlan(); plan != nil && plan.remainingCond == nil {
  1345. var count int64
  1346. for _, kr := range plan.ranges {
  1347. err := plan.handler.RangeScan(q.table.handle, plan.meta.EntryPage,
  1348. kr.startKey, kr.endKey, kr.startInclusive, kr.endInclusive, false,
  1349. func(row []byte) bool {
  1350. if len(row) >= 8 {
  1351. count++
  1352. }
  1353. return true
  1354. })
  1355. if err != nil {
  1356. return 0, err
  1357. }
  1358. }
  1359. return count, nil
  1360. }
  1361. var count int64
  1362. err := q.scanRaw(func(_ uint64, _ []byte) bool {
  1363. count++
  1364. return true
  1365. })
  1366. return count, err
  1367. }
  1368. var count int64
  1369. err := q.scan(func(row []types.FieldValue) bool {
  1370. count++
  1371. return true
  1372. })
  1373. return count, err
  1374. }
  1375. // countAllLive 逐页累加活行数 (无条件 COUNT(*) 的 O(页数) 路径)。
  1376. func (q *Query) countAllLive() int64 {
  1377. if q.table.indexMeta == nil {
  1378. return 0
  1379. }
  1380. primMeta, primHandler, ok := q.table.indexMeta.rowStoreMeta()
  1381. if !ok || primMeta == nil || primHandler == nil {
  1382. return 0
  1383. }
  1384. // 处理器实现了免物化计数就用它; 否则退回"读全部行再取 len"
  1385. type liveCounter interface {
  1386. ReadDataPageLiveCount(handle page.HandleDb, dpID uint32) int
  1387. }
  1388. counter, canCount := primHandler.(liveCounter)
  1389. var total int64
  1390. for _, dpID := range primHandler.GetDataPageIDs(q.table.handle, primMeta.EntryPage) {
  1391. if canCount {
  1392. total += int64(counter.ReadDataPageLiveCount(q.table.handle, dpID))
  1393. continue
  1394. }
  1395. total += int64(len(primHandler.ReadDataPageRows(q.table.handle, dpID)))
  1396. }
  1397. return total
  1398. }
  1399. // Sum 流式求和。
  1400. // 每行只解码目标一列 (Table.deserializeField), 不再物化整行; 带 ORDER BY 时
  1401. // 排序管线需要整行, 保持旧路径。条件过滤 (whereCond/remainingCond) 在裸字节上
  1402. // 进行, 与旧路径同一套 Match。
  1403. func (q *Query) Sum(col string) (float64, error) {
  1404. if len(q.orderBys) > 0 {
  1405. var sum float64
  1406. err := q.scan(func(row []types.FieldValue) bool {
  1407. for _, fv := range row {
  1408. if string(fv.FieldName) == col {
  1409. sum += toFloat64(fv.Value)
  1410. break
  1411. }
  1412. }
  1413. return true
  1414. })
  1415. return sum, err
  1416. }
  1417. var sum float64
  1418. err := q.scanRaw(func(_ uint64, rowData []byte) bool {
  1419. if v, ok := q.table.deserializeField(rowData, col); ok {
  1420. sum += toFloat64(v)
  1421. }
  1422. return true
  1423. })
  1424. return sum, err
  1425. }
  1426. // Max 流式求最大值。
  1427. //
  1428. // 加速分两档:
  1429. // 1. 目标列是某二级索引首列且无 WHERE/分页/排序 → 直接取索引端点
  1430. // (反向 RangeScan 第一条即最大键), O(log N) —— 旧实现对 100 万行
  1431. // 线性扫 1.4s, MySQL/SQLite 同场景是 2.6ms/45µs;
  1432. // 2. 其余 → 裸字节扫描, 每行只解码目标一列。
  1433. func (q *Query) Max(col string) (interface{}, error) {
  1434. if v, hit, err := q.minMaxViaIndex(col, true); hit || err != nil {
  1435. return v, err
  1436. }
  1437. ft := q.fieldTypeOf(col)
  1438. if len(q.orderBys) > 0 {
  1439. var maxVal interface{}
  1440. err := q.scan(func(row []types.FieldValue) bool {
  1441. for _, fv := range row {
  1442. if string(fv.FieldName) == col {
  1443. if maxVal == nil || compareFieldValues(fv.Value, maxVal, ft) > 0 {
  1444. maxVal = fv.Value
  1445. }
  1446. break
  1447. }
  1448. }
  1449. return true
  1450. })
  1451. return maxVal, err
  1452. }
  1453. var maxVal interface{}
  1454. err := q.scanRaw(func(_ uint64, rowData []byte) bool {
  1455. if v, ok := q.table.deserializeField(rowData, col); ok {
  1456. if maxVal == nil || compareFieldValues(v, maxVal, ft) > 0 {
  1457. maxVal = v
  1458. }
  1459. }
  1460. return true
  1461. })
  1462. return maxVal, err
  1463. }
  1464. // Min 流式求最小值 (加速路径同 Max, 端点取正向第一条)。
  1465. func (q *Query) Min(col string) (interface{}, error) {
  1466. if v, hit, err := q.minMaxViaIndex(col, false); hit || err != nil {
  1467. return v, err
  1468. }
  1469. ft := q.fieldTypeOf(col)
  1470. if len(q.orderBys) > 0 {
  1471. var minVal interface{}
  1472. err := q.scan(func(row []types.FieldValue) bool {
  1473. for _, fv := range row {
  1474. if string(fv.FieldName) == col {
  1475. if minVal == nil || compareFieldValues(fv.Value, minVal, ft) < 0 {
  1476. minVal = fv.Value
  1477. }
  1478. break
  1479. }
  1480. }
  1481. return true
  1482. })
  1483. return minVal, err
  1484. }
  1485. var minVal interface{}
  1486. err := q.scanRaw(func(_ uint64, rowData []byte) bool {
  1487. if v, ok := q.table.deserializeField(rowData, col); ok {
  1488. if minVal == nil || compareFieldValues(v, minVal, ft) < 0 {
  1489. minVal = v
  1490. }
  1491. }
  1492. return true
  1493. })
  1494. return minVal, err
  1495. }
  1496. // minMaxViaIndex 取索引端点求 Max/Min。
  1497. //
  1498. // 前提: 目标列是某个二级索引的首列, 且查询不带 WHERE/分页/排序 —— 此时
  1499. // "全表最大值"就是"该索引里最大的键" (索引键编码与行内字节同源, 字节序即值序,
  1500. // 见 encodeIndexKey 的说明), 反向 (Max) / 正向 (Min) RangeScan 的第一条即答案。
  1501. // 回调返回 false 提前终止遍历, 成本只有一次树下降。
  1502. //
  1503. // 返回 (值, 是否命中快速路径, err); 未命中时调用方走全扫路径。
  1504. func (q *Query) minMaxViaIndex(col string, wantMax bool) (interface{}, bool, error) {
  1505. if q.whereCond != nil || q.limit > 0 || q.offset > 0 || len(q.orderBys) > 0 {
  1506. return nil, false, nil
  1507. }
  1508. if q.table.indexMeta == nil {
  1509. return nil, false, nil
  1510. }
  1511. for i := range q.table.indexMeta.metas {
  1512. m := &q.table.indexMeta.metas[i]
  1513. if m.Flag&0x80 != 0 || m.IndexType == page.IndexTypePrimary {
  1514. continue
  1515. }
  1516. if q.fieldNameFromMeta(m) != col {
  1517. continue
  1518. }
  1519. if _, ok := q.buildKeyLayout(m); !ok {
  1520. continue // 索引当前不可用 (列被删 / 动态列), 退回全扫
  1521. }
  1522. handler, ok := index.Compose.GetHandler(m.IndexType)
  1523. if !ok {
  1524. continue
  1525. }
  1526. var (
  1527. got interface{}
  1528. found bool
  1529. )
  1530. err := handler.RangeScan(q.table.handle, m.EntryPage,
  1531. nil, nil, true, true, wantMax,
  1532. func(row []byte) bool {
  1533. if len(row) < 8 {
  1534. return true
  1535. }
  1536. storeRow, ok := q.table.indexMeta.ResolveByPK(binary.BigEndian.Uint64(row[:8]))
  1537. if !ok {
  1538. return true // 端点条目解不出行: 索引端点不可信, 由外层退回全扫
  1539. }
  1540. if v, ok := q.table.deserializeField(storeRow[8:], col); ok {
  1541. got, found = v, true
  1542. }
  1543. return false // 只取端点一条
  1544. })
  1545. if err != nil || !found {
  1546. return nil, false, err
  1547. }
  1548. return got, true, nil
  1549. }
  1550. return nil, false, nil
  1551. }
  1552. func toFloat64(v interface{}) float64 {
  1553. switch val := v.(type) {
  1554. case float64:
  1555. return val
  1556. case float32:
  1557. return float64(val)
  1558. case uint64:
  1559. return float64(val)
  1560. case int64:
  1561. return float64(val)
  1562. case int:
  1563. return float64(val)
  1564. case int8:
  1565. return float64(val)
  1566. case int16:
  1567. return float64(val)
  1568. case int32:
  1569. return float64(val)
  1570. case byte:
  1571. return float64(val)
  1572. case bool:
  1573. if val {
  1574. return 1
  1575. }
  1576. return 0
  1577. case types.Decimal:
  1578. // 近似: decimal → float64 会失真, 但 Sum/Avg 的返回值类型就是 float64。
  1579. // 需要精确求和的金额场景请用 Decimal.Add 自行累加。
  1580. return val.Float64()
  1581. case *big.Int:
  1582. if val == nil {
  1583. return 0
  1584. }
  1585. f, _ := new(big.Float).SetInt(val).Float64()
  1586. return f
  1587. }
  1588. return 0
  1589. }