github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/sem/tree/format_test.go (about)

     1  // Copyright 2017 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package tree_test
    12  
    13  import (
    14  	"context"
    15  	"fmt"
    16  	"io/ioutil"
    17  	"path/filepath"
    18  	"testing"
    19  
    20  	"github.com/cockroachdb/cockroach/pkg/internal/rsg"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/parser"
    22  	_ "github.com/cockroachdb/cockroach/pkg/sql/sem/builtins"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    24  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    25  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    26  )
    27  
    28  func TestFormatStatement(t *testing.T) {
    29  	defer leaktest.AfterTest(t)()
    30  	testData := []struct {
    31  		stmt     string
    32  		f        tree.FmtFlags
    33  		expected string
    34  	}{
    35  		{`CREATE USER foo WITH PASSWORD 'bar'`, tree.FmtSimple,
    36  			`CREATE USER 'foo' WITH PASSWORD *****`},
    37  		{`CREATE USER foo WITH PASSWORD 'bar'`, tree.FmtShowPasswords,
    38  			`CREATE USER 'foo' WITH PASSWORD 'bar'`},
    39  
    40  		{`CREATE TABLE foo (x INT8)`, tree.FmtAnonymize,
    41  			`CREATE TABLE _ (_ INT8)`},
    42  		{`INSERT INTO foo(x) TABLE bar`, tree.FmtAnonymize,
    43  			`INSERT INTO _(_) TABLE _`},
    44  		{`UPDATE foo SET x = y`, tree.FmtAnonymize,
    45  			`UPDATE _ SET _ = _`},
    46  		{`DELETE FROM foo`, tree.FmtAnonymize,
    47  			`DELETE FROM _`},
    48  		{`TRUNCATE foo`, tree.FmtAnonymize,
    49  			`TRUNCATE TABLE _`},
    50  		{`ALTER TABLE foo RENAME TO bar`, tree.FmtAnonymize,
    51  			`ALTER TABLE _ RENAME TO _`},
    52  		{`SHOW COLUMNS FROM foo`, tree.FmtAnonymize,
    53  			`SHOW COLUMNS FROM _`},
    54  		{`SHOW CREATE TABLE foo`, tree.FmtAnonymize,
    55  			`SHOW CREATE _`},
    56  		{`GRANT SELECT ON bar TO foo`, tree.FmtAnonymize,
    57  			`GRANT SELECT ON TABLE _ TO _`},
    58  
    59  		{`INSERT INTO a VALUES (-2, +3)`,
    60  			tree.FmtHideConstants,
    61  			`INSERT INTO a VALUES (_, _)`},
    62  
    63  		{`INSERT INTO a VALUES (0), (0), (0), (0), (0), (0)`,
    64  			tree.FmtHideConstants,
    65  			`INSERT INTO a VALUES (_), (__more5__)`},
    66  		{`INSERT INTO a VALUES (0, 0, 0, 0, 0, 0)`,
    67  			tree.FmtHideConstants,
    68  			`INSERT INTO a VALUES (_, _, __more4__)`},
    69  		{`INSERT INTO a VALUES (ARRAY[0, 0, 0, 0, 0, 0, 0])`,
    70  			tree.FmtHideConstants,
    71  			`INSERT INTO a VALUES (ARRAY[_, _, __more5__])`},
    72  		{`INSERT INTO a VALUES (ARRAY[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ` +
    73  			`0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ` +
    74  			`0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])`,
    75  			tree.FmtHideConstants,
    76  			`INSERT INTO a VALUES (ARRAY[_, _, __more30__])`},
    77  
    78  		{`SELECT 1+COALESCE(NULL, 'a', x)-ARRAY[3.14]`, tree.FmtHideConstants,
    79  			`SELECT (_ + COALESCE(_, _, x)) - ARRAY[_]`},
    80  
    81  		// This here checks encodeSQLString on non-tree.DString strings also
    82  		// calls encodeSQLString with the right formatter.
    83  		// See TestFormatExprs below for the test on DStrings.
    84  		{`CREATE DATABASE foo TEMPLATE = 'bar-baz'`, tree.FmtBareStrings,
    85  			`CREATE DATABASE foo TEMPLATE = bar-baz`},
    86  		{`CREATE DATABASE foo TEMPLATE = 'bar baz'`, tree.FmtBareStrings,
    87  			`CREATE DATABASE foo TEMPLATE = 'bar baz'`},
    88  		{`CREATE DATABASE foo TEMPLATE = 'bar,baz'`, tree.FmtBareStrings,
    89  			`CREATE DATABASE foo TEMPLATE = 'bar,baz'`},
    90  		{`CREATE DATABASE foo TEMPLATE = 'bar{baz}'`, tree.FmtBareStrings,
    91  			`CREATE DATABASE foo TEMPLATE = 'bar{baz}'`},
    92  
    93  		{`SET "time zone" = UTC`, tree.FmtSimple,
    94  			`SET "time zone" = utc`},
    95  		{`SET "time zone" = UTC`, tree.FmtBareIdentifiers,
    96  			`SET time zone = utc`},
    97  		{`SET "time zone" = UTC`, tree.FmtBareStrings,
    98  			`SET "time zone" = utc`},
    99  	}
   100  
   101  	for i, test := range testData {
   102  		t.Run(fmt.Sprintf("%d %s", i, test.stmt), func(t *testing.T) {
   103  			stmt, err := parser.ParseOne(test.stmt)
   104  			if err != nil {
   105  				t.Fatal(err)
   106  			}
   107  			stmtStr := tree.AsStringWithFlags(stmt.AST, test.f)
   108  			if stmtStr != test.expected {
   109  				t.Fatalf("expected %q, got %q", test.expected, stmtStr)
   110  			}
   111  		})
   112  	}
   113  }
   114  
   115  func TestFormatTableName(t *testing.T) {
   116  	defer leaktest.AfterTest(t)()
   117  	testData := []struct {
   118  		stmt     string
   119  		expected string
   120  	}{
   121  		{`CREATE TABLE foo (x INT8)`,
   122  			`CREATE TABLE xoxoxo (x INT8)`},
   123  		{`INSERT INTO foo(x) TABLE bar`,
   124  			`INSERT INTO xoxoxo(x) TABLE xoxoxo`},
   125  		{`UPDATE foo SET x = y`,
   126  			`UPDATE xoxoxo SET x = y`},
   127  		{`DELETE FROM foo`,
   128  			`DELETE FROM xoxoxo`},
   129  		{`ALTER TABLE foo RENAME TO bar`,
   130  			`ALTER TABLE xoxoxo RENAME TO xoxoxo`},
   131  		{`SHOW COLUMNS FROM foo`,
   132  			`SHOW COLUMNS FROM xoxoxo`},
   133  		{`SHOW CREATE TABLE foo`,
   134  			`SHOW CREATE xoxoxo`},
   135  		// TODO(knz): TRUNCATE and GRANT table names are removed by
   136  		// tree.FmtAnonymize but not processed by table formatters.
   137  		//
   138  		// {`TRUNCATE foo`,
   139  		// `TRUNCATE TABLE xoxoxo`},
   140  		// {`GRANT SELECT ON bar TO foo`,
   141  		// `GRANT SELECT ON xoxoxo TO foo`},
   142  	}
   143  
   144  	f := tree.NewFmtCtx(tree.FmtSimple)
   145  	f.SetReformatTableNames(func(ctx *tree.FmtCtx, _ *tree.TableName) {
   146  		ctx.WriteString("xoxoxo")
   147  	})
   148  
   149  	for i, test := range testData {
   150  		t.Run(fmt.Sprintf("%d %s", i, test.stmt), func(t *testing.T) {
   151  			stmt, err := parser.ParseOne(test.stmt)
   152  			if err != nil {
   153  				t.Fatal(err)
   154  			}
   155  			f.Reset()
   156  			f.FormatNode(stmt.AST)
   157  			stmtStr := f.String()
   158  			if stmtStr != test.expected {
   159  				t.Fatalf("expected %q, got %q", test.expected, stmtStr)
   160  			}
   161  		})
   162  	}
   163  }
   164  
   165  func TestFormatExpr(t *testing.T) {
   166  	defer leaktest.AfterTest(t)()
   167  	testData := []struct {
   168  		expr     string
   169  		f        tree.FmtFlags
   170  		expected string
   171  	}{
   172  		{`null`, tree.FmtShowTypes,
   173  			`(NULL)[unknown]`},
   174  		{`true`, tree.FmtShowTypes,
   175  			`(true)[bool]`},
   176  		{`123`, tree.FmtShowTypes,
   177  			`(123)[int]`},
   178  		{`123.456`, tree.FmtShowTypes,
   179  			`(123.456)[decimal]`},
   180  		{`'abc'`, tree.FmtShowTypes,
   181  			`('abc')[string]`},
   182  		{`b'abc'`, tree.FmtShowTypes,
   183  			`('\x616263')[bytes]`},
   184  		{`B'10010'`, tree.FmtShowTypes,
   185  			`(B'10010')[varbit]`},
   186  		{`interval '3s'`, tree.FmtShowTypes,
   187  			`('00:00:03')[interval]`},
   188  		{`date '2003-01-01'`, tree.FmtShowTypes,
   189  			`('2003-01-01')[date]`},
   190  		{`timestamp '2003-01-01 00:00:00'`, tree.FmtShowTypes,
   191  			`('2003-01-01 00:00:00+00:00')[timestamp]`},
   192  		{`timestamptz '2003-01-01 00:00:00+03'`, tree.FmtShowTypes,
   193  			`('2003-01-01 00:00:00+03:00')[timestamptz]`},
   194  		{`greatest(unique_rowid(), 12)`, tree.FmtShowTypes,
   195  			`(greatest((unique_rowid())[int], (12)[int]))[int]`},
   196  
   197  		// While TestFormatStmt above checks StrVals, this here
   198  		// checks DStrings.
   199  		{`ARRAY['a','b c','d,e','f{g','h}i']`, tree.FmtBareStrings,
   200  			`ARRAY[a, 'b c', 'd,e', 'f{g', 'h}i']`},
   201  		// TODO(jordan): pg does *not* quote strings merely containing hex
   202  		// escapes when included in array values. #16487
   203  		// {`ARRAY[e'j\x10k']`, tree.FmtBareStrings,
   204  		//	 `ARRAY[j\x10k]`},
   205  
   206  		{`(-1):::INT`, tree.FmtParsableNumerics, "(-1)"},
   207  		{`'NaN':::FLOAT`, tree.FmtParsableNumerics, "'NaN'"},
   208  		{`'-Infinity':::FLOAT`, tree.FmtParsableNumerics, "'-Inf'"},
   209  		{`'Infinity':::FLOAT`, tree.FmtParsableNumerics, "'+Inf'"},
   210  		{`3.00:::FLOAT`, tree.FmtParsableNumerics, "3.0"},
   211  		{`(-3.00):::FLOAT`, tree.FmtParsableNumerics, "(-3.0)"},
   212  		{`'NaN':::DECIMAL`, tree.FmtParsableNumerics, "'NaN'"},
   213  		{`'-Infinity':::DECIMAL`, tree.FmtParsableNumerics, "'-Infinity'"},
   214  		{`'Infinity':::DECIMAL`, tree.FmtParsableNumerics, "'Infinity'"},
   215  		{`3.00:::DECIMAL`, tree.FmtParsableNumerics, "3.00"},
   216  		{`(-3.00):::DECIMAL`, tree.FmtParsableNumerics, "(-3.00)"},
   217  
   218  		{`1`, tree.FmtParsable, "1:::INT8"},
   219  		{`1:::INT`, tree.FmtParsable, "1:::INT8"},
   220  		{`9223372036854775807`, tree.FmtParsable, "9223372036854775807:::INT8"},
   221  		{`9223372036854775808`, tree.FmtParsable, "9223372036854775808:::DECIMAL"},
   222  		{`-1`, tree.FmtParsable, "(-1):::INT8"},
   223  		{`(-1):::INT`, tree.FmtParsable, "(-1):::INT8"},
   224  		{`-9223372036854775808`, tree.FmtParsable, "(-9223372036854775808):::INT8"},
   225  		{`-9223372036854775809`, tree.FmtParsable, "(-9223372036854775809):::DECIMAL"},
   226  		{`(-92233.1):::FLOAT`, tree.FmtParsable, "(-92233.1):::FLOAT8"},
   227  		{`92233.00:::DECIMAL`, tree.FmtParsable, "92233.00:::DECIMAL"},
   228  
   229  		{`B'00100'`, tree.FmtParsable, "B'00100'"},
   230  
   231  		{`unique_rowid() + 123`, tree.FmtParsable,
   232  			`unique_rowid() + 123:::INT8`},
   233  		{`sqrt(123.0) + 456`, tree.FmtParsable,
   234  			`sqrt(123.0:::DECIMAL) + 456:::DECIMAL`},
   235  		{`ROW()`, tree.FmtParsable, `()`},
   236  		{`now() + interval '3s'`, tree.FmtSimple,
   237  			`now() + '00:00:03'`},
   238  		{`now() + interval '3s'`, tree.FmtParsable,
   239  			`now():::TIMESTAMPTZ + '00:00:03':::INTERVAL`},
   240  		{`current_date() - date '2003-01-01'`, tree.FmtSimple,
   241  			`current_date() - '2003-01-01'`},
   242  		{`current_date() - date '2003-01-01'`, tree.FmtParsable,
   243  			`current_date() - '2003-01-01':::DATE`},
   244  		{`now() - timestamp '2003-01-01'`, tree.FmtSimple,
   245  			`now() - '2003-01-01 00:00:00+00:00'`},
   246  		{`now() - timestamp '2003-01-01'`, tree.FmtParsable,
   247  			`now():::TIMESTAMPTZ - '2003-01-01 00:00:00+00:00':::TIMESTAMP`},
   248  		{`'+Inf':::DECIMAL + '-Inf':::DECIMAL + 'NaN':::DECIMAL`, tree.FmtParsable,
   249  			`('Infinity':::DECIMAL + '-Infinity':::DECIMAL) + 'NaN':::DECIMAL`},
   250  		{`'+Inf':::FLOAT8 + '-Inf':::FLOAT8 + 'NaN':::FLOAT8`, tree.FmtParsable,
   251  			`('+Inf':::FLOAT8 + '-Inf':::FLOAT8) + 'NaN':::FLOAT8`},
   252  		{`'12:00:00':::TIME`, tree.FmtParsable,
   253  			`'12:00:00':::TIME`},
   254  		{`'63616665-6630-3064-6465-616462656562':::UUID`, tree.FmtParsable,
   255  			`'63616665-6630-3064-6465-616462656562':::UUID`},
   256  
   257  		{`(123:::INT, 123:::DECIMAL)`, tree.FmtCheckEquivalence,
   258  			`(123:::INT8, 123:::DECIMAL)`},
   259  
   260  		{`(1, COALESCE(NULL, 123), ARRAY[45.6])`, tree.FmtHideConstants,
   261  			`(_, COALESCE(_, _), ARRAY[_])`},
   262  	}
   263  
   264  	ctx := context.Background()
   265  	for i, test := range testData {
   266  		t.Run(fmt.Sprintf("%d %s", i, test.expr), func(t *testing.T) {
   267  			expr, err := parser.ParseExpr(test.expr)
   268  			if err != nil {
   269  				t.Fatal(err)
   270  			}
   271  			semaContext := tree.MakeSemaContext()
   272  			typeChecked, err := tree.TypeCheck(ctx, expr, &semaContext, types.Any)
   273  			if err != nil {
   274  				t.Fatal(err)
   275  			}
   276  			exprStr := tree.AsStringWithFlags(typeChecked, test.f)
   277  			if exprStr != test.expected {
   278  				t.Fatalf("expected %q, got %q", test.expected, exprStr)
   279  			}
   280  		})
   281  	}
   282  }
   283  
   284  func TestFormatExpr2(t *testing.T) {
   285  	defer leaktest.AfterTest(t)()
   286  	// This tests formatting from an expr AST. Suitable for use if your input
   287  	// isn't easily creatable from a string without running an Eval.
   288  	testData := []struct {
   289  		expr     tree.Expr
   290  		f        tree.FmtFlags
   291  		expected string
   292  	}{
   293  		{tree.NewDOidWithName(tree.DInt(10), types.RegClass, "foo"),
   294  			tree.FmtParsable, `crdb_internal.create_regclass(10,'foo'):::REGCLASS`},
   295  		{tree.NewDOidWithName(tree.DInt(10), types.RegProc, "foo"),
   296  			tree.FmtParsable, `crdb_internal.create_regproc(10,'foo'):::REGPROC`},
   297  		{tree.NewDOidWithName(tree.DInt(10), types.RegType, "foo"),
   298  			tree.FmtParsable, `crdb_internal.create_regtype(10,'foo'):::REGTYPE`},
   299  		{tree.NewDOidWithName(tree.DInt(10), types.RegNamespace, "foo"),
   300  			tree.FmtParsable, `crdb_internal.create_regnamespace(10,'foo'):::REGNAMESPACE`},
   301  
   302  		// Ensure that nulls get properly type annotated when printed in an
   303  		// enclosing tuple that has a type for their position within the tuple.
   304  		{tree.NewDTuple(
   305  			types.MakeTuple([]*types.T{types.Int, types.String}),
   306  			tree.DNull, tree.NewDString("foo")),
   307  			tree.FmtParsable,
   308  			`(NULL::INT8, 'foo':::STRING)`,
   309  		},
   310  		{tree.NewDTuple(
   311  			types.MakeTuple([]*types.T{types.Unknown, types.String}),
   312  			tree.DNull, tree.NewDString("foo")),
   313  			tree.FmtParsable,
   314  			`(NULL, 'foo':::STRING)`,
   315  		},
   316  		{&tree.DArray{
   317  			ParamTyp: types.Int,
   318  			Array:    tree.Datums{tree.DNull, tree.DNull},
   319  			HasNulls: true,
   320  		},
   321  			tree.FmtParsable,
   322  			`ARRAY[NULL,NULL]:::INT8[]`,
   323  		},
   324  
   325  		// Ensure that nulls get properly type annotated when printed in an
   326  	}
   327  
   328  	ctx := context.Background()
   329  	for i, test := range testData {
   330  		t.Run(fmt.Sprintf("%d %s", i, test.expr), func(t *testing.T) {
   331  			semaCtx := tree.MakeSemaContext()
   332  			typeChecked, err := tree.TypeCheck(ctx, test.expr, &semaCtx, types.Any)
   333  			if err != nil {
   334  				t.Fatal(err)
   335  			}
   336  			exprStr := tree.AsStringWithFlags(typeChecked, test.f)
   337  			if exprStr != test.expected {
   338  				t.Fatalf("expected %q, got %q", test.expected, exprStr)
   339  			}
   340  		})
   341  	}
   342  }
   343  
   344  func TestFormatPgwireText(t *testing.T) {
   345  	defer leaktest.AfterTest(t)()
   346  	testData := []struct {
   347  		expr     string
   348  		expected string
   349  	}{
   350  		{`true`, `t`},
   351  		{`false`, `f`},
   352  		{`ROW(1)`, `(1)`},
   353  		{`ROW(1, NULL)`, `(1,)`},
   354  		{`ROW(1, true, 3)`, `(1,t,3)`},
   355  		{`ROW(1, (2, 3))`, `(1,"(2,3)")`},
   356  		{`ROW(1, (2, 'a b'))`, `(1,"(2,""a b"")")`},
   357  		{`ROW(1, (2, 'a"b'))`, `(1,"(2,""a""""b"")")`},
   358  		{`ROW(1, 2, ARRAY[1,2,3])`, `(1,2,"{1,2,3}")`},
   359  		{`ROW(1, 2, ARRAY[1,NULL,3])`, `(1,2,"{1,NULL,3}")`},
   360  		{`ROW(1, 2, ARRAY['a','b','c'])`, `(1,2,"{a,b,c}")`},
   361  		{`ROW(1, 2, ARRAY[true,false,true])`, `(1,2,"{t,f,t}")`},
   362  		{`ARRAY[(1,2),(3,4)]`, `{"(1,2)","(3,4)"}`},
   363  		{`ARRAY[(false,'a'),(true,'b')]`, `{"(f,a)","(t,b)"}`},
   364  		{`ARRAY[(1,ARRAY[2,NULL])]`, `{"(1,\"{2,NULL}\")"}`},
   365  		{`ARRAY[(1,(1,2)),(2,(3,4))]`, `{"(1,\"(1,2)\")","(2,\"(3,4)\")"}`},
   366  
   367  		{`(((1, 'a b', 3), (4, 'c d'), ROW(6)), (7, 8), ROW('e f'))`,
   368  			`("(""(1,""""a b"""",3)"",""(4,""""c d"""")"",""(6)"")","(7,8)","(""e f"")")`},
   369  
   370  		{`(((1, '2', 3), (4, '5'), ROW(6)), (7, 8), ROW('9'))`,
   371  			`("(""(1,2,3)"",""(4,5)"",""(6)"")","(7,8)","(9)")`},
   372  
   373  		{`ARRAY[('a b',ARRAY['c d','e f']), ('g h',ARRAY['i j','k l'])]`,
   374  			`{"(\"a b\",\"{\"\"c d\"\",\"\"e f\"\"}\")","(\"g h\",\"{\"\"i j\"\",\"\"k l\"\"}\")"}`},
   375  
   376  		{`ARRAY[('1',ARRAY['2','3']), ('4',ARRAY['5','6'])]`,
   377  			`{"(1,\"{2,3}\")","(4,\"{5,6}\")"}`},
   378  
   379  		{`ARRAY[e'\U00002001☃']`, `{ ☃}`},
   380  	}
   381  	ctx := context.Background()
   382  	var evalCtx tree.EvalContext
   383  	for i, test := range testData {
   384  		t.Run(fmt.Sprintf("%d %s", i, test.expr), func(t *testing.T) {
   385  			expr, err := parser.ParseExpr(test.expr)
   386  			if err != nil {
   387  				t.Fatal(err)
   388  			}
   389  			semaCtx := tree.MakeSemaContext()
   390  			typeChecked, err := tree.TypeCheck(ctx, expr, &semaCtx, types.Any)
   391  			if err != nil {
   392  				t.Fatal(err)
   393  			}
   394  			typeChecked, err = evalCtx.NormalizeExpr(typeChecked)
   395  			if err != nil {
   396  				t.Fatal(err)
   397  			}
   398  			exprStr := tree.AsStringWithFlags(typeChecked, tree.FmtPgwireText)
   399  			if exprStr != test.expected {
   400  				t.Fatalf("expected %s, got %s", test.expected, exprStr)
   401  			}
   402  		})
   403  	}
   404  }
   405  
   406  // BenchmarkFormatRandomStatements measures the time needed to format
   407  // 1000 random statements.
   408  func BenchmarkFormatRandomStatements(b *testing.B) {
   409  	// Generate a bunch of random statements.
   410  	yBytes, err := ioutil.ReadFile(filepath.Join("..", "..", "parser", "sql.y"))
   411  	if err != nil {
   412  		b.Fatalf("error reading grammar: %v", err)
   413  	}
   414  	// Use a constant seed so multiple runs are consistent.
   415  	const seed = 1134
   416  	r, err := rsg.NewRSG(seed, string(yBytes), false)
   417  	if err != nil {
   418  		b.Fatalf("error instantiating RSG: %v", err)
   419  	}
   420  	strs := make([]string, 1000)
   421  	stmts := make([]tree.Statement, 1000)
   422  	for i := 0; i < 1000; {
   423  		rdm := r.Generate("stmt", 20)
   424  		stmt, err := parser.ParseOne(rdm)
   425  		if err != nil {
   426  			// Some statements (e.g. those containing error terminals) do
   427  			// not parse.  It's all right. Just ignore this and continue
   428  			// until we have all we want.
   429  			continue
   430  		}
   431  		strs[i] = rdm
   432  		stmts[i] = stmt.AST
   433  		i++
   434  	}
   435  
   436  	// Benchmark the parses.
   437  	b.Run("parse", func(b *testing.B) {
   438  		for i := 0; i < b.N; i++ {
   439  			for _, sql := range strs {
   440  				_, err := parser.ParseOne(sql)
   441  				if err != nil {
   442  					b.Fatal(err)
   443  				}
   444  			}
   445  		}
   446  	})
   447  
   448  	// Benchmark the formats.
   449  	b.Run("format", func(b *testing.B) {
   450  		for i := 0; i < b.N; i++ {
   451  			for i, stmt := range stmts {
   452  				f := tree.NewFmtCtx(tree.FmtSimple)
   453  				f.FormatNode(stmt)
   454  				strs[i] = f.CloseAndGetString()
   455  			}
   456  		}
   457  	})
   458  }