sync.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  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 mysql
  15. import (
  16. "fmt"
  17. "strings"
  18. "yunion.io/x/log"
  19. "yunion.io/x/sqlchemy"
  20. )
  21. func (mysql *SMySQLBackend) 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 `%s` ON `%s`", idx.Name(), ts.Name())
  25. ret = append(ret, sql)
  26. log.Infof("%s;", sql)
  27. }
  28. alters := make([]string, 0)
  29. // first check if primary key is modifed
  30. changePrimary := false
  31. for _, col := range changes.RemoveColumns {
  32. if col.IsPrimary() {
  33. changePrimary = true
  34. break
  35. }
  36. }
  37. if !changePrimary {
  38. for _, cols := range changes.UpdatedColumns {
  39. if cols.OldCol.IsPrimary() != cols.NewCol.IsPrimary() {
  40. changePrimary = true
  41. break
  42. }
  43. }
  44. }
  45. if !changePrimary {
  46. for _, col := range changes.AddColumns {
  47. if col.IsPrimary() {
  48. changePrimary = true
  49. break
  50. }
  51. }
  52. }
  53. // in case of a primary key change, we first need to drop primary key.
  54. // BUT if a mysql table has no primary key at all,
  55. // exec drop primary key will cause error
  56. if changePrimary {
  57. oldHasPrimary := false
  58. for _, col := range changes.OldColumns {
  59. if col.IsPrimary() {
  60. oldHasPrimary = true
  61. break
  62. }
  63. }
  64. if oldHasPrimary {
  65. alters = append(alters, "DROP PRIMARY KEY")
  66. }
  67. }
  68. /* IGNORE DROP STATEMENT */
  69. for _, col := range changes.RemoveColumns {
  70. sql := fmt.Sprintf("DROP COLUMN `%s`", col.Name())
  71. log.Debugf("skip ALTER TABLE %s %s;", ts.Name(), sql)
  72. // alters = append(alters, sql)
  73. // ignore drop statement
  74. // if the column is auto_increment integer column,
  75. // then need to drop auto_increment attribute
  76. if col.IsAutoIncrement() {
  77. // make sure the column is nullable
  78. col.SetNullable(true)
  79. log.Errorf("column %s is auto_increment, drop auto_inrement attribute", col.Name())
  80. col.SetAutoIncrement(false)
  81. sql := fmt.Sprintf("MODIFY COLUMN %s", col.DefinitionString())
  82. alters = append(alters, sql)
  83. }
  84. // if the column is not nullable but no default
  85. // then need to drop the not-nullable attribute
  86. if !col.IsNullable() && col.Default() == "" {
  87. col.SetNullable(true)
  88. sql := fmt.Sprintf("MODIFY COLUMN %s", col.DefinitionString())
  89. alters = append(alters, sql)
  90. log.Errorf("column %s is not nullable but no default, drop not nullable attribute", col.Name())
  91. }
  92. }
  93. for _, cols := range changes.UpdatedColumns {
  94. if cols.OldCol.Name() != cols.NewCol.Name() {
  95. sql := fmt.Sprintf("CHANGE COLUMN `%s` %s", cols.OldCol.Name(), cols.NewCol.DefinitionString())
  96. alters = append(alters, sql)
  97. } else {
  98. sql := fmt.Sprintf("MODIFY COLUMN %s", cols.NewCol.DefinitionString())
  99. alters = append(alters, sql)
  100. }
  101. }
  102. for _, col := range changes.AddColumns {
  103. sql := fmt.Sprintf("ADD COLUMN %s", col.DefinitionString())
  104. alters = append(alters, sql)
  105. }
  106. if changePrimary {
  107. primaries := make([]string, 0)
  108. for _, c := range ts.Columns() {
  109. if c.IsPrimary() {
  110. primaries = append(primaries, fmt.Sprintf("`%s`", c.Name()))
  111. }
  112. }
  113. if len(primaries) > 0 {
  114. sql := fmt.Sprintf("ADD PRIMARY KEY(%s)", strings.Join(primaries, ", "))
  115. alters = append(alters, sql)
  116. }
  117. }
  118. if len(alters) > 0 {
  119. sql := fmt.Sprintf("ALTER TABLE `%s` %s;", ts.Name(), strings.Join(alters, ", "))
  120. ret = append(ret, sql)
  121. }
  122. for _, idx := range changes.AddIndexes {
  123. sql := createIndexSQL(ts, idx)
  124. ret = append(ret, sql)
  125. log.Infof("%s;", sql)
  126. }
  127. return ret
  128. }
  129. func createIndexSQL(ts sqlchemy.ITableSpec, idx sqlchemy.STableIndex) string {
  130. return fmt.Sprintf("CREATE INDEX `%s` ON `%s` (%s)", idx.Name(), ts.Name(), strings.Join(idx.QuotedColumns("`"), ","))
  131. }