vitess.io/vitess@v0.16.2/go/vt/schemadiff/view_test.go (about) 1 /* 2 Copyright 2022 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package schemadiff 18 19 import ( 20 "testing" 21 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 25 "vitess.io/vitess/go/vt/sqlparser" 26 ) 27 28 func TestCreateViewDiff(t *testing.T) { 29 tt := []struct { 30 name string 31 from string 32 to string 33 fromName string 34 toName string 35 diff string 36 cdiff string 37 isError bool 38 }{ 39 { 40 name: "identical", 41 from: "create view v1 as select a, b, c from t", 42 to: "create view v1 as select a, b, c from t", 43 }, 44 { 45 name: "identical, case change", 46 from: "create view v1 as SELECT a, b, c from t", 47 to: "create view v1 as select a, b, c from t", 48 }, 49 { 50 name: "identical, case change on target", 51 from: "create view v1 as select a, b, c from t", 52 to: "create view v1 as SELECT a, b, c from t", 53 }, 54 { 55 name: "identical, case and qualifiers", 56 from: "create view v1 as select `a`, `b`, c from t", 57 to: "create view v1 as SELECT a, b, `c` from t", 58 }, 59 { 60 name: "identical, column list, qualified", 61 from: "create view v1 (col1, `col2`, `col3`) as select `a`, `b`, c from t", 62 to: "create view v1 (`col1`, col2, col3) as select a, b, `c` from t", 63 }, 64 { 65 name: "change of column list, qualifiers", 66 from: "create view v1 (col1, `col2`, `col3`) as select `a`, `b`, c from t", 67 to: "create view v1 (`col1`, col2, colother) as select a, b, `c` from t", 68 diff: "alter view v1(col1, col2, colother) as select a, b, c from t", 69 cdiff: "ALTER VIEW `v1`(`col1`, `col2`, `colother`) AS SELECT `a`, `b`, `c` FROM `t`", 70 fromName: "v1", 71 toName: "v1", 72 }, 73 { 74 name: "change of column list, must have qualifiers", 75 from: "create view v1 (col1, `col2`, `col3`) as select `a`, `b`, c from t", 76 to: "create view v1 (`col1.with.dot`, `col2`, colother) as select a, b, `c` from t", 77 diff: "alter view v1(`col1.with.dot`, col2, colother) as select a, b, c from t", 78 cdiff: "ALTER VIEW `v1`(`col1.with.dot`, `col2`, `colother`) AS SELECT `a`, `b`, `c` FROM `t`", 79 }, 80 { 81 name: "identical, spacing, case change", 82 from: "create view v1 as select a, b, c FROM t", 83 to: `create view v1 as 84 SELECT a, b, c 85 from t`, 86 }, 87 { 88 name: "change of query", 89 from: "create view v1 as select a from t", 90 to: "create view v1 as select a, b from t", 91 diff: "alter view v1 as select a, b from t", 92 cdiff: "ALTER VIEW `v1` AS SELECT `a`, `b` FROM `t`", 93 }, 94 { 95 name: "change of view name", 96 from: "create view v1 as select a from t", 97 to: "create view v2 as select a, b from t", 98 diff: "alter view v1 as select a, b from t", 99 cdiff: "ALTER VIEW `v1` AS SELECT `a`, `b` FROM `t`", 100 }, 101 { 102 name: "change of columns, spacing", 103 from: "create view v1 as select a from t", 104 to: `create view v2 as 105 select a, b 106 from t`, 107 diff: "alter view v1 as select a, b from t", 108 cdiff: "ALTER VIEW `v1` AS SELECT `a`, `b` FROM `t`", 109 fromName: "v1", 110 toName: "v2", 111 }, 112 { 113 name: "algorithm, case change", 114 from: "create view v1 as select a from t", 115 to: "create algorithm=temptable view v2 as select a FROM t", 116 diff: "alter algorithm = temptable view v1 as select a from t", 117 cdiff: "ALTER ALGORITHM = TEMPTABLE VIEW `v1` AS SELECT `a` FROM `t`", 118 }, 119 { 120 name: "algorithm, case change 2", 121 from: "create view v1 as select a FROM t", 122 to: "create algorithm=temptable view v2 as select a from t", 123 diff: "alter algorithm = temptable view v1 as select a from t", 124 cdiff: "ALTER ALGORITHM = TEMPTABLE VIEW `v1` AS SELECT `a` FROM `t`", 125 }, 126 { 127 name: "algorithm, case change 3", 128 from: "create ALGORITHM=MERGE view v1 as select a FROM t", 129 to: "create ALGORITHM=TEMPTABLE view v2 as select a from t", 130 diff: "alter algorithm = TEMPTABLE view v1 as select a from t", 131 cdiff: "ALTER ALGORITHM = TEMPTABLE VIEW `v1` AS SELECT `a` FROM `t`", 132 }, 133 { 134 name: "algorithm value is case sensitive", 135 from: "create ALGORITHM=TEMPTABLE view v1 as select a from t", 136 to: "create ALGORITHM=temptable view v2 as select a from t", 137 diff: "alter algorithm = temptable view v1 as select a from t", 138 cdiff: "ALTER ALGORITHM = TEMPTABLE VIEW `v1` AS SELECT `a` FROM `t`", 139 }, 140 { 141 name: "algorithm value is case sensitive 2", 142 from: "create ALGORITHM=temptable view v1 as select a from t", 143 to: "create ALGORITHM=TEMPTABLE view v2 as select a from t", 144 diff: "alter algorithm = TEMPTABLE view v1 as select a from t", 145 cdiff: "ALTER ALGORITHM = TEMPTABLE VIEW `v1` AS SELECT `a` FROM `t`", 146 }, 147 } 148 hints := &DiffHints{} 149 for _, ts := range tt { 150 t.Run(ts.name, func(t *testing.T) { 151 fromStmt, err := sqlparser.ParseStrictDDL(ts.from) 152 assert.NoError(t, err) 153 fromCreateView, ok := fromStmt.(*sqlparser.CreateView) 154 assert.True(t, ok) 155 156 toStmt, err := sqlparser.ParseStrictDDL(ts.to) 157 assert.NoError(t, err) 158 toCreateView, ok := toStmt.(*sqlparser.CreateView) 159 assert.True(t, ok) 160 161 c, err := NewCreateViewEntity(fromCreateView) 162 require.NoError(t, err) 163 other, err := NewCreateViewEntity(toCreateView) 164 require.NoError(t, err) 165 alter, err := c.Diff(other, hints) 166 switch { 167 case ts.isError: 168 assert.Error(t, err) 169 case ts.diff == "": 170 assert.NoError(t, err) 171 assert.Nil(t, alter) 172 default: 173 assert.NoError(t, err) 174 require.NotNil(t, alter) 175 require.False(t, alter.IsEmpty()) 176 { 177 diff := alter.StatementString() 178 assert.Equal(t, ts.diff, diff) 179 // validate we can parse back the statement 180 _, err := sqlparser.ParseStrictDDL(diff) 181 assert.NoError(t, err) 182 183 eFrom, eTo := alter.Entities() 184 if ts.fromName != "" { 185 assert.Equal(t, ts.fromName, eFrom.Name()) 186 } 187 if ts.toName != "" { 188 assert.Equal(t, ts.toName, eTo.Name()) 189 } 190 { // Validate "apply()" on "from" converges with "to" 191 applied, err := c.Apply(alter) 192 assert.NoError(t, err) 193 require.NotNil(t, applied) 194 appliedDiff, err := eTo.Diff(applied, hints) 195 require.NoError(t, err) 196 assert.True(t, appliedDiff.IsEmpty(), "expected empty diff, found changes: %v", appliedDiff.CanonicalStatementString()) 197 } 198 } 199 { 200 cdiff := alter.CanonicalStatementString() 201 assert.Equal(t, ts.cdiff, cdiff) 202 _, err := sqlparser.ParseStrictDDL(cdiff) 203 assert.NoError(t, err) 204 } 205 } 206 }) 207 } 208 } 209 210 func TestNormalizeView(t *testing.T) { 211 tt := []struct { 212 name string 213 from string 214 to string 215 }{ 216 { 217 name: "basic view", 218 from: "create view v1 as select a, b, c from t", 219 to: "CREATE VIEW `v1` AS SELECT `a`, `b`, `c` FROM `t`", 220 }, 221 { 222 name: "default algorithm", 223 from: "create algorithm=undefined view v1 as select a, b, c from t", 224 to: "CREATE VIEW `v1` AS SELECT `a`, `b`, `c` FROM `t`", 225 }, 226 { 227 name: "non-default algorithm", 228 from: "create algorithm=merge view v1 as select a, b, c from t", 229 to: "CREATE ALGORITHM = merge VIEW `v1` AS SELECT `a`, `b`, `c` FROM `t`", 230 }, 231 { 232 name: "default security model", 233 from: "create sql security DEFINER view v1 as select a, b, c from t", 234 to: "CREATE VIEW `v1` AS SELECT `a`, `b`, `c` FROM `t`", 235 }, 236 { 237 name: "non-default security model", 238 from: "create sql security invoker view v1 as select a, b, c from t", 239 to: "CREATE SQL SECURITY INVOKER VIEW `v1` AS SELECT `a`, `b`, `c` FROM `t`", 240 }, 241 } 242 for _, ts := range tt { 243 t.Run(ts.name, func(t *testing.T) { 244 stmt, err := sqlparser.ParseStrictDDL(ts.from) 245 require.NoError(t, err) 246 fromCreateView, ok := stmt.(*sqlparser.CreateView) 247 require.True(t, ok) 248 249 from, err := NewCreateViewEntity(fromCreateView) 250 require.NoError(t, err) 251 assert.Equal(t, ts.to, sqlparser.CanonicalString(from)) 252 }) 253 } 254 }