SQL Parameterizer
database.sql_parameterize
Overview
You send one SQL statement with values written inline, and we hand back the same statement with bind markers plus a typed list of the slots we created. We work on the WHERE clause of a SELECT, UPDATE or DELETE, and optionally on the LIMIT value; values anywhere else stay exactly where you wrote them. The values themselves never come back — only their position, kind and marker. Reach for something else if you want to run the statement or to swap table and column names, which stay untouched by design.
Regex literal stripping corrupts SQL and leaks values into logs. We rewrite through the parser so shape stays intact and secrets stay out.
Reliability
Same statement in, same template out, for as long as the pinned parser stays put; a parser upgrade can change spacing or keyword casing in the rewritten SQL, so compare parserProfile before treating two runs as identical. We rewrite at most 500 literals, and only inside WHERE clauses of SELECT, UPDATE and DELETE plus the LIMIT value — literals in SELECT lists, INSERT rows, JOIN conditions and identifiers stay as they are. Send one statement per call: if you send several, only the first comes back rewritten. Literal values never appear in the response. Four errors can come back: SQL_PARSE_FAILED — trigger: the text is empty or does not parse as SQL; retryable: no; next: run database.sql_validate_syntax to see the parse error, fix it and call again. SQL_DIALECT_UNSUPPORTED — trigger: dialect is missing or outside postgresql, mysql, mariadb, sqlserver, oracle, sqlite and h2; retryable: no; next: send one of those seven names in lower case. SQL_PARAMETER_LIMIT_EXCEEDED — trigger: the statement holds more than 500 literals to bind, usually a giant IN list; retryable: no; next: split the query or set options.parameterizeInLists to false. SQL_REWRITE_NOT_REPRESENTABLE — trigger: placeholderStyle is not one we know, or the rewritten statement no longer re-parses cleanly; retryable: no; next: check placeholderStyle, then try question_mark, which is the safest shape. A statement nested more than 32 levels deep stops earlier with SQL_PARSE_LIMIT_EXCEEDED — flatten the subqueries and call again.
Context footprint
One call returns the template, parameter metadata, and any literals we could not rewrite. A successful call costs 1 execution credit.
When to use it
When literals must become bind parameters without echoing their values.
When you need to execute the statement or parameterize identifiers.
Powered by JSqlParser, an open-source SQL parser used for AST-based literal rewriting — no regex stripping.
Scope
Non-goals
- Does not execute SQL
- Does not echo literal values in the response
- Does not rewrite identifiers (table or column names)
- Does not use regex-based literal stripping
Properties
Capabilities
Cost & billing
Flat rate per invocation
File handling
How we handle your data
What this means
This skill is designed to detect, mask, redact, validate, or otherwise process sensitive data.
Squillify guarantees
- Runs inside Squillify
- This skill runs inside Squillify.
- Payloads are not sent to an external service by this skill.
- Squillify does not permanently store submitted payloads.
- Telemetry records metadata only, not submitted content.
- Submitted payloads are not used for training.
- Submitted payloads are not reviewed by humans.
- Targets sensitive data
- The response does not contain submitted content.
Your responsibility
Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
| sql | string | Yes | Bounded SQL source parsed without execution. |
| dialect | string | No | SQL dialect; omit it for generic. |
| placeholderStyle | string | No | Placeholder style; omit it for the selected dialect default. |
| options | object | No | Purpose-bound bounded parameterization option object; omit it for safe defaults. It contains from 0 through 1,000 purpose-bound properties — unconstrained RFC 8259 JSON items. |
Output schema
| Field | Type | Required | Description |
|---|---|---|---|
| parameterized | string | Yes | SQL template with bind placeholders. |
| parameters | array | Yes | Bounded array of extracted literal receipts in placeholder order. The item shape is defined by the nested schema and the array contains from 0 through 100000 items. |
| parameterCount | integer | Yes | Extracted parameter count. |
| unrewritten | array | Yes | Bounded array of literals intentionally left unchanged. The item shape is defined by the nested schema and the array contains from 0 through 100000 items. |
| complete | boolean | Yes | Whether every eligible literal was rewritten. |
| findings | array | Yes | Bounded array of safe structured database findings. The item shape is defined by the nested schema and the array contains from 0 through 20000 items. |
| _meta | object | Yes | Closed parameterizer metadata receipt. Its documented receipt properties are bounded to 128 entries — unconstrained RFC 8259 JSON items. |
API contract
POST /v1/executecurl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"database.sql_parameterize","input":{"sql":"SELECT 1","dialect":"postgresql"}}'import { Squillify } from "@squillify/sdk";
const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });
const { output } = await sq.execute("database.sql_parameterize", {"sql":"SELECT * FROM users WHERE email = '[email protected]'","dialect":"postgresql"});Errors
| Code | HTTP | Retryable | Description |
|---|---|---|---|
| VALIDATION_ERROR | 400 | No | The request payload failed schema validation. |
| UNAUTHORIZED | 401 | No | Missing or invalid API key. |
| SKILL_NOT_ACCESSIBLE | 403 | No | The API key is not granted access to this skill. |
| SKILL_NOT_AVAILABLE_FOR_PLAN | 403 | No | This skill is not included in your current plan. |
| PLAN_ELIGIBILITY_UNAVAILABLE | 503 | Yes | Plan eligibility could not be decided. Retry after backoff. |
| SKILL_NOT_FOUND | 404 | No | The requested skill or version does not exist. |
| TENANT_RATE_LIMITED | 429 | Yes | Request rate limit exceeded. Retry after backoff. |
| QUOTA_EXCEEDED | 429 | Yes | Plan quota exhausted. Retryable once the quota period resets. |
| EXECUTION_TIMEOUT | 504 | Yes | Execution exceeded the allowed time budget. |
| SQL_PARSE_FAILED | 400 | No | The request payload failed this skill's input validation. |
| SQL_DIALECT_UNSUPPORTED | 400 | No | The skill does not support the requested variant. |
| SQL_PARAMETER_LIMIT_EXCEEDED | 429 | No | A size, quota, rate, or time limit was exceeded. |
| SQL_REWRITE_NOT_REPRESENTABLE | 400 | No | The skill does not support the requested variant. |
Other limits
| Limit | Value |
|---|---|
| Recommended inline bytes | 32 KiB |
Limitations
- Does not execute SQL
- Does not echo literal values in the response
- Does not rewrite identifiers (table or column names)
- Does not use regex-based literal stripping
- Parameterizing dynamic table or column names
- Running or explaining the query
How to call
POST /v1/execute (requires authentication)
{
"skillKey": "database.sql_parameterize",
"input": {
"sql": "SELECT * FROM users WHERE email = '[email protected]'",
"dialect": "postgresql"
}
}Examples
Email filter turned into a single bind slot
{
"sql": "SELECT * FROM users WHERE email = '[email protected]'",
"dialect": "postgresql"
}{
"findings": [],
"_meta": {
"parserProfile": "jsqlparser-5.3"
},
"parameters": [
{
"type": "STRING",
"valueRedacted": true,
"index": 1,
"placeholder": "?"
}
],
"parameterCount": 1,
"parameterized": "SELECT * FROM users WHERE email = ?",
"unrewritten": [],
"complete": true
}Numeric and text literals with numbered bind slots
{
"placeholderStyle": "numbered",
"sql": "SELECT * FROM orders WHERE id = 42 AND status = 'open'",
"dialect": "postgresql"
}{
"findings": [],
"_meta": {
"parserProfile": "jsqlparser-5.3"
},
"parameters": [
{
"type": "INTEGER",
"valueRedacted": true,
"index": 1,
"placeholder": "$1"
},
{
"type": "STRING",
"valueRedacted": true,
"index": 2,
"placeholder": "$2"
}
],
"parameterCount": 2,
"parameterized": "SELECT * FROM orders WHERE id = ? AND status = ?",
"unrewritten": [],
"complete": true
}Recommended use cases
- Prepare agent-generated SQL for safe binding before execution
- Keep sensitive literals out of logs while preserving query shape
Avoid for
- Parameterizing dynamic table or column names
- Running or explaining the query
Related skills
Composable with
Safety & privacy
- Runs without calling any external service.
- Your payloads are never stored permanently.
- Telemetry captures metadata only — never your payload contents.
- We never train models on your payloads.
- No human reviews your payloads.