> For the complete documentation index, see [llms.txt](https://docs.pal.aic.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.pal.aic.io/using-pal.net/sql.md).

# SQL

The SQL façade models the query lifecycle: submit, inspect status, read results, and cancel. Results are streamed and must be disposed.

## Register and execute

```csharp
services.AddPalantir(options);
services.AddPalantirSql();

var sql = scope.ServiceProvider.GetRequiredService<IPalSqlClient>();

var status = await sql.ExecuteAsync(new PalSqlQueryRequest
{
    Query = "SELECT employee_id, display_name FROM employees",
    FallbackBranchIds = ["master"],
    SerializationFormat = PalSqlSerializationFormat.Arrow
}, cancellationToken);

var queryId = status.QueryId
    ?? throw new InvalidOperationException("The SQL response did not contain a query id.");
```

`PalSqlQueryRequest.Validate` rejects an empty query and empty fallback branch IDs. Choose `Arrow` or `Csv` before submission.

## Poll status

```csharp
var current = await sql.GetStatusAsync(queryId, cancellationToken);
Console.WriteLine(current.Raw);
```

The status contract keeps the raw JSON so new upstream status variants remain inspectable. Use `PalantirOperationPoller` for a cancellable, timeout-bounded loop:

```csharp
var poller = new PalantirOperationPoller();
var completed = await poller.WaitUntilAsync(
    token => new ValueTask<PalSqlQueryStatus>(sql.GetStatusAsync(queryId, token)),
    state => state.Raw.TryGetProperty("status", out var value)
          && value.GetString() is "COMPLETED" or "FAILED" or "CANCELLED",
    new PalantirPollingOptions
    {
        Interval = TimeSpan.FromSeconds(2),
        Timeout = TimeSpan.FromMinutes(10)
    },
    cancellationToken);
```

If the timeout expires, the poller throws `PalantirPollingTimeoutException`. Caller cancellation remains `OperationCanceledException`.

## Read results

```csharp
await using var results = await sql.GetResultsAsync(queryId, cancellationToken);
await results.Content.CopyToAsync(outputStream, cancellationToken);
```

`PalSqlQueryResult.ContentType` exposes the upstream media type. PAL.NET does not buffer or decode the result; the application chooses a CSV or Arrow reader.

## Cancel queries

```csharp
await sql.CancelAsync(queryId, cancellationToken);
```

Cancellation of the local HTTP request and cancellation of the upstream SQL query are separate concerns. Call `CancelAsync` when the business workflow requires upstream cancellation, and always pass the host cancellation token to every local call.
