# `QuackDB.SQL`
[🔗](https://github.com/elixir-vibe/quackdb/blob/main/lib/quack_db/sql.ex#L1)

Client-side SQL parameter formatting for DuckDB Quack queries.

DuckDB's current Quack protocol request shape does not expose server-side bind
parameters. QuackDB therefore formats positional `?` placeholders as DuckDB SQL
literals before sending a `PrepareRequest`.

The formatter scans SQL and ignores placeholders inside quoted strings and SQL
comments. It supports conservative scalar values and raises `QuackDB.Error` for
unsupported parameter shapes rather than producing lossy SQL.

# `parameter`

```elixir
@type parameter() ::
  nil
  | boolean()
  | integer()
  | float()
  | :nan
  | :infinity
  | :neg_infinity
  | String.t()
  | Decimal.t()
  | Date.t()
  | Time.t()
  | NaiveDateTime.t()
  | DateTime.t()
  | QuackDB.Interval.t()
  | Duration.t()
  | {:blob, binary()}
  | {:uuid, binary()}
  | {:json, term()}
  | {:interval, integer(), integer(), integer()}
  | [parameter()]
```

# `call`

```elixir
@spec call(atom() | String.t(), [parameter()], keyword(parameter())) :: iodata()
```

Builds a `CALL function(args..., option = value...);` statement.

# `columns`

```elixir
@spec columns(
  :star | String.t() | [atom() | String.t()] | keyword(),
  keyword()
) :: iodata()
```

Builds a DuckDB `COLUMNS(...)` expression.

# `cube`

```elixir
@spec cube([atom() | String.t() | {:expr, iodata()}]) :: iodata()
```

Builds a DuckDB `CUBE (...)` grouping expression.

# `explain`

```elixir
@spec explain(
  iodata(),
  keyword()
) :: iodata()
```

Builds an `EXPLAIN ...` or `EXPLAIN ANALYZE ...` statement.

Pass `analyze: true` to run the query and include DuckDB execution timings.
Pass `format: :json`, `:html`, `:graphviz`, `:mermaid`, or `:text` to use
DuckDB's `EXPLAIN (FORMAT ...)` output.

# `format`

```elixir
@spec format(iodata(), [parameter()]) ::
  {:ok, String.t()} | {:error, QuackDB.Error.t()}
```

# `grouping_sets`

```elixir
@spec grouping_sets([[atom() | String.t() | {:expr, iodata()}]]) :: iodata()
```

Builds a DuckDB `GROUPING SETS (...)` grouping expression.

# `install`

```elixir
@spec install(atom() | String.t()) :: iodata()
```

Builds an `INSTALL extension;` statement.

# `literal`

```elixir
@spec literal(parameter()) :: {:ok, iodata()} | {:error, QuackDB.Error.t()}
```

# `literal!`

```elixir
@spec literal!(parameter()) :: iodata()
```

Builds a DuckDB SQL literal or raises `QuackDB.Error` for unsupported values.

# `load`

```elixir
@spec load(atom() | String.t()) :: iodata()
```

Builds a `LOAD extension;` statement.

# `pivot`

```elixir
@spec pivot(
  iodata(),
  keyword()
) :: iodata()
```

Builds a DuckDB `PIVOT` statement.

# `reset_variable`

```elixir
@spec reset_variable(atom() | String.t()) :: iodata()
```

Builds `RESET VARIABLE name;`.

# `rollup`

```elixir
@spec rollup([atom() | String.t() | {:expr, iodata()}]) :: iodata()
```

Builds a DuckDB `ROLLUP (...)` grouping expression.

# `set`

```elixir
@spec set(atom() | String.t(), parameter()) :: iodata()
```

Builds a `SET name = value;` statement.

# `set_global`

```elixir
@spec set_global(atom() | String.t(), parameter()) :: iodata()
```

Builds a `SET GLOBAL name = value;` statement.

# `set_variable`

```elixir
@spec set_variable(atom() | String.t(), parameter()) :: iodata()
```

Builds `SET VARIABLE name = value;`. Queries read it as `$name` in DuckDB
2.0, or with `QuackDB.Ecto.Analytics.variable/1`.

# `star`

```elixir
@spec star(keyword()) :: iodata()
```

Builds a DuckDB star expression such as `* EXCLUDE (...)` or `table.* REPLACE (...)`.

# `unpack_columns`

```elixir
@spec unpack_columns(
  :star | String.t() | [atom() | String.t()] | keyword(),
  keyword()
) :: iodata()
```

Builds a DuckDB `*COLUMNS(...)` unpacked columns expression.

# `unpivot`

```elixir
@spec unpivot(
  iodata(),
  keyword()
) :: iodata()
```

Builds a DuckDB `UNPIVOT` statement.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
