github.com/XiaoMi/Gaea@v1.2.5/parser/ast/dml_test.go (about)

     1  // Copyright 2017 PingCAP, Inc.
     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  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package ast_test
    15  
    16  import (
    17  	. "github.com/pingcap/check"
    18  
    19  	. "github.com/XiaoMi/Gaea/parser/ast"
    20  )
    21  
    22  var _ = Suite(&testDMLSuite{})
    23  
    24  type testDMLSuite struct {
    25  }
    26  
    27  func (ts *testDMLSuite) TestDMLVisitorCover(c *C) {
    28  	ce := &checkExpr{}
    29  
    30  	tableRefsClause := &TableRefsClause{TableRefs: &Join{Left: &TableSource{Source: &TableName{}}, On: &OnCondition{Expr: ce}}}
    31  
    32  	stmts := []struct {
    33  		node             Node
    34  		expectedEnterCnt int
    35  		expectedLeaveCnt int
    36  	}{
    37  		{&DeleteStmt{TableRefs: tableRefsClause, Tables: &DeleteTableList{}, Where: ce,
    38  			Order: &OrderByClause{}, Limit: &Limit{Count: ce, Offset: ce}}, 4, 4},
    39  		{&ShowStmt{Table: &TableName{}, Column: &ColumnName{}, Pattern: &PatternLikeExpr{Expr: ce, Pattern: ce}, Where: ce}, 3, 3},
    40  		{&LoadDataStmt{Table: &TableName{}, Columns: []*ColumnName{{}}, FieldsInfo: &FieldsClause{}, LinesInfo: &LinesClause{}}, 0, 0},
    41  		{&Assignment{Column: &ColumnName{}, Expr: ce}, 1, 1},
    42  		{&ByItem{Expr: ce}, 1, 1},
    43  		{&GroupByClause{Items: []*ByItem{{Expr: ce}, {Expr: ce}}}, 2, 2},
    44  		{&HavingClause{Expr: ce}, 1, 1},
    45  		{&Join{Left: &TableSource{Source: &TableName{}}}, 0, 0},
    46  		{&Limit{Count: ce, Offset: ce}, 2, 2},
    47  		{&OnCondition{Expr: ce}, 1, 1},
    48  		{&OrderByClause{Items: []*ByItem{{Expr: ce}, {Expr: ce}}}, 2, 2},
    49  		{&SelectField{Expr: ce, WildCard: &WildCardField{}}, 1, 1},
    50  		{&TableName{}, 0, 0},
    51  		{tableRefsClause, 1, 1},
    52  		{&TableSource{Source: &TableName{}}, 0, 0},
    53  		{&WildCardField{}, 0, 0},
    54  
    55  		// TODO: cover childrens
    56  		{&InsertStmt{Table: tableRefsClause}, 1, 1},
    57  		{&UnionStmt{}, 0, 0},
    58  		{&UpdateStmt{TableRefs: tableRefsClause}, 1, 1},
    59  		{&SelectStmt{}, 0, 0},
    60  		{&FieldList{}, 0, 0},
    61  		{&UnionSelectList{}, 0, 0},
    62  		{&WindowSpec{}, 0, 0},
    63  		{&PartitionByClause{}, 0, 0},
    64  		{&FrameClause{}, 0, 0},
    65  		{&FrameBound{}, 0, 0},
    66  	}
    67  
    68  	for _, v := range stmts {
    69  		ce.reset()
    70  		v.node.Accept(checkVisitor{})
    71  		c.Check(ce.enterCnt, Equals, v.expectedEnterCnt)
    72  		c.Check(ce.leaveCnt, Equals, v.expectedLeaveCnt)
    73  		v.node.Accept(visitor1{})
    74  	}
    75  }
    76  
    77  func (ts *testDMLSuite) TestTableNameRestore(c *C) {
    78  	testCases := []NodeRestoreTestCase{
    79  		{"dbb.`tbb1`", "`dbb`.`tbb1`"},
    80  		{"`tbb2`", "`tbb2`"},
    81  		{"tbb3", "`tbb3`"},
    82  		{"dbb.`hello-world`", "`dbb`.`hello-world`"},
    83  		{"`dbb`.`hello-world`", "`dbb`.`hello-world`"},
    84  		{"`dbb.HelloWorld`", "`dbb.HelloWorld`"},
    85  	}
    86  	extractNodeFunc := func(node Node) Node {
    87  		return node.(*CreateTableStmt).Table
    88  	}
    89  	RunNodeRestoreTest(c, testCases, "CREATE TABLE %s (id VARCHAR(128) NOT NULL);", extractNodeFunc)
    90  }
    91  
    92  func (ts *testDMLSuite) TestTableNameIndexHintsRestore(c *C) {
    93  	testCases := []NodeRestoreTestCase{
    94  		{"t use index (hello)", "`t` USE INDEX (`hello`)"},
    95  		{"t use index (hello, world)", "`t` USE INDEX (`hello`, `world`)"},
    96  		{"t use index ()", "`t` USE INDEX ()"},
    97  		{"t use key ()", "`t` USE INDEX ()"},
    98  		{"t ignore key ()", "`t` IGNORE INDEX ()"},
    99  		{"t force key ()", "`t` FORCE INDEX ()"},
   100  		{"t use index for order by (idx1)", "`t` USE INDEX FOR ORDER BY (`idx1`)"},
   101  
   102  		{"t use index (hello, world, yes) force key (good)", "`t` USE INDEX (`hello`, `world`, `yes`) FORCE INDEX (`good`)"},
   103  		{"t use index (hello, world, yes) use index for order by (good)", "`t` USE INDEX (`hello`, `world`, `yes`) USE INDEX FOR ORDER BY (`good`)"},
   104  		{"t ignore key (hello, world, yes) force key (good)", "`t` IGNORE INDEX (`hello`, `world`, `yes`) FORCE INDEX (`good`)"},
   105  
   106  		{"t use index for group by (idx1) use index for order by (idx2)", "`t` USE INDEX FOR GROUP BY (`idx1`) USE INDEX FOR ORDER BY (`idx2`)"},
   107  		{"t use index for group by (idx1) ignore key for order by (idx2)", "`t` USE INDEX FOR GROUP BY (`idx1`) IGNORE INDEX FOR ORDER BY (`idx2`)"},
   108  		{"t use index for group by (idx1) ignore key for group by (idx2)", "`t` USE INDEX FOR GROUP BY (`idx1`) IGNORE INDEX FOR GROUP BY (`idx2`)"},
   109  		{"t use index for order by (idx1) ignore key for group by (idx2)", "`t` USE INDEX FOR ORDER BY (`idx1`) IGNORE INDEX FOR GROUP BY (`idx2`)"},
   110  
   111  		{"t use index for order by (idx1) ignore key for group by (idx2) use index (idx3)", "`t` USE INDEX FOR ORDER BY (`idx1`) IGNORE INDEX FOR GROUP BY (`idx2`) USE INDEX (`idx3`)"},
   112  		{"t use index for order by (idx1) ignore key for group by (idx2) use index (idx3)", "`t` USE INDEX FOR ORDER BY (`idx1`) IGNORE INDEX FOR GROUP BY (`idx2`) USE INDEX (`idx3`)"},
   113  
   114  		{"t use index (`foo``bar`) force index (`baz``1`, `xyz`)", "`t` USE INDEX (`foo``bar`) FORCE INDEX (`baz``1`, `xyz`)"},
   115  		{"t force index (`foo``bar`) ignore index (`baz``1`, xyz)", "`t` FORCE INDEX (`foo``bar`) IGNORE INDEX (`baz``1`, `xyz`)"},
   116  		{"t ignore index (`foo``bar`) force key (`baz``1`, xyz)", "`t` IGNORE INDEX (`foo``bar`) FORCE INDEX (`baz``1`, `xyz`)"},
   117  		{"t ignore index (`foo``bar`) ignore key for group by (`baz``1`, xyz)", "`t` IGNORE INDEX (`foo``bar`) IGNORE INDEX FOR GROUP BY (`baz``1`, `xyz`)"},
   118  		{"t ignore index (`foo``bar`) ignore key for order by (`baz``1`, xyz)", "`t` IGNORE INDEX (`foo``bar`) IGNORE INDEX FOR ORDER BY (`baz``1`, `xyz`)"},
   119  
   120  		{"t use index for group by (`foo``bar`) use index for order by (`baz``1`, `xyz`)", "`t` USE INDEX FOR GROUP BY (`foo``bar`) USE INDEX FOR ORDER BY (`baz``1`, `xyz`)"},
   121  		{"t use index for group by (`foo``bar`) ignore key for order by (`baz``1`, `xyz`)", "`t` USE INDEX FOR GROUP BY (`foo``bar`) IGNORE INDEX FOR ORDER BY (`baz``1`, `xyz`)"},
   122  		{"t use index for group by (`foo``bar`) ignore key for group by (`baz``1`, `xyz`)", "`t` USE INDEX FOR GROUP BY (`foo``bar`) IGNORE INDEX FOR GROUP BY (`baz``1`, `xyz`)"},
   123  		{"t use index for order by (`foo``bar`) ignore key for group by (`baz``1`, `xyz`)", "`t` USE INDEX FOR ORDER BY (`foo``bar`) IGNORE INDEX FOR GROUP BY (`baz``1`, `xyz`)"},
   124  	}
   125  	extractNodeFunc := func(node Node) Node {
   126  		return node.(*SelectStmt).From.TableRefs.Left.(*TableSource).Source.(*TableName)
   127  	}
   128  	RunNodeRestoreTest(c, testCases, "SELECT * FROM %s", extractNodeFunc)
   129  }
   130  
   131  func (ts *testDMLSuite) TestLimitRestore(c *C) {
   132  	testCases := []NodeRestoreTestCase{
   133  		{"limit 10", "LIMIT 10"},
   134  		{"limit 10,20", "LIMIT 10,20"},
   135  		{"limit 20 offset 10", "LIMIT 10,20"},
   136  	}
   137  	extractNodeFunc := func(node Node) Node {
   138  		return node.(*SelectStmt).Limit
   139  	}
   140  	RunNodeRestoreTest(c, testCases, "SELECT 1 %s", extractNodeFunc)
   141  }
   142  
   143  func (ts *testDMLSuite) TestWildCardFieldRestore(c *C) {
   144  	testCases := []NodeRestoreTestCase{
   145  		{"*", "*"},
   146  		{"t.*", "`t`.*"},
   147  		{"testdb.t.*", "`testdb`.`t`.*"},
   148  	}
   149  	extractNodeFunc := func(node Node) Node {
   150  		return node.(*SelectStmt).Fields.Fields[0].WildCard
   151  	}
   152  	RunNodeRestoreTest(c, testCases, "SELECT %s", extractNodeFunc)
   153  }
   154  
   155  func (ts *testDMLSuite) TestSelectFieldRestore(c *C) {
   156  	testCases := []NodeRestoreTestCase{
   157  		{"*", "*"},
   158  		{"t.*", "`t`.*"},
   159  		{"testdb.t.*", "`testdb`.`t`.*"},
   160  		{"col as a", "`col` AS `a`"},
   161  		{"col + 1 a", "`col`+1 AS `a`"},
   162  	}
   163  	extractNodeFunc := func(node Node) Node {
   164  		return node.(*SelectStmt).Fields.Fields[0]
   165  	}
   166  	RunNodeRestoreTest(c, testCases, "SELECT %s", extractNodeFunc)
   167  }
   168  
   169  func (ts *testDMLSuite) TestFieldListRestore(c *C) {
   170  	testCases := []NodeRestoreTestCase{
   171  		{"*", "*"},
   172  		{"t.*", "`t`.*"},
   173  		{"testdb.t.*", "`testdb`.`t`.*"},
   174  		{"col as a", "`col` AS `a`"},
   175  		{"`t`.*, s.col as a", "`t`.*, `s`.`col` AS `a`"},
   176  	}
   177  	extractNodeFunc := func(node Node) Node {
   178  		return node.(*SelectStmt).Fields
   179  	}
   180  	RunNodeRestoreTest(c, testCases, "SELECT %s", extractNodeFunc)
   181  }
   182  
   183  func (ts *testDMLSuite) TestTableSourceRestore(c *C) {
   184  	testCases := []NodeRestoreTestCase{
   185  		{"tbl", "`tbl`"},
   186  		{"tbl as t", "`tbl` AS `t`"},
   187  		{"(select * from tbl) as t", "(SELECT * FROM `tbl`) AS `t`"},
   188  		{"(select * from a union select * from b) as t", "(SELECT * FROM `a` UNION SELECT * FROM `b`) AS `t`"},
   189  	}
   190  	extractNodeFunc := func(node Node) Node {
   191  		return node.(*SelectStmt).From.TableRefs.Left
   192  	}
   193  	RunNodeRestoreTest(c, testCases, "select * from %s", extractNodeFunc)
   194  }
   195  
   196  func (ts *testDMLSuite) TestOnConditionRestore(c *C) {
   197  	testCases := []NodeRestoreTestCase{
   198  		{"on t1.a=t2.a", "ON `t1`.`a`=`t2`.`a`"},
   199  		{"on t1.a=t2.a and t1.b=t2.b", "ON `t1`.`a`=`t2`.`a` AND `t1`.`b`=`t2`.`b`"},
   200  	}
   201  	extractNodeFunc := func(node Node) Node {
   202  		return node.(*SelectStmt).From.TableRefs.On
   203  	}
   204  	RunNodeRestoreTest(c, testCases, "select * from t1 join t2 %s", extractNodeFunc)
   205  }
   206  
   207  func (ts *testDMLSuite) TestJoinRestore(c *C) {
   208  	testCases := []NodeRestoreTestCase{
   209  		{"t1 natural join t2", "`t1` NATURAL JOIN `t2`"},
   210  		{"t1 natural left join t2", "`t1` NATURAL LEFT JOIN `t2`"},
   211  		{"t1 natural right outer join t2", "`t1` NATURAL RIGHT JOIN `t2`"},
   212  		{"t1 straight_join t2", "`t1` STRAIGHT_JOIN `t2`"},
   213  		{"t1 straight_join t2 on t1.a>t2.a", "`t1` STRAIGHT_JOIN `t2` ON `t1`.`a`>`t2`.`a`"},
   214  		{"t1 cross join t2", "`t1` JOIN `t2`"},
   215  		{"t1 cross join t2 on t1.a>t2.a", "`t1` JOIN `t2` ON `t1`.`a`>`t2`.`a`"},
   216  		{"t1 inner join t2 using (b)", "`t1` JOIN `t2` USING (`b`)"},
   217  		{"t1 join t2 using (b,c) left join t3 on t1.a>t3.a", "(`t1` JOIN `t2` USING (`b`,`c`)) LEFT JOIN `t3` ON `t1`.`a`>`t3`.`a`"},
   218  		{"t1 natural join t2 right outer join t3 using (b,c)", "(`t1` NATURAL JOIN `t2`) RIGHT JOIN `t3` USING (`b`,`c`)"},
   219  		{"(a al left join b bl on al.a1 > bl.b1) join (a ar right join b br on ar.a1 > br.b1)", "(`a` AS `al` LEFT JOIN `b` AS `bl` ON `al`.`a1`>`bl`.`b1`) JOIN (`a` AS `ar` RIGHT JOIN `b` AS `br` ON `ar`.`a1`>`br`.`b1`)"},
   220  		{"a al left join b bl on al.a1 > bl.b1, a ar right join b br on ar.a1 > br.b1", "(`a` AS `al` LEFT JOIN `b` AS `bl` ON `al`.`a1`>`bl`.`b1`) JOIN (`a` AS `ar` RIGHT JOIN `b` AS `br` ON `ar`.`a1`>`br`.`b1`)"},
   221  		{"t1, t2", "(`t1`) JOIN `t2`"},
   222  		{"t1, t2, t3", "((`t1`) JOIN `t2`) JOIN `t3`"},
   223  	}
   224  	extractNodeFunc := func(node Node) Node {
   225  		return node.(*SelectStmt).From.TableRefs
   226  	}
   227  	RunNodeRestoreTest(c, testCases, "select * from %s", extractNodeFunc)
   228  }
   229  
   230  func (ts *testDMLSuite) TestTableRefsClauseRestore(c *C) {
   231  	testCases := []NodeRestoreTestCase{
   232  		{"t", "`t`"},
   233  		{"t1 join t2", "`t1` JOIN `t2`"},
   234  		{"t1, t2", "(`t1`) JOIN `t2`"},
   235  	}
   236  	extractNodeFunc := func(node Node) Node {
   237  		return node.(*SelectStmt).From
   238  	}
   239  	RunNodeRestoreTest(c, testCases, "select * from %s", extractNodeFunc)
   240  }
   241  
   242  func (ts *testDMLSuite) TestDeleteTableListRestore(c *C) {
   243  	testCases := []NodeRestoreTestCase{
   244  		{"t1,t2", "`t1`,`t2`"},
   245  	}
   246  	extractNodeFunc := func(node Node) Node {
   247  		return node.(*DeleteStmt).Tables
   248  	}
   249  	RunNodeRestoreTest(c, testCases, "DELETE %s FROM t1, t2;", extractNodeFunc)
   250  	RunNodeRestoreTest(c, testCases, "DELETE FROM %s USING t1, t2;", extractNodeFunc)
   251  }
   252  
   253  func (ts *testExpressionsSuite) TestByItemRestore(c *C) {
   254  	testCases := []NodeRestoreTestCase{
   255  		{"a", "`a`"},
   256  		{"a desc", "`a` DESC"},
   257  		{"NULL", "NULL"},
   258  	}
   259  	extractNodeFunc := func(node Node) Node {
   260  		return node.(*SelectStmt).OrderBy.Items[0]
   261  	}
   262  	RunNodeRestoreTest(c, testCases, "select * from t order by %s", extractNodeFunc)
   263  }
   264  
   265  func (ts *testExpressionsSuite) TestGroupByClauseRestore(c *C) {
   266  	testCases := []NodeRestoreTestCase{
   267  		{"GROUP BY a,b desc", "GROUP BY `a`,`b` DESC"},
   268  		{"GROUP BY 1 desc,b", "GROUP BY 1 DESC,`b`"},
   269  	}
   270  	extractNodeFunc := func(node Node) Node {
   271  		return node.(*SelectStmt).GroupBy
   272  	}
   273  	RunNodeRestoreTest(c, testCases, "select * from t %s", extractNodeFunc)
   274  }
   275  
   276  func (ts *testDMLSuite) TestOrderByClauseRestore(c *C) {
   277  	testCases := []NodeRestoreTestCase{
   278  		{"ORDER BY a", "ORDER BY `a`"},
   279  		{"ORDER BY a,b", "ORDER BY `a`,`b`"},
   280  	}
   281  	extractNodeFunc := func(node Node) Node {
   282  		return node.(*SelectStmt).OrderBy
   283  	}
   284  	RunNodeRestoreTest(c, testCases, "SELECT 1 FROM t1 %s", extractNodeFunc)
   285  
   286  	extractNodeFromUnionStmtFunc := func(node Node) Node {
   287  		return node.(*UnionStmt).OrderBy
   288  	}
   289  	RunNodeRestoreTest(c, testCases, "SELECT 1 FROM t1 UNION SELECT 2 FROM t2 %s", extractNodeFromUnionStmtFunc)
   290  }
   291  
   292  func (ts *testDMLSuite) TestAssignmentRestore(c *C) {
   293  	testCases := []NodeRestoreTestCase{
   294  		{"a=1", "`a`=1"},
   295  		{"b=1+2", "`b`=1+2"},
   296  	}
   297  	extractNodeFunc := func(node Node) Node {
   298  		return node.(*UpdateStmt).List[0]
   299  	}
   300  	RunNodeRestoreTest(c, testCases, "UPDATE t1 SET %s", extractNodeFunc)
   301  }
   302  
   303  func (ts *testDMLSuite) TestHavingClauseRestore(c *C) {
   304  	testCases := []NodeRestoreTestCase{
   305  		{"HAVING a", "HAVING `a`"},
   306  		{"HAVING NULL", "HAVING NULL"},
   307  		{"HAVING a>b", "HAVING `a`>`b`"},
   308  	}
   309  	extractNodeFunc := func(node Node) Node {
   310  		return node.(*SelectStmt).Having
   311  	}
   312  	RunNodeRestoreTest(c, testCases, "select 1 from t1 group by 1 %s", extractNodeFunc)
   313  }
   314  
   315  func (ts *testDMLSuite) TestFrameBoundRestore(c *C) {
   316  	testCases := []NodeRestoreTestCase{
   317  		{"CURRENT ROW", "CURRENT ROW"},
   318  		{"UNBOUNDED PRECEDING", "UNBOUNDED PRECEDING"},
   319  		{"1 PRECEDING", "1 PRECEDING"},
   320  		{"? PRECEDING", "? PRECEDING"},
   321  		{"INTERVAL 5 DAY PRECEDING", "INTERVAL 5 DAY PRECEDING"},
   322  		{"UNBOUNDED FOLLOWING", "UNBOUNDED FOLLOWING"},
   323  		{"1 FOLLOWING", "1 FOLLOWING"},
   324  		{"? FOLLOWING", "? FOLLOWING"},
   325  		{"INTERVAL '2:30' MINUTE_SECOND FOLLOWING", "INTERVAL '2:30' MINUTE_SECOND FOLLOWING"},
   326  	}
   327  	extractNodeFunc := func(node Node) Node {
   328  		return &node.(*SelectStmt).Fields.Fields[0].Expr.(*WindowFuncExpr).Spec.Frame.Extent.Start
   329  	}
   330  	RunNodeRestoreTest(c, testCases, "select avg(val) over (rows between %s and current row) from t", extractNodeFunc)
   331  }
   332  
   333  func (ts *testDMLSuite) TestFrameClauseRestore(c *C) {
   334  	testCases := []NodeRestoreTestCase{
   335  		{"ROWS CURRENT ROW", "ROWS BETWEEN CURRENT ROW AND CURRENT ROW"},
   336  		{"ROWS UNBOUNDED PRECEDING", "ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW"},
   337  		{"ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING", "ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING"},
   338  		{"RANGE BETWEEN ? PRECEDING AND ? FOLLOWING", "RANGE BETWEEN ? PRECEDING AND ? FOLLOWING"},
   339  		{"RANGE BETWEEN INTERVAL 5 DAY PRECEDING AND INTERVAL '2:30' MINUTE_SECOND FOLLOWING", "RANGE BETWEEN INTERVAL 5 DAY PRECEDING AND INTERVAL '2:30' MINUTE_SECOND FOLLOWING"},
   340  	}
   341  	extractNodeFunc := func(node Node) Node {
   342  		return node.(*SelectStmt).Fields.Fields[0].Expr.(*WindowFuncExpr).Spec.Frame
   343  	}
   344  	RunNodeRestoreTest(c, testCases, "select avg(val) over (%s) from t", extractNodeFunc)
   345  }
   346  
   347  func (ts *testDMLSuite) TestPartitionByClauseRestore(c *C) {
   348  	testCases := []NodeRestoreTestCase{
   349  		{"PARTITION BY a", "PARTITION BY `a`"},
   350  		{"PARTITION BY NULL", "PARTITION BY NULL"},
   351  		{"PARTITION BY a, b", "PARTITION BY `a`, `b`"},
   352  	}
   353  	extractNodeFunc := func(node Node) Node {
   354  		return node.(*SelectStmt).Fields.Fields[0].Expr.(*WindowFuncExpr).Spec.PartitionBy
   355  	}
   356  	RunNodeRestoreTest(c, testCases, "select avg(val) over (%s rows current row) from t", extractNodeFunc)
   357  }
   358  
   359  func (ts *testDMLSuite) TestWindowSpecRestore(c *C) {
   360  	testCases := []NodeRestoreTestCase{
   361  		{"w as ()", "`w` AS ()"},
   362  		{"w as (w1)", "`w` AS (`w1`)"},
   363  		{"w as (w1 order by country)", "`w` AS (`w1` ORDER BY `country`)"},
   364  		{"w as (partition by a order by b rows current row)", "`w` AS (PARTITION BY `a` ORDER BY `b` ROWS BETWEEN CURRENT ROW AND CURRENT ROW)"},
   365  	}
   366  	extractNodeFunc := func(node Node) Node {
   367  		return &node.(*SelectStmt).WindowSpecs[0]
   368  	}
   369  	RunNodeRestoreTest(c, testCases, "select rank() over w from t window %s", extractNodeFunc)
   370  
   371  	testCases = []NodeRestoreTestCase{
   372  		{"w", "(`w`)"},
   373  		{"()", "()"},
   374  		{"(w PARTITION BY country)", "(`w` PARTITION BY `country`)"},
   375  		{"(PARTITION BY a ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)", "(PARTITION BY `a` ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING)"},
   376  	}
   377  	extractNodeFunc = func(node Node) Node {
   378  		return &node.(*SelectStmt).Fields.Fields[0].Expr.(*WindowFuncExpr).Spec
   379  	}
   380  	RunNodeRestoreTest(c, testCases, "select rank() over %s from t window w as (order by a)", extractNodeFunc)
   381  }