131 lines
3.6 KiB
Bash
Executable File
131 lines
3.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
ENV_FILE="${ROOT}/.env"
|
|
[[ -f "$ENV_FILE" ]] && source "$ENV_FILE"
|
|
|
|
: "${OLLAMA_URL:=http://127.0.0.1:11434}"
|
|
: "${EXPERT_MODEL:=jr-sql-expert}"
|
|
|
|
ts() { date -Is; }
|
|
|
|
log_dir="${ROOT}/logs"
|
|
mkdir -p "$log_dir"
|
|
log_file="${log_dir}/sqlai-$(date -I).log"
|
|
|
|
# log everything (stdout+stderr)
|
|
exec > >(tee -a "$log_file") 2>&1
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage:
|
|
sqlai <mode> [--file path]
|
|
Modes:
|
|
analyze-tsql
|
|
analyze-proc
|
|
analyze-view
|
|
analyze-plan
|
|
utf8-migration
|
|
|
|
Examples:
|
|
cat query.sql | sqlai analyze-tsql
|
|
sqlai analyze-plan --file showplan.xml
|
|
EOF
|
|
}
|
|
|
|
mode="${1:-}"
|
|
[[ -z "$mode" ]] && { usage; exit 1; }
|
|
shift || true
|
|
|
|
file=""
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--file) file="$2"; shift 2;;
|
|
*) echo "[$(ts)] ERROR: Unknown arg: $1"; usage; exit 2;;
|
|
esac
|
|
done
|
|
|
|
input=""
|
|
if [[ -n "$file" ]]; then
|
|
if [[ ! -f "$file" ]]; then
|
|
echo "[$(ts)] ERROR: file not found: $file"
|
|
exit 3
|
|
fi
|
|
input="$(cat "$file")"
|
|
else
|
|
input="$(cat)"
|
|
fi
|
|
|
|
if [[ -z "${input//[[:space:]]/}" ]]; then
|
|
echo "[$(ts)] ERROR: empty input"
|
|
exit 4
|
|
fi
|
|
|
|
case "$mode" in
|
|
analyze-tsql)
|
|
instruction="Analysiere das folgende T-SQL (SQL Server 2022). Finde Performance-Probleme, SARGability, Indizes, Statistiken, Parameter Sniffing Risiken und gib konkrete Verbesserungen."
|
|
;;
|
|
analyze-proc)
|
|
instruction="Analysiere die folgende Stored Procedure (SQL Server 2022). Finde Performance-/Correctness-Risiken, Transaktions-/Locking-Themen, Parameter Sniffing, fehlende Indizes. Gib konkrete Refactorings."
|
|
;;
|
|
analyze-view)
|
|
instruction="Analysiere die folgende View (SQL Server 2022). Prüfe SARGability, Expand/Inlining-Effekte, mögliche Indexing-Optionen (z.B. indexed view falls sinnvoll) und Plan-Auswirkungen."
|
|
;;
|
|
analyze-plan)
|
|
instruction="Analysiere den folgenden SQL Server Execution Plan (XML Showplan oder Text). Identifiziere teure Operatoren, Spills, Warnungen, Kardinalitätsfehler, fehlende Indizes und gib konkrete Fixes."
|
|
;;
|
|
utf8-migration)
|
|
instruction="Erstelle einen Migrationsplan, um Tabellen/Spalten auf UTF-8 umzustellen (UTF-8 enabled collations mit _UTF8). Berücksichtige Abhängigkeiten (FK/PK/Indexes/Computed/Triggers), Risiken und gib eine Schritt-für-Schritt Checkliste."
|
|
;;
|
|
*)
|
|
echo "[$(ts)] ERROR: unknown mode: $mode"
|
|
usage
|
|
exit 5
|
|
;;
|
|
esac
|
|
|
|
prompt=$(cat <<EOF
|
|
${instruction}
|
|
|
|
---BEGIN INPUT---
|
|
${input}
|
|
---END INPUT---
|
|
EOF
|
|
)
|
|
|
|
echo "[$(ts)] sqlai: MODE=$mode MODEL=$EXPERT_MODEL OLLAMA_URL=$OLLAMA_URL"
|
|
echo "[$(ts)] sqlai: INPUT_BYTES=$(printf "%s" "$input" | wc -c)"
|
|
|
|
payload="$(python - <<'PY'
|
|
import json, os, sys
|
|
model=os.environ.get("EXPERT_MODEL","jr-sql-expert")
|
|
prompt=sys.stdin.read()
|
|
print(json.dumps({"model": model, "prompt": prompt, "stream": False}, ensure_ascii=False))
|
|
PY
|
|
<<<"$prompt")"
|
|
|
|
echo "[$(ts)] sqlai: sending request..."
|
|
resp="$(curl -sS -X POST "${OLLAMA_URL}/api/generate" -H 'Content-Type: application/json' --data-binary "$payload")" || {
|
|
rc=$?
|
|
echo "[$(ts)] sqlai: ERROR: curl failed rc=$rc"
|
|
exit 10
|
|
}
|
|
|
|
python - <<'PY'
|
|
import json,sys
|
|
obj=json.loads(sys.stdin.read())
|
|
print("\n" + (obj.get("response","").rstrip()) + "\n")
|
|
md = {
|
|
"total_duration": obj.get("total_duration"),
|
|
"load_duration": obj.get("load_duration"),
|
|
"prompt_eval_count": obj.get("prompt_eval_count"),
|
|
"prompt_eval_duration": obj.get("prompt_eval_duration"),
|
|
"eval_count": obj.get("eval_count"),
|
|
"eval_duration": obj.get("eval_duration"),
|
|
}
|
|
print("METRICS=" + json.dumps(md, ensure_ascii=False))
|
|
PY <<<"$resp"
|
|
|
|
echo "[$(ts)] sqlai: done"
|