2
0

table.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. package storage
  2. import (
  3. "fmt"
  4. "strings"
  5. "sync"
  6. "github.com/goccy/go-json"
  7. )
  8. // Row represents a database row.
  9. type Row map[string]interface{}
  10. // TableManager manages table data operations.
  11. type TableManager struct {
  12. pool *KVPool
  13. schema *SchemaManager
  14. database string
  15. cacheMu sync.RWMutex
  16. rowCache map[string][]Row // table name → all rows (nil means not loaded)
  17. rowIDMap map[string]map[int64]Row
  18. indexCache map[string]map[string][]int64 // index name → indexed value → rowids
  19. indexTable map[string]string // index name → table name
  20. }
  21. // NewTableManager creates a new table manager.
  22. func NewTableManager(pool *KVPool, schema *SchemaManager, database string) *TableManager {
  23. return &TableManager{
  24. pool: pool,
  25. schema: schema,
  26. database: database,
  27. rowCache: make(map[string][]Row),
  28. rowIDMap: make(map[string]map[int64]Row),
  29. indexCache: make(map[string]map[string][]int64),
  30. indexTable: make(map[string]string),
  31. }
  32. }
  33. // invalidateCache removes a table's rows from the in-memory cache.
  34. func (m *TableManager) invalidateCache(table string) {
  35. m.cacheMu.Lock()
  36. key := strings.ToLower(table)
  37. delete(m.rowCache, key)
  38. delete(m.rowIDMap, key)
  39. for indexName, tableName := range m.indexTable {
  40. if tableName == key {
  41. delete(m.indexCache, indexName)
  42. delete(m.indexTable, indexName)
  43. }
  44. }
  45. m.cacheMu.Unlock()
  46. }
  47. // InvalidateCache is the exported version for use by the executor.
  48. func (m *TableManager) InvalidateCache(table string) {
  49. m.invalidateCache(table)
  50. }
  51. // dataKey returns the key for a row.
  52. func (m *TableManager) dataKey(table, pk string) string {
  53. return fmt.Sprintf("%s:_data:%s:%s", m.database, strings.ToLower(table), pk)
  54. }
  55. // dataPrefix returns the prefix for all rows in a table.
  56. func (m *TableManager) dataPrefix(table string) string {
  57. return fmt.Sprintf("%s:_data:%s:", m.database, strings.ToLower(table))
  58. }
  59. // Insert inserts a new row.
  60. func (m *TableManager) Insert(table string, row Row) error {
  61. schema, err := m.schema.GetSchema(table)
  62. if err != nil {
  63. return err
  64. }
  65. // Get primary key value
  66. pkValue, ok := row[schema.PrimaryKey]
  67. if !ok {
  68. // Try case-insensitive lookup
  69. for k, v := range row {
  70. if strings.EqualFold(k, schema.PrimaryKey) {
  71. pkValue = v
  72. ok = true
  73. break
  74. }
  75. }
  76. }
  77. // Check if PK is INTEGER PRIMARY KEY (implicit ROWID alias)
  78. pkCol, _ := schema.GetColumn(schema.PrimaryKey)
  79. isIntegerPK := pkCol != nil && isIntegerType(pkCol.Type)
  80. // Auto-generate ROWID if no primary key provided or if it's INTEGER PRIMARY KEY
  81. var rowid int64
  82. if !ok || pkValue == nil {
  83. if isIntegerPK || !ok {
  84. // Generate ROWID
  85. rowid, err = m.schema.GetNextRowID(table)
  86. if err != nil {
  87. return err
  88. }
  89. pkValue = rowid
  90. row[schema.PrimaryKey] = rowid
  91. ok = true
  92. } else {
  93. return fmt.Errorf("missing primary key: %s", schema.PrimaryKey)
  94. }
  95. } else if isIntegerPK {
  96. // User provided INTEGER PRIMARY KEY value - track it
  97. switch v := pkValue.(type) {
  98. case int64:
  99. rowid = v
  100. case float64:
  101. rowid = int64(v)
  102. case int:
  103. rowid = int64(v)
  104. default:
  105. rowid = 0
  106. }
  107. if rowid > 0 {
  108. m.schema.UpdateMaxRowID(table, rowid)
  109. }
  110. }
  111. pk := fmt.Sprintf("%v", pkValue)
  112. // Check for duplicate
  113. key := m.dataKey(table, pk)
  114. err = m.pool.WithClient(func(c *KVClient) error {
  115. _, err := c.Read(key)
  116. return err
  117. })
  118. if err == nil {
  119. return fmt.Errorf("duplicate primary key: %s", pk)
  120. }
  121. // Validate required columns
  122. for _, col := range schema.Columns {
  123. if !col.Nullable && col.Default == nil {
  124. val, hasVal := row[col.Name]
  125. if !hasVal {
  126. // Try case-insensitive lookup
  127. for k, v := range row {
  128. if strings.EqualFold(k, col.Name) {
  129. val = v
  130. hasVal = true
  131. break
  132. }
  133. }
  134. }
  135. if !hasVal || val == nil {
  136. return fmt.Errorf("missing required column: %s", col.Name)
  137. }
  138. }
  139. }
  140. // Normalize column names to match schema
  141. normalizedRow := make(Row)
  142. for _, col := range schema.Columns {
  143. for k, v := range row {
  144. if strings.EqualFold(k, col.Name) {
  145. normalizedRow[col.Name] = v
  146. break
  147. }
  148. }
  149. }
  150. // Apply defaults
  151. for _, col := range schema.Columns {
  152. if _, ok := normalizedRow[col.Name]; !ok && col.Default != nil {
  153. normalizedRow[col.Name] = col.Default
  154. }
  155. }
  156. // Store ROWID (use PK value for INTEGER PRIMARY KEY, otherwise generate)
  157. if rowid > 0 {
  158. normalizedRow["_rowid_"] = rowid
  159. } else {
  160. // Generate ROWID for non-integer primary keys
  161. newRowID, _ := m.schema.GetNextRowID(table)
  162. normalizedRow["_rowid_"] = newRowID
  163. }
  164. // Serialize row
  165. data, err := json.Marshal(normalizedRow)
  166. if err != nil {
  167. return fmt.Errorf("failed to serialize row: %w", err)
  168. }
  169. // Write row
  170. err = m.pool.WithClient(func(c *KVClient) error {
  171. return c.Write(key, string(data))
  172. })
  173. if err != nil {
  174. return err
  175. }
  176. // Update in-memory indexes only. Durable index entries are derived from rows.
  177. m.updateIndexesForRow(table, normalizedRow, true)
  178. m.invalidateCache(table)
  179. return nil
  180. }
  181. // InsertBulk inserts multiple rows efficiently, parallelizing KV writes across
  182. // the connection pool. Skips per-row duplicate checks (caller must ensure
  183. // uniqueness). Used by INSERT ... SELECT.
  184. func (m *TableManager) InsertBulk(table string, rows []Row) (int, error) {
  185. if len(rows) == 0 {
  186. return 0, nil
  187. }
  188. schema, err := m.schema.GetSchema(table)
  189. if err != nil {
  190. return 0, err
  191. }
  192. pkCol, _ := schema.GetColumn(schema.PrimaryKey)
  193. isIntegerPK := pkCol != nil && isIntegerType(pkCol.Type)
  194. // Normalize rows and assign _rowid_.
  195. normalized := make([]Row, 0, len(rows))
  196. var maxRowID int64
  197. for _, row := range rows {
  198. nr := make(Row)
  199. for _, col := range schema.Columns {
  200. for k, v := range row {
  201. if strings.EqualFold(k, col.Name) {
  202. nr[col.Name] = v
  203. break
  204. }
  205. }
  206. }
  207. for _, col := range schema.Columns {
  208. if _, ok := nr[col.Name]; !ok && col.Default != nil {
  209. nr[col.Name] = col.Default
  210. }
  211. }
  212. var rowid int64
  213. var hasRowid bool
  214. if isIntegerPK {
  215. switch v := nr[schema.PrimaryKey].(type) {
  216. case float64:
  217. rowid = int64(v)
  218. hasRowid = true
  219. case int64:
  220. rowid = v
  221. hasRowid = true
  222. case int:
  223. rowid = int64(v)
  224. hasRowid = true
  225. }
  226. }
  227. if !hasRowid {
  228. // Fall back to sequential insert for non-integer-pk rows.
  229. if err := m.Insert(table, row); err != nil {
  230. return len(normalized), err
  231. }
  232. continue
  233. }
  234. nr["_rowid_"] = rowid
  235. if rowid > maxRowID {
  236. maxRowID = rowid
  237. }
  238. normalized = append(normalized, nr)
  239. }
  240. if maxRowID > 0 {
  241. m.schema.UpdateMaxRowID(table, maxRowID)
  242. }
  243. // Serialize all rows.
  244. type kv struct{ key, val string }
  245. rowKVs := make([]kv, 0, len(normalized))
  246. for _, nr := range normalized {
  247. pk := fmt.Sprintf("%v", nr[schema.PrimaryKey])
  248. data, err := json.Marshal(nr)
  249. if err != nil {
  250. return 0, err
  251. }
  252. rowKVs = append(rowKVs, kv{m.dataKey(table, pk), string(data)})
  253. }
  254. // Write rows concurrently.
  255. errs := make([]error, len(rowKVs))
  256. var wg sync.WaitGroup
  257. for i, w := range rowKVs {
  258. wg.Add(1)
  259. i, w := i, w
  260. go func() {
  261. defer wg.Done()
  262. errs[i] = m.pool.WithClient(func(c *KVClient) error {
  263. return c.Write(w.key, w.val)
  264. })
  265. }()
  266. }
  267. wg.Wait()
  268. for _, e := range errs {
  269. if e != nil {
  270. return 0, e
  271. }
  272. }
  273. m.invalidateCache(table)
  274. return len(normalized), nil
  275. }
  276. // updateIndexesForRow adds or removes entries from already-built in-memory
  277. // indexes. Index entries are rebuildable from durable row data, so this method
  278. // intentionally does not write idx:* keys to KV.
  279. func (m *TableManager) updateIndexesForRow(table string, row Row, add bool) {
  280. indexes, err := m.schema.ListTableIndexes(table)
  281. if err != nil || len(indexes) == 0 {
  282. return
  283. }
  284. rowid, ok := rowIDFromRow(row)
  285. if !ok {
  286. return
  287. }
  288. for _, idx := range indexes {
  289. indexName := strings.ToLower(idx.Name)
  290. m.cacheMu.RLock()
  291. _, initialized := m.indexCache[indexName]
  292. m.cacheMu.RUnlock()
  293. if !initialized {
  294. continue
  295. }
  296. columns := make([]string, len(idx.Columns))
  297. for i, col := range idx.Columns {
  298. columns[i] = col.Name
  299. }
  300. colValue := m.buildIndexValue(row, columns)
  301. if add {
  302. m.AddIndexEntry(idx.Name, colValue, rowid)
  303. } else {
  304. m.RemoveIndexEntry(idx.Name, colValue, rowid)
  305. }
  306. }
  307. }
  308. // Select retrieves rows from a table.
  309. func (m *TableManager) Select(table string, filter func(Row) bool) ([]Row, error) {
  310. if !m.schema.TableExists(table) {
  311. return nil, fmt.Errorf("table not found: %s", table)
  312. }
  313. key := strings.ToLower(table)
  314. m.cacheMu.RLock()
  315. cached, ok := m.rowCache[key]
  316. m.cacheMu.RUnlock()
  317. if !ok {
  318. prefix := m.dataPrefix(table)
  319. var values []string
  320. err := m.pool.WithClient(func(c *KVClient) error {
  321. var err error
  322. values, err = c.Reads(prefix)
  323. return err
  324. })
  325. if err != nil {
  326. return nil, err
  327. }
  328. loaded := make([]Row, 0, len(values))
  329. byRowID := make(map[int64]Row, len(values))
  330. for _, data := range values {
  331. var row Row
  332. if err := json.Unmarshal([]byte(data), &row); err != nil {
  333. continue
  334. }
  335. loaded = append(loaded, row)
  336. if rowid, ok := valueAsInt64(row["_rowid_"]); ok {
  337. byRowID[rowid] = row
  338. }
  339. }
  340. m.cacheMu.Lock()
  341. m.rowCache[key] = loaded
  342. m.rowIDMap[key] = byRowID
  343. m.cacheMu.Unlock()
  344. cached = loaded
  345. }
  346. if filter == nil {
  347. result := make([]Row, len(cached))
  348. copy(result, cached)
  349. return result, nil
  350. }
  351. rows := make([]Row, 0, len(cached))
  352. for _, row := range cached {
  353. if filter(row) {
  354. rows = append(rows, row)
  355. }
  356. }
  357. return rows, nil
  358. }
  359. // SelectWithLimit retrieves rows with limit and offset.
  360. func (m *TableManager) SelectWithLimit(table string, filter func(Row) bool, limit, offset int) ([]Row, error) {
  361. rows, err := m.Select(table, filter)
  362. if err != nil {
  363. return nil, err
  364. }
  365. // Apply offset
  366. if offset > 0 {
  367. if offset >= len(rows) {
  368. return nil, nil
  369. }
  370. rows = rows[offset:]
  371. }
  372. // Apply limit
  373. if limit > 0 && limit < len(rows) {
  374. rows = rows[:limit]
  375. }
  376. return rows, nil
  377. }
  378. // Update updates rows matching the filter.
  379. func (m *TableManager) Update(table string, updates Row, filter func(Row) bool) (int, error) {
  380. schema, err := m.schema.GetSchema(table)
  381. if err != nil {
  382. return 0, err
  383. }
  384. // Get all rows
  385. rows, err := m.Select(table, filter)
  386. if err != nil {
  387. return 0, err
  388. }
  389. count := 0
  390. for _, row := range rows {
  391. // Remove old index entries before update
  392. m.updateIndexesForRow(table, row, false)
  393. // Apply updates
  394. for k, v := range updates {
  395. // Normalize column name
  396. for _, col := range schema.Columns {
  397. if strings.EqualFold(k, col.Name) {
  398. row[col.Name] = v
  399. break
  400. }
  401. }
  402. }
  403. // Get primary key
  404. pkValue := row[schema.PrimaryKey]
  405. pk := fmt.Sprintf("%v", pkValue)
  406. // Serialize row
  407. data, err := json.Marshal(row)
  408. if err != nil {
  409. continue
  410. }
  411. // Write back
  412. key := m.dataKey(table, pk)
  413. err = m.pool.WithClient(func(c *KVClient) error {
  414. return c.Write(key, string(data))
  415. })
  416. if err == nil {
  417. // Add new index entries after update
  418. m.updateIndexesForRow(table, row, true)
  419. count++
  420. }
  421. }
  422. m.invalidateCache(table)
  423. return count, nil
  424. }
  425. // UpdateFunc updates rows matching the filter using a function to compute new values.
  426. // The updateFn receives the current row and returns the updates to apply.
  427. func (m *TableManager) UpdateFunc(table string, updateFn func(Row) (Row, error), filter func(Row) bool) (int, error) {
  428. schema, err := m.schema.GetSchema(table)
  429. if err != nil {
  430. return 0, err
  431. }
  432. // Get all rows
  433. rows, err := m.Select(table, filter)
  434. if err != nil {
  435. return 0, err
  436. }
  437. count := 0
  438. for _, row := range rows {
  439. // Remove old index entries before update
  440. m.updateIndexesForRow(table, row, false)
  441. // Compute updates using the provided function
  442. updates, err := updateFn(row)
  443. if err != nil {
  444. return count, err
  445. }
  446. // Apply updates
  447. for k, v := range updates {
  448. // Normalize column name
  449. for _, col := range schema.Columns {
  450. if strings.EqualFold(k, col.Name) {
  451. row[col.Name] = v
  452. break
  453. }
  454. }
  455. }
  456. // Get primary key
  457. pkValue := row[schema.PrimaryKey]
  458. pk := fmt.Sprintf("%v", pkValue)
  459. // Serialize row
  460. data, err := json.Marshal(row)
  461. if err != nil {
  462. continue
  463. }
  464. // Write back
  465. key := m.dataKey(table, pk)
  466. err = m.pool.WithClient(func(c *KVClient) error {
  467. return c.Write(key, string(data))
  468. })
  469. if err == nil {
  470. // Add new index entries after update
  471. m.updateIndexesForRow(table, row, true)
  472. count++
  473. }
  474. }
  475. m.invalidateCache(table)
  476. return count, nil
  477. }
  478. // Delete deletes rows matching the filter.
  479. func (m *TableManager) Delete(table string, filter func(Row) bool) (int, error) {
  480. schema, err := m.schema.GetSchema(table)
  481. if err != nil {
  482. return 0, err
  483. }
  484. // Get all rows
  485. rows, err := m.Select(table, filter)
  486. if err != nil {
  487. return 0, err
  488. }
  489. count := 0
  490. for _, row := range rows {
  491. // Remove index entries before deleting row
  492. m.updateIndexesForRow(table, row, false)
  493. pkValue := row[schema.PrimaryKey]
  494. pk := fmt.Sprintf("%v", pkValue)
  495. key := m.dataKey(table, pk)
  496. err = m.pool.WithClient(func(c *KVClient) error {
  497. return c.Delete(key)
  498. })
  499. if err == nil {
  500. count++
  501. }
  502. }
  503. m.invalidateCache(table)
  504. return count, nil
  505. }
  506. // GetByPK retrieves a row by primary key.
  507. func (m *TableManager) GetByPK(table string, pk string) (Row, error) {
  508. if !m.schema.TableExists(table) {
  509. return nil, fmt.Errorf("table not found: %s", table)
  510. }
  511. key := m.dataKey(table, pk)
  512. var data string
  513. err := m.pool.WithClient(func(c *KVClient) error {
  514. var err error
  515. data, err = c.Read(key)
  516. return err
  517. })
  518. if err != nil {
  519. if err == ErrKeyNotFound {
  520. return nil, fmt.Errorf("row not found: %s", pk)
  521. }
  522. return nil, err
  523. }
  524. var row Row
  525. if err := json.Unmarshal([]byte(data), &row); err != nil {
  526. return nil, fmt.Errorf("failed to parse row: %w", err)
  527. }
  528. return row, nil
  529. }
  530. // Count returns the number of rows in a table.
  531. func (m *TableManager) Count(table string, filter func(Row) bool) (int, error) {
  532. rows, err := m.Select(table, filter)
  533. if err != nil {
  534. return 0, err
  535. }
  536. return len(rows), nil
  537. }
  538. // Truncate removes all rows from a table.
  539. func (m *TableManager) Truncate(table string) (int, error) {
  540. return m.Delete(table, nil)
  541. }
  542. // isIntegerType checks if a type name is an integer type.
  543. func isIntegerType(typeName string) bool {
  544. t := strings.ToUpper(typeName)
  545. switch t {
  546. case "INTEGER", "INT", "SMALLINT", "BIGINT", "TINYINT", "MEDIUMINT":
  547. return true
  548. }
  549. return false
  550. }
  551. // IsRowIDColumn checks if a column name is a ROWID alias.
  552. func IsRowIDColumn(name string) bool {
  553. n := strings.ToLower(name)
  554. return n == "rowid" || n == "oid" || n == "_rowid_"
  555. }
  556. // Index entry methods - leveraging radix trie for prefix-based lookups
  557. // Format: {database}:idx:{index_name}:{column_value} → JSON array of rowids
  558. // indexEntryKey returns the key for an index entry.
  559. func (m *TableManager) indexEntryKey(indexName string, colValue interface{}) string {
  560. return fmt.Sprintf("%s:idx:%s:%s", m.database, strings.ToLower(indexName), formatIndexValue(colValue))
  561. }
  562. // indexPrefix returns the prefix for all entries of an index.
  563. func (m *TableManager) indexPrefix(indexName string) string {
  564. return fmt.Sprintf("%s:idx:%s:", m.database, strings.ToLower(indexName))
  565. }
  566. func formatIndexValue(value interface{}) string {
  567. switch v := value.(type) {
  568. case float64:
  569. if v == float64(int64(v)) {
  570. return fmt.Sprintf("%d", int64(v))
  571. }
  572. return fmt.Sprintf("%f", v)
  573. case int64:
  574. return fmt.Sprintf("%d", v)
  575. case int:
  576. return fmt.Sprintf("%d", v)
  577. default:
  578. return fmt.Sprintf("%v", v)
  579. }
  580. }
  581. func rowIDFromRow(row Row) (int64, bool) {
  582. switch v := row["_rowid_"].(type) {
  583. case int64:
  584. return v, true
  585. case int:
  586. return int64(v), true
  587. case float64:
  588. return int64(v), true
  589. default:
  590. return 0, false
  591. }
  592. }
  593. func (m *TableManager) ensureIndex(index *Index) error {
  594. indexKey := strings.ToLower(index.Name)
  595. m.cacheMu.RLock()
  596. _, initialized := m.indexCache[indexKey]
  597. m.cacheMu.RUnlock()
  598. if initialized {
  599. return nil
  600. }
  601. columns := make([]string, len(index.Columns))
  602. for i, col := range index.Columns {
  603. columns[i] = col.Name
  604. }
  605. rows, err := m.Select(index.Table, nil)
  606. if err != nil {
  607. return err
  608. }
  609. values := make(map[string][]int64)
  610. for _, row := range rows {
  611. rowid, ok := rowIDFromRow(row)
  612. if !ok {
  613. continue
  614. }
  615. colValue := m.buildIndexValue(row, columns)
  616. valueKey := formatIndexValue(colValue)
  617. values[valueKey] = append(values[valueKey], rowid)
  618. }
  619. m.cacheMu.Lock()
  620. if _, initialized := m.indexCache[indexKey]; !initialized {
  621. m.indexCache[indexKey] = values
  622. m.indexTable[indexKey] = strings.ToLower(index.Table)
  623. }
  624. m.cacheMu.Unlock()
  625. return nil
  626. }
  627. // AddIndexEntry adds a rowid to an in-memory index entry.
  628. func (m *TableManager) AddIndexEntry(indexName string, colValue interface{}, rowid int64) error {
  629. indexKey := strings.ToLower(indexName)
  630. valueKey := formatIndexValue(colValue)
  631. m.cacheMu.Lock()
  632. defer m.cacheMu.Unlock()
  633. values, ok := m.indexCache[indexKey]
  634. if !ok {
  635. return nil
  636. }
  637. rowids := values[valueKey]
  638. for _, r := range rowids {
  639. if r == rowid {
  640. return nil
  641. }
  642. }
  643. values[valueKey] = append(rowids, rowid)
  644. return nil
  645. }
  646. // RemoveIndexEntry removes a rowid from an in-memory index entry.
  647. func (m *TableManager) RemoveIndexEntry(indexName string, colValue interface{}, rowid int64) error {
  648. indexKey := strings.ToLower(indexName)
  649. valueKey := formatIndexValue(colValue)
  650. m.cacheMu.Lock()
  651. defer m.cacheMu.Unlock()
  652. values, ok := m.indexCache[indexKey]
  653. if !ok {
  654. return nil
  655. }
  656. rowids := values[valueKey]
  657. newRowids := make([]int64, 0, len(rowids))
  658. for _, r := range rowids {
  659. if r != rowid {
  660. newRowids = append(newRowids, r)
  661. }
  662. }
  663. if len(newRowids) == 0 {
  664. delete(values, valueKey)
  665. return nil
  666. }
  667. values[valueKey] = newRowids
  668. return nil
  669. }
  670. // LookupIndex returns rowids matching a column value using the index.
  671. func (m *TableManager) LookupIndex(indexName string, colValue interface{}) ([]int64, error) {
  672. index, err := m.schema.GetIndex(indexName)
  673. if err != nil {
  674. return nil, err
  675. }
  676. if err := m.ensureIndex(index); err != nil {
  677. return nil, err
  678. }
  679. indexKey := strings.ToLower(indexName)
  680. valueKey := formatIndexValue(colValue)
  681. m.cacheMu.RLock()
  682. rowids := append([]int64(nil), m.indexCache[indexKey][valueKey]...)
  683. m.cacheMu.RUnlock()
  684. return rowids, nil
  685. }
  686. // ClearIndex removes all entries for an index by scanning table and removing entries.
  687. func (m *TableManager) ClearIndex(indexName, tableName string, columns []string) error {
  688. rows, err := m.Select(tableName, nil)
  689. if err != nil {
  690. return err
  691. }
  692. for _, row := range rows {
  693. colValue := m.buildIndexValue(row, columns)
  694. key := m.indexEntryKey(indexName, colValue)
  695. m.pool.WithClient(func(c *KVClient) error {
  696. return c.Delete(key)
  697. })
  698. }
  699. return nil
  700. }
  701. // BuildIndex builds index entries for all existing rows in a table.
  702. func (m *TableManager) BuildIndex(indexName, tableName string, columns []string) error {
  703. index, err := m.schema.GetIndex(indexName)
  704. if err == nil {
  705. return m.ensureIndex(index)
  706. }
  707. rows, err := m.Select(tableName, nil)
  708. if err != nil {
  709. return err
  710. }
  711. values := make(map[string][]int64)
  712. for _, row := range rows {
  713. rowid, ok := rowIDFromRow(row)
  714. if !ok {
  715. continue
  716. }
  717. colValue := m.buildIndexValue(row, columns)
  718. values[formatIndexValue(colValue)] = append(values[formatIndexValue(colValue)], rowid)
  719. }
  720. indexKey := strings.ToLower(indexName)
  721. m.cacheMu.Lock()
  722. m.indexCache[indexKey] = values
  723. m.indexTable[indexKey] = strings.ToLower(tableName)
  724. m.cacheMu.Unlock()
  725. return nil
  726. }
  727. // buildIndexValue creates the index key value from row columns.
  728. func (m *TableManager) buildIndexValue(row Row, columns []string) string {
  729. formatValue := func(v interface{}) string {
  730. switch val := v.(type) {
  731. case float64:
  732. // Check if it's actually an integer value
  733. if val == float64(int64(val)) {
  734. return fmt.Sprintf("%d", int64(val))
  735. }
  736. return fmt.Sprintf("%f", val)
  737. case int64:
  738. return fmt.Sprintf("%d", val)
  739. case int:
  740. return fmt.Sprintf("%d", val)
  741. default:
  742. return fmt.Sprintf("%v", val)
  743. }
  744. }
  745. if len(columns) == 1 {
  746. return formatValue(row[columns[0]])
  747. }
  748. // Multi-column index: concatenate values with separator
  749. var parts []string
  750. for _, col := range columns {
  751. parts = append(parts, formatValue(row[col]))
  752. }
  753. return strings.Join(parts, "\x00")
  754. }
  755. // SelectByIndex retrieves rows using an index lookup.
  756. func (m *TableManager) SelectByIndex(table, indexName string, colValue interface{}) ([]Row, error) {
  757. rowids, err := m.LookupIndex(indexName, colValue)
  758. if err != nil {
  759. return nil, err
  760. }
  761. // If no rowids found, return empty result
  762. if len(rowids) == 0 {
  763. return []Row{}, nil
  764. }
  765. // Build a set of target rowids for O(1) lookup.
  766. key := strings.ToLower(table)
  767. m.cacheMu.RLock()
  768. byRowID, ok := m.rowIDMap[key]
  769. m.cacheMu.RUnlock()
  770. if !ok {
  771. if _, err := m.Select(table, nil); err != nil {
  772. return nil, err
  773. }
  774. m.cacheMu.RLock()
  775. byRowID = m.rowIDMap[key]
  776. m.cacheMu.RUnlock()
  777. }
  778. rows := make([]Row, 0, len(rowids))
  779. seen := make(map[int64]struct{}, len(rowids))
  780. for _, rid := range rowids {
  781. if _, duplicate := seen[rid]; duplicate {
  782. continue
  783. }
  784. seen[rid] = struct{}{}
  785. if row, ok := byRowID[rid]; ok {
  786. rows = append(rows, row)
  787. }
  788. }
  789. return rows, nil
  790. }