Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add actual check of --error command not just that an error exists #52

Merged
merged 25 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
50cd967
Add actual check of --error command not just that an error exists
mjonss Jan 14, 2022
503d997
Added --check-error flag (default false) to keep old behavior unless set
mjonss Jan 19, 2022
d6aaba0
Added tool for generate perror which also includes TiDB error codes
mjonss Jan 19, 2022
9f216d9
Merge remote-tracking branch 'pingcap/master' into check-error
mjonss Nov 9, 2022
9b48712
Merge remote-tracking branch 'pingcap/master' into check-error
mjonss Nov 21, 2023
f765db4
Cleanup from manual merge (removed commented out code)
mjonss Nov 21, 2023
a9d9a88
removed duplicate perror and updated warning for unset --check-error
mjonss Nov 21, 2023
c493931
Added wait for exec.Command().Start()
mjonss Nov 21, 2023
bec7b97
Fixed log levels
mjonss Nov 21, 2023
6a94e90
Lowered log levels
mjonss Nov 21, 2023
12fc198
minor Makefile update
mjonss Nov 21, 2023
27f93fa
Update generate_perror/main.go
mjonss Nov 21, 2023
6dd3181
Update .gitignore
mjonss Nov 21, 2023
6d4fae9
Update generate_perror/main.go
mjonss Nov 21, 2023
80e0743
Update generate_perror/main.go
mjonss Nov 21, 2023
2e026ea
Added error check in generate_perror
mjonss Nov 21, 2023
dd155fd
code cleanup (commented out code only)
mjonss Nov 21, 2023
260499d
Code cleanup
mjonss Nov 21, 2023
555cefe
simplify the logging of gen_perror
mjonss Nov 21, 2023
8373650
Updated to go 1.21
mjonss Nov 21, 2023
85f2af2
Used the fileHeader constant
mjonss Nov 21, 2023
606e03a
fixed make test
mjonss Nov 21, 2023
7e1d9e1
Added support for --error with --replace_regex
mjonss Nov 22, 2023
2cf23e5
Added support for --error with --replace_regex
mjonss Nov 22, 2023
4d06c73
Update generate_perror/main.go
mjonss Nov 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mysql-tester
gen_perror
### STS ###
.apt_generated
.classpath
Expand Down
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ default: build
build:
go build -o mysql-tester ./src

test:
debug:
go build -gcflags="all=-N -l" -o mysql-tester ./src

test: build
go test -cover ./...
#./mysql-tester -check-error

tidy:
go mod tidy
Expand All @@ -15,3 +19,5 @@ clean:
go clean -i ./...
rm -rf mysql-tester

gen_perror: generate_perror/main.go
go build -o gen_perror ./generate_perror
183 changes: 183 additions & 0 deletions generate_perror/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// Copyright 2023 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"bufio"
"flag"
"fmt"
"log"
"os"
"os/exec"
"regexp"
"sort"
"strconv"
)

const (
fileHeader = `// Copyright 2023 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

// Generated by generate_perror/main.go
package main

var MysqlErrNameToNum = map[string]int{
`
)

var (
tidbCodePath string
)

func init() {
flag.StringVar(&tidbCodePath, "path", "../tidb", "Path to TiDB source code root directory.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean we need to rely on tidb?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in the same way as it relies on perror (a binary from the mysql distribution, to map error numbers to error code names).
If TiDB would have a similar program/binary/utility, to map error codes to names, we could use that instead of reading the source code.

But since we are generating the perror.go file, with the mapping, and that is checked into the mysql-tester repository, it only depends on perror and tidb repository when it needs to be updated. So it does not have any direct dependencies, only needs the dependencies when new error codes needs to be added.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it.

}

func checkNewErr(errCode string, i int, nameToNum map[string]int) {
if v, ok := nameToNum[errCode]; ok {
if i != v {
if errCode != "handler" {
// Ignore the HA_ERR codes, which are all 'handler'
log.Printf("Duplicate error errCode %s (%d != %d)", errCode, i, v)
}
}
} else {
nameToNum[errCode] = i
}
}

func scanErrCodeFile(fileName string, nameToNum map[string]int) {
f, err := os.Open(fileName)
if err != nil {
log.Fatal(err)
}
defer f.Close()
s := bufio.NewScanner(f)
r := regexp.MustCompile(`^\s+(\w+)*\s+=\s+(\d+)$`)
for s.Scan() {
m := r.FindStringSubmatch(s.Text())
if m != nil && len(m) == 3 && m[1] != "" && m[2] != "" {
i, err := strconv.Atoi(m[2])
if err != nil {
log.Fatal(err)
}
checkNewErr(m[1], i, nameToNum)
}
}
if s.Err() != nil {
log.Fatal(s.Err())
}
}

type ErrorCodeAndName struct {
Code int
Name string
}

func main() {
NameToNum := make(map[string]int)

// First extract the known error names => numbers from TiDB errno module

// Second extract the known error names => numbers from TiDB parser/mysql module

// Last use the perror program to extract error names from 1..20000 from MySQL

flag.Parse()

scanErrCodeFile(filepath.Join(tidbCodePath, "/pkg/errno/errcode.go"), NameToNum)
errnoCodes := len(NameToNum)
log.Printf("Got %d error codes from errno/errcode.go!", errnoCodes)
scanErrCodeFile(tidbCodePath+"/pkg/parser/mysql/errcode.go", NameToNum)
parserCodes := len(NameToNum) - errnoCodes
log.Printf("Got %d New error codes from parser/mysql/errcode.go!", parserCodes)

// similar to:
//seq 1 100000 | xargs perror 2> /dev/null | grep '^MySQL error code MY-[0-9]* ([A-Z_]*).*' | sed 's/^MySQL error code MY-0*\([[:digit:]]*\) (\([^)]*\)).*/"\2": \1,/'
maxError := 20000
log.Printf("Running perror for error codes 1..%d, may take some time...", maxError)
for i := 1; i <= maxError; i++ {
if i%1000 == 0 {
fmt.Printf("\r%d", i)
}
cmd := exec.Command("perror", strconv.Itoa(i))
stdout, err := cmd.StdoutPipe()
if err != nil {
log.Fatal(err)
}
if err = cmd.Start(); err != nil {
log.Fatal(err)
}
s := bufio.NewScanner(stdout)
r := regexp.MustCompile(`^MySQL error code MY-0*(\d+) \((\w+)\)`)
for s.Scan() {
m := r.FindStringSubmatch(s.Text())
if m != nil && len(m) == 3 && m[1] != "" && m[2] != "" {
c, err := strconv.Atoi(m[1])
if err != nil {
log.Fatal(err)
}
if c != i {
log.Fatalf("perror gave error with wrong number? (Want: %d Got: %d)", i, c)
}
checkNewErr(m[2], i, NameToNum)
}
}
cmd.Wait()
}
if maxError >= 1000 {
fmt.Printf("\r")
}
log.Printf("Got %d New error codes from perror!", len(NameToNum)-parserCodes-errnoCodes)
f, err := os.Create("perror.go")
if err != nil {
log.Fatal(err)
}
defer f.Close()
w := bufio.NewWriter(f)
_, err = w.WriteString(fileHeader)

if err != nil {
log.Fatal(err)
}

codes := make([]ErrorCodeAndName, 0, len(NameToNum))
for k, v := range NameToNum {
codes = append(codes, ErrorCodeAndName{Code: v, Name: k})
}
sort.Slice(codes, func(i, j int) bool {
return codes[i].Code < codes[j].Code || codes[i].Code == codes[j].Code && codes[i].Name < codes[j].Name
})
for i, _ := range codes {
_, err = w.WriteString("\t\"" + codes[i].Name + `": ` + strconv.Itoa(codes[i].Code) + ",\n")
if err != nil {
log.Fatal(err)
}
}
_, err = w.WriteString("}\n")
if err != nil {
log.Fatal(err)
}
w.Flush()
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/pingcap/mysql-tester

go 1.19
go 1.21

require (
// It forks from github.com/go-sql-driver/mysql v1.7.1
Expand Down
20 changes: 20 additions & 0 deletions r/example.result
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,25 @@ insert into t values(1, 1), (2, 2), (3, 3), (4, 4), (5, 5);
select * from t where a = 1;
a b
1 1
SELECT 1 FROM NON_EXISTING_TABLE;
Error 1146 (42S02): Table 'example.NON_EXISTING_TABLE' doesn't exist
SELECT 2 FROM NON_EXISTING_TABLE;
SELECT 3 FROM NON_EXISTING_TABLE;
Got one of the listed errors
SELECT 4;
4
4
SELECT 5;
5
5
SELECT 6;
6
6
1 SELECT;
Error 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use line 1 column 1 near "1 SELECT;"
2 SELECT;
Copy link
Contributor

@Defined2014 Defined2014 Nov 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this SQL doesn't have any error message? Seems error no begin with 0 will ignore the error msg. Does it same as mysql?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked MySQL-Server, they are same.

3 SELECT;
Got one of the listed errors
explain analyze format='brief' select * from t;
id estRows actRows task access object execution info operator info memory disk
TableReader 10000.00 5 root NULL time:<num>, loops:<num>, RU:<num>, cop_task: {num:<num>, max:<num>, proc_keys:<num>, rpc_num:<num>, rpc_time:<num>, copr_cache_hit_ratio:<num>, build_task_duration:<num>, max_distsql_concurrency:<num>} data:TableFullScan <num> Bytes N/A
Expand All @@ -26,3 +45,4 @@ info:
INSERT t1 VALUES (1, 1), (1, 1) ON DUPLICATE KEY UPDATE f1 = 2, f2 = 2;
affected rows: 3
info: Records: 2 Duplicates: 1 Warnings: 0
use `test`;;
2 changes: 2 additions & 0 deletions r/extensions.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
SELECT 1 FROM NON_EXISTING_TABLE;
Got one of the listed errors
Loading