2
0

table.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926
  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. for i, row := range cached {
  349. result[i] = cloneRow(row)
  350. }
  351. return result, nil
  352. }
  353. rows := make([]Row, 0, len(cached))
  354. for _, row := range cached {
  355. if filter(row) {
  356. rows = append(rows, cloneRow(row))
  357. }
  358. }
  359. return rows, nil
  360. }
  361. func cloneRow(row Row) Row {
  362. if row == nil {
  363. return nil
  364. }
  365. cloned := make(Row, len(row))
  366. for k, v := range row {
  367. cloned[k] = v
  368. }
  369. return cloned
  370. }
  371. // SelectWithLimit retrieves rows with limit and offset.
  372. func (m *TableManager) SelectWithLimit(table string, filter func(Row) bool, limit, offset int) ([]Row, error) {
  373. rows, err := m.Select(table, filter)
  374. if err != nil {
  375. return nil, err
  376. }
  377. // Apply offset
  378. if offset > 0 {
  379. if offset >= len(rows) {
  380. return nil, nil
  381. }
  382. rows = rows[offset:]
  383. }
  384. // Apply limit
  385. if limit > 0 && limit < len(rows) {
  386. rows = rows[:limit]
  387. }
  388. return rows, nil
  389. }
  390. // Update updates rows matching the filter.
  391. func (m *TableManager) Update(table string, updates Row, filter func(Row) bool) (int, error) {
  392. schema, err := m.schema.GetSchema(table)
  393. if err != nil {
  394. return 0, err
  395. }
  396. // Get all rows
  397. rows, err := m.Select(table, filter)
  398. if err != nil {
  399. return 0, err
  400. }
  401. count := 0
  402. for _, row := range rows {
  403. // Remove old index entries before update
  404. m.updateIndexesForRow(table, row, false)
  405. // Apply updates
  406. for k, v := range updates {
  407. // Normalize column name
  408. for _, col := range schema.Columns {
  409. if strings.EqualFold(k, col.Name) {
  410. row[col.Name] = v
  411. break
  412. }
  413. }
  414. }
  415. // Get primary key
  416. pkValue := row[schema.PrimaryKey]
  417. pk := fmt.Sprintf("%v", pkValue)
  418. // Serialize row
  419. data, err := json.Marshal(row)
  420. if err != nil {
  421. continue
  422. }
  423. // Write back
  424. key := m.dataKey(table, pk)
  425. err = m.pool.WithClient(func(c *KVClient) error {
  426. return c.Write(key, string(data))
  427. })
  428. if err == nil {
  429. // Add new index entries after update
  430. m.updateIndexesForRow(table, row, true)
  431. count++
  432. }
  433. }
  434. m.invalidateCache(table)
  435. return count, nil
  436. }
  437. // UpdateFunc updates rows matching the filter using a function to compute new values.
  438. // The updateFn receives the current row and returns the updates to apply.
  439. func (m *TableManager) UpdateFunc(table string, updateFn func(Row) (Row, error), filter func(Row) bool) (int, error) {
  440. schema, err := m.schema.GetSchema(table)
  441. if err != nil {
  442. return 0, err
  443. }
  444. // Get all rows
  445. rows, err := m.Select(table, filter)
  446. if err != nil {
  447. return 0, err
  448. }
  449. count := 0
  450. for _, row := range rows {
  451. // Remove old index entries before update
  452. m.updateIndexesForRow(table, row, false)
  453. // Compute updates using the provided function
  454. updates, err := updateFn(row)
  455. if err != nil {
  456. return count, err
  457. }
  458. // Apply updates
  459. for k, v := range updates {
  460. // Normalize column name
  461. for _, col := range schema.Columns {
  462. if strings.EqualFold(k, col.Name) {
  463. row[col.Name] = v
  464. break
  465. }
  466. }
  467. }
  468. // Get primary key
  469. pkValue := row[schema.PrimaryKey]
  470. pk := fmt.Sprintf("%v", pkValue)
  471. // Serialize row
  472. data, err := json.Marshal(row)
  473. if err != nil {
  474. continue
  475. }
  476. // Write back
  477. key := m.dataKey(table, pk)
  478. err = m.pool.WithClient(func(c *KVClient) error {
  479. return c.Write(key, string(data))
  480. })
  481. if err == nil {
  482. // Add new index entries after update
  483. m.updateIndexesForRow(table, row, true)
  484. count++
  485. }
  486. }
  487. m.invalidateCache(table)
  488. return count, nil
  489. }
  490. // Delete deletes rows matching the filter.
  491. func (m *TableManager) Delete(table string, filter func(Row) bool) (int, error) {
  492. schema, err := m.schema.GetSchema(table)
  493. if err != nil {
  494. return 0, err
  495. }
  496. // Get all rows
  497. rows, err := m.Select(table, filter)
  498. if err != nil {
  499. return 0, err
  500. }
  501. count := 0
  502. for _, row := range rows {
  503. // Remove index entries before deleting row
  504. m.updateIndexesForRow(table, row, false)
  505. pkValue := row[schema.PrimaryKey]
  506. pk := fmt.Sprintf("%v", pkValue)
  507. key := m.dataKey(table, pk)
  508. err = m.pool.WithClient(func(c *KVClient) error {
  509. return c.Delete(key)
  510. })
  511. if err == nil {
  512. count++
  513. }
  514. }
  515. m.invalidateCache(table)
  516. return count, nil
  517. }
  518. // GetByPK retrieves a row by primary key.
  519. func (m *TableManager) GetByPK(table string, pk string) (Row, error) {
  520. if !m.schema.TableExists(table) {
  521. return nil, fmt.Errorf("table not found: %s", table)
  522. }
  523. key := m.dataKey(table, pk)
  524. var data string
  525. err := m.pool.WithClient(func(c *KVClient) error {
  526. var err error
  527. data, err = c.Read(key)
  528. return err
  529. })
  530. if err != nil {
  531. if err == ErrKeyNotFound {
  532. return nil, fmt.Errorf("row not found: %s", pk)
  533. }
  534. return nil, err
  535. }
  536. var row Row
  537. if err := json.Unmarshal([]byte(data), &row); err != nil {
  538. return nil, fmt.Errorf("failed to parse row: %w", err)
  539. }
  540. return row, nil
  541. }
  542. // Count returns the number of rows in a table.
  543. func (m *TableManager) Count(table string, filter func(Row) bool) (int, error) {
  544. rows, err := m.Select(table, filter)
  545. if err != nil {
  546. return 0, err
  547. }
  548. return len(rows), nil
  549. }
  550. // Truncate removes all rows from a table.
  551. func (m *TableManager) Truncate(table string) (int, error) {
  552. return m.Delete(table, nil)
  553. }
  554. // isIntegerType checks if a type name is an integer type.
  555. func isIntegerType(typeName string) bool {
  556. t := strings.ToUpper(typeName)
  557. switch t {
  558. case "INTEGER", "INT", "SMALLINT", "BIGINT", "TINYINT", "MEDIUMINT":
  559. return true
  560. }
  561. return false
  562. }
  563. // IsRowIDColumn checks if a column name is a ROWID alias.
  564. func IsRowIDColumn(name string) bool {
  565. n := strings.ToLower(name)
  566. return n == "rowid" || n == "oid" || n == "_rowid_"
  567. }
  568. // Index entry methods - leveraging radix trie for prefix-based lookups
  569. // Format: {database}:idx:{index_name}:{column_value} → JSON array of rowids
  570. // indexEntryKey returns the key for an index entry.
  571. func (m *TableManager) indexEntryKey(indexName string, colValue interface{}) string {
  572. return fmt.Sprintf("%s:idx:%s:%s", m.database, strings.ToLower(indexName), formatIndexValue(colValue))
  573. }
  574. // indexPrefix returns the prefix for all entries of an index.
  575. func (m *TableManager) indexPrefix(indexName string) string {
  576. return fmt.Sprintf("%s:idx:%s:", m.database, strings.ToLower(indexName))
  577. }
  578. func formatIndexValue(value interface{}) string {
  579. switch v := value.(type) {
  580. case float64:
  581. if v == float64(int64(v)) {
  582. return fmt.Sprintf("%d", int64(v))
  583. }
  584. return fmt.Sprintf("%f", v)
  585. case int64:
  586. return fmt.Sprintf("%d", v)
  587. case int:
  588. return fmt.Sprintf("%d", v)
  589. default:
  590. return fmt.Sprintf("%v", v)
  591. }
  592. }
  593. func rowIDFromRow(row Row) (int64, bool) {
  594. switch v := row["_rowid_"].(type) {
  595. case int64:
  596. return v, true
  597. case int:
  598. return int64(v), true
  599. case float64:
  600. return int64(v), true
  601. default:
  602. return 0, false
  603. }
  604. }
  605. func (m *TableManager) ensureIndex(index *Index) error {
  606. indexKey := strings.ToLower(index.Name)
  607. m.cacheMu.RLock()
  608. _, initialized := m.indexCache[indexKey]
  609. m.cacheMu.RUnlock()
  610. if initialized {
  611. return nil
  612. }
  613. columns := make([]string, len(index.Columns))
  614. for i, col := range index.Columns {
  615. columns[i] = col.Name
  616. }
  617. rows, err := m.Select(index.Table, nil)
  618. if err != nil {
  619. return err
  620. }
  621. values := make(map[string][]int64)
  622. for _, row := range rows {
  623. rowid, ok := rowIDFromRow(row)
  624. if !ok {
  625. continue
  626. }
  627. colValue := m.buildIndexValue(row, columns)
  628. valueKey := formatIndexValue(colValue)
  629. values[valueKey] = append(values[valueKey], rowid)
  630. }
  631. m.cacheMu.Lock()
  632. if _, initialized := m.indexCache[indexKey]; !initialized {
  633. m.indexCache[indexKey] = values
  634. m.indexTable[indexKey] = strings.ToLower(index.Table)
  635. }
  636. m.cacheMu.Unlock()
  637. return nil
  638. }
  639. // AddIndexEntry adds a rowid to an in-memory index entry.
  640. func (m *TableManager) AddIndexEntry(indexName string, colValue interface{}, rowid int64) error {
  641. indexKey := strings.ToLower(indexName)
  642. valueKey := formatIndexValue(colValue)
  643. m.cacheMu.Lock()
  644. defer m.cacheMu.Unlock()
  645. values, ok := m.indexCache[indexKey]
  646. if !ok {
  647. return nil
  648. }
  649. rowids := values[valueKey]
  650. for _, r := range rowids {
  651. if r == rowid {
  652. return nil
  653. }
  654. }
  655. values[valueKey] = append(rowids, rowid)
  656. return nil
  657. }
  658. // RemoveIndexEntry removes a rowid from an in-memory index entry.
  659. func (m *TableManager) RemoveIndexEntry(indexName string, colValue interface{}, rowid int64) error {
  660. indexKey := strings.ToLower(indexName)
  661. valueKey := formatIndexValue(colValue)
  662. m.cacheMu.Lock()
  663. defer m.cacheMu.Unlock()
  664. values, ok := m.indexCache[indexKey]
  665. if !ok {
  666. return nil
  667. }
  668. rowids := values[valueKey]
  669. newRowids := make([]int64, 0, len(rowids))
  670. for _, r := range rowids {
  671. if r != rowid {
  672. newRowids = append(newRowids, r)
  673. }
  674. }
  675. if len(newRowids) == 0 {
  676. delete(values, valueKey)
  677. return nil
  678. }
  679. values[valueKey] = newRowids
  680. return nil
  681. }
  682. // LookupIndex returns rowids matching a column value using the index.
  683. func (m *TableManager) LookupIndex(indexName string, colValue interface{}) ([]int64, error) {
  684. index, err := m.schema.GetIndex(indexName)
  685. if err != nil {
  686. return nil, err
  687. }
  688. if err := m.ensureIndex(index); err != nil {
  689. return nil, err
  690. }
  691. indexKey := strings.ToLower(indexName)
  692. valueKey := formatIndexValue(colValue)
  693. m.cacheMu.RLock()
  694. rowids := append([]int64(nil), m.indexCache[indexKey][valueKey]...)
  695. m.cacheMu.RUnlock()
  696. return rowids, nil
  697. }
  698. // ClearIndex removes all entries for an index by scanning table and removing entries.
  699. func (m *TableManager) ClearIndex(indexName, tableName string, columns []string) error {
  700. rows, err := m.Select(tableName, nil)
  701. if err != nil {
  702. return err
  703. }
  704. for _, row := range rows {
  705. colValue := m.buildIndexValue(row, columns)
  706. key := m.indexEntryKey(indexName, colValue)
  707. m.pool.WithClient(func(c *KVClient) error {
  708. return c.Delete(key)
  709. })
  710. }
  711. return nil
  712. }
  713. // BuildIndex builds index entries for all existing rows in a table.
  714. func (m *TableManager) BuildIndex(indexName, tableName string, columns []string) error {
  715. index, err := m.schema.GetIndex(indexName)
  716. if err == nil {
  717. return m.ensureIndex(index)
  718. }
  719. rows, err := m.Select(tableName, nil)
  720. if err != nil {
  721. return err
  722. }
  723. values := make(map[string][]int64)
  724. for _, row := range rows {
  725. rowid, ok := rowIDFromRow(row)
  726. if !ok {
  727. continue
  728. }
  729. colValue := m.buildIndexValue(row, columns)
  730. values[formatIndexValue(colValue)] = append(values[formatIndexValue(colValue)], rowid)
  731. }
  732. indexKey := strings.ToLower(indexName)
  733. m.cacheMu.Lock()
  734. m.indexCache[indexKey] = values
  735. m.indexTable[indexKey] = strings.ToLower(tableName)
  736. m.cacheMu.Unlock()
  737. return nil
  738. }
  739. // buildIndexValue creates the index key value from row columns.
  740. func (m *TableManager) buildIndexValue(row Row, columns []string) string {
  741. formatValue := func(v interface{}) string {
  742. switch val := v.(type) {
  743. case float64:
  744. // Check if it's actually an integer value
  745. if val == float64(int64(val)) {
  746. return fmt.Sprintf("%d", int64(val))
  747. }
  748. return fmt.Sprintf("%f", val)
  749. case int64:
  750. return fmt.Sprintf("%d", val)
  751. case int:
  752. return fmt.Sprintf("%d", val)
  753. default:
  754. return fmt.Sprintf("%v", val)
  755. }
  756. }
  757. if len(columns) == 1 {
  758. return formatValue(row[columns[0]])
  759. }
  760. // Multi-column index: concatenate values with separator
  761. var parts []string
  762. for _, col := range columns {
  763. parts = append(parts, formatValue(row[col]))
  764. }
  765. return strings.Join(parts, "\x00")
  766. }
  767. // SelectByIndex retrieves rows using an index lookup.
  768. func (m *TableManager) SelectByIndex(table, indexName string, colValue interface{}) ([]Row, error) {
  769. rowids, err := m.LookupIndex(indexName, colValue)
  770. if err != nil {
  771. return nil, err
  772. }
  773. // If no rowids found, return empty result
  774. if len(rowids) == 0 {
  775. return []Row{}, nil
  776. }
  777. // Build a set of target rowids for O(1) lookup.
  778. key := strings.ToLower(table)
  779. m.cacheMu.RLock()
  780. byRowID, ok := m.rowIDMap[key]
  781. m.cacheMu.RUnlock()
  782. if !ok {
  783. if _, err := m.Select(table, nil); err != nil {
  784. return nil, err
  785. }
  786. m.cacheMu.RLock()
  787. byRowID = m.rowIDMap[key]
  788. m.cacheMu.RUnlock()
  789. }
  790. rows := make([]Row, 0, len(rowids))
  791. seen := make(map[int64]struct{}, len(rowids))
  792. for _, rid := range rowids {
  793. if _, duplicate := seen[rid]; duplicate {
  794. continue
  795. }
  796. seen[rid] = struct{}{}
  797. if row, ok := byRowID[rid]; ok {
  798. rows = append(rows, row)
  799. }
  800. }
  801. return rows, nil
  802. }