github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/cmd/docgen/diagrams.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 main 12 13 import ( 14 "bytes" 15 "fmt" 16 "io" 17 "io/ioutil" 18 "log" 19 "os" 20 "path/filepath" 21 "regexp" 22 "sort" 23 "strings" 24 "sync" 25 26 "github.com/cockroachdb/cockroach/pkg/cmd/docgen/extract" 27 "github.com/cockroachdb/cockroach/pkg/util/envutil" 28 "github.com/cockroachdb/errors" 29 "github.com/spf13/cobra" 30 ) 31 32 func init() { 33 const topStmt = "stmt_block" 34 35 // Global vars. 36 var ( 37 filter string 38 invertMatch bool 39 ) 40 41 write := func(name string, data []byte) { 42 if err := os.MkdirAll(filepath.Dir(name), 0755); err != nil { 43 log.Fatal(err) 44 } 45 if err := ioutil.WriteFile(name, data, 0644); err != nil { 46 log.Fatal(err) 47 } 48 } 49 50 // BNF vars. 51 var ( 52 addr string 53 ) 54 55 cmdBNF := &cobra.Command{ 56 Use: "bnf [dir]", 57 Short: "Generate EBNF from sql.y.", 58 Args: cobra.ExactArgs(1), 59 Run: func(cmd *cobra.Command, args []string) { 60 bnfDir := args[0] 61 bnf, err := runBNF(addr) 62 if err != nil { 63 log.Fatal(err) 64 } 65 br := func() io.Reader { 66 return bytes.NewReader(bnf) 67 } 68 69 filterRE := regexp.MustCompile(filter) 70 71 if filterRE.MatchString(topStmt) != invertMatch { 72 name := topStmt 73 if !quiet { 74 fmt.Println("processing", name) 75 } 76 g, err := runParse(br(), nil, name, true, true, nil, nil) 77 if err != nil { 78 log.Fatalf("%s: %+v", name, err) 79 } 80 write(filepath.Join(bnfDir, name+".bnf"), g) 81 } 82 83 for _, s := range specs { 84 if filterRE.MatchString(s.name) == invertMatch { 85 continue 86 } 87 if !quiet { 88 fmt.Println("processing", s.name) 89 } 90 if s.stmt == "" { 91 s.stmt = s.name 92 } 93 g, err := runParse(br(), s.inline, s.stmt, false, s.nosplit, s.match, s.exclude) 94 if err != nil { 95 log.Fatalf("%s: %+v", s.name, err) 96 } 97 if !quiet { 98 fmt.Printf("raw data:\n%s\n", string(g)) 99 } 100 replacements := make([]string, 0, len(s.replace)) 101 for from := range s.replace { 102 replacements = append(replacements, from) 103 } 104 sort.Strings(replacements) 105 for _, from := range replacements { 106 if !quiet { 107 fmt.Printf("replacing: %q -> %q\n", from, s.replace[from]) 108 } 109 g = bytes.Replace(g, []byte(from), []byte(s.replace[from]), -1) 110 } 111 replacements = replacements[:0] 112 for from := range s.regreplace { 113 replacements = append(replacements, from) 114 } 115 sort.Strings(replacements) 116 for _, from := range replacements { 117 if !quiet { 118 fmt.Printf("replacing re: %q -> %q\n", from, s.replace[from]) 119 } 120 re := regexp.MustCompile(from) 121 g = re.ReplaceAll(g, []byte(s.regreplace[from])) 122 } 123 if !quiet { 124 fmt.Printf("result:\n%s\n", string(g)) 125 } 126 write(filepath.Join(bnfDir, s.name+".bnf"), g) 127 } 128 }, 129 } 130 131 cmdBNF.Flags().StringVar(&addr, "addr", "./pkg/sql/parser/sql.y", "Location of sql.y file. Can also specify an http address.") 132 133 // SVG vars. 134 var ( 135 maxWorkers int 136 railroadJar string 137 ) 138 139 cmdSVG := &cobra.Command{ 140 Use: "svg [bnf dir] [svg dir]", 141 Short: "Generate SVG diagrams from SQL grammar", 142 Long: `With no arguments, generates SQL diagrams for all statements.`, 143 Args: cobra.ExactArgs(2), 144 Run: func(cmd *cobra.Command, args []string) { 145 bnfDir := args[0] 146 svgDir := args[1] 147 if railroadJar != "" { 148 _, err := os.Stat(railroadJar) 149 if err != nil { 150 if envutil.EnvOrDefaultBool("COCKROACH_REQUIRE_RAILROAD", false) { 151 log.Fatalf("%s not found\n", railroadJar) 152 } else { 153 log.Printf("%s not found, falling back to slower web service (employees can find Railroad.jar on Google Drive).", railroadJar) 154 railroadJar = "" 155 } 156 } 157 } 158 159 filterRE := regexp.MustCompile(filter) 160 stripRE := regexp.MustCompile("\n(\n| )+") 161 162 matches, err := filepath.Glob(filepath.Join(bnfDir, "*.bnf")) 163 if err != nil { 164 log.Fatal(err) 165 } 166 167 specMap := make(map[string]stmtSpec) 168 for _, s := range specs { 169 specMap[s.name] = s 170 } 171 if len(specs) != len(specMap) { 172 log.Fatal("duplicate spec name") 173 } 174 175 var wg sync.WaitGroup 176 sem := make(chan struct{}, maxWorkers) // max number of concurrent workers 177 for _, m := range matches { 178 name := strings.TrimSuffix(filepath.Base(m), ".bnf") 179 if filterRE.MatchString(name) == invertMatch { 180 continue 181 } 182 wg.Add(1) 183 sem <- struct{}{} 184 go func(m, name string) { 185 defer wg.Done() 186 defer func() { <-sem }() 187 188 if !quiet { 189 fmt.Printf("generating svg of %s (%s)\n", name, m) 190 } 191 192 f, err := os.Open(m) 193 if err != nil { 194 log.Fatal(err) 195 } 196 defer f.Close() 197 198 rr, err := runRR(f, railroadJar) 199 if err != nil { 200 log.Fatalf("%s: %s\n", m, err) 201 } 202 203 var body string 204 if strings.HasSuffix(m, topStmt+".bnf") { 205 body, err = extract.InnerTag(bytes.NewReader(rr), "body") 206 body = strings.SplitN(body, "<hr/>", 2)[0] 207 body += `<p>generated by <a href="http://www.bottlecaps.de/rr/ui" data-proofer-ignore>Railroad Diagram Generator</a></p>` 208 body = fmt.Sprintf("<div>%s</div>", body) 209 if err != nil { 210 log.Fatal(err) 211 } 212 } else { 213 s, ok := specMap[name] 214 if !ok { 215 log.Fatalf("unfound spec: %s", name) 216 } 217 body, err = extract.Tag(bytes.NewReader(rr), "svg") 218 if err != nil { 219 log.Fatal(err) 220 } 221 body = strings.Replace(body, `<a xlink:href="#`, `<a xlink:href="sql-grammar.html#`, -1) 222 for _, u := range s.unlink { 223 s := fmt.Sprintf(`<a xlink:href="sql-grammar.html#%s" xlink:title="%s">((?s).*?)</a>`, u, u) 224 link := regexp.MustCompile(s) 225 body = link.ReplaceAllString(body, "$1") 226 } 227 for from, to := range s.relink { 228 replaceFrom := fmt.Sprintf(`<a xlink:href="sql-grammar.html#%s" xlink:title="%s">`, from, from) 229 replaceTo := fmt.Sprintf(`<a xlink:href="sql-grammar.html#%s" xlink:title="%s">`, to, to) 230 body = strings.Replace(body, replaceFrom, replaceTo, -1) 231 } 232 // Wrap the output in a <div> so that the Markdown parser 233 // doesn't attempt to parse the inside of the contained 234 // <svg> as Markdown. 235 body = fmt.Sprintf(`<div>%s</div>`, body) 236 // Remove blank lines and strip spaces. 237 body = stripRE.ReplaceAllString(body, "\n") + "\n" 238 } 239 name = strings.Replace(name, "_stmt", "", 1) 240 write(filepath.Join(svgDir, name+".html"), []byte(body)) 241 }(m, name) 242 } 243 wg.Wait() 244 }, 245 } 246 247 cmdSVG.Flags().IntVar(&maxWorkers, "max-workers", 1, "maximum number of concurrent workers") 248 cmdSVG.Flags().StringVar(&railroadJar, "railroad", "", "Location of Railroad.jar; empty to use website") 249 250 diagramCmd := &cobra.Command{ 251 Use: "grammar", 252 Short: "Generate diagrams.", 253 } 254 255 diagramCmd.PersistentFlags().StringVar(&filter, "filter", ".*", "Filter statement names (regular expression)") 256 diagramCmd.PersistentFlags().BoolVar(&invertMatch, "invert-match", false, "Generate everything that doesn't match the filter") 257 258 diagramCmd.AddCommand(cmdBNF, cmdSVG) 259 cmds = append(cmds, diagramCmd) 260 } 261 262 // stmtSpec is needed for each top-level bnf file to process. 263 // See the wiki page for more details about what these controls do. 264 // https://github.com/cockroachdb/docs/wiki/SQL-Grammar-Railroad-Diagram-Changes#structure 265 type stmtSpec struct { 266 name string 267 stmt string // if unspecified, uses name 268 inline []string 269 replace map[string]string 270 regreplace map[string]string 271 match, exclude []*regexp.Regexp 272 unlink []string 273 relink map[string]string 274 nosplit bool 275 } 276 277 func runBNF(addr string) ([]byte, error) { 278 return extract.GenerateBNF(addr) 279 } 280 281 func runParse( 282 r io.Reader, 283 inline []string, 284 topStmt string, 285 descend, nosplit bool, 286 match, exclude []*regexp.Regexp, 287 ) ([]byte, error) { 288 g, err := extract.ParseGrammar(r) 289 if err != nil { 290 return nil, errors.Wrap(err, "parse grammar") 291 } 292 if err := g.Inline(inline...); err != nil { 293 return nil, errors.Wrap(err, "inline") 294 } 295 b, err := g.ExtractProduction(topStmt, descend, nosplit, match, exclude) 296 b = bytes.Replace(b, []byte("'IDENT'"), []byte("'identifier'"), -1) 297 b = bytes.Replace(b, []byte("_LA"), []byte(""), -1) 298 return b, err 299 } 300 301 func runRR(r io.Reader, railroadJar string) ([]byte, error) { 302 b, err := ioutil.ReadAll(r) 303 if err != nil { 304 return nil, err 305 } 306 var html []byte 307 if railroadJar == "" { 308 html, err = extract.GenerateRRNet(b) 309 } else { 310 html, err = extract.GenerateRRJar(railroadJar, b) 311 } 312 if err != nil { 313 return nil, err 314 } 315 s, err := extract.XHTMLtoHTML(bytes.NewReader(html)) 316 return []byte(s), err 317 } 318 319 var specs = []stmtSpec{ 320 { 321 name: "add_column", 322 stmt: "alter_onetable_stmt", 323 inline: []string{"alter_table_cmds", "alter_table_cmd", "column_def", "col_qual_list"}, 324 regreplace: map[string]string{ 325 ` \( \( col_qualification \) \)\* .*`: `( ( col_qualification ) )*`, 326 }, 327 match: []*regexp.Regexp{regexp.MustCompile("'ADD' ('COLUMN')? ?('IF' 'NOT' 'EXISTS')? ?column_name")}, 328 replace: map[string]string{ 329 "relation_expr": "table_name", 330 }, 331 unlink: []string{"table_name"}, 332 }, 333 { 334 name: "add_constraint", 335 stmt: "alter_onetable_stmt", 336 replace: map[string]string{"relation_expr": "table_name", "alter_table_cmds": "'ADD' 'CONSTRAINT' constraint_name constraint_elem opt_validate_behavior"}, 337 unlink: []string{"table_name"}, 338 }, 339 { 340 name: "alter_column", 341 stmt: "alter_onetable_stmt", 342 inline: []string{"alter_table_cmds", "alter_table_cmd", "opt_column", "alter_column_default", "opt_set_data", "opt_collate", "opt_alter_column_using"}, 343 regreplace: map[string]string{ 344 regList: "", 345 }, 346 match: []*regexp.Regexp{regexp.MustCompile("relation_expr 'ALTER' ")}, 347 replace: map[string]string{ 348 "relation_expr": "table_name", 349 }, 350 unlink: []string{"table_name"}, 351 }, 352 { 353 name: "alter_role_stmt", 354 inline: []string{"role_or_group_or_user", "opt_role_options"}, 355 replace: map[string]string{ 356 "string_or_placeholder": "name", 357 "opt_role_options": "OPTIONS", 358 "string_or_placeholder 'PASSWORD'": "name 'PASSWORD'", 359 "'PASSWORD' string_or_placeholder": "'PASSWORD' password"}, 360 unlink: []string{"name", "password"}, 361 }, 362 { 363 name: "alter_sequence_options_stmt", 364 inline: []string{"sequence_option_list", "sequence_option_elem"}, 365 replace: map[string]string{"relation_expr": "sequence_name", "signed_iconst64": "integer"}, 366 unlink: []string{"integer", "sequence_name"}, 367 nosplit: true, 368 }, 369 { 370 name: "alter_table", 371 stmt: "alter_onetable_stmt", 372 inline: []string{"alter_table_cmds", "alter_table_cmd", "column_def", "opt_drop_behavior", "alter_column_default", "opt_column", "opt_set_data", "table_constraint", "opt_collate", "opt_alter_column_using"}, 373 replace: map[string]string{ 374 "'VALIDATE' 'CONSTRAINT' name": "", 375 "opt_validate_behavior": "", 376 "relation_expr": "table_name"}, 377 unlink: []string{"table_name"}, 378 nosplit: true, 379 }, 380 { 381 name: "alter_type", 382 stmt: "alter_onetable_stmt", 383 inline: []string{"alter_table_cmds", "alter_table_cmd", "opt_column", "opt_set_data"}, 384 match: []*regexp.Regexp{regexp.MustCompile(`'ALTER' ('COLUMN')? column_name ('SET' 'DATA')? 'TYPE'`)}, 385 regreplace: map[string]string{ 386 regList: "", 387 " opt_collate": "", 388 " opt_alter_column_using": "", 389 }, 390 replace: map[string]string{ 391 "relation_expr": "table_name", 392 }, 393 unlink: []string{"table_name", "column_name"}, 394 }, 395 { 396 name: "alter_view", 397 stmt: "alter_rename_view_stmt", 398 inline: []string{"opt_transaction"}, 399 replace: map[string]string{"relation_expr": "view_name", "qualified_name": "name"}, unlink: []string{"view_name", "name"}, 400 }, 401 { 402 name: "alter_zone_database_stmt", 403 inline: []string{"set_zone_config", "var_set_list"}, 404 replace: map[string]string{"var_name": "variable", "var_value": "value"}, 405 unlink: []string{"variable", "value"}, 406 }, 407 { 408 name: "alter_zone_index_stmt", 409 inline: []string{"table_index_name", "set_zone_config", "var_set_list"}, 410 replace: map[string]string{"var_name": "variable", "var_value": "value", "standalone_index_name": "index_name"}, 411 unlink: []string{"variable", "value"}, 412 }, 413 { 414 name: "alter_zone_range_stmt", 415 inline: []string{"set_zone_config", "var_set_list"}, 416 replace: map[string]string{"zone_name": "range_name", "var_name": "variable", "var_value": "value"}, 417 unlink: []string{"range_name", "variable", "value"}, 418 }, 419 { 420 name: "alter_zone_table_stmt", 421 inline: []string{"set_zone_config", "var_set_list"}, 422 replace: map[string]string{"var_name": "variable", "var_value": "value"}, 423 unlink: []string{"variable", "value"}, 424 }, 425 { 426 name: "alter_zone_partition_stmt", 427 inline: []string{"table_index_name", "set_zone_config", "var_set_list"}, 428 replace: map[string]string{"var_name": "variable", "var_value": "value", "standalone_index_name": "index_name"}, 429 unlink: []string{"variable", "value"}, 430 }, 431 { 432 name: "backup", 433 stmt: "backup_stmt", 434 inline: []string{"table_pattern_list", "name_list", "opt_as_of_clause", "opt_incremental", "opt_with_options"}, 435 match: []*regexp.Regexp{regexp.MustCompile("'BACKUP'")}, 436 replace: map[string]string{ 437 "non_reserved_word_or_sconst": "destination", 438 "'AS' 'OF' 'SYSTEM' 'TIME' a_expr": "'AS OF SYSTEM TIME' timestamp", 439 "'INCREMENTAL' 'FROM' string_or_placeholder_list": "'INCREMENTAL FROM' full_backup_location ( | ',' incremental_backup_location ( ',' incremental_backup_location )* )", 440 "'WITH' 'OPTIONS' '(' kv_option_list ')'": "", 441 "targets": "( ( 'TABLE' | ) table_pattern ( ( ',' table_pattern ) )* | 'DATABASE' database_name ( ( ',' database_name ) )* )", 442 }, 443 unlink: []string{"destination", "timestamp", "full_backup_location", "incremental_backup_location"}, 444 }, 445 { 446 name: "begin_transaction", 447 stmt: "begin_stmt", 448 inline: []string{ 449 "opt_transaction", 450 "begin_transaction", 451 "transaction_mode", 452 "transaction_user_priority", 453 "user_priority", 454 "iso_level", 455 "transaction_mode_list", 456 "opt_comma", 457 "transaction_read_mode", 458 "as_of_clause", 459 }, 460 exclude: []*regexp.Regexp{ 461 regexp.MustCompile("'START'"), 462 }, 463 }, 464 { 465 name: "check_column_level", 466 stmt: "stmt_block", 467 replace: map[string]string{" stmt": " 'CREATE' 'TABLE' table_name '(' column_name column_type 'CHECK' '(' check_expr ')' ( column_constraints | ) ( ',' ( column_def ( ',' column_def )* ) | ) ( table_constraints | ) ')' ')'"}, 468 unlink: []string{"table_name", "column_name", "column_type", "check_expr", "column_constraints", "table_constraints"}, 469 }, 470 { 471 name: "check_table_level", 472 stmt: "stmt_block", 473 replace: map[string]string{" stmt": " 'CREATE' 'TABLE' table_name '(' ( column_def ( ',' column_def )* ) ( 'CONSTRAINT' constraint_name | ) 'CHECK' '(' check_expr ')' ( table_constraints | ) ')'"}, 474 unlink: []string{"table_name", "check_expr", "table_constraints"}, 475 }, 476 { 477 name: "column_def", 478 stmt: "column_def", 479 inline: []string{"col_qual_list"}, 480 }, 481 { 482 name: "col_qualification", 483 stmt: "col_qualification", 484 inline: []string{"col_qualification_elem"}, 485 }, 486 { 487 name: "comment", 488 stmt: "comment_stmt", 489 replace: map[string]string{"column_path": "column_name"}, 490 unlink: []string{"column_path"}, 491 }, 492 { 493 name: "commit_transaction", 494 stmt: "commit_stmt", 495 inline: []string{"opt_transaction"}, 496 match: []*regexp.Regexp{regexp.MustCompile("'COMMIT'|'END'")}, 497 }, 498 { 499 name: "cancel_job", 500 stmt: "cancel_jobs_stmt", 501 replace: map[string]string{"a_expr": "job_id"}, 502 unlink: []string{"job_id"}, 503 }, 504 { 505 name: "create_as_col_qual_list", 506 inline: []string{"create_as_col_qualification", "create_as_col_qualification_elem"}, 507 }, 508 { 509 name: "create_as_constraint_def", 510 inline: []string{"create_as_constraint_elem"}, 511 }, 512 {name: "cancel_query", stmt: "cancel_queries_stmt", replace: map[string]string{"a_expr": "query_id"}, unlink: []string{"query_id"}}, 513 {name: "cancel_session", stmt: "cancel_sessions_stmt", replace: map[string]string{"a_expr": "session_id"}, unlink: []string{"session_id"}}, 514 {name: "create_database_stmt", inline: []string{"opt_encoding_clause"}, replace: map[string]string{"'SCONST'": "encoding"}, unlink: []string{"name", "encoding"}}, 515 { 516 name: "create_changefeed_stmt", 517 inline: []string{"changefeed_targets", "single_table_pattern_list", "opt_changefeed_sink", "opt_with_options", "kv_option_list", "kv_option"}, 518 replace: map[string]string{ 519 "table_option": "table_name", 520 "'INTO' string_or_placeholder": "'INTO' sink", 521 "name": "option", 522 "'SCONST'": "option", 523 "'=' string_or_placeholder": "'=' value"}, 524 exclude: []*regexp.Regexp{ 525 regexp.MustCompile("'OPTIONS'")}, 526 unlink: []string{"table_name", "sink", "option", "value"}, 527 }, 528 { 529 name: "create_index_stmt", 530 inline: []string{"opt_unique", "opt_storing", "storing", "index_params", "index_elem", "opt_asc_desc", "opt_using_gin_btree"}, 531 replace: map[string]string{ 532 "a_expr": "column_name", 533 "opt_nulls_order": "", 534 }, 535 regreplace: map[string]string{ 536 ".* 'CREATE' .* 'INVERTED' 'INDEX' .*": "", 537 }, 538 nosplit: true, 539 }, 540 { 541 name: "create_index_interleaved_stmt", 542 stmt: "create_index_stmt", 543 match: []*regexp.Regexp{regexp.MustCompile("'INTERLEAVE'")}, 544 inline: []string{"opt_unique", "opt_storing", "opt_interleave"}, 545 replace: map[string]string{ 546 "a_expr": "column_name", 547 " opt_index_name": "", 548 " opt_partition_by": "", 549 " opt_using_gin_btree": "", 550 "'ON' table_name '(' index_params ')'": "'...'", 551 "storing '(' name_list ')'": "'STORING' '(' stored_columns ')'", 552 "table_name '(' name_list": "parent_table '(' interleave_prefix", 553 }, 554 exclude: []*regexp.Regexp{ 555 regexp.MustCompile("'CREATE' 'INVERTED'"), 556 regexp.MustCompile("'EXISTS'"), 557 }, 558 unlink: []string{"stored_columns", "parent_table", "interleave_prefix"}, 559 }, 560 { 561 name: "create_inverted_index_stmt", 562 stmt: "create_index_stmt", 563 match: []*regexp.Regexp{regexp.MustCompile("'CREATE' 'INVERTED'")}, 564 inline: []string{"opt_storing", "storing", "opt_unique", "opt_name", "index_params", "index_elem", "opt_asc_desc"}, 565 }, 566 { 567 name: "create_sequence_stmt", 568 inline: []string{"opt_sequence_option_list", "sequence_option_list", "sequence_option_elem"}, 569 replace: map[string]string{"signed_iconst64": "integer", "any_name": "sequence_name"}, 570 unlink: []string{"integer", "sequence_name"}, 571 nosplit: true, 572 }, 573 { 574 name: "create_stats_stmt", 575 replace: map[string]string{"name_list": "column_name"}, 576 unlink: []string{"statistics_name", "column_name"}, 577 }, 578 { 579 name: "create_table_as_stmt", 580 inline: []string{"create_as_opt_col_list", "create_as_table_defs"}, 581 }, 582 { 583 name: "create_table_stmt", 584 inline: []string{"opt_table_elem_list", "table_elem_list", "table_elem"}, 585 }, 586 { 587 name: "create_view_stmt", 588 inline: []string{"opt_column_list"}, 589 }, 590 { 591 name: "create_role_stmt", 592 inline: []string{"role_or_group_or_user", "opt_role_options"}, 593 replace: map[string]string{ 594 "string_or_placeholder": "name", 595 "opt_role_options": "OPTIONS", 596 "string_or_placeholder 'PASSWORD'": "name 'PASSWORD'", 597 "'PASSWORD' string_or_placeholder": "'PASSWORD' password"}, 598 }, 599 { 600 name: "default_value_column_level", 601 stmt: "stmt_block", 602 replace: map[string]string{ 603 " stmt": " 'CREATE' 'TABLE' table_name '(' column_name column_type 'DEFAULT' default_value ( column_constraints | ) ( ',' ( column_def ( ',' column_def )* ) | ) ( table_constraints | ) ')' ')'", 604 }, 605 unlink: []string{"table_name", "column_name", "column_type", "default_value", "table_constraints"}, 606 }, 607 { 608 name: "delete_stmt", 609 inline: []string{"opt_with_clause", "with_clause", "cte_list", "table_expr_opt_alias_idx", "table_name_opt_idx", "opt_where_clause", "where_clause", "returning_clause", "opt_sort_clause", "opt_limit_clause"}, 610 replace: map[string]string{ 611 "relation_expr": "table_name", 612 }, 613 unlink: []string{"count"}, 614 nosplit: true, 615 }, 616 { 617 name: "with_clause", 618 inline: []string{"cte_list", "common_table_expr", "name_list", "opt_column_list"}, 619 replace: map[string]string{ 620 "preparable_stmt ')' ) ) )* )": "preparable_stmt ')' ) ) )* ) ( insert_stmt | update_stmt | delete_stmt | upsert_stmt | select_stmt )", 621 }, 622 nosplit: true, 623 }, 624 { 625 name: "drop_column", 626 stmt: "alter_onetable_stmt", 627 inline: []string{"alter_table_cmds", "alter_table_cmd", "opt_column", "opt_drop_behavior"}, 628 match: []*regexp.Regexp{regexp.MustCompile("relation_expr 'DROP' 'COLUMN'")}, 629 regreplace: map[string]string{ 630 regList: "", 631 }, 632 replace: map[string]string{ 633 "relation_expr": "table_name", 634 "column_name": "name", 635 }, 636 unlink: []string{"table_name", "name"}, 637 }, 638 { 639 name: "drop_constraint", 640 stmt: "alter_onetable_stmt", 641 inline: []string{"alter_table_cmds", "alter_table_cmd", "opt_drop_behavior"}, 642 match: []*regexp.Regexp{regexp.MustCompile("relation_expr 'DROP' 'CONSTRAINT'")}, 643 regreplace: map[string]string{ 644 regList: "", 645 }, 646 replace: map[string]string{ 647 "relation_expr": "table_name", 648 "constraint_name": "name", 649 }, 650 unlink: []string{"table_name"}, 651 }, 652 { 653 name: "drop_database", 654 stmt: "drop_database_stmt", 655 inline: []string{"opt_drop_behavior"}, 656 match: []*regexp.Regexp{regexp.MustCompile("'DROP' 'DATABASE'")}, 657 }, 658 { 659 name: "drop_index", 660 stmt: "drop_index_stmt", 661 match: []*regexp.Regexp{regexp.MustCompile("'DROP' 'INDEX'")}, 662 inline: []string{"opt_drop_behavior", "table_index_name_list", "table_index_name"}, 663 regreplace: map[string]string{ 664 regList: "", 665 }, 666 replace: map[string]string{"standalone_index_name": "index_name"}, 667 }, 668 { 669 name: "drop_role_stmt", 670 inline: []string{"role_or_group_or_user"}, 671 replace: map[string]string{"string_or_placeholder_list": "name"}, 672 }, 673 { 674 name: "drop_sequence_stmt", 675 inline: []string{"table_name_list", "opt_drop_behavior"}, 676 unlink: []string{"sequence_name"}, 677 }, 678 { 679 name: "drop_stmt", 680 inline: []string{"table_name_list", "drop_ddl_stmt"}, 681 }, 682 { 683 name: "drop_table", 684 stmt: "drop_table_stmt", 685 inline: []string{"opt_drop_behavior", "table_name_list"}, 686 match: []*regexp.Regexp{regexp.MustCompile("'DROP' 'TABLE'")}, 687 }, 688 { 689 name: "drop_view", 690 stmt: "drop_view_stmt", 691 inline: []string{"opt_drop_behavior", "table_name_list"}, 692 match: []*regexp.Regexp{regexp.MustCompile("'DROP' 'VIEW'")}, 693 }, 694 { 695 name: "experimental_audit", 696 stmt: "alter_onetable_stmt", 697 inline: []string{"audit_mode", "alter_table_cmd", "alter_table_cmds"}, 698 match: []*regexp.Regexp{regexp.MustCompile(`relation_expr 'EXPERIMENTAL_AUDIT'`)}, 699 replace: map[string]string{ 700 "relation_expr": "table_name", 701 }, 702 regreplace: map[string]string{ 703 `'READ' 'WRITE' .*`: `'READ' 'WRITE'`, 704 `'OFF' .*`: `'OFF'`, 705 }, 706 }, 707 { 708 name: "alter_table_partition_by", 709 stmt: "alter_onetable_stmt", 710 inline: []string{"alter_table_cmds", "alter_table_cmd", "partition_by"}, 711 replace: map[string]string{"relation_expr": "table_name"}, 712 regreplace: map[string]string{ 713 `'NOTHING' .*`: `'NOTHING'`, 714 `_partitions '\)' .*`: `_partitions ')'`, 715 }, 716 match: []*regexp.Regexp{regexp.MustCompile("relation_expr 'PARTITION")}, 717 }, 718 { 719 name: "alter_index_partition_by", 720 stmt: "alter_oneindex_stmt", 721 inline: []string{"alter_index_cmds", "alter_index_cmd", "partition_by", "table_index_name"}, 722 replace: map[string]string{"standalone_index_name": "index_name"}, 723 }, 724 { 725 name: "create_table_partition_by", 726 stmt: "create_table_stmt", 727 inline: []string{"opt_partition_by", "partition_by"}, 728 replace: map[string]string{"opt_table_elem_list": "table_definition", "opt_interleave": ""}, 729 match: []*regexp.Regexp{regexp.MustCompile("PARTITION")}, 730 unlink: []string{"table_definition"}, 731 }, 732 { 733 name: "explain_stmt", 734 inline: []string{"explain_option_list"}, 735 replace: map[string]string{ 736 "explain_option_name": "( 'VERBOSE' | 'TYPES' | 'OPT' | 'DISTSQL' | 'VEC' )", 737 }, 738 exclude: []*regexp.Regexp{ 739 regexp.MustCompile("'ANALYZE'"), 740 regexp.MustCompile("'ANALYSE'"), 741 }, 742 }, 743 { 744 name: "explain_analyze_stmt", 745 stmt: "explain_stmt", 746 match: []*regexp.Regexp{regexp.MustCompile("'ANALY[SZ]E'")}, 747 replace: map[string]string{ 748 "explain_option_list": "'DISTSQL'", 749 }, 750 unlink: []string{"'DISTSQL'"}, 751 }, 752 { 753 name: "export_stmt", 754 replace: map[string]string{ 755 "import_data_format": "CSV", 756 "string_or_placeholder": "file_location", 757 "select_stmt": "(| 'select_stmt' | 'TABLE' 'table_name')", 758 }, 759 unlink: []string{"CSV", "file_location"}, 760 }, 761 { 762 name: "family_def", 763 inline: []string{"name_list"}, 764 }, 765 { 766 name: "grant_privileges", 767 stmt: "grant_stmt", 768 inline: []string{"privileges", "privilege_list", "privilege", "table_pattern_list", "name_list"}, 769 replace: map[string]string{ 770 "( name | 'CREATE' | 'GRANT' | 'SELECT' )": "( 'CREATE' | 'GRANT' | 'SELECT' | 'DROP' | 'INSERT' | 'DELETE' | 'UPDATE' )", 771 "table_pattern": "table_name", 772 "'TO' ( ( name ) ( ( ',' name ) )*": "'TO' ( ( user_name ) ( ( ',' user_name ) )*", 773 "| 'GRANT' ( ( ( 'CREATE' | 'GRANT' | 'SELECT' | 'DROP' | 'INSERT' | 'DELETE' | 'UPDATE' ) ) ( ( ',' ( 'CREATE' | 'GRANT' | 'SELECT' | 'DROP' | 'INSERT' | 'DELETE' | 'UPDATE' ) ) )* ) 'TO' ( ( user_name ) ( ( ',' user_name ) )* )": "", 774 "'WITH' 'ADMIN' 'OPTION'": "", 775 "targets": "( ( 'TABLE' | ) table_pattern ( ( ',' table_pattern ) )* | 'DATABASE' database_name ( ( ',' database_name ) )* )", 776 }, 777 unlink: []string{"table_name", "database_name", "user_name"}, 778 nosplit: true, 779 }, 780 { 781 name: "grant_roles", 782 stmt: "grant_stmt", 783 replace: map[string]string{ 784 "'GRANT' privileges 'ON' targets 'TO' name_list": "", 785 "'GRANT' privilege_list 'TO' name_list 'WITH' 'ADMIN' 'OPTION'": "'GRANT' ( role_name ) ( ( ',' role_name ) )* 'TO' ( user_name ) ( ( ',' user_name ) )* 'WITH' 'ADMIN' 'OPTION'", 786 "| 'GRANT' privilege_list 'TO' name_list": "'GRANT' ( role_name ) ( ( ',' role_name ) )* 'TO' ( user_name ) ( ( ',' user_name ) )*", 787 }, 788 unlink: []string{"role_name", "user_name"}, 789 }, 790 { 791 name: "foreign_key_column_level", 792 stmt: "stmt_block", 793 replace: map[string]string{" stmt": " 'CREATE' 'TABLE' table_name '(' column_name column_type 'REFERENCES' parent_table ( '(' ref_column_name ')' | ) ( column_constraints | ) ( ',' ( column_def ( ',' column_def )* ) | ) ( table_constraints | ) ')' ')'"}, 794 unlink: []string{"table_name", "column_name", "column_type", "parent_table", "table_constraints"}, 795 }, 796 { 797 name: "foreign_key_table_level", 798 stmt: "stmt_block", 799 replace: map[string]string{" stmt": " 'CREATE' 'TABLE' table_name '(' ( column_def ( ',' column_def )* ) ( 'CONSTRAINT' constraint_name | ) 'FOREIGN KEY' '(' ( fk_column_name ( ',' fk_column_name )* ) ')' 'REFERENCES' parent_table ( '(' ( ref_column_name ( ',' ref_column_name )* ) ')' | ) ( table_constraints | ) ')'"}, 800 unlink: []string{"table_name", "column_name", "parent_table", "table_constraints"}, 801 }, 802 { 803 name: "index_def", 804 inline: []string{"opt_storing", "storing", "index_params", "opt_name"}, 805 }, 806 { 807 name: "import_csv", 808 stmt: "import_stmt", 809 inline: []string{"string_or_placeholder_list", "opt_with_options"}, 810 exclude: []*regexp.Regexp{ 811 regexp.MustCompile("'IMPORT' import_format"), 812 regexp.MustCompile("'FROM' import_format"), 813 regexp.MustCompile("'WITH' 'OPTIONS'"), 814 }, 815 replace: map[string]string{ 816 "string_or_placeholder": "file_location", 817 "import_format": "'CSV'", 818 }, 819 unlink: []string{"file_location"}, 820 }, 821 { 822 name: "import_into", 823 stmt: "import_stmt", 824 match: []*regexp.Regexp{regexp.MustCompile("INTO")}, 825 inline: []string{"insert_column_list", "string_or_placeholder_list", "opt_with_options", "kv_option_list"}, 826 replace: map[string]string{ 827 "table_option": "table_name", 828 "insert_column_item": "column_name", 829 "import_format": "'CSV'", 830 "string_or_placeholder": "file_location", 831 "kv_option": "option '=' value"}, 832 unlink: []string{"table_name", "column_name", "file_location", "option", "value"}, 833 exclude: []*regexp.Regexp{ 834 regexp.MustCompile("'WITH' 'OPTIONS'"), 835 }, 836 }, 837 { 838 name: "import_dump", 839 stmt: "import_stmt", 840 inline: []string{"string_or_placeholder_list", "opt_with_options"}, 841 exclude: []*regexp.Regexp{ 842 regexp.MustCompile("CREATE' 'USING'"), 843 regexp.MustCompile("table_elem_list"), 844 regexp.MustCompile("'WITH' 'OPTIONS'"), 845 }, 846 replace: map[string]string{ 847 "string_or_placeholder": "file_location", 848 }, 849 unlink: []string{"file_location"}, 850 }, 851 { 852 name: "insert_stmt", 853 inline: []string{"insert_target", "insert_rest", "returning_clause", "insert_column_list", "insert_column_item", "target_list", "opt_with_clause", "with_clause", "cte_list"}, 854 nosplit: true, 855 }, 856 { 857 name: "on_conflict", 858 inline: []string{"opt_conf_expr", "name_list", "set_clause_list", "insert_column_list", 859 "insert_column_item", "set_clause", "single_set_clause", "multiple_set_clause", "in_expr", "expr_list", 860 "expr_tuple1_ambiguous", "tuple1_ambiguous_values"}, 861 replace: map[string]string{ 862 "select_with_parens": "'(' select_stmt ')'", 863 "opt_where_clause": "", 864 }, 865 nosplit: true, 866 }, 867 {name: "iso_level"}, 868 { 869 name: "interleave", 870 stmt: "create_table_stmt", 871 inline: []string{"opt_interleave"}, 872 replace: map[string]string{"opt_table_elem_list": "table_definition"}, 873 unlink: []string{"table_definition"}, 874 }, 875 { 876 name: "not_null_column_level", 877 stmt: "stmt_block", 878 replace: map[string]string{" stmt": " 'CREATE' 'TABLE' table_name '(' column_name column_type 'NOT NULL' ( column_constraints | ) ( ',' ( column_def ( ',' column_def )* ) | ) ( table_constraints | ) ')' ')'"}, 879 unlink: []string{"table_name", "column_name", "column_type", "table_constraints"}, 880 }, 881 { 882 name: "opt_interleave", 883 }, 884 { 885 name: "pause_job", 886 stmt: "pause_stmt", 887 replace: map[string]string{"a_expr": "job_id"}, 888 unlink: []string{"job_id"}, 889 }, 890 { 891 name: "primary_key_column_level", 892 stmt: "stmt_block", 893 replace: map[string]string{" stmt": " 'CREATE' 'TABLE' table_name '(' column_name column_type 'PRIMARY KEY' ( column_constraints | ) ( ',' ( column_def ( ',' column_def )* ) | ) ( table_constraints | ) ')' ')'"}, 894 unlink: []string{"table_name", "column_name", "column_type", "table_constraints"}, 895 }, 896 { 897 name: "primary_key_table_level", 898 stmt: "stmt_block", 899 replace: map[string]string{" stmt": " 'CREATE' 'TABLE' table_name '(' ( column_def ( ',' column_def )* ) ( 'CONSTRAINT' name | ) 'PRIMARY KEY' '(' ( column_name ( ',' column_name )* ) ')' ( table_constraints | ) ')'"}, 900 unlink: []string{"table_name", "column_name", "table_constraints"}, 901 }, 902 { 903 name: "release_savepoint", 904 stmt: "release_stmt", 905 inline: []string{"savepoint_name"}, 906 }, 907 { 908 name: "rename_column", 909 stmt: "alter_rename_table_stmt", 910 inline: []string{"opt_column"}, 911 match: []*regexp.Regexp{regexp.MustCompile("'ALTER' 'TABLE' .* 'RENAME' ('COLUMN'|name)")}, 912 replace: map[string]string{"relation_expr": "table_name", "name 'TO'": "current_name 'TO'"}, 913 unlink: []string{"table_name", "current_name"}, 914 }, 915 { 916 name: "rename_constraint", 917 stmt: "alter_onetable_stmt", 918 replace: map[string]string{"relation_expr": "table_name", "alter_table_cmds": "'RENAME' 'CONSTRAINT' current_name 'TO' name"}, 919 unlink: []string{"table_name", "current_name"}, 920 }, 921 { 922 name: "rename_database", 923 stmt: "alter_rename_database_stmt", 924 match: []*regexp.Regexp{regexp.MustCompile("'ALTER' 'DATABASE'")}}, 925 { 926 name: "rename_index", 927 stmt: "alter_rename_index_stmt", 928 match: []*regexp.Regexp{regexp.MustCompile("'ALTER' 'INDEX'")}, 929 inline: []string{"table_index_name"}, 930 replace: map[string]string{"standalone_index_name": "index_name"}, 931 }, 932 { 933 name: "rename_sequence", 934 stmt: "alter_rename_sequence_stmt", 935 match: []*regexp.Regexp{regexp.MustCompile("'ALTER' 'SEQUENCE' .* 'RENAME' 'TO'")}, 936 replace: map[string]string{"relation_expr": "current_name", "sequence_name": "new_name"}, 937 unlink: []string{"current_name"}, 938 relink: map[string]string{"new_name": "name"}}, 939 { 940 name: "rename_table", 941 stmt: "alter_rename_table_stmt", 942 match: []*regexp.Regexp{regexp.MustCompile("'ALTER' 'TABLE' .* 'RENAME' 'TO'")}, 943 replace: map[string]string{"relation_expr": "current_name", "qualified_name": "new_name"}, 944 unlink: []string{"current_name"}, relink: map[string]string{"new_name": "name"}}, 945 { 946 name: "restore", 947 stmt: "restore_stmt", 948 inline: []string{"as_of_clause", "opt_with_options"}, 949 replace: map[string]string{ 950 "a_expr": "timestamp", 951 "string_or_placeholder_list": "full_backup_location ( | incremental_backup_location ( ',' incremental_backup_location )*)", 952 "'WITH' 'OPTIONS' '(' kv_option_list ')'": "", 953 "targets": "( ( 'TABLE' | ) table_pattern ( ( ',' table_pattern ) )* | 'DATABASE' database_name ( ( ',' database_name ) )* )", 954 }, 955 unlink: []string{"timestamp", "full_backup_location", "incremental_backup_location"}, 956 }, 957 { 958 name: "resume_job", 959 stmt: "resume_stmt", 960 replace: map[string]string{"a_expr": "job_id"}, 961 unlink: []string{"job_id"}, 962 }, 963 { 964 name: "revoke_privileges", 965 stmt: "revoke_stmt", 966 inline: []string{"privileges", "privilege_list", "privilege", "name_list"}, 967 replace: map[string]string{ 968 "( name | 'CREATE' | 'GRANT' | 'SELECT' )": "( 'CREATE' | 'GRANT' | 'SELECT' | 'DROP' | 'INSERT' | 'DELETE' | 'UPDATE' )", 969 "targets": "( ( 'TABLE' | ) table_pattern ( ( ',' table_pattern ) )* | 'DATABASE' database_name ( ( ',' database_name ) )* )", 970 "'FROM' ( ( name ) ( ( ',' name ) )*": "'FROM' ( ( user_name ) ( ( ',' user_name ) )*", 971 "| 'REVOKE' ( ( ( 'CREATE' | 'GRANT' | 'SELECT' | 'DROP' | 'INSERT' | 'DELETE' | 'UPDATE' ) ) ( ( ',' ( 'CREATE' | 'GRANT' | 'SELECT' | 'DROP' | 'INSERT' | 'DELETE' | 'UPDATE' ) ) )* ) 'FROM' ( ( user_name ) ( ( ',' user_name ) )* )": "", 972 "| 'REVOKE' ( ( ( 'CREATE' | 'GRANT' | 'SELECT' | 'DROP' | 'INSERT' | 'DELETE' | 'UPDATE' ) ) ( ( ',' ( 'CREATE' | 'GRANT' | 'SELECT' | 'DROP' | 'INSERT' | 'DELETE' | 'UPDATE' ) ) )* ) 'FROM' ( ( user_name ) ( ( ',' user_name ) )* )": "", 973 "'ADMIN' 'OPTION' 'FOR'": "", 974 }, 975 unlink: []string{"table_name", "database_name", "user_name"}, 976 nosplit: true, 977 }, 978 { 979 name: "revoke_roles", 980 stmt: "revoke_stmt", 981 replace: map[string]string{ 982 "'REVOKE' privileges 'ON' targets 'FROM' name_list": "", 983 "'REVOKE' 'ADMIN' 'OPTION' 'FOR' privilege_list 'FROM' name_list": "'REVOKE' 'ADMIN' 'OPTION' 'FOR' ( role_name ) ( ( ',' role_name ) )* 'FROM' ( user_name ) ( ( ',' user_name ) )*", 984 "| 'REVOKE' privilege_list 'FROM' name_list": "'REVOKE' ( role_name ) ( ( ',' role_name ) )* 'FROM' ( user_name ) ( ( ',' user_name ) )*", 985 }, 986 unlink: []string{"role_name", "user_name"}, 987 }, 988 { 989 name: "rollback_transaction", 990 stmt: "rollback_stmt", 991 inline: []string{"opt_transaction"}, 992 match: []*regexp.Regexp{regexp.MustCompile("'ROLLBACK'")}, 993 replace: map[string]string{"'TRANSACTION'": "", "'TO'": "'TO' 'SAVEPOINT'"}, 994 }, 995 { 996 name: "limit_clause", 997 inline: []string{"row_or_rows", "first_or_next"}, 998 replace: map[string]string{ 999 "select_limit_value": "count", 1000 "opt_select_fetch_first_value": "count", 1001 }, 1002 }, 1003 { 1004 name: "offset_clause", 1005 inline: []string{"row_or_rows"}, 1006 }, 1007 {name: "savepoint_stmt", inline: []string{"savepoint_name"}}, 1008 { 1009 name: "select_stmt", 1010 inline: []string{ 1011 "with_clause", 1012 "cte_list", 1013 "select_no_parens", 1014 "opt_sort_clause", 1015 "select_limit", 1016 }, 1017 replace: map[string]string{ 1018 "( simple_select |": "(", 1019 "| select_with_parens": "", 1020 "select_clause sort_clause | select_clause ( sort_clause | ) ( limit_clause offset_clause | offset_clause limit_clause | limit_clause | offset_clause )": "select_clause ( sort_clause | ) ( limit_clause | ) ( offset_clause | )", 1021 "| ( 'WITH' ( ( common_table_expr ) ( ( ',' common_table_expr ) )* ) ) select_clause sort_clause | ( 'WITH' ( ( common_table_expr ) ( ( ',' common_table_expr ) )* ) ) select_clause ( sort_clause | ) ( limit_clause offset_clause | offset_clause limit_clause | limit_clause | offset_clause )": "( sort_clause | ) ( limit_clause | ) ( offset_clause | )", 1022 }, 1023 unlink: []string{"index_name"}, 1024 nosplit: true, 1025 }, 1026 { 1027 name: "select_clause", 1028 inline: []string{"simple_select"}, 1029 replace: map[string]string{ 1030 "| select_with_parens": "| '(' ( simple_select_clause | values_clause | table_clause | set_operation ) ')'", 1031 }, 1032 nosplit: true, 1033 }, 1034 {name: "table_clause"}, 1035 { 1036 name: "set_operation", 1037 inline: []string{"all_or_distinct"}, 1038 nosplit: true, 1039 }, 1040 { 1041 name: "values_clause", 1042 inline: []string{"expr_list"}, 1043 }, 1044 { 1045 name: "simple_select_clause", 1046 inline: []string{"opt_all_clause", "distinct_clause", "distinct_on_clause", "opt_as_of_clause", "as_of_clause", "expr_list", "target_list", "from_clause", "opt_where_clause", "where_clause", "group_clause", "having_clause", "window_clause", "from_list"}, 1047 unlink: []string{"index_name"}, 1048 nosplit: true, 1049 }, 1050 { 1051 name: "joined_table", 1052 inline: []string{"join_qual", "name_list", "join_type", "join_outer"}, 1053 nosplit: true, 1054 }, 1055 { 1056 name: "table_ref", 1057 inline: []string{"opt_ordinality", "opt_alias_clause", "opt_expr_list", "opt_column_list", "name_list", "alias_clause"}, 1058 replace: map[string]string{ 1059 "select_with_parens": "'(' select_stmt ')'", 1060 "opt_index_flags": "( '@' index_name | )", 1061 "relation_expr": "table_name", 1062 "func_table": "func_application", 1063 // "| func_name '(' ( expr_list | ) ')' ( 'WITH' 'ORDINALITY' | ) ( ( 'AS' table_alias_name ( '(' ( ( name ) ( ( ',' name ) )* ) ')' | ) | table_alias_name ( '(' ( ( name ) ( ( ',' name ) )* ) ')' | ) ) | )": "", 1064 "| special_function ( 'WITH' 'ORDINALITY' | ) ( ( 'AS' table_alias_name ( '(' ( ( name ) ( ( ',' name ) )* ) ')' | ) | table_alias_name ( '(' ( ( name ) ( ( ',' name ) )* ) ')' | ) ) | )": "", 1065 "| '(' joined_table ')' ( 'WITH' 'ORDINALITY' | ) ( 'AS' table_alias_name ( '(' ( ( name ) ( ( ',' name ) )* ) ')' | ) | table_alias_name ( '(' ( ( name ) ( ( ',' name ) )* ) ')' | ) )": "| '(' joined_table ')' ( 'WITH' 'ORDINALITY' | ) ( ( 'AS' table_alias_name ( '(' ( ( name ) ( ( ',' name ) )* ) ')' | ) | table_alias_name ( '(' ( ( name ) ( ( ',' name ) )* ) ')' | ) ) | )", 1066 }, 1067 unlink: []string{"index_name"}, 1068 nosplit: true, 1069 }, 1070 { 1071 name: "set_var", 1072 stmt: "preparable_set_stmt", 1073 inline: []string{"set_session_stmt", "set_rest_more", "generic_set", "var_list", "to_or_eq"}, 1074 exclude: []*regexp.Regexp{ 1075 regexp.MustCompile(`'SET' . 'TRANSACTION'`), 1076 regexp.MustCompile(`'SET' 'TRANSACTION'`), 1077 regexp.MustCompile(`'SET' 'SESSION' var_name`), 1078 regexp.MustCompile(`'SET' 'SESSION' 'TRANSACTION'`), 1079 regexp.MustCompile(`'SET' 'SESSION' 'CHARACTERISTICS'`), 1080 regexp.MustCompile("'SET' 'CLUSTER'"), 1081 }, 1082 replace: map[string]string{ 1083 "'=' 'DEFAULT'": "'=' 'DEFAULT' | 'SET' 'TIME' 'ZONE' ( var_value | 'DEFAULT' | 'LOCAL' )", 1084 "'SET' var_name": "'SET' ( 'SESSION' | ) var_name", 1085 }, 1086 }, 1087 { 1088 name: "set_cluster_setting", 1089 stmt: "preparable_set_stmt", 1090 inline: []string{"set_csetting_stmt", "generic_set", "var_list", "to_or_eq"}, 1091 match: []*regexp.Regexp{ 1092 regexp.MustCompile("'SET' 'CLUSTER'"), 1093 }, 1094 }, 1095 { 1096 name: "set_transaction", 1097 stmt: "nonpreparable_set_stmt", 1098 inline: []string{ 1099 "set_transaction_stmt", 1100 "transaction_mode", 1101 "transaction_mode_list", 1102 "transaction_read_mode", 1103 "transaction_user_priority", 1104 "user_priority", 1105 "as_of_clause", 1106 "opt_comma", 1107 }, 1108 match: []*regexp.Regexp{regexp.MustCompile("'SET' 'TRANSACTION'")}, 1109 }, 1110 { 1111 name: "show_var", 1112 stmt: "show_stmt", 1113 exclude: []*regexp.Regexp{ 1114 regexp.MustCompile("'SHOW' 'ALL' 'CLUSTER'"), 1115 regexp.MustCompile("'SHOW' 'IN"), // INDEX, INDEXES 1116 regexp.MustCompile("'SHOW' '[B-HJ-Z]"), // Keep ALL and IDENT. 1117 }, 1118 replace: map[string]string{"identifier": "var_name"}, 1119 }, 1120 { 1121 name: "show_cluster_setting", 1122 stmt: "show_csettings_stmt", 1123 }, 1124 { 1125 name: "show_columns_stmt", 1126 inline: []string{"with_comment"}, 1127 }, 1128 { 1129 name: "show_constraints", 1130 stmt: "show_stmt", 1131 match: []*regexp.Regexp{regexp.MustCompile("'SHOW' 'CONSTRAINTS'")}, 1132 replace: map[string]string{"var_name": "table_name"}, 1133 unlink: []string{"table_name"}, 1134 }, 1135 { 1136 name: "show_create_stmt", 1137 replace: map[string]string{"table_name": "object_name"}, 1138 unlink: []string{"object_name"}, 1139 }, 1140 { 1141 name: "show_databases_stmt", 1142 inline: []string{"with_comment"}, 1143 }, 1144 { 1145 name: "show_backup", 1146 stmt: "show_backup_stmt", 1147 match: []*regexp.Regexp{regexp.MustCompile("'SHOW' 'BACKUP'")}, 1148 replace: map[string]string{"string_or_placeholder": "location"}, 1149 unlink: []string{"location"}, 1150 }, 1151 { 1152 name: "show_jobs", 1153 stmt: "show_jobs_stmt", 1154 replace: map[string]string{"a_expr": "job_id"}, 1155 unlink: []string{"job_id"}, 1156 }, 1157 { 1158 name: "show_grants_stmt", 1159 inline: []string{"name_list", "opt_on_targets_roles", "for_grantee_clause", "name_list"}, 1160 replace: map[string]string{ 1161 "targets_roles": "( 'ROLE' | 'ROLE' name ( ',' name ) )* | ( 'TABLE' | ) table_pattern ( ( ',' table_pattern ) )* | 'DATABASE' database_name ( ( ',' database_name ) )* )", 1162 "'FOR' name ( ( ',' name ) )*": "'FOR' user_name ( ( ',' user_name ) )*", 1163 }, 1164 unlink: []string{"role_name", "table_name", "database_name", "user_name"}, 1165 }, 1166 { 1167 name: "show_indexes", 1168 stmt: "show_indexes_stmt", 1169 }, 1170 { 1171 name: "show_index", 1172 stmt: "show_stmt", 1173 match: []*regexp.Regexp{regexp.MustCompile("'SHOW' 'INDEX'")}, 1174 replace: map[string]string{"var_name": "table_name"}, 1175 unlink: []string{"table_name"}, 1176 }, 1177 { 1178 name: "show_keys", 1179 stmt: "show_stmt", 1180 match: []*regexp.Regexp{regexp.MustCompile("'SHOW' 'KEYS'")}, 1181 }, 1182 { 1183 name: "show_locality", 1184 stmt: "show_roles_stmt", 1185 replace: map[string]string{"'ROLES'": "'LOCALITY'"}, 1186 }, 1187 { 1188 name: "show_partitions_stmt", 1189 }, 1190 { 1191 name: "show_queries", 1192 stmt: "show_queries_stmt", 1193 inline: []string{"opt_cluster"}, 1194 }, 1195 { 1196 name: "show_roles_stmt", 1197 }, 1198 { 1199 name: "show_users_stmt", 1200 }, 1201 { 1202 name: "show_ranges_stmt", 1203 stmt: "show_ranges_stmt", 1204 }, 1205 { 1206 name: "show_range_for_row_stmt", 1207 stmt: "show_range_for_row_stmt", 1208 inline: []string{"expr_list"}, 1209 replace: map[string]string{"a_expr": "row_vals"}, 1210 unlink: []string{"row_vals"}, 1211 }, 1212 { 1213 name: "show_schemas", 1214 stmt: "show_schemas_stmt", 1215 }, 1216 { 1217 name: "show_sequences", 1218 stmt: "show_sequences_stmt", 1219 }, 1220 { 1221 name: "show_sessions", 1222 stmt: "show_sessions_stmt", 1223 inline: []string{"opt_cluster"}, 1224 }, 1225 { 1226 name: "show_stats", 1227 stmt: "show_stats_stmt", 1228 }, 1229 { 1230 name: "show_tables", 1231 stmt: "show_tables_stmt", 1232 inline: []string{"with_comment"}, 1233 replace: map[string]string{"'FROM' name": "'FROM' database_name", "'.' name": "'.' schema_name"}, 1234 unlink: []string{"schema.name"}, 1235 }, 1236 { 1237 name: "show_trace", 1238 stmt: "show_trace_stmt", 1239 inline: []string{"opt_compact"}, 1240 exclude: []*regexp.Regexp{regexp.MustCompile("'SHOW' 'EXPERIMENTAL_REPLICA'")}, 1241 }, 1242 { 1243 name: "show_transaction", 1244 stmt: "show_stmt", 1245 match: []*regexp.Regexp{regexp.MustCompile("'SHOW' 'TRANSACTION'")}, 1246 }, 1247 { 1248 name: "show_savepoint_status", 1249 stmt: "show_savepoint_stmt", 1250 match: []*regexp.Regexp{regexp.MustCompile("'SHOW' 'SAVEPOINT' 'STATUS'")}, 1251 }, 1252 { 1253 name: "show_zone_stmt", 1254 inline: []string{"opt_partition", "table_index_name", "partition"}, 1255 }, 1256 { 1257 name: "sort_clause", 1258 inline: []string{"sortby_list", "sortby", "opt_asc_desc", "opt_nulls_order"}, 1259 }, 1260 { 1261 name: "split_index_at", 1262 stmt: "alter_split_index_stmt", 1263 inline: []string{"table_index_name"}, 1264 replace: map[string]string{"standalone_index_name": "index_name"}, 1265 }, 1266 { 1267 name: "split_table_at", 1268 stmt: "alter_split_stmt", 1269 unlink: []string{"table_name"}, 1270 }, 1271 { 1272 name: "table_constraint", 1273 inline: []string{"constraint_elem", "opt_storing", "storing"}, 1274 }, 1275 { 1276 name: "truncate_stmt", 1277 inline: []string{"opt_table", "relation_expr_list", "opt_drop_behavior"}, 1278 replace: map[string]string{"relation_expr": "table_name"}, 1279 unlink: []string{"table_name"}, 1280 }, 1281 { 1282 name: "unique_column_level", 1283 stmt: "stmt_block", 1284 replace: map[string]string{" stmt": " 'CREATE' 'TABLE' table_name '(' column_name column_type 'UNIQUE' ( column_constraints | ) ( ',' ( column_def ( ',' column_def )* ) | ) ( table_constraints | ) ')' ')'"}, 1285 unlink: []string{"table_name", "column_name", "column_type", "table_constraints"}, 1286 }, 1287 { 1288 name: "unique_table_level", 1289 stmt: "stmt_block", 1290 replace: map[string]string{" stmt": " 'CREATE' 'TABLE' table_name '(' ( column_def ( ',' column_def )* ) ( 'CONSTRAINT' name | ) 'UNIQUE' '(' ( column_name ( ',' column_name )* ) ')' ( table_constraints | ) ')'"}, 1291 unlink: []string{"table_name", "check_expr", "table_constraints"}, 1292 }, 1293 { 1294 name: "unsplit_index_at", 1295 stmt: "alter_unsplit_index_stmt", 1296 inline: []string{"table_index_name"}, 1297 replace: map[string]string{"standalone_index_name": "index_name"}, 1298 }, 1299 { 1300 name: "unsplit_table_at", 1301 stmt: "alter_unsplit_stmt", 1302 unlink: []string{"table_name"}, 1303 }, 1304 { 1305 name: "update_stmt", 1306 inline: []string{ 1307 "opt_with_clause", 1308 "with_clause", 1309 "cte_list", 1310 "table_expr_opt_alias_idx", 1311 "table_name_opt_idx", 1312 "set_clause_list", 1313 "set_clause", 1314 "single_set_clause", 1315 "multiple_set_clause", 1316 "in_expr", 1317 "expr_list", 1318 "expr_tuple1_ambiguous", 1319 "tuple1_ambiguous_values", 1320 "opt_where_clause", 1321 "where_clause", 1322 "opt_sort_clause", 1323 "returning_clause", 1324 "insert_column_list", 1325 "insert_column_item", 1326 "opt_limit_clause", 1327 }, 1328 replace: map[string]string{ 1329 "relation_expr": "table_name", 1330 "select_with_parens": "'(' select_stmt ')'", 1331 }, 1332 relink: map[string]string{ 1333 "table_name": "relation_expr", 1334 "column_name_list": "insert_column_list", 1335 }, 1336 nosplit: true, 1337 }, 1338 { 1339 name: "upsert_stmt", 1340 stmt: "upsert_stmt", 1341 inline: []string{"insert_target", "insert_rest", "returning_clause", "opt_with_clause", "with_clause", "cte_list", "insert_column_list", "insert_column_item"}, 1342 unlink: []string{"select_stmt"}, 1343 nosplit: true, 1344 }, 1345 { 1346 name: "validate_constraint", 1347 stmt: "alter_onetable_stmt", 1348 replace: map[string]string{"alter_table_cmds": "'VALIDATE' 'CONSTRAINT' constraint_name", "relation_expr": "table_name"}, 1349 unlink: []string{"constraint_name", "table_name"}, 1350 }, 1351 { 1352 name: "window_definition", 1353 inline: []string{"window_specification"}, 1354 }, 1355 { 1356 name: "opt_frame_clause", 1357 inline: []string{"frame_extent"}, 1358 }, 1359 } 1360 1361 // regList is a common regex used when removing loops from alter and drop 1362 // statements. 1363 const regList = ` \( \( ',' .* \) \)\*`