init: 4 skills (bms-test-log-query, bms-prd-log-query, bms-mysql-test, bms-mysql-prd)

This commit is contained in:
yongjiang.lin
2026-06-11 14:46:29 +08:00
commit 337e26858b
8 changed files with 775 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
---
name: bms-mysql-prd
description: Connect to BMS production MySQL database. Use when the user asks to query BMS production database, check production data, or says "查询生产数据库", "查生产数据", "BMS生产库", "BMS正式库". Production database is read-only — any write/DDL will fail.
---
# BMS MySQL 生产数据库连接 Skill
Connect to the BMS production MySQL database for read-only queries.
## Available Databases
| Database | Description |
| ----------------------- | -------------------- |
| `bms_base_center` | 基础数据中心 |
| `bms_buyinvoice_center` | 采购发票中心 |
| `bms_ext_center` | 外部扩展中心 |
| `bms_invoice_center` | 发票中心 |
| `bms_order_center` | 订单中心 |
| `bms_payable_center` | 应付中心 |
| `bms_task_center` | 任务中心 |
| `cache_db` | 缓存数据库 |
| `leshop_v3` | 乐商 V3 |
| `lts` | LTS |
| `manager_db` | 管理数据库 |
| `mq_db` | 消息队列数据库 |
| `sap_push_data` | SAP 推送数据 |
| `sf_db` | SF 数据库 |
| `mysql` | 系统数据库 |
| `information_schema` | 系统信息库 |
## How to Use
Run the helper script with a SQL query:
```bash
python scripts/bms-mysql-prd.py --query "SELECT * FROM bms_base_center.enterprise_info LIMIT 10"
```
## Safety Rules
- **Production is read-only** — the database account only has SELECT permission
- Any `INSERT`/`UPDATE`/`DELETE`/DDL will be rejected by the database
- Write/DDL operations still require a confirmation popup before attempting
- Results are printed in a formatted table
## Script Location
- `scripts/bms-mysql-prd.py` — the execution script (uses PyMySQL)
## Examples
```bash
# Query enterprise info
python scripts/bms-mysql-prd.py --query "SELECT * FROM bms_base_center.enterprise_info WHERE company_code = '7600'"
# List tables in a database
python scripts/bms-mysql-prd.py --query "SHOW TABLES FROM bms_order_center"
```
## Output Format
Results are printed as a formatted table with column headers and aligned values. Empty results show "0 rows returned." Write operations (if attempted) will fail with a permission error.
+193
View File
@@ -0,0 +1,193 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
BMS MySQL Production Database Query Tool
Read-only access to the BMS production MySQL database.
- SELECT/SHOW/DESC/EXPLAIN: execute directly
- INSERT/UPDATE/DELETE/DDL: require confirmation popup (will fail with permission error)
"""
import argparse
import re
import sys
import pymysql
# ─── Connection Config ───────────────────────────────────────────────────────
DB_CONFIG = {
"host": "47.106.125.251",
"port": 9696,
"user": "i7bSEtwU",
"password": "",
"charset": "utf8mb4",
"cursorclass": pymysql.cursors.DictCursor,
}
# ─── Query Classification ────────────────────────────────────────────────────
READ_ONLY_PATTERNS = re.compile(
r"^\s*(SELECT|SHOW|DESC|DESCRIBE|EXPLAIN|USE|SET)\b", re.IGNORECASE
)
WRITE_DDL_PATTERNS = re.compile(
r"^\s*(INSERT|UPDATE|DELETE|REPLACE|CREATE|ALTER|DROP|TRUNCATE|RENAME|GRANT|REVOKE|LOAD\s+DATA)\b",
re.IGNORECASE,
)
def is_read_only(sql: str) -> bool:
"""Return True if the SQL is a read-only query."""
return bool(READ_ONLY_PATTERNS.match(sql))
def is_write_or_ddl(sql: str) -> bool:
"""Return True if the SQL modifies data or schema."""
return bool(WRITE_DDL_PATTERNS.match(sql))
# ─── Confirmation Dialog ─────────────────────────────────────────────────────
def ask_confirmation(sql: str) -> bool:
"""Show a Windows popup dialog asking the user to confirm the SQL execution.
Returns True if the user clicks 'Yes', False otherwise.
"""
import tkinter as tk
from tkinter import messagebox
root = tk.Tk()
root.withdraw() # Hide the main window
title = "BMS MySQL 生产 - 写操作确认"
message = (
"即将执行以下写操作 / DDL 语句(生产库只读,该操作将报错),是否继续?\n\n"
f"SQL:\n{sql}\n"
)
result = messagebox.askyesno(title, message, icon="warning")
root.destroy()
return result
def show_error_popup(sql: str, error: str) -> None:
"""Show a Windows popup dialog when a write operation is rejected."""
import tkinter as tk
from tkinter import messagebox
root = tk.Tk()
root.withdraw()
title = "BMS MySQL 生产 - 操作被拒绝"
message = (
"生产库为只读权限,以下写操作已被数据库拒绝:\n\n"
f"SQL:\n{sql}\n\n"
f"错误信息:\n{error}"
)
messagebox.showwarning(title, message)
root.destroy()
# ─── Table Formatting ────────────────────────────────────────────────────────
def format_table(rows: list, columns: list) -> str:
"""Format query results as an aligned text table."""
if not rows:
return "0 rows returned."
# Calculate column widths
widths = {col: len(str(col)) for col in columns}
for row in rows:
for col in columns:
val = str(row.get(col, ""))
widths[col] = max(widths[col], len(val))
# Build header
header = " | ".join(str(col).ljust(widths[col]) for col in columns)
separator = "-+-".join("-" * widths[col] for col in columns)
# Build rows
lines = [header, separator]
for row in rows:
line = " | ".join(
str(row.get(col, "")).ljust(widths[col]) for col in columns
)
lines.append(line)
lines.append(f"\n{len(rows)} row(s) returned.")
return "\n".join(lines)
# ─── Main Execution ──────────────────────────────────────────────────────────
def execute_query(sql: str) -> None:
"""Connect to the database and execute the given SQL query."""
print(f"\n{'='*60}")
print(f"BMS MySQL Production (47.106.125.251:9696)")
print(f"{'='*60}")
print(f"SQL: {sql}\n")
# Classify the query
if is_read_only(sql):
query_type = "READ-ONLY"
elif is_write_or_ddl(sql):
query_type = "WRITE / DDL (只读库,将报错)"
else:
query_type = "UNKNOWN"
print(f"类型: {query_type}\n")
# For write/DDL, require confirmation
if is_write_or_ddl(sql):
if not ask_confirmation(sql):
print("用户已取消操作。")
sys.exit(0)
# Connect and execute
try:
conn = pymysql.connect(**DB_CONFIG)
cursor = conn.cursor()
cursor.execute(sql)
if is_read_only(sql):
rows = cursor.fetchall()
columns = [desc[0] for desc in cursor.description] if cursor.description else []
print(format_table(rows, columns))
else:
conn.commit()
affected = cursor.rowcount
print(f"操作成功,影响 {affected} 行。")
cursor.close()
conn.close()
except pymysql.MySQLError as e:
error_msg = str(e)
print(f"数据库错误: {error_msg}", file=sys.stderr)
if is_write_or_ddl(sql):
show_error_popup(sql, error_msg)
sys.exit(1)
except Exception as e:
print(f"执行失败: {e}", file=sys.stderr)
sys.exit(1)
def main():
parser = argparse.ArgumentParser(
description="BMS MySQL 生产数据库查询工具(只读)"
)
parser.add_argument(
"--query", "-q",
required=True,
help="要执行的 SQL 语句",
)
args = parser.parse_args()
execute_query(args.query)
if __name__ == "__main__":
main()