AgentSkillsCN

Testsql

Testsql

SKILL.md

/testsql - SQL Server Test Environment Manager

Manages a Docker-based SQL Server 2022 test environment for YourProject script development and testing.


User Documentation

Commands

bash
/testsql setup [scriptname] [sql|azuresql]  # Setup SQL Server with optional script and engine type
/testsql backup                             # Backup current database to bootstrap folder
/testsql restore <filename>                 # Restore database from backup file
/testsql shutdown                           # Backup and teardown container
/testsql status                             # Show connection information and system status
/testsql help                               # Show this help message

Engine Types

  • sql (default): SQL Server 2022 - Full feature set, best for YourProject testing
  • azuresql: Azure SQL Edge - Lightweight, optimized for edge/IoT scenarios

Quick Start

bash
# Start SQL Server with Northwind sample database
/testsql setup

# Output: Connection details (server, database, username, password)

# Work with database in SSMS...

# Backup when done
/testsql backup

# Shutdown
/testsql shutdown

Connection Information

After setup, you'll receive:

  • Server: localhost,1433
  • Database: testdb (or custom from script)
  • Username: sa
  • Password: Pass@word1
  • Connection String: For SSMS/Azure Data Studio

Prerequisites

  • Docker Desktop (8GB+ RAM allocated)
  • 120GB+ disk space
  • Windows/macOS/Linux

File Locations

  • Bootstrap scripts: .claude/testSQL/bootstrap/*.sql
  • Backups: .claude/testSQL/bootstrap/*.bak
  • Docker config: .claude/testSQLSetup/

Implementation Instructions for Claude

When User Invokes: /testsql setup [scriptname] [sql|azuresql]

Step 1: Parse Command Arguments

Extract arguments and determine engine type:

Argument parsing logic:

code
Arguments: None
→ scriptname: northwind.sql
→ engine: sql

Arguments: azuresql
→ scriptname: northwind.sql
→ engine: azuresql

Arguments: myscript.sql
→ scriptname: myscript.sql
→ engine: sql

Arguments: myscript.sql sql
→ scriptname: myscript.sql
→ engine: sql

Arguments: myscript.sql azuresql
→ scriptname: myscript.sql
→ engine: azuresql

Detection rules:

  1. If first argument is "azuresql" or "sql" → It's engine type, script is default (northwind.sql)
  2. If first argument ends with .sql → It's script name, check second argument for engine
  3. If second argument is "azuresql" or "sql" → Use that engine
  4. Otherwise → Default to "sql" engine

Store variables:

  • scriptname - Bootstrap script filename
  • engine - Engine type: "sql" or "azuresql"
  • containerName - Container name based on engine:
    • sql → sqlserver-dev
    • azuresql → azuresql-dev
  • imageName - Docker image:
    • sql → mcr.microsoft.com/mssql/server:2022-latest
    • azuresql → mcr.microsoft.com/azure-sql-edge:latest

Step 2: Check Prerequisites

Use the Bash tool to verify:

bash
# Check Docker installed
docker --version

# Check Docker running
docker info

# Check Docker Compose available
docker compose version

If any check fails:

Step 3: Create Directories

Use Bash tool to create folders if missing:

bash
mkdir -p .claude/testSQL/bootstrap
mkdir -p .claude/testSQLSetup/data
mkdir -p .claude/testSQLSetup/logs

Step 4: Ensure Bootstrap Script Exists

If using default (no script argument):

Check if northwind.sql exists:

bash
test -f .claude/testSQL/bootstrap/northwind.sql && echo "exists" || echo "missing"

If missing, create it using Write tool:

File: .claude/testSQL/bootstrap/northwind.sql

Content:

sql
-- Northwind Sample Database for Testing
-- Auto-generated by /testsql skill

CREATE DATABASE testdb;
GO

USE testdb;
GO

-- Customers table
CREATE TABLE Customers (
    CustomerID INT PRIMARY KEY IDENTITY(1,1),
    CompanyName NVARCHAR(100) NOT NULL,
    ContactName NVARCHAR(100),
    Country NVARCHAR(50),
    CreatedDate DATETIME DEFAULT GETDATE()
);

-- Orders table
CREATE TABLE Orders (
    OrderID INT PRIMARY KEY IDENTITY(1,1),
    CustomerID INT FOREIGN KEY REFERENCES Customers(CustomerID),
    OrderDate DATETIME DEFAULT GETDATE(),
    TotalAmount DECIMAL(10,2)
);

-- Products table
CREATE TABLE Products (
    ProductID INT PRIMARY KEY IDENTITY(1,1),
    ProductName NVARCHAR(100) NOT NULL,
    UnitPrice DECIMAL(10,2),
    UnitsInStock INT DEFAULT 0
);

-- Sample data
INSERT INTO Customers (CompanyName, ContactName, Country) VALUES
('Contoso Ltd', 'John Doe', 'USA'),
('Fabrikam Inc', 'Jane Smith', 'Canada'),
('Adventure Works', 'Bob Johnson', 'UK'),
('Northwind Traders', 'Alice Williams', 'Germany');

INSERT INTO Products (ProductName, UnitPrice, UnitsInStock) VALUES
('Widget', 9.99, 100),
('Gadget', 19.99, 50),
('Doohickey', 14.99, 75),
('Thingamajig', 24.99, 30);

INSERT INTO Orders (CustomerID, OrderDate, TotalAmount) VALUES
(1, '2026-01-15', 1500.00),
(1, '2026-01-20', 2300.50),
(2, '2026-01-18', 750.25),
(3, '2026-01-22', 980.00);

PRINT 'Northwind sample database created successfully';
GO

If using custom script:

Check if custom script exists:

bash
test -f .claude/testSQL/bootstrap/SCRIPTNAME && echo "exists" || echo "missing"

If missing:

  • Output error: "Script not found: .claude/testSQL/bootstrap/SCRIPTNAME"
  • Suggest: "Place your SQL script in .claude/testSQL/bootstrap/"
  • Stop execution

Step 5: Detect Database Name from Script

Use Read tool to read the bootstrap script content.

Parse the script to find database name:

Look for patterns (case-insensitive):

  • CREATE DATABASE [DatabaseName]
  • CREATE DATABASE DatabaseName
  • CREATE DATABASE "DatabaseName"
  • CREATE DATABASE 'DatabaseName'

Extract database name:

  • If pattern found: Extract the database name (remove brackets/quotes)
  • If pattern NOT found: Use default testdb

Example parsing logic:

code
Script contains: "CREATE DATABASE MyCustomDB;"
→ Extracted database name: MyCustomDB

Script contains: "CREATE TABLE Users (...);"
→ No CREATE DATABASE found
→ Default database name: testdb

Store the detected database name in a variable for later use.

Step 6: Check Container Status

Use Bash to check if container exists and its state (use containerName from Step 1):

bash
docker ps -a --filter "name=${containerName}" --format "{{.Names}}\t{{.Status}}"

Where containerName is:

  • sqlserver-dev (for sql engine)
  • azuresql-dev (for azuresql engine)

Possible states:

  1. Container running:

    • Output: "Container already running (${containerName}). Checking connection..."
    • Skip to Step 9 (verify connection)
  2. Container stopped:

    • Output: "Container exists but stopped (${containerName}). Starting..."
    • Use: docker start ${containerName}
    • Continue to Step 9
  3. Container not found:

    • Output: "Creating new ${engine} container..."
    • Continue to Step 7

Additional check - Detect existing SQL containers:

If target container not found, check for ANY SQL container:

bash
docker ps --format "{{.Names}}\t{{.Image}}" | grep -iE "sql|mssql"

If other SQL containers found:

  • List them: "Found existing SQL containers: container1, container2"
  • Output: "Creating new ${containerName} for this setup"
  • Continue to Step 7 (user can manually use other containers if needed)

Step 7: Start Docker Container

Use direct docker run command instead of docker-compose (simpler for multiple engine support):

For SQL Server (sql engine):

bash
docker run -d \
  --name sqlserver-dev \
  -e "ACCEPT_EULA=Y" \
  -e "SA_PASSWORD=YourSecurePassword123!" \
  -e "MSSQL_PID=Developer" \
  -e "MSSQL_AGENT_ENABLED=true" \
  -p 1433:1433 \
  -v "$(pwd)/.claude/testSQL/bootstrap:/var/opt/mssql/backup" \
  -v "$(pwd)/.claude/testSQLSetup/data:/var/opt/mssql/data" \
  -v "$(pwd)/.claude/testSQLSetup/logs:/var/opt/mssql/log" \
  --memory=7g \
  --cpus=4 \
  mcr.microsoft.com/mssql/server:2022-latest

For Azure SQL Edge (azuresql engine):

bash
docker run -d \
  --name azuresql-dev \
  -e "ACCEPT_EULA=Y" \
  -e "SA_PASSWORD=YourSecurePassword123!" \
  -e "MSSQL_PID=Developer" \
  -p 1433:1433 \
  -v "$(pwd)/.claude/testSQL/bootstrap:/var/opt/mssql/backup" \
  -v "$(pwd)/.claude/testSQLSetup/data-azuresql:/var/opt/mssql/data" \
  -v "$(pwd)/.claude/testSQLSetup/logs-azuresql:/var/opt/mssql/log" \
  --memory=4g \
  --cpus=2 \
  mcr.microsoft.com/azure-sql-edge:latest

Note: Azure SQL Edge uses less memory (4GB vs 7GB) and fewer CPUs (2 vs 4).

If command fails:

  • Check if image exists: docker images | grep ${imageName}
  • If image missing: Pull it first
    bash
    docker pull ${imageName}
    
  • Retry the docker run command

Output progress:

code
✓ Starting ${engine} container (${containerName})...
  Pulling image if needed...
  This may take 2-3 minutes on first run...

Step 8: Wait for SQL Server to be Ready

Poll SQL Server every 5 seconds for up to 3 minutes (use containerName from Step 1):

bash
docker exec ${containerName} /opt/mssql-tools/bin/sqlcmd \
  -S localhost -U sa -P 'YourSecurePassword123!' -Q "SELECT 1" 2>/dev/null

While waiting:

  • Show progress every 30 seconds: "Still waiting for ${engine}... (elapsed: 30s)"
  • If timeout (3 minutes):
    • Output error: "${engine} failed to start within 3 minutes"
    • Suggest: "Check logs with: docker logs ${containerName}"
    • Stop execution

When ready:

code
✓ ${engine} is ready!

Step 9: Run Bootstrap Script

Use containerName from Step 1.

If database name was NOT found in script (use testdb):

  1. Create testdb first:
bash
docker exec ${containerName} /opt/mssql-tools/bin/sqlcmd \
  -S localhost -U sa -P 'YourSecurePassword123!' \
  -Q "IF DB_ID('testdb') IS NULL CREATE DATABASE testdb;"
  1. Run script in context of testdb:
bash
docker cp .claude/testSQL/bootstrap/${scriptname} ${containerName}:/tmp/bootstrap.sql

docker exec ${containerName} /opt/mssql-tools/bin/sqlcmd \
  -S localhost -U sa -P 'YourSecurePassword123!' -d testdb \
  -i /tmp/bootstrap.sql

If database name WAS found in script:

Run script directly (it will create its own database):

bash
docker cp .claude/testSQL/bootstrap/${scriptname} ${containerName}:/tmp/bootstrap.sql

docker exec ${containerName} /opt/mssql-tools/bin/sqlcmd \
  -S localhost -U sa -P 'YourSecurePassword123!' \
  -i /tmp/bootstrap.sql

If script execution fails:

  • Output error message
  • Show last 20 lines of output
  • Suggest: "Check script syntax in .claude/testSQL/bootstrap/${scriptname}"

Step 10: Display Connection Information

Output a nicely formatted connection info box:

code
========================================
  SQL Server Connection Information
========================================
Engine Type:    [SQL Server 2022 | Azure SQL Edge]
Container:      [CONTAINER_NAME]
Server Name:    localhost,1433
Database Name:  [DETECTED_DATABASE_NAME]
Username:       sa
Password:       YourSecurePassword123!

Connection String (SSMS/Azure Data Studio):
Server=localhost,1433;Database=[DETECTED_DATABASE_NAME];User Id=sa;Password=YourSecurePassword123!;TrustServerCertificate=True;

========================================
Ready to connect! Open SSMS and use the credentials above.
========================================

Replace values:

  • [SQL Server 2022 | Azure SQL Edge] with friendly engine name:
    • sql → "SQL Server 2022"
    • azuresql → "Azure SQL Edge"
  • [CONTAINER_NAME] with actual container name from Step 1
  • [DETECTED_DATABASE_NAME] with actual database name from Step 5

When User Invokes: /testsql backup

Step 1: Detect and Check Running Container

Find any running SQL container:

bash
docker ps --format "{{.Names}}\t{{.Image}}" | grep -iE "dams.*sql"

Expected matches:

  • sqlserver-dev (SQL Server)
  • azuresql-dev (Azure SQL Edge)

If multiple containers running:

  • Use the first one found
  • Output: "Using container: ${containerName}"

If no container running:

  • Output: "No SQL container running. Start with: /testsql setup"
  • Stop execution

Store containerName for subsequent steps.

Step 2: Detect Current Database Name

Query SQL Server to get the first user database (use containerName from Step 1):

bash
docker exec ${containerName} /opt/mssql-tools/bin/sqlcmd \
  -S localhost -U sa -P 'YourSecurePassword123!' -h -1 \
  -Q "SET NOCOUNT ON; SELECT TOP 1 name FROM sys.databases WHERE database_id > 4 ORDER BY database_id"

Store database name (e.g., testdb, MyCustomDB, etc.)

If no user database found:

  • Output: "No user database found to backup"
  • Stop execution

Step 3: Generate Timestamp

Create timestamp in format: YYYYMMDD_HHMMSS

Example: 20260129_143022

Step 4: Create Backup

Backup filename: [DATABASE_NAME]_[TIMESTAMP].bak

Use containerName from Step 1:

bash
docker exec ${containerName} /opt/mssql-tools/bin/sqlcmd \
  -S localhost -U sa -P 'YourSecurePassword123!' \
  -Q "BACKUP DATABASE [DATABASE_NAME] TO DISK='/var/opt/mssql/backup/[DATABASE_NAME]_[TIMESTAMP].bak' WITH COMPRESSION, INIT;"

Replace [DATABASE_NAME] and [TIMESTAMP] with actual values.

If backup fails:

  • Output error message
  • Check disk space: df -h .claude/testSQL/bootstrap
  • Suggest deleting old backups

Step 5: Get Backup Size

bash
ls -lh .claude/testSQL/bootstrap/[DATABASE_NAME]_[TIMESTAMP].bak | awk '{print $5}'

Step 6: Display Success Message

code
✓ Backup completed successfully

Backup Details:
  File: [DATABASE_NAME]_[TIMESTAMP].bak
  Location: .claude/testSQL/bootstrap/
  Size: [SIZE] MB (compressed)
  Timestamp: [HUMAN_READABLE_TIME]

When User Invokes: /testsql restore <filename>

Step 1: Parse Command Arguments

Extract filename:

  • If no argument: Show error and list available backups (interactive mode)
  • If argument provided: Use that filename

Step 2: Detect and Check Running Container

Find any running SQL container (same logic as backup Step 1):

bash
docker ps --format "{{.Names}}\t{{.Image}}" | grep -iE "dams.*sql"

If no container running:

  • Output: "No SQL container running. Start with: /testsql setup"
  • Stop execution

Store containerName for subsequent steps.

Step 3: Verify Backup File Exists

bash
test -f .claude/testSQL/bootstrap/FILENAME && echo "exists" || echo "missing"

If missing:

  • Output: "Backup file not found: FILENAME"
  • List available backups:
bash
ls -lht .claude/testSQL/bootstrap/*.bak | head -10
  • Stop execution

Step 4: Extract Database Name from Backup Filename

Parse filename to extract database name.

Pattern: DBNAME_YYYYMMDD_HHMMSS.bak

Example:

  • testdb_20260129_143022.bak → Database: testdb
  • MyCustomDB_20260128_091534.bak → Database: MyCustomDB

Step 5: Close Active Connections

Kill all connections to the target database (use containerName from Step 2):

bash
docker exec ${containerName} /opt/mssql-tools/bin/sqlcmd \
  -S localhost -U sa -P 'YourSecurePassword123!' \
  -Q "ALTER DATABASE [DBNAME] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;"

If fails (database doesn't exist):

  • This is OK, continue (restore will create it)

Step 6: Restore Database

bash
docker exec ${containerName} /opt/mssql-tools/bin/sqlcmd \
  -S localhost -U sa -P 'YourSecurePassword123!' \
  -Q "RESTORE DATABASE [DBNAME] FROM DISK='/var/opt/mssql/backup/FILENAME' WITH REPLACE;"

If restore fails:

  • Output error message
  • Show SQL Server error details
  • Suggest checking backup file integrity

Step 7: Set Database to Multi-User

bash
docker exec ${containerName} /opt/mssql-tools/bin/sqlcmd \
  -S localhost -U sa -P 'YourSecurePassword123!' \
  -Q "ALTER DATABASE [DBNAME] SET MULTI_USER;"

Step 8: Get Database Size

bash
docker exec ${containerName} /opt/mssql-tools/bin/sqlcmd \
  -S localhost -U sa -P 'YourSecurePassword123!' -h -1 \
  -Q "SET NOCOUNT ON; SELECT CAST(SUM(size) * 8.0 / 1024 AS DECIMAL(10,2)) FROM sys.master_files WHERE database_id = DB_ID('[DBNAME]');"

Step 9: Display Success Message

code
✓ Database restored successfully

Restore Details:
  Database: [DBNAME]
  Size: [SIZE] MB
  Source: FILENAME
  Restored: [CURRENT_TIMESTAMP]

When User Invokes: /testsql shutdown

Step 1: Detect and Check Running Container

Find any running SQL container (same logic as backup Step 1):

bash
docker ps --format "{{.Names}}\t{{.Image}}" | grep -iE "dams.*sql"

If no container running:

  • Output: "No SQL container running. Nothing to shutdown."
  • Stop execution

Store containerName for subsequent steps.

Step 2: Auto-Backup First

Output: "Creating automatic backup before shutdown..."

Follow the same logic as /testsql backup:

  1. Detect database name
  2. Generate timestamp
  3. Create backup
  4. Show backup details

If backup fails:

  • Ask user: "Backup failed. Continue shutdown anyway? (yes/no)"
  • If no: Stop execution
  • If yes: Continue to Step 3

Step 3: Stop Container

Use containerName from Step 1:

bash
docker stop ${containerName}

Output:

code
✓ Stopping container (${containerName})...
✓ Container stopped successfully

Step 4: Remove Container (Keep Data)

bash
docker rm ${containerName}

Note: This removes container but keeps Docker volumes (data persists in .claude/testSQLSetup/data* folders)

Step 5: Display Summary

code
========================================
  Shutdown Complete
========================================
✓ Backup created: [FILENAME]
✓ Container stopped and removed
✓ Data volumes preserved
✓ Port 1433 released
✓ Memory freed: ~7 GB

Next startup will be fast (~30 seconds)
Run: /testsql setup
========================================

When User Invokes: /testsql status

Step 1: Detect All SQL Containers

Find all SQL containers (running or stopped):

bash
docker ps -a --format "{{.Names}}\t{{.Image}}\t{{.Status}}\t{{.RunningFor}}" | grep -iE "dams.*sql"

Store all found containers. If multiple found, show status for all.

Parse output for each:

  • If "Up": Container running
  • If "Exited": Container stopped

Use the first running container for detailed stats, or the most recently used stopped container.

Step 2: Get Container Stats (if running)

Use containerName from Step 1:

bash
docker stats ${containerName} --no-stream --format "{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"

Step 3: Detect Engine Type

Based on container name or image:

  • sqlserver-dev → "SQL Server 2022"
  • azuresql-dev → "Azure SQL Edge"

Step 4: Test SQL Server Connection (if running)

bash
docker exec ${containerName} /opt/mssql-tools/bin/sqlcmd \
  -S localhost -U sa -P 'YourSecurePassword123!' \
  -Q "SELECT @@VERSION" 2>/dev/null

If successful: Extract SQL Server version

Step 5: Get Database Name (if running)

bash
docker exec ${containerName} /opt/mssql-tools/bin/sqlcmd \
  -S localhost -U sa -P 'YourSecurePassword123!' -h -1 \
  -Q "SET NOCOUNT ON; SELECT TOP 1 name FROM sys.databases WHERE database_id > 4"

Step 6: List Available Backups

bash
ls -lht .claude/testSQL/bootstrap/*.bak 2>/dev/null | head -5

Parse output to show filename, size, timestamp

Step 7: Display Status Report

If container running:

code
========================================
  SQL Server Status
========================================
Engine Type:    [SQL Server 2022 | Azure SQL Edge]
Container:      [CONTAINER_NAME]
Status:         ✓ Running
Uptime:         [UPTIME]
CPU Usage:      [CPU]%
Memory Usage:   [MEM_USED] / [MEM_TOTAL] GB
Network I/O:    [NET_RX] / [NET_TX]
Disk I/O:       [DISK_READ] / [DISK_WRITE]

SQL Server Version: [VERSION]
Connection: ✓ Active

========================================
  Connection Information
========================================
Server Name:    localhost,1433
Database Name:  [DBNAME]
Username:       sa
Password:       YourSecurePassword123!

Connection String (SSMS/Azure Data Studio):
Server=localhost,1433;Database=[DBNAME];User Id=sa;Password=YourSecurePassword123!;TrustServerCertificate=True;

========================================
  Available Backups
========================================
[BACKUP_LIST with sizes and timestamps]

Total: [COUNT] backups
========================================

Replace values:

  • [SQL Server 2022 | Azure SQL Edge] with detected engine type from Step 3
  • [CONTAINER_NAME] with actual container name from Step 1

If container not running:

code
========================================
  SQL Server Status
========================================
Container Status: ✗ Not Running

To start SQL Server, run:
  /testsql setup

========================================
  Available Backups
========================================
[BACKUP_LIST]
========================================

When User Invokes: /testsql help

Display the user documentation section (commands, usage, prerequisites).


Error Handling Guidelines

Common Errors to Handle Gracefully:

  1. Docker not installed:

  2. Docker not running:

    • Clear message: "Docker is not running"
    • Suggest: "Start Docker Desktop and try again"
    • Exit cleanly
  3. Port 1433 in use:

    • Detect: netstat -an | grep :1433 or lsof -i :1433
    • Clear message: "Port 1433 is already in use"
    • Suggest: "Stop other SQL Server instances or change port in .env"
  4. Insufficient disk space:

    • Detect: df -h .claude/testSQL/bootstrap
    • Clear message: "Insufficient disk space"
    • Suggest: "Delete old backups or free up space"
  5. Script syntax error:

    • Show SQL error message
    • Suggest: "Check script syntax in .claude/testSQL/bootstrap/[SCRIPT]"
    • Offer to continue with default northwind.sql
  6. Container startup timeout:

    • Clear message: "SQL Server failed to start within 3 minutes"
    • Suggest: "Check logs: docker logs sqlserver-dev"
    • Suggest: "Try rebuilding: docker compose build --no-cache"

Output Formatting Guidelines

Use Clear Visual Separators:

code
========================================
  Section Title
========================================
Content here...
========================================

Use Status Indicators:

  • Success: ✓ Operation completed
  • Error: ✗ Operation failed
  • Warning: ⚠ Warning message
  • Info: ℹ Information

Use Progress Indicators:

code
✓ Step 1 completed
✓ Step 2 completed
⋯ Step 3 in progress...

Use Code Blocks for Commands:

When suggesting commands to user:

code
To check logs, run:
```bash
docker logs sqlserver-dev
```

Testing Recommendations

Before finalizing, test these scenarios:

  1. ✓ First-time setup (no Docker image)
  2. ✓ Setup with default Northwind
  3. ✓ Setup with custom script (with CREATE DATABASE)
  4. ✓ Setup with custom script (without CREATE DATABASE)
  5. ✓ Backup and restore workflow
  6. ✓ Shutdown and restart
  7. ✓ Error handling (Docker not running, script error, etc.)

Version: 2.0 (Agent-Based) Created: 2026-01-29 Type: Agent-Based Skill (no .sh file needed) Maintained by: YourProject Team