golang使用TiDB的SQL Parse对SQL指纹化

复制代码
//mkdir sqlaprse && cd sqlaprse
//export GOPROXY=https://proxy.golang.com.cn,direct
//go mod init sqlaprse && touch main.go
//go get -v github.com/pingcap/tidb/parser@40b72e7
//go get github.com/fatih/color
//go get github.com/pingcap/tidb/types/parser_driver@40b72e7
//go run main.go -sql="select * from t1 where id=1 and date>'2023-08-18'"
package main

import (
	"bytes"
	"flag"
	"fmt"
	"github.com/fatih/color"
	"github.com/pingcap/tidb/parser"
	"github.com/pingcap/tidb/parser/ast"
	"github.com/pingcap/tidb/parser/format"
	driver "github.com/pingcap/tidb/types/parser_driver"
	"sync" // 导入 sync 包用于 WaitGroup
)

type FingerprintVisitor struct{}

func (f *FingerprintVisitor) Enter(n ast.Node) (node ast.Node, skipChildren bool) {
	if v, ok := n.(*driver.ValueExpr); ok {
		v.SetValue([]byte("?"))
	}
	return n, false
}

func (f *FingerprintVisitor) Leave(n ast.Node) (node ast.Node, ok bool) {
	return n, true
}

var (
	Success *color.Color
	Err     *color.Color
	sql     string
)

func processSQL(sql string, wg *sync.WaitGroup) {
	defer wg.Done() // 通知 WaitGroup 此 goroutine 已完成
	p := parser.New()
	stmt, err := p.ParseOneStmt(sql, "", "")
	if err != nil {
		Err.Println("解析错误:" + err.Error())
		return
	}
	stmt.Accept(&FingerprintVisitor{})

	buf := new(bytes.Buffer)
	restoreCtx := format.NewRestoreCtx(format.RestoreKeyWordUppercase|format.RestoreNameBackQuotes, buf)
	err = stmt.Restore(restoreCtx)
	if nil != err {
		Err.Println("解析错误:" + err.Error())
		return
	}
	Success.Println(buf.String())
}

func main() {
	Success = color.New(color.FgHiGreen, color.Bold, color.Underline)
	Err = color.New(color.FgHiRed, color.Bold)
	flag.StringVar(&sql, "sql", "", "SQL语句")
	flag.Parse()

	// 分割 SQL 语句
	statements := splitSQLStatements(sql)

	// 创建 WaitGroup 以等待所有 goroutine 完成
	var wg sync.WaitGroup

	for _, stmt := range statements {
		wg.Add(1) // 为每个 goroutine 增加 WaitGroup 计数
		go processSQL(stmt, &wg)
	}

	// 等待所有 goroutine 完成
	wg.Wait()
}

// 用于分割 SQL 语句的辅助函数
func splitSQLStatements(sql string) []string {
	// 在此实现分割 SQL 语句的逻辑
	// 例如,如果每个语句位于单独的行上并以分号结尾,则可以按分号分割
	// 并根据需要修改此函数。这是为了演示目的的简化示例。
	// 您可能需要处理边缘情况并改进分割逻辑。
	statements := []string{sql}
	return statements
}
相关推荐
科技小花7 小时前
全球化深水区,数据治理成为企业出海 “核心竞争力”
大数据·数据库·人工智能·数据治理·数据中台·全球化
X56618 小时前
如何在 Laravel 中正确保存嵌套动态表单数据(主服务与子服务)
jvm·数据库·python
虹科网络安全9 小时前
艾体宝干货|数据复制详解:类型、原理与适用场景
java·开发语言·数据库
2301_771717219 小时前
解决mysql报错:1406, Data too long for column
android·数据库·mysql
小江的记录本10 小时前
【Kafka核心】架构模型:Producer、Broker、Consumer、Consumer Group、Topic、Partition、Replica
java·数据库·分布式·后端·搜索引擎·架构·kafka
dvjr cloi10 小时前
MySQL Workbench菜单汉化为中文
android·数据库·mysql
dFObBIMmai10 小时前
MySQL主从同步中大事务导致的延迟_如何拆分大事务优化同步
jvm·数据库·python
szccyw010 小时前
mysql如何限制特定存储过程执行权限_MySQL存储过程安全访问
jvm·数据库·python
czlczl2002092510 小时前
利用“延迟关联”优化 MySQL 巨量数据的深分页查询
数据库·mysql
ACP广源盛1392462567311 小时前
IX8024与科学大模型的碰撞@ACP#筑牢科研 AI 算力高速枢纽分享
运维·服务器·网络·数据库·人工智能·嵌入式硬件·电脑