Database Parsers Setup
Overview
This guide covers the complete setup process for SQL and NoSQL syntax validators in Runner Codes. These parsers validate query syntax WITHOUT requiring real database connections.
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Host Machine │
│ ┌─────────────────┐ ┌──────────────────────────────────┐│
│ │ infra.operator │───▶│ Firecracker microVM ││
│ │ (host mode) │ │ ┌────────────────────────────┐ ││
│ └─────────────────┘ │ │ guest-runner │ ││
│ │ │ └─────────────────────────│ ││
│ │ │ │ Node.js │ ││
│ │ │ │ └── node-sql-parser │ ││
│ │ │ │ └── mysql-run.js │ ││
│ │ └──│─────────────────────────│ ││
│ └─────┴──────────────────────────┴──┘│
└─────────────────────────────────────────────────────────────┘
Prerequisites
- EC2 instance with Firecracker installed
- Docker for building images
- AWS credentials for S3 uploads
infra.operatorbinary installed
Step 1: Create Docker Images
Directory Structure
docker/
├── mysql-parser/
│ ├── Dockerfile
│ └── mysql-run.js
├── postgresql-parser/
│ ├── Dockerfile
│ └── psql-run.js
├── mariadb-parser/
│ ├── Dockerfile
│ └── mariadb-run.js
├── sqlite-parser/
│ ├── Dockerfile
│ └── sqlite-run.js
├── mongodb-parser/
│ ├── Dockerfile
│ └── mongodb-run.js
└── redis-parser/
├── Dockerfile
└── redis-run.js
SQL Parser Dockerfile
# docker/mysql-parser/Dockerfile
FROM node:22-alpine3.20
# Install node-sql-parser
WORKDIR /opt/sql-parser
RUN npm init -y && npm install node-sql-parser --save
# Copy the runner script
COPY mysql-run.js /usr/local/bin/mysql-run
RUN chmod +x /usr/local/bin/mysql-run
# Set NODE_PATH for node-sql-parser
ENV NODE_PATH=/opt/sql-parser/node_modules
CMD ["node", "--version"]
SQL Parser Script (mysql-run.js)
#!/usr/bin/env node
const fs = require('fs');
const { Parser } = require('node-sql-parser');
const parser = new Parser();
const DATABASE = 'MySQL'; // or PostgreSQL, MariaDB, sqlite
const args = process.argv.slice(2);
if (args.length === 0) {
console.error('Usage: mysql-run.js <file.sql>');
process.exit(1);
}
const sql = fs.readFileSync(args[0], 'utf8').trim();
try {
const ast = parser.astify(sql, { database: DATABASE });
const formatted = parser.sqlify(ast, { database: DATABASE });
console.log('=== SQL Validation Result ===');
console.log('Status: VALID');
console.log('');
console.log('=== Formatted SQL ===');
console.log(formatted);
console.log('');
console.log('=== Statement Summary ===');
if (Array.isArray(ast)) {
console.log(`Total statements: ${ast.length}`);
ast.forEach((stmt, i) => {
console.log(` ${i + 1}. ${stmt.type || 'unknown'}`);
});
} else {
console.log(`Statement type: ${ast.type || 'unknown'}`);
}
process.exit(0);
} catch (err) {
console.log('=== SQL Validation Result ===');
console.log('Status: INVALID');
console.error(`Syntax Error: ${err.message}`);
process.exit(1);
}
NoSQL Parser Dockerfile (MongoDB)
# docker/mongodb-parser/Dockerfile
FROM node:22-alpine3.20
WORKDIR /opt/mongodb-parser
COPY mongodb-run.js /usr/local/bin/mongodb-run
RUN chmod +x /usr/local/bin/mongodb-run
CMD ["node", "--version"]
Step 2: Build and Push Docker Images
# Build and push all images
for parser in mysql-parser postgresql-parser mariadb-parser sqlite-parser mongodb-parser redis-parser; do
echo "Building ${parser}..."
docker build -t ttl.sh/llm-fc-${parser}:24h ./docker/${parser}/
docker push ttl.sh/llm-fc-${parser}:24h
done
Using ttl.sh as ephemeral registry. Images auto-delete after 24 hours.
For production, use a permanent registry like ECR or Docker Hub.
Step 3: Create Rootfs Images
ssh -i key.pem ubuntu@EC2_IP
# SQL parsers need 500MB for node_modules
for parser in mysql-parser postgresql-parser mariadb-parser sqlite-parser; do
echo "Creating rootfs for ${parser}..."
sudo infra.operator rootfs from-docker \
--name ${parser} \
--image ttl.sh/llm-fc-${parser}:24h \
--size 500
done
# NoSQL parsers need 300MB
for parser in mongodb-parser redis-parser; do
echo "Creating rootfs for ${parser}..."
sudo infra.operator rootfs from-docker \
--name ${parser} \
--image ttl.sh/llm-fc-${parser}:24h \
--size 300
done
Verify Rootfs Creation
ls -lah /srv/firecracker/images/rootfs-*-parser.ext4
Step 4: Create Snapshots
# Create snapshots (256MB memory is sufficient)
for parser in mysql-parser postgresql-parser mariadb-parser sqlite-parser mongodb-parser redis-parser; do
echo "Creating snapshot for ${parser}..."
sudo infra.operator snapshot create \
--lang ${parser} \
--mem 256 \
--vcpus 1
done
Verify Snapshots
ls -la /dev/shm/snapshots/ | grep parser
Step 5: Upload to S3
export AWS_ACCESS_KEY_ID="your-key"
export AWS_SECRET_ACCESS_KEY="your-secret"
export AWS_DEFAULT_REGION="us-east-1"
for parser in mysql-parser postgresql-parser mariadb-parser sqlite-parser mongodb-parser redis-parser; do
echo "Uploading rootfs ${parser}..."
sudo -E infra.operator rootfs upload \
--lang ${parser} \
--bucket runner-codes
done
for parser in mysql-parser postgresql-parser mariadb-parser sqlite-parser mongodb-parser redis-parser; do
echo "Uploading snapshot ${parser}..."
sudo -E infra.operator snapshot upload \
--lang ${parser} \
--bucket runner-codes
done
Verify S3 Upload
aws s3 ls s3://runner-codes/ | grep parser
aws s3 ls s3://runner-codes/snapshots/ | grep parser
Step 6: Update executor.go
Add the new languages to pkg/guest/executor.go:
// Tier 11: SQL Syntax Validators (node-sql-parser based)
"mysql-parser": {
Name: "mysql-parser",
Extension: ".sql",
Command: "/usr/local/bin/node",
Args: []string{"/usr/local/bin/mysql-run"},
Env: []string{"NODE_PATH=/opt/sql-parser/node_modules"},
},
"postgresql-parser": {
Name: "postgresql-parser",
Extension: ".sql",
Command: "/usr/local/bin/node",
Args: []string{"/usr/local/bin/psql-run"},
Env: []string{"NODE_PATH=/opt/sql-parser/node_modules"},
},
// ... more parsers
// Tier 12: NoSQL Query Validators
"mongodb-parser": {
Name: "mongodb-parser",
Extension: ".json",
Command: "/usr/local/bin/node",
Args: []string{"/usr/local/bin/mongodb-run"},
},
"redis-parser": {
Name: "redis-parser",
Extension: ".redis",
Command: "/usr/local/bin/node",
Args: []string{"/usr/local/bin/redis-run"},
},
Also add NODE_PATH to the environment in runCommandWithStdin:
// node-sql-parser module path for SQL validators
"NODE_PATH=/opt/sql-parser/node_modules",
Step 7: Rebuild and Deploy Binary
cd /path/to/runner-codes
GOOS=linux GOARCH=amd64 go build -o bin/infra.operator-linux ./cmd/infra.operator/...
scp -i key.pem bin/infra.operator-linux ubuntu@EC2_IP:/tmp/infra.operator
ssh ubuntu@EC2_IP
sudo cp /tmp/infra.operator /usr/local/bin/infra.operator
sudo chmod +x /usr/local/bin/infra.operator
for parser in mysql-parser postgresql-parser mariadb-parser sqlite-parser mongodb-parser redis-parser; do
sudo mkdir -p /mnt/${parser}
sudo mount -o loop /srv/firecracker/images/rootfs-${parser}.ext4 /mnt/${parser}
sudo cp /tmp/infra.operator /mnt/${parser}/usr/local/bin/infra.operator
sudo chmod +x /mnt/${parser}/usr/local/bin/infra.operator
sync
sudo umount /mnt/${parser}
sudo rmdir /mnt/${parser}
done
Step 8: Recreate Snapshots
for parser in mysql-parser postgresql-parser mariadb-parser sqlite-parser mongodb-parser redis-parser; do
sudo rm -rf /dev/shm/snapshots/${parser}
done
for parser in mysql-parser postgresql-parser mariadb-parser sqlite-parser mongodb-parser redis-parser; do
sudo infra.operator snapshot create --lang ${parser} --mem 256 --vcpus 1
done
export AWS_ACCESS_KEY_ID="your-key"
export AWS_SECRET_ACCESS_KEY="your-secret"
for parser in mysql-parser postgresql-parser mariadb-parser sqlite-parser mongodb-parser redis-parser; do
sudo -E infra.operator snapshot upload --lang ${parser} --bucket runner-codes
done
Step 9: Test Execution
sudo infra.operator host \
--lang mysql-parser \
--snapshot \
--mem 256 \
--vcpus 1 \
--code "SELECT * FROM users WHERE id = 1;"
sudo infra.operator host \
--lang postgresql-parser \
--snapshot \
--mem 256 \
--vcpus 1 \
--code "SELECT * FROM products ORDER BY price DESC LIMIT 10;"
sudo infra.operator host \
--lang mongodb-parser \
--snapshot \
--mem 256 \
--vcpus 1 \
--code '{"collection": "users", "filter": {"age": 25}}'
sudo infra.operator host \
--lang redis-parser \
--snapshot \
--mem 256 \
--vcpus 1 \
--code "SET user:1 john
GET user:1
HSET user:1:profile name John"
Expected Output
MySQL Parser Success
{
"trace_id": "tr-xxx",
"status": "success",
"stdout": "=== SQL Validation Result ===\nStatus: VALID\n...",
"exit_code": 0,
"executionTime": "~2.8s"
}
Performance Metrics
| Parser | Execution Time | Memory | Rootfs Size |
|---|---|---|---|
| MySQL Parser | ~2.8s | 256MB | 500MB |
| PostgreSQL Parser | ~2.8s | 256MB | 500MB |
| MariaDB Parser | ~2.8s | 256MB | 500MB |
| SQLite Parser | ~2.8s | 256MB | 500MB |
| MongoDB Parser | ~2.7s | 256MB | 300MB |
| Redis Parser | ~2.7s | 256MB | 300MB |
Execution time includes Node.js cold start (~2.5s). Subsequent executions with warm Node.js would be faster, but each microVM execution is isolated.
Troubleshooting
"unsupported language" Error
Cause: The guest-runner doesn't recognize the language.
Solution: Ensure:
executor.gohas the language config- Binary was recompiled and deployed
- Rootfs contains the updated binary
- Snapshots were recreated
"MODULE_NOT_FOUND" Error
Cause: Node.js can't find node-sql-parser.
Solution: Ensure:
NODE_PATHis set in environment- Rootfs has
/opt/sql-parser/node_modules/
Timeout Errors
Cause: Parser execution exceeding timeout.
Solution: Increase timeout or check:
- Memory is sufficient (256MB minimum)
- CPU is not overloaded
- Vsock connection is working
Summary
Database parsers provide a lightweight way to validate SQL and NoSQL query syntax without running actual databases. The complete setup involves:
- Docker images with Node.js + parser scripts
- Rootfs created from Docker images via infra.operator
- Snapshots for fast VM startup
- S3 upload for distribution
- executor.go configuration for language support
- Binary deployment to all rootfs images