> For the complete documentation index, see [llms.txt](https://v2.dataos.info/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://v2.dataos.info/references/dataos-resources/vulcan/incremental-by-time/transpiling-semantics.md).

# Transpiling semantics

`vulcan transpile` converts a semantic query into the SQL your engine actually runs. Use it to preview, debug, and validate semantic logic before execution, so you catch errors and spot inefficient joins or filters up front instead of at runtime.

## What is transpilation?

Semantic queries are written in business language: you reference measures and dimensions by their semantic names and let Vulcan resolve the joins, aggregations, and dialect-specific syntax. The engine only understands SQL. Transpilation bridges that gap, translating a semantic query into engine SQL without executing it. It works from two input shapes:

* **Semantic SQL** — SQL-like queries with a `MEASURE()` wrapper. Transpile with `--format sql`.
* **REST payload** — the JSON body you would POST to the semantic API. Transpile with `--format json`.

```bash
vulcan transpile --format sql "SELECT MEASURE(total_users) FROM users"
vulcan transpile --format json '{"query": {"measures": ["users.total_users"]}}'
```

Both print the generated SQL to stdout. If the query is invalid, you get the error here rather than after a warehouse round-trip.

## Pushdown vs post-processing

By default, transpilation runs in **post-processing** mode: Vulcan can layer pre-aggregations and caching on top of the query, but the generated SQL cannot use CTEs. Adding `--disable-post-processing` switches to **pushdown** mode, which supports CTEs and more complex SQL structures but gives up pre-aggregations.

```bash
vulcan transpile --format sql "<query>" --disable-post-processing
```

| Mode                      | Flag                        | CTEs | Pre-aggregations |
| ------------------------- | --------------------------- | ---- | ---------------- |
| Post-processing (default) | *(none)*                    | No   | Yes              |
| Pushdown                  | `--disable-post-processing` | Yes  | No               |

{% hint style="info" %}
Choose by need: keep the default when a query benefits from pre-aggregations and caching; use `--disable-post-processing` when the query relies on CTEs or advanced SQL that post-processing cannot express.
{% endhint %}

## Semantic-SQL grammar

Semantic SQL is standard SQL with a few semantic-layer rules:

```sql
SELECT
  users.plan_type,          -- dimensions: referenced as alias.dimension
  MEASURE(total_users)      -- measures: MUST be wrapped in MEASURE()
FROM users                  -- FROM the semantic model alias, not the physical table
CROSS JOIN subscriptions    -- join condition is inferred automatically
WHERE users.status = 'active'
  AND active_users = true   -- segments only support = true
GROUP BY users.plan_type    -- every non-aggregated column must appear here
ORDER BY MEASURE(total_users)
LIMIT 100
OFFSET 0                    -- pagination offset
```

* **`MEASURE(...)`** is a required wrapper; a measure referenced without it will not aggregate.
* **`CROSS JOIN`** is the join syntax — you do not write an `ON` clause. Vulcan infers the join condition from the semantic model definitions.
* **`OFFSET`** pairs with `LIMIT` for pagination.
* **Segments** are boolean and only support `= true`; `= false` is not supported.

## REST payload fields

The `--format json` input mirrors the semantic REST API body. The core fields (`measures`, `dimensions`, `timeDimensions`, `filters`, `segments`, `order`, `limit`, `offset`, `timezone`) are covered in [Semantic query lifecycle](/references/dataos-resources/vulcan/incremental-by-time/semantic-query-lifecycle.md). The field-level details that most affect transpilation:

| Field                | Details                                                                                                                                      |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `filters[].operator` | One of `equals`, `notEquals`, `contains`, `notContains`, `gt`, `gte`, `lt`, `lte`, `set`, `notSet`, `inDateRange`.                           |
| `filters[].member`   | Fully qualified `alias.member_name`.                                                                                                         |
| `segments`           | Array of segment names. No alias prefix needed — use the segment name directly (e.g., `"mobile_users"`, not `"subscriptions.mobile_users"`). |
| `order`              | Object mapping members to direction: `{"alias.measure": "desc", "alias.dim": "asc"}`.                                                        |
| `renewQuery`         | Boolean inside `query`. When `true`, bypasses the cache and forces a fresh execution.                                                        |
| `ttl_minutes`        | Top-level (sibling of `query`). Cache duration in minutes.                                                                                   |

## Worked examples

**Dimension query** — group a measure by a dimension:

```bash
vulcan transpile --format sql "SELECT users.plan_type, MEASURE(total_users) FROM users GROUP BY users.plan_type"
```

```sql
SELECT "users".plan_type, sum("users".user_id) AS total_users
FROM analytics.users AS "users"
GROUP BY "users".plan_type
```

**Filter** — a REST payload with a `filters` clause:

```bash
vulcan transpile --format json '{"query": {"measures": ["subscriptions.total_arr"], "filters": [{"member": "subscriptions.status", "operator": "equals", "values": ["active"]}]}}'
```

```sql
SELECT sum("subscriptions".arr) AS total_arr
FROM analytics.subscriptions AS "subscriptions"
WHERE "subscriptions".status = 'active'
```

**Time grouping** — truncate a date dimension to a granularity:

```bash
vulcan transpile --format sql "SELECT DATE_TRUNC('month', subscriptions.start_date) as month, MEASURE(total_arr) FROM subscriptions GROUP BY month"
```

```sql
SELECT DATE_TRUNC('month', "subscriptions".start_date) AS month,
       sum("subscriptions".arr) AS total_arr
FROM analytics.subscriptions AS "subscriptions"
GROUP BY DATE_TRUNC('month', "subscriptions".start_date)
```

**Join** — a `CROSS JOIN` with the condition inferred by Vulcan:

```bash
vulcan transpile --format sql "SELECT users.industry, MEASURE(total_arr) FROM subscriptions CROSS JOIN users GROUP BY users.industry"
```

```sql
SELECT "users".industry, sum("subscriptions".arr) AS total_arr
FROM analytics.subscriptions AS "subscriptions"
CROSS JOIN analytics.users AS "users"
WHERE "subscriptions".user_id = "users".user_id
GROUP BY "users".industry
```

## MySQL wire protocol

The MySQL wire protocol exposes the semantic layer as a MySQL-compatible server, so any standard SQL client or BI tool can query it directly. Semantic queries are transpiled to the underlying engine dialect on the server side — you write SQL against your semantic models, and Vulcan handles the translation.

Connect using the standard MySQL client:

```bash
mysql -h <host> -P <port> -u <user> -p
```

The port is typically `3306` (remote) or `3307` (local), as configured in your Vulcan deployment.

After connecting, discover available models:

```sql
SHOW TABLES;          -- lists available semantic models
DESCRIBE <model>;     -- shows columns and types
```

**Representative queries:**

1. Basic measure:

   ```sql
   SELECT total_revenue FROM subscriptions;
   ```
2. Measure with dimension:

   ```sql
   SELECT plan_type, total_revenue FROM subscriptions;
   ```
3. With filter:

   ```sql
   SELECT plan_type, total_revenue FROM subscriptions WHERE region = 'US';
   ```
4. Time grouping:

   ```sql
   SELECT DATE_TRUNC('month', created_at) AS month, COUNT(*) AS new_users FROM users GROUP BY 1;
   ```
5. Join:

   ```sql
   SELECT users.plan_type, SUM(orders.amount) AS revenue FROM orders JOIN users ON orders.user_id = users.id;
   ```

{% hint style="info" %}
Queries sent through the MySQL wire protocol are transpiled to the underlying engine dialect. Complex aggregations may behave differently than native SQL — inspect the transpiled output with `vulcan transpile` if results are unexpected.
{% endhint %}

## Use cases

**Query validation** — validate a semantic query locally before sending it to the API. `vulcan transpile` surfaces any errors immediately, before a warehouse round-trip.

```bash
vulcan transpile --format sql "SELECT users.plan_type, MEASURE(total_users) FROM users GROUP BY users.plan_type"
```

**Debugging** — inspect the generated SQL to understand join order, filter placement, and aggregation. When a query returns unexpected results, transpile it to see exactly what Vulcan sends to the engine.

```bash
vulcan transpile --format json '{"query": {"measures": ["subscriptions.total_arr"], "filters": [{"member": "subscriptions.status", "operator": "equals", "values": ["active"]}]}}'
```

**Performance tuning** — identify which joins or filters are being pushed down vs. post-processed. Review the generated SQL for unnecessary cross-joins or late-stage filters, then adjust the semantic model or switch modes accordingly.

```bash
vulcan transpile --format sql "SELECT users.industry, MEASURE(total_arr) FROM subscriptions CROSS JOIN users WHERE subscriptions.status = 'active' GROUP BY users.industry" --disable-post-processing
```

**CI/CD** — add `vulcan transpile` to a pre-commit or CI step to catch semantic query regressions before they reach production. Exit code is non-zero on error, making it suitable for pipeline gating.

```bash
vulcan transpile --format sql "SELECT MEASURE(total_users) FROM users"
```

## Common errors and solutions

| Error                                        | Symptom                                       | Fix                                                                                                                             |
| -------------------------------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `Unknown member: X`                          | A dimension or member does not resolve.       | Verify it exists in the semantic model, check spelling and casing (case-sensitive), and use the fully qualified `alias.member`. |
| `Measure not found: X`                       | A measure reference is not recognized.        | Wrap it in `MEASURE(...)` for `--format sql`, or use `alias.measure_name` for `--format json`, and confirm it is defined.       |
| `Model not found: X`                         | The `FROM` alias matches no model.            | Check the aliases in `models/semantics/`; confirm spelling, casing, and that the model is defined.                              |
| `Invalid JSON format`                        | The request body could not be parsed as JSON. | Validate your JSON payload with a linter; check for trailing commas, unescaped quotes, or encoding issues.                      |
| `Projection references non-aggregate values` | A column is neither aggregated nor grouped.   | Add every non-aggregated column to `GROUP BY`, and wrap all measures in `MEASURE()`.                                            |

## Related docs

* [Semantic query lifecycle](/references/dataos-resources/vulcan/incremental-by-time/semantic-query-lifecycle.md): how a transpiled query is submitted, cached, executed, and fetched.
* [Semantic model and components](/references/dataos-resources/vulcan/core-concepts/semantic-model-and-components.md): the definitions your queries resolve against.
* [Import Snowflake semantic views](/references/dataos-resources/vulcan/incremental-by-time/import-snowflake-semantic-views.md): bring existing semantic views into your Vulcan project.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://v2.dataos.info/references/dataos-resources/vulcan/incremental-by-time/transpiling-semantics.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
