2
0

schema.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926
  1. package storage
  2. import (
  3. "fmt"
  4. "strings"
  5. "sync"
  6. "time"
  7. "github.com/goccy/go-json"
  8. "github.com/danfragoso/pizzasql-next/pkg/analyzer"
  9. )
  10. // Schema represents a table schema.
  11. type Schema struct {
  12. Name string `json:"name"`
  13. Columns []Column `json:"columns"`
  14. PrimaryKey string `json:"primary_key"`
  15. CreatedAt time.Time `json:"created_at"`
  16. NextRowID int64 `json:"next_rowid"`
  17. AutoIncrement bool `json:"autoincrement"`
  18. }
  19. // Column represents a column definition.
  20. type Column struct {
  21. Name string `json:"name"`
  22. Type string `json:"type"`
  23. Nullable bool `json:"nullable"`
  24. Default interface{} `json:"default,omitempty"`
  25. PrimaryKey bool `json:"primary_key"`
  26. }
  27. // Index represents an index definition.
  28. type Index struct {
  29. Name string `json:"name"`
  30. Table string `json:"table"`
  31. Columns []IndexColumn `json:"columns"`
  32. Unique bool `json:"unique"`
  33. CreatedAt time.Time `json:"created_at"`
  34. }
  35. // IndexColumn represents a column in an index.
  36. type IndexColumn struct {
  37. Name string `json:"name"`
  38. Desc bool `json:"desc"`
  39. }
  40. // SchemaManager manages table schemas.
  41. type SchemaManager struct {
  42. pool *KVPool
  43. database string
  44. cache map[string]*Schema
  45. mu sync.RWMutex
  46. }
  47. // NewSchemaManager creates a new schema manager.
  48. func NewSchemaManager(pool *KVPool, database string) *SchemaManager {
  49. return &SchemaManager{
  50. pool: pool,
  51. database: database,
  52. cache: make(map[string]*Schema),
  53. }
  54. }
  55. // GetDatabaseName returns the database name.
  56. func (m *SchemaManager) GetDatabaseName() string {
  57. return m.database
  58. }
  59. // GetPool returns the KV pool.
  60. func (m *SchemaManager) GetPool() *KVPool {
  61. return m.pool
  62. }
  63. // schemaKey returns the key for a table schema.
  64. func (m *SchemaManager) schemaKey(table string) string {
  65. return fmt.Sprintf("%s:_schema:%s", m.database, strings.ToLower(table))
  66. }
  67. // catalogKey returns the key for the table catalog.
  68. func (m *SchemaManager) catalogKey() string {
  69. return fmt.Sprintf("%s:_sys:tables", m.database)
  70. }
  71. // rowIDKey returns the key for a table's next ROWID counter.
  72. func (m *SchemaManager) rowIDKey(table string) string {
  73. return fmt.Sprintf("%s:_sys:rowid:%s", m.database, strings.ToLower(table))
  74. }
  75. // CreateTable creates a new table.
  76. func (m *SchemaManager) CreateTable(schema *Schema) error {
  77. m.mu.Lock()
  78. defer m.mu.Unlock()
  79. // Check if table already exists
  80. key := m.schemaKey(schema.Name)
  81. err := m.pool.WithClient(func(c *KVClient) error {
  82. _, err := c.Read(key)
  83. return err
  84. })
  85. if err == nil {
  86. return fmt.Errorf("table already exists: %s", schema.Name)
  87. }
  88. // Set creation time
  89. schema.CreatedAt = time.Now()
  90. // Determine primary key if not set
  91. if schema.PrimaryKey == "" {
  92. for _, col := range schema.Columns {
  93. if col.PrimaryKey {
  94. schema.PrimaryKey = col.Name
  95. break
  96. }
  97. }
  98. // No explicit primary key declared — use synthetic _rowid_ so user
  99. // columns remain unconstrained and can hold duplicate or NULL values.
  100. if schema.PrimaryKey == "" {
  101. schema.PrimaryKey = "_rowid_"
  102. }
  103. }
  104. // Serialize schema
  105. data, err := json.Marshal(schema)
  106. if err != nil {
  107. return fmt.Errorf("failed to serialize schema: %w", err)
  108. }
  109. // Write schema
  110. err = m.pool.WithClient(func(c *KVClient) error {
  111. return c.Write(key, string(data))
  112. })
  113. if err != nil {
  114. return fmt.Errorf("failed to write schema: %w", err)
  115. }
  116. // Update catalog
  117. if err := m.addToCatalog(schema.Name); err != nil {
  118. // Rollback schema write
  119. m.pool.WithClient(func(c *KVClient) error {
  120. return c.Delete(key)
  121. })
  122. return err
  123. }
  124. // Update cache
  125. m.cache[strings.ToLower(schema.Name)] = schema
  126. return nil
  127. }
  128. // DropTable drops a table.
  129. func (m *SchemaManager) DropTable(name string) error {
  130. m.mu.Lock()
  131. defer m.mu.Unlock()
  132. key := m.schemaKey(name)
  133. // Check if table exists
  134. err := m.pool.WithClient(func(c *KVClient) error {
  135. _, err := c.Read(key)
  136. return err
  137. })
  138. if err != nil {
  139. return fmt.Errorf("table not found: %s", name)
  140. }
  141. // Delete all rows
  142. dataPrefix := fmt.Sprintf("%s:_data:%s:", m.database, strings.ToLower(name))
  143. err = m.pool.WithClient(func(c *KVClient) error {
  144. // Get all keys with this prefix and delete them
  145. // Note: This is a simplified version - in production you'd want batch delete
  146. values, err := c.Reads(dataPrefix)
  147. if err != nil {
  148. return err
  149. }
  150. // The Reads command returns values, not keys, so we can't delete them directly
  151. // In a real implementation, we'd need a keys scan command
  152. _ = values
  153. return nil
  154. })
  155. // Delete schema
  156. err = m.pool.WithClient(func(c *KVClient) error {
  157. return c.Delete(key)
  158. })
  159. if err != nil {
  160. return fmt.Errorf("failed to delete schema: %w", err)
  161. }
  162. // Delete ROWID state.
  163. m.pool.WithClient(func(c *KVClient) error {
  164. return c.Delete(m.rowIDKey(name))
  165. })
  166. // Update catalog
  167. if err := m.removeFromCatalog(name); err != nil {
  168. return err
  169. }
  170. // Update cache
  171. delete(m.cache, strings.ToLower(name))
  172. return nil
  173. }
  174. // GetSchema retrieves a table schema.
  175. func (m *SchemaManager) GetSchema(name string) (*Schema, error) {
  176. m.mu.RLock()
  177. if schema, ok := m.cache[strings.ToLower(name)]; ok {
  178. m.mu.RUnlock()
  179. return schema, nil
  180. }
  181. m.mu.RUnlock()
  182. m.mu.Lock()
  183. defer m.mu.Unlock()
  184. // Double-check after acquiring write lock
  185. if schema, ok := m.cache[strings.ToLower(name)]; ok {
  186. return schema, nil
  187. }
  188. key := m.schemaKey(name)
  189. var data string
  190. err := m.pool.WithClient(func(c *KVClient) error {
  191. var err error
  192. data, err = c.Read(key)
  193. return err
  194. })
  195. if err != nil {
  196. if err == ErrKeyNotFound {
  197. return nil, fmt.Errorf("table not found: %s", name)
  198. }
  199. return nil, err
  200. }
  201. var schema Schema
  202. if err := json.Unmarshal([]byte(data), &schema); err != nil {
  203. return nil, fmt.Errorf("failed to parse schema: %w", err)
  204. }
  205. m.cache[strings.ToLower(name)] = &schema
  206. return &schema, nil
  207. }
  208. // TableExists checks if a table exists.
  209. func (m *SchemaManager) TableExists(name string) bool {
  210. _, err := m.GetSchema(name)
  211. return err == nil
  212. }
  213. // ListTables returns all table names.
  214. func (m *SchemaManager) ListTables() ([]string, error) {
  215. var data string
  216. err := m.pool.WithClient(func(c *KVClient) error {
  217. var err error
  218. data, err = c.Read(m.catalogKey())
  219. return err
  220. })
  221. if err != nil {
  222. if err == ErrKeyNotFound {
  223. return nil, nil
  224. }
  225. return nil, err
  226. }
  227. var tables []string
  228. if err := json.Unmarshal([]byte(data), &tables); err != nil {
  229. return nil, fmt.Errorf("failed to parse catalog: %w", err)
  230. }
  231. return tables, nil
  232. }
  233. // addToCatalog adds a table to the catalog.
  234. func (m *SchemaManager) addToCatalog(name string) error {
  235. tables, err := m.ListTables()
  236. if err != nil && err != ErrKeyNotFound {
  237. return err
  238. }
  239. // Check if already exists
  240. lowerName := strings.ToLower(name)
  241. for _, t := range tables {
  242. if strings.ToLower(t) == lowerName {
  243. return nil
  244. }
  245. }
  246. tables = append(tables, name)
  247. data, err := json.Marshal(tables)
  248. if err != nil {
  249. return err
  250. }
  251. return m.pool.WithClient(func(c *KVClient) error {
  252. return c.Write(m.catalogKey(), string(data))
  253. })
  254. }
  255. // removeFromCatalog removes a table from the catalog.
  256. func (m *SchemaManager) removeFromCatalog(name string) error {
  257. tables, err := m.ListTables()
  258. if err != nil {
  259. return err
  260. }
  261. lowerName := strings.ToLower(name)
  262. newTables := make([]string, 0, len(tables))
  263. for _, t := range tables {
  264. if strings.ToLower(t) != lowerName {
  265. newTables = append(newTables, t)
  266. }
  267. }
  268. data, err := json.Marshal(newTables)
  269. if err != nil {
  270. return err
  271. }
  272. return m.pool.WithClient(func(c *KVClient) error {
  273. return c.Write(m.catalogKey(), string(data))
  274. })
  275. }
  276. // InvalidateCache clears the cache for a table.
  277. func (m *SchemaManager) InvalidateCache(name string) {
  278. m.mu.Lock()
  279. defer m.mu.Unlock()
  280. delete(m.cache, strings.ToLower(name))
  281. }
  282. // ToAnalyzerTableInfo converts a Schema to analyzer.TableInfo.
  283. func (s *Schema) ToAnalyzerTableInfo() *analyzer.TableInfo {
  284. info := &analyzer.TableInfo{
  285. Name: s.Name,
  286. }
  287. for _, col := range s.Columns {
  288. info.Columns = append(info.Columns, analyzer.ColumnInfo{
  289. Name: col.Name,
  290. Type: analyzer.TypeFromName(col.Type),
  291. Nullable: col.Nullable,
  292. PrimaryKey: col.PrimaryKey,
  293. TableName: s.Name,
  294. })
  295. }
  296. return info
  297. }
  298. // GetColumn returns a column by name.
  299. func (s *Schema) GetColumn(name string) (*Column, bool) {
  300. lowerName := strings.ToLower(name)
  301. for i := range s.Columns {
  302. if strings.ToLower(s.Columns[i].Name) == lowerName {
  303. return &s.Columns[i], true
  304. }
  305. }
  306. return nil, false
  307. }
  308. // GetNextRowID gets and increments the next ROWID for a table.
  309. func (m *SchemaManager) GetNextRowID(table string) (int64, error) {
  310. m.mu.Lock()
  311. defer m.mu.Unlock()
  312. schema, err := m.getSchemaLocked(table)
  313. if err != nil {
  314. return 0, err
  315. }
  316. nextRowID, err := m.getNextRowIDLocked(schema)
  317. if err != nil {
  318. return 0, err
  319. }
  320. if err := m.saveNextRowIDLocked(schema.Name, nextRowID+1); err != nil {
  321. return 0, err
  322. }
  323. return nextRowID, nil
  324. }
  325. // UpdateMaxRowID updates the next ROWID if the provided value is higher.
  326. func (m *SchemaManager) UpdateMaxRowID(table string, rowid int64) error {
  327. m.mu.Lock()
  328. defer m.mu.Unlock()
  329. schema, err := m.getSchemaLocked(table)
  330. if err != nil {
  331. return err
  332. }
  333. nextRowID, err := m.getNextRowIDLocked(schema)
  334. if err != nil {
  335. return err
  336. }
  337. if rowid >= nextRowID {
  338. return m.saveNextRowIDLocked(schema.Name, rowid+1)
  339. }
  340. return nil
  341. }
  342. // getNextRowIDLocked reads a table's next ROWID counter (must hold lock).
  343. func (m *SchemaManager) getNextRowIDLocked(schema *Schema) (int64, error) {
  344. key := m.rowIDKey(schema.Name)
  345. var data string
  346. err := m.pool.WithClient(func(c *KVClient) error {
  347. var err error
  348. data, err = c.Read(key)
  349. return err
  350. })
  351. if err == nil {
  352. var nextRowID int64
  353. if _, scanErr := fmt.Sscanf(data, "%d", &nextRowID); scanErr != nil {
  354. return 0, fmt.Errorf("failed to parse rowid counter: %w", scanErr)
  355. }
  356. if nextRowID < 1 {
  357. nextRowID = 1
  358. }
  359. return nextRowID, nil
  360. }
  361. if err != ErrKeyNotFound {
  362. return 0, err
  363. }
  364. if schema.NextRowID > 0 {
  365. return schema.NextRowID, nil
  366. }
  367. return 1, nil
  368. }
  369. // saveNextRowIDLocked saves a table's next ROWID counter (must hold lock).
  370. func (m *SchemaManager) saveNextRowIDLocked(table string, nextRowID int64) error {
  371. if nextRowID < 1 {
  372. nextRowID = 1
  373. }
  374. err := m.pool.WithClient(func(c *KVClient) error {
  375. return c.Write(m.rowIDKey(table), fmt.Sprintf("%d", nextRowID))
  376. })
  377. if err != nil {
  378. return fmt.Errorf("failed to write rowid counter: %w", err)
  379. }
  380. if schema, ok := m.cache[strings.ToLower(table)]; ok {
  381. schema.NextRowID = nextRowID
  382. }
  383. return nil
  384. }
  385. // getSchemaLocked retrieves schema (must hold lock).
  386. func (m *SchemaManager) getSchemaLocked(name string) (*Schema, error) {
  387. if schema, ok := m.cache[strings.ToLower(name)]; ok {
  388. return schema, nil
  389. }
  390. key := m.schemaKey(name)
  391. var data string
  392. err := m.pool.WithClient(func(c *KVClient) error {
  393. var err error
  394. data, err = c.Read(key)
  395. return err
  396. })
  397. if err != nil {
  398. if err == ErrKeyNotFound {
  399. return nil, fmt.Errorf("table not found: %s", name)
  400. }
  401. return nil, err
  402. }
  403. var schema Schema
  404. if err := json.Unmarshal([]byte(data), &schema); err != nil {
  405. return nil, fmt.Errorf("failed to parse schema: %w", err)
  406. }
  407. m.cache[strings.ToLower(name)] = &schema
  408. return &schema, nil
  409. }
  410. // saveSchemaLocked saves schema (must hold lock).
  411. func (m *SchemaManager) saveSchemaLocked(schema *Schema) error {
  412. data, err := json.Marshal(schema)
  413. if err != nil {
  414. return fmt.Errorf("failed to serialize schema: %w", err)
  415. }
  416. key := m.schemaKey(schema.Name)
  417. err = m.pool.WithClient(func(c *KVClient) error {
  418. return c.Write(key, string(data))
  419. })
  420. if err != nil {
  421. return fmt.Errorf("failed to write schema: %w", err)
  422. }
  423. m.cache[strings.ToLower(schema.Name)] = schema
  424. return nil
  425. }
  426. // Index management methods
  427. // indexKey returns the key for an index.
  428. func (m *SchemaManager) indexKey(name string) string {
  429. return fmt.Sprintf("%s:index:%s", m.database, strings.ToLower(name))
  430. }
  431. // indexListKey returns the key for the index list.
  432. func (m *SchemaManager) indexListKey() string {
  433. return fmt.Sprintf("%s:indexes", m.database)
  434. }
  435. // CreateIndex creates a new index.
  436. func (m *SchemaManager) CreateIndex(index *Index) error {
  437. m.mu.Lock()
  438. defer m.mu.Unlock()
  439. // Check if index already exists
  440. key := m.indexKey(index.Name)
  441. err := m.pool.WithClient(func(c *KVClient) error {
  442. _, err := c.Read(key)
  443. return err
  444. })
  445. if err == nil {
  446. return fmt.Errorf("index already exists: %s", index.Name)
  447. }
  448. // Verify table exists
  449. if _, err := m.getSchemaLocked(index.Table); err != nil {
  450. return fmt.Errorf("table not found: %s", index.Table)
  451. }
  452. // Save index
  453. index.CreatedAt = time.Now()
  454. data, err := json.Marshal(index)
  455. if err != nil {
  456. return fmt.Errorf("failed to serialize index: %w", err)
  457. }
  458. err = m.pool.WithClient(func(c *KVClient) error {
  459. return c.Write(key, string(data))
  460. })
  461. if err != nil {
  462. return fmt.Errorf("failed to write index: %w", err)
  463. }
  464. // Add to index list
  465. return m.addToIndexList(index.Name)
  466. }
  467. // DropIndex drops an index.
  468. func (m *SchemaManager) DropIndex(name string) error {
  469. m.mu.Lock()
  470. defer m.mu.Unlock()
  471. key := m.indexKey(name)
  472. err := m.pool.WithClient(func(c *KVClient) error {
  473. return c.Delete(key)
  474. })
  475. if err != nil {
  476. return fmt.Errorf("failed to delete index: %w", err)
  477. }
  478. return m.removeFromIndexList(name)
  479. }
  480. // IndexExists checks if an index exists.
  481. func (m *SchemaManager) IndexExists(name string) bool {
  482. m.mu.RLock()
  483. defer m.mu.RUnlock()
  484. key := m.indexKey(name)
  485. err := m.pool.WithClient(func(c *KVClient) error {
  486. _, err := c.Read(key)
  487. return err
  488. })
  489. return err == nil
  490. }
  491. // GetIndex retrieves an index by name.
  492. func (m *SchemaManager) GetIndex(name string) (*Index, error) {
  493. m.mu.RLock()
  494. defer m.mu.RUnlock()
  495. key := m.indexKey(name)
  496. var data string
  497. err := m.pool.WithClient(func(c *KVClient) error {
  498. var err error
  499. data, err = c.Read(key)
  500. return err
  501. })
  502. if err != nil {
  503. return nil, fmt.Errorf("index not found: %s", name)
  504. }
  505. var index Index
  506. if err := json.Unmarshal([]byte(data), &index); err != nil {
  507. return nil, fmt.Errorf("failed to parse index: %w", err)
  508. }
  509. return &index, nil
  510. }
  511. // ListIndexes returns all index names.
  512. func (m *SchemaManager) ListIndexes() ([]string, error) {
  513. m.mu.RLock()
  514. defer m.mu.RUnlock()
  515. key := m.indexListKey()
  516. var data string
  517. err := m.pool.WithClient(func(c *KVClient) error {
  518. var err error
  519. data, err = c.Read(key)
  520. return err
  521. })
  522. if err != nil {
  523. return []string{}, nil
  524. }
  525. var indexes []string
  526. if err := json.Unmarshal([]byte(data), &indexes); err != nil {
  527. return []string{}, nil
  528. }
  529. return indexes, nil
  530. }
  531. // ListTableIndexes returns all indexes for a table.
  532. func (m *SchemaManager) ListTableIndexes(table string) ([]*Index, error) {
  533. indexes, err := m.ListIndexes()
  534. if err != nil {
  535. return nil, err
  536. }
  537. var result []*Index
  538. for _, name := range indexes {
  539. idx, err := m.GetIndex(name)
  540. if err != nil {
  541. continue
  542. }
  543. if strings.EqualFold(idx.Table, table) {
  544. result = append(result, idx)
  545. }
  546. }
  547. return result, nil
  548. }
  549. // addToIndexList adds an index name to the list.
  550. func (m *SchemaManager) addToIndexList(name string) error {
  551. key := m.indexListKey()
  552. var indexes []string
  553. var data string
  554. err := m.pool.WithClient(func(c *KVClient) error {
  555. var err error
  556. data, err = c.Read(key)
  557. return err
  558. })
  559. if err == nil {
  560. json.Unmarshal([]byte(data), &indexes)
  561. }
  562. indexes = append(indexes, name)
  563. newData, _ := json.Marshal(indexes)
  564. return m.pool.WithClient(func(c *KVClient) error {
  565. return c.Write(key, string(newData))
  566. })
  567. }
  568. // removeFromIndexList removes an index name from the list.
  569. func (m *SchemaManager) removeFromIndexList(name string) error {
  570. key := m.indexListKey()
  571. var indexes []string
  572. var data string
  573. err := m.pool.WithClient(func(c *KVClient) error {
  574. var err error
  575. data, err = c.Read(key)
  576. return err
  577. })
  578. if err != nil {
  579. return nil
  580. }
  581. json.Unmarshal([]byte(data), &indexes)
  582. var newIndexes []string
  583. for _, idx := range indexes {
  584. if !strings.EqualFold(idx, name) {
  585. newIndexes = append(newIndexes, idx)
  586. }
  587. }
  588. newData, _ := json.Marshal(newIndexes)
  589. return m.pool.WithClient(func(c *KVClient) error {
  590. return c.Write(key, string(newData))
  591. })
  592. }
  593. // AddColumn adds a new column to a table.
  594. func (m *SchemaManager) AddColumn(table string, column Column) error {
  595. m.mu.Lock()
  596. defer m.mu.Unlock()
  597. schema, err := m.getSchemaUnsafe(table)
  598. if err != nil {
  599. return err
  600. }
  601. // Check if column already exists
  602. for _, col := range schema.Columns {
  603. if strings.EqualFold(col.Name, column.Name) {
  604. return fmt.Errorf("column already exists: %s", column.Name)
  605. }
  606. }
  607. // Add column
  608. schema.Columns = append(schema.Columns, column)
  609. // Update schema
  610. return m.updateSchemaUnsafe(schema)
  611. }
  612. // DropColumn removes a column from a table.
  613. func (m *SchemaManager) DropColumn(table, columnName string) error {
  614. m.mu.Lock()
  615. defer m.mu.Unlock()
  616. schema, err := m.getSchemaUnsafe(table)
  617. if err != nil {
  618. return err
  619. }
  620. // Cannot drop primary key column
  621. if strings.EqualFold(schema.PrimaryKey, columnName) {
  622. return fmt.Errorf("cannot drop primary key column: %s", columnName)
  623. }
  624. // Find and remove column
  625. newColumns := make([]Column, 0, len(schema.Columns)-1)
  626. found := false
  627. for _, col := range schema.Columns {
  628. if strings.EqualFold(col.Name, columnName) {
  629. found = true
  630. continue
  631. }
  632. newColumns = append(newColumns, col)
  633. }
  634. if !found {
  635. return fmt.Errorf("column not found: %s", columnName)
  636. }
  637. schema.Columns = newColumns
  638. // Update schema
  639. return m.updateSchemaUnsafe(schema)
  640. }
  641. // RenameTable renames a table.
  642. func (m *SchemaManager) RenameTable(oldName, newName string) error {
  643. m.mu.Lock()
  644. defer m.mu.Unlock()
  645. // Check if old table exists
  646. schema, err := m.getSchemaUnsafe(oldName)
  647. if err != nil {
  648. return err
  649. }
  650. // Check if new table name already exists
  651. _, err = m.getSchemaUnsafe(newName)
  652. if err == nil {
  653. return fmt.Errorf("table already exists: %s", newName)
  654. }
  655. // Update schema name
  656. schema.Name = newName
  657. var nextRowID string
  658. rowIDKey := m.rowIDKey(oldName)
  659. m.pool.WithClient(func(c *KVClient) error {
  660. data, err := c.Read(rowIDKey)
  661. if err == nil {
  662. nextRowID = data
  663. }
  664. return nil
  665. })
  666. // Delete old schema
  667. oldKey := m.schemaKey(oldName)
  668. err = m.pool.WithClient(func(c *KVClient) error {
  669. return c.Delete(oldKey)
  670. })
  671. if err != nil {
  672. return err
  673. }
  674. // Remove from catalog
  675. m.removeFromCatalog(oldName)
  676. // Move ROWID state.
  677. m.pool.WithClient(func(c *KVClient) error {
  678. return c.Delete(rowIDKey)
  679. })
  680. if nextRowID != "" {
  681. err = m.pool.WithClient(func(c *KVClient) error {
  682. return c.Write(m.rowIDKey(newName), nextRowID)
  683. })
  684. if err != nil {
  685. return err
  686. }
  687. }
  688. // Update cache
  689. delete(m.cache, strings.ToLower(oldName))
  690. // Write new schema
  691. newKey := m.schemaKey(newName)
  692. data, _ := json.Marshal(schema)
  693. err = m.pool.WithClient(func(c *KVClient) error {
  694. return c.Write(newKey, string(data))
  695. })
  696. if err != nil {
  697. return err
  698. }
  699. // Add to catalog
  700. m.addToCatalog(newName)
  701. // Update cache
  702. m.cache[strings.ToLower(newName)] = schema
  703. return nil
  704. }
  705. // RenameColumn renames a column in a table.
  706. func (m *SchemaManager) RenameColumn(table, oldName, newName string) error {
  707. m.mu.Lock()
  708. defer m.mu.Unlock()
  709. schema, err := m.getSchemaUnsafe(table)
  710. if err != nil {
  711. return err
  712. }
  713. // Check if new column name already exists
  714. for _, col := range schema.Columns {
  715. if strings.EqualFold(col.Name, newName) {
  716. return fmt.Errorf("column already exists: %s", newName)
  717. }
  718. }
  719. // Find and rename column
  720. found := false
  721. for i, col := range schema.Columns {
  722. if strings.EqualFold(col.Name, oldName) {
  723. schema.Columns[i].Name = newName
  724. found = true
  725. // Update primary key reference if needed
  726. if strings.EqualFold(schema.PrimaryKey, oldName) {
  727. schema.PrimaryKey = newName
  728. }
  729. break
  730. }
  731. }
  732. if !found {
  733. return fmt.Errorf("column not found: %s", oldName)
  734. }
  735. // Update schema
  736. return m.updateSchemaUnsafe(schema)
  737. }
  738. // getSchemaUnsafe gets a schema without locking (internal use).
  739. func (m *SchemaManager) getSchemaUnsafe(table string) (*Schema, error) {
  740. tableLower := strings.ToLower(table)
  741. // Check cache
  742. if schema, ok := m.cache[tableLower]; ok {
  743. return schema, nil
  744. }
  745. // Read from storage
  746. key := m.schemaKey(table)
  747. var data string
  748. err := m.pool.WithClient(func(c *KVClient) error {
  749. var err error
  750. data, err = c.Read(key)
  751. return err
  752. })
  753. if err != nil {
  754. return nil, fmt.Errorf("table not found: %s", table)
  755. }
  756. var schema Schema
  757. if err := json.Unmarshal([]byte(data), &schema); err != nil {
  758. return nil, err
  759. }
  760. m.cache[tableLower] = &schema
  761. return &schema, nil
  762. }
  763. // updateSchemaUnsafe updates a schema without locking (internal use).
  764. func (m *SchemaManager) updateSchemaUnsafe(schema *Schema) error {
  765. key := m.schemaKey(schema.Name)
  766. data, _ := json.Marshal(schema)
  767. err := m.pool.WithClient(func(c *KVClient) error {
  768. return c.Write(key, string(data))
  769. })
  770. if err != nil {
  771. return err
  772. }
  773. // Update cache
  774. m.cache[strings.ToLower(schema.Name)] = schema
  775. return nil
  776. }