sync.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package sqlite
  15. import (
  16. "fmt"
  17. "strings"
  18. "yunion.io/x/log"
  19. "yunion.io/x/sqlchemy"
  20. )
  21. func (sqlite *SSqliteBackend) CommitTableChangeSQL(ts sqlchemy.ITableSpec, changes sqlchemy.STableChanges) []string {
  22. ret := make([]string, 0)
  23. for _, idx := range changes.RemoveIndexes {
  24. sql := fmt.Sprintf("DROP INDEX IF EXISTS `%s`.`%s`", ts.Name(), idx.Name())
  25. ret = append(ret, sql)
  26. log.Infof("%s;", sql)
  27. }
  28. needNewTable := false
  29. // first check if primary key is modifed
  30. changePrimary := false
  31. oldHasPrimary := false
  32. for _, col := range changes.RemoveColumns {
  33. if col.IsPrimary() {
  34. changePrimary = true
  35. oldHasPrimary = true
  36. }
  37. }
  38. for _, cols := range changes.UpdatedColumns {
  39. if cols.OldCol.IsPrimary() != cols.NewCol.IsPrimary() {
  40. changePrimary = true
  41. }
  42. if cols.OldCol.IsPrimary() {
  43. oldHasPrimary = true
  44. }
  45. }
  46. for _, col := range changes.AddColumns {
  47. if col.IsPrimary() {
  48. changePrimary = true
  49. }
  50. }
  51. if changePrimary && oldHasPrimary {
  52. needNewTable = true
  53. }
  54. /* IGNORE DROP STATEMENT */
  55. for _, col := range changes.RemoveColumns {
  56. sql := fmt.Sprintf("DROP COLUMN `%s`", col.Name())
  57. log.Debugf("skip ALTER TABLE %s %s;", ts.Name(), sql)
  58. // alters = append(alters, sql)
  59. // ignore drop statement
  60. // if the column is auto_increment integer column,
  61. // then need to drop auto_increment attribute
  62. if col.IsAutoIncrement() {
  63. needNewTable = true
  64. }
  65. // if the column is not nullable but no default
  66. // then need to drop the not-nullable attribute
  67. if !col.IsNullable() && col.Default() == "" {
  68. needNewTable = true
  69. }
  70. }
  71. if len(changes.UpdatedColumns) > 0 {
  72. needNewTable = true
  73. }
  74. for _, col := range changes.AddColumns {
  75. sql := fmt.Sprintf("ALTER TABLE `%s` ADD COLUMN %s", ts.Name(), col.DefinitionString())
  76. ret = append(ret, sql)
  77. }
  78. if changePrimary {
  79. needNewTable = true
  80. }
  81. if needNewTable {
  82. newTableName := fmt.Sprintf("%s_tmp", ts.Name())
  83. oldTableName := fmt.Sprintf("%s_old", ts.Name())
  84. // create a table with alter name
  85. // var newTable *sqlchemy.STableSpec
  86. newTable := ts.(*sqlchemy.STableSpec).Clone(newTableName, 0)
  87. createSqls := newTable.CreateSQLs()
  88. ret = append(ret, createSqls...)
  89. // insert
  90. colNameMap := make(map[string]string)
  91. for _, cols := range changes.UpdatedColumns {
  92. if cols.OldCol.Name() != cols.NewCol.Name() {
  93. colNameMap[cols.NewCol.Name()] = cols.OldCol.Name()
  94. }
  95. }
  96. colNames := make([]string, 0)
  97. srcCols := make([]string, 0)
  98. for _, col := range ts.Columns() {
  99. colName := col.Name()
  100. srcName := colName
  101. if n, ok := colNameMap[colName]; ok {
  102. srcName = n
  103. }
  104. colNames = append(colNames, fmt.Sprintf("`%s`", colName))
  105. srcCols = append(srcCols, fmt.Sprintf("`%s`", srcName))
  106. }
  107. sql := fmt.Sprintf("INSERT INTO `%s`(%s) SELECT %s FROM `%s`", newTableName, strings.Join(colNames, ", "), strings.Join(srcCols, ", "), ts.Name())
  108. ret = append(ret, sql)
  109. // change name
  110. sql = fmt.Sprintf("ALTER TABLE `%s` RENAME TO `%s`", ts.Name(), oldTableName)
  111. ret = append(ret, sql)
  112. sql = fmt.Sprintf("ALTER TABLE `%s` RENAME TO `%s`", newTableName, ts.Name())
  113. ret = append(ret, sql)
  114. }
  115. for _, idx := range changes.AddIndexes {
  116. sql := createIndexSQL(ts, idx)
  117. ret = append(ret, sql)
  118. log.Infof("%s;", sql)
  119. }
  120. return ret
  121. }
  122. func createIndexSQL(ts sqlchemy.ITableSpec, idx sqlchemy.STableIndex) string {
  123. return fmt.Sprintf("CREATE INDEX `%s` ON `%s` (%s)", idx.Name(), ts.Name(), strings.Join(idx.QuotedColumns("`"), ","))
  124. }