Files
MyGoNavi/tools/generate-driver-agent-revisions.sh
Syngnat 358d799af8 🐛 fix(mysql): 兼容 allowMultiQueries 连接参数
- 将 JDBC allowMultiQueries 参数映射为 MySQL driver 支持的 multiStatements

- 修复自定义 MySQL DSN 透传导致旧版本 MySQL 连接失败的问题

- 更新 MySQL 兼容 driver-agent revision

Refs #441
2026-05-24 10:59:52 +08:00

397 lines
9.8 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$SCRIPT_DIR"
DEFAULT_DRIVERS=(mariadb oceanbase diros starrocks sphinx sqlserver sqlite duckdb dameng kingbase highgo vastbase opengauss iris mongodb tdengine clickhouse)
OUTPUT_FILE="internal/db/driver_agent_revisions_gen.go"
usage() {
cat <<'EOF'
用法:
./tools/generate-driver-agent-revisions.sh [选项]
选项:
--platform <GOOS/GOARCH> 按目标平台解析 Go build tags默认使用当前 Go 环境
--drivers <列表> 只更新指定驱动(逗号分隔),并保留其他已生成 revision
-h, --help 显示帮助
EOF
}
normalize_driver() {
local value
value="$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | tr -d '[:space:]')"
case "$value" in
doris|diros) echo "diros" ;;
oceanbase) echo "oceanbase" ;;
opengauss|open_gauss|open-gauss) echo "opengauss" ;;
mariadb|diros|starrocks|sphinx|sqlserver|sqlite|duckdb|dameng|kingbase|highgo|vastbase|iris|mongodb|tdengine|clickhouse)
echo "$value"
;;
*)
return 1
;;
esac
}
build_driver_name() {
echo "$1"
}
driver_build_tags() {
local driver="$1"
local build_driver tag
build_driver="$(build_driver_name "$driver")"
tag="gonavi_${build_driver}_driver"
if [[ "$driver" == "duckdb" && "$goos" == "windows" && "$goarch" == "amd64" ]]; then
tag="$tag duckdb_use_lib"
fi
echo "$tag"
}
hash_file() {
local target="$1"
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$target" | awk '{print $1}'
return
fi
if command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$target" | awk '{print $1}'
return
fi
echo "未找到 sha256sum 或 shasum" >&2
exit 1
}
files_equal() {
local left="$1"
local right="$2"
if command -v cmp >/dev/null 2>&1; then
cmp -s "$left" "$right"
return
fi
[[ "$(hash_file "$left")" == "$(hash_file "$right")" ]]
}
should_include_internal_db_file() {
local driver="$1"
local identity="$2"
case "$identity" in
internal/db/agent_process_stub.go|\
internal/db/agent_process_windows.go|\
internal/db/database.go|\
internal/db/database_optional_factories_full.go|\
internal/db/database_optional_factories_lite.go|\
internal/db/driver_agent_binary_check.go|\
internal/db/driver_support.go|\
internal/db/json_decode.go|\
internal/db/mysql_agent_path.go|\
internal/db/optional_driver_agent_impl.go|\
internal/db/optional_driver_build_full.go|\
internal/db/optional_driver_build_lite.go|\
internal/db/query_value.go|\
internal/db/scan_rows.go|\
internal/db/ssl_mode.go|\
internal/db/timeout.go)
return 0
;;
esac
case "$driver:$identity" in
mariadb:internal/db/mariadb_impl.go|\
mariadb:internal/db/mysql_impl.go|\
oceanbase:internal/db/oceanbase_impl.go|\
oceanbase:internal/db/oracle_impl.go|\
oceanbase:internal/db/mysql_impl.go|\
diros:internal/db/diros_impl.go|\
diros:internal/db/mysql_impl.go|\
starrocks:internal/db/starrocks_impl.go|\
starrocks:internal/db/mysql_impl.go|\
sphinx:internal/db/sphinx_impl.go|\
sphinx:internal/db/mysql_impl.go|\
sqlserver:internal/db/sqlserver_impl.go|\
sqlite:internal/db/sqlite_impl.go|\
duckdb:internal/db/duckdb_impl.go|\
duckdb:internal/db/duckdb_driver_import.go|\
duckdb:internal/db/duckdb_platform_supported.go|\
duckdb:internal/db/duckdb_platform_unsupported.go|\
dameng:internal/db/dameng_impl.go|\
dameng:internal/db/dameng_metadata.go|\
kingbase:internal/db/kingbase_impl.go|\
kingbase:internal/db/kingbase_identifier_utils.go|\
highgo:internal/db/highgo_impl.go|\
vastbase:internal/db/vastbase_impl.go|\
opengauss:internal/db/opengauss_impl.go|\
opengauss:internal/db/postgres_impl.go|\
iris:internal/db/iris_impl.go|\
mongodb:internal/db/mongodb_impl.go|\
mongodb:internal/db/mongodb_impl_v1.go|\
tdengine:internal/db/tdengine_impl.go|\
clickhouse:internal/db/clickhouse_impl.go)
return 0
;;
esac
return 1
}
should_include_source_file() {
local driver="$1"
local identity="$2"
if [[ "$identity" == internal/db/* ]]; then
should_include_internal_db_file "$driver" "$identity"
return
fi
return 0
}
target_platform=""
driver_csv=""
while [[ $# -gt 0 ]]; do
case "$1" in
--platform)
target_platform="${2:-}"
shift 2
;;
--drivers)
driver_csv="${2:-}"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "未知参数:$1" >&2
usage
exit 1
;;
esac
done
if ! command -v go >/dev/null 2>&1; then
echo "未找到 Go请先安装 Go 并确保 go 在 PATH 中。" >&2
exit 1
fi
if [[ -z "$target_platform" ]]; then
target_platform="$(go env GOOS)/$(go env GOARCH)"
fi
if [[ "$target_platform" != */* ]]; then
echo "--platform 参数格式错误,应为 GOOS/GOARCH例如 darwin/arm64" >&2
exit 1
fi
goos="${target_platform%%/*}"
goarch="${target_platform##*/}"
gomodcache="$(go env GOMODCACHE)"
declare -a drivers=()
if [[ -n "$driver_csv" ]]; then
IFS=',' read -r -a raw_drivers <<<"$driver_csv"
for item in "${raw_drivers[@]}"; do
drivers+=("$(normalize_driver "$item")")
done
else
drivers=("${DEFAULT_DRIVERS[@]}")
fi
selected_driver_set="|"
for driver in "${drivers[@]}"; do
selected_driver_set="${selected_driver_set}${driver}|"
done
existing_revision_for() {
local target="$1"
local line
[[ -n "$driver_csv" && -f "$OUTPUT_FILE" ]] || return 1
while IFS= read -r line; do
if [[ "$line" =~ \"([^\"]+)\"[[:space:]]*:[[:space:]]*\"([^\"]+)\" ]]; then
if [[ "${BASH_REMATCH[1]}" == "$target" ]]; then
printf '%s\n' "${BASH_REMATCH[2]}"
return 0
fi
fi
done <"$OUTPUT_FILE"
return 1
}
detect_revision_jobs() {
local configured="${GONAVI_DRIVER_REVISION_JOBS:-}"
local detected
if [[ "$configured" =~ ^[0-9]+$ && "$configured" -gt 0 ]]; then
echo "$configured"
return
fi
if command -v nproc >/dev/null 2>&1; then
detected="$(nproc)"
elif command -v sysctl >/dev/null 2>&1; then
detected="$(sysctl -n hw.ncpu 2>/dev/null || true)"
else
detected=""
fi
if ! [[ "$detected" =~ ^[0-9]+$ && "$detected" -gt 0 ]]; then
detected=4
fi
if [[ "$detected" -gt 4 ]]; then
detected=4
fi
echo "$detected"
}
declare -a output_drivers=()
if [[ -n "$driver_csv" ]]; then
output_drivers=("${DEFAULT_DRIVERS[@]}")
else
output_drivers=("${drivers[@]}")
fi
fingerprint_driver() {
local driver="$1"
local build_driver tag cgo_enabled tmp file identity file_hash revision
build_driver="$(build_driver_name "$driver")"
tag="$(driver_build_tags "$driver")"
cgo_enabled=0
if [[ "$driver" == "duckdb" ]]; then
cgo_enabled=1
fi
tmp="$(mktemp "${TMPDIR:-/tmp}/gonavi-agent-revision.XXXXXX")"
{
printf 'driver=%s\n' "$driver"
printf 'build_tag=%s\n' "$tag"
printf 'goos=%s\n' "$goos"
printf 'goarch=%s\n' "$goarch"
} >"$tmp"
while IFS= read -r file; do
[[ -n "$file" && -f "$file" ]] || continue
case "$file" in
"$SCRIPT_DIR"/*)
identity="${file#$SCRIPT_DIR/}"
;;
"$gomodcache"/*)
identity="gomod/${file#$gomodcache/}"
;;
*)
identity="$file"
;;
esac
if [[ "$identity" == "$OUTPUT_FILE" ]]; then
continue
fi
if ! should_include_source_file "$driver" "$identity"; then
continue
fi
file_hash="$(hash_file "$file")"
printf '%s %s\n' "$file_hash" "$identity"
done < <(
CGO_ENABLED="$cgo_enabled" GOOS="$goos" GOARCH="$goarch" GOTOOLCHAIN=auto \
go list -deps \
-tags "$tag" \
-f '{{if not .Standard}}{{range .GoFiles}}{{$.Dir}}/{{.}}{{"\n"}}{{end}}{{range .CgoFiles}}{{$.Dir}}/{{.}}{{"\n"}}{{end}}{{end}}' \
./cmd/optional-driver-agent | sort -u
) >>"$tmp"
revision="$(hash_file "$tmp" | cut -c1-16)"
rm -f "$tmp"
printf 'src-%s' "$revision"
}
revision_jobs="$(detect_revision_jobs)"
revision_tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/gonavi-agent-revisions.XXXXXX")"
cleanup_revision_tmp_dir() {
rm -rf "$revision_tmp_dir"
}
trap cleanup_revision_tmp_dir EXIT
declare -a revision_pids=()
declare -a revision_pid_drivers=()
revision_failed=0
wait_for_oldest_revision_job() {
local pid driver
pid="${revision_pids[0]}"
driver="${revision_pid_drivers[0]}"
if ! wait "$pid"; then
echo "❌ 生成 driver-agent revision 失败:$driver ($goos/$goarch)" >&2
revision_failed=1
fi
if [[ ${#revision_pids[@]} -le 1 ]]; then
revision_pids=()
revision_pid_drivers=()
else
revision_pids=("${revision_pids[@]:1}")
revision_pid_drivers=("${revision_pid_drivers[@]:1}")
fi
}
start_revision_job() {
local driver="$1"
{
fingerprint_driver "$driver" >"$revision_tmp_dir/$driver.revision"
} &
revision_pids+=("$!")
revision_pid_drivers+=("$driver")
}
for driver in "${output_drivers[@]}"; do
if [[ -n "$driver_csv" && "$selected_driver_set" != *"|$driver|"* ]] && revision="$(existing_revision_for "$driver")"; then
printf '%s\n' "$revision" >"$revision_tmp_dir/$driver.revision"
continue
fi
while [[ ${#revision_pids[@]} -ge "$revision_jobs" ]]; do
wait_for_oldest_revision_job
done
start_revision_job "$driver"
done
while [[ ${#revision_pids[@]} -gt 0 ]]; do
wait_for_oldest_revision_job
done
if [[ "$revision_failed" -ne 0 ]]; then
exit 1
fi
tmp_output="$(mktemp "${TMPDIR:-/tmp}/gonavi-agent-revisions-go.XXXXXX")"
{
cat <<'EOF'
// Code generated by tools/generate-driver-agent-revisions.sh; DO NOT EDIT.
package db
func init() {
optionalDriverAgentRevisions = map[string]string{
EOF
for driver in "${output_drivers[@]}"; do
revision="$(<"$revision_tmp_dir/$driver.revision")"
printf '\t\t"%s": "%s",\n' "$driver" "$revision"
done
cat <<'EOF'
}
}
EOF
} >"$tmp_output"
gofmt -w "$tmp_output"
if [[ -f "$OUTPUT_FILE" ]] && files_equal "$tmp_output" "$OUTPUT_FILE"; then
rm -f "$tmp_output"
else
mv "$tmp_output" "$OUTPUT_FILE"
fi
echo "已生成 driver-agent revisions: $OUTPUT_FILE ($goos/$goarch)"