---
title: Develop a C++ Client Query
sidebar_label: C++
---

This section of the crash course covers Deephaven Enterprise's client APIs. This guide discusses the C++ client, which allows you to:

- Create new workers
- Connect to existing Persistent Queries (PQs)
- Run queries server-side
- Fetch and interact with tables
- And more!

The Enterprise C++ client is built on top of the [Community C++ client](/core/client-api/cpp/), giving you access to its rich feature set.

## Installation

The C++ client requires building from source. Contact your Deephaven representative to obtain the C++ client source bundle (`dhe-cpp-src-<version>.tgz`). Ensure the version matches your Deephaven Enterprise server.

### Supported operating systems

You can build and use the C++ client with:

- Ubuntu 22.04 or 24.04
- RHEL 9

### Build the client

The source bundle includes a Dockerized build script. Prerequisites:

- Docker with `buildx` installed
- Root access (or Docker configured for non-root users)

Unpack the source bundle and build:

```bash
# Unpack the source bundle
VERSION=<version>  # e.g., 1.20240517.564
cd /path/to/source/bundle
tar -xvf dhe-cpp-src-$VERSION.tgz

# Build for Ubuntu 24.04
cd coreplus/cpp-client
PREFIX=/opt/deephaven
./docker-build.sh --base-distro ubuntu:24.04 --prefix $PREFIX
```

### Install the build bundle

Unpack the generated bundle to your filesystem:

```bash
cd build
sudo tar -xvf dhe-cpp-latest-ubuntu-24.04.tgz --directory=/
```

### Set up the environment

Before using the C++ client, source the environment script:

```bash
source $PREFIX/env.sh
```

For detailed installation instructions, see the [C++ client installation guide](../../clients/install-cpp-client.md).

## Create a session

The first step when using the C++ client is to create a `SessionManager`. A `SessionManager` manages connections to the Deephaven Enterprise Controller and Authentication services. It requires a URL to the server's `connection.json` file.

```cpp
#include <string>

#include "deephaven/dhcore/utility/utility.h"
#include "deephaven_enterprise/session/session_manager.h"

using deephaven::dhcore::utility::Basename;
using deephaven::dhcore::utility::GetTidAsString;
using deephaven_enterprise::session::SessionManager;

int main(int argc, char *argv[]) {
  // Create a descriptive name for logging
  const std::string descriptive_name =
      std::string(Basename(argv[0])) + " tid=" + GetTidAsString();

  // Connect to the server
  const std::string json_url =
      "https://deephaven-host:8000/iris/connection.json";
  SessionManager session_manager =
      SessionManager::FromUrl(descriptive_name, json_url);

  // ... use the session manager
  return 0;
}
```

> [!NOTE]
> This example uses port `8000`. Your server may use a different port. Typically, the port is `8123` for servers _without_ Envoy and `8000` for servers _with_ Envoy.

The `descriptive_name` helps identify your client in server logs. Including the thread ID (via `GetTidAsString()`) makes it easier to trace operations.

To compile this program, use a command like:

```bash
g++ -std=c++20 -I$PREFIX/include -L$PREFIX/lib session_example.cc -ldhcore -ldhclient -ldhe_client
```

## Authenticate

Once a `SessionManager` is created, authenticate with the server. You can use either password authentication or private key authentication:

```cpp
// Password authentication
bool auth_result = session_manager.PasswordAuthentication(
    "username", "password", "username");

// Or private key authentication
// bool auth_result =
//     session_manager.PrivateKeyAuthentication("/path/to/private_key");

if (!auth_result) {
  std::cerr << "Authentication failed!\n";
  return 1;
}
```

> [!NOTE]
> The third argument to `PasswordAuthentication` is the `operate_as` parameter. Under normal circumstances, pass the same value as the username.

## Use the client

### Connect to an existing PQ

To connect to a running PQ, use either its name or serial number:

```cpp
// Connect by name
const std::string pq_name = "my_favorite_pq";
DndClient client = session_manager.ConnectToPqByName(pq_name, false);

// Or connect by serial
// using deephaven_enterprise::session::pqserial_t;
// const pqserial_t pq_serial = 9876543210L;
// DndClient client = session_manager.ConnectToPqBySerial(pq_serial, false);
```

### Create a new temporary PQ

To create a new temporary worker, use a `PqConfigBuilder`:

```cpp
const std::string pq_name = "my_new_pq";
PqConfigBuilder pq_builder = session_manager.MakeTempPqConfigBuilder(pq_name);
pq_builder.SetMaxHeapSizeGb(4);
pq_builder.SetScriptLanguage("python");  // or "groovy"

DndClient client = session_manager.AddQueryAndConnect(pq_builder.Build());
```

### Run queries and fetch tables

To interact with tables, create a `DndTableHandleManager` from the `DndClient`:

```cpp
DndTableHandleManager table_manager = client.GetManager();

// Run a script on the server
table_manager.RunScript(
    "from deephaven import time_table\n"
    "my_table = time_table('PT1S')");

// Wait for the table to populate (requires <unistd.h>)
sleep(2);

// Fetch the table
TableHandle table_handle = table_manager.FetchTable("my_table");

// Print the table to stdout
std::cout << "*** Table my_table:\n"
          << table_handle.Stream(true) << "\n";
```

> [!NOTE]
> The script language must match the PQ's configuration. Use `PqConfigBuilder::SetScriptLanguage` when creating a new PQ, passing either `"groovy"` or `"python"`.

### Close connections

When finished, close the `DndClient` and `SessionManager` objects to release resources:

```cpp
client.Close();
session_manager.Close();
```

> [!CAUTION]
> Once `Close()` is called, any subsequent operation on that object results in an error.

Objects are also automatically closed when destroyed, but explicitly closing them ensures prompt resource cleanup.

## Complete example

Here's a complete example that connects to a server, creates a temporary PQ, runs a query, and prints the result:

```cpp
#include <iostream>
#include <string>
#include <unistd.h>

#include "deephaven/dhcore/utility/utility.h"
#include "deephaven/client/client.h"
#include "deephaven_enterprise/session/dnd_client.h"
#include "deephaven_enterprise/session/session_manager.h"

using deephaven::client::TableHandle;
using deephaven::dhcore::utility::Basename;
using deephaven::dhcore::utility::GetTidAsString;
using deephaven_enterprise::session::DndClient;
using deephaven_enterprise::session::DndTableHandleManager;
using deephaven_enterprise::session::PqConfigBuilder;
using deephaven_enterprise::session::SessionManager;

int main(int argc, char *argv[]) {
  try {
    // Create session manager
    const std::string descriptive_name =
        std::string(Basename(argv[0])) + " tid=" + GetTidAsString();
    const std::string json_url =
        "https://deephaven-host:8000/iris/connection.json";

    std::cout << "Creating session manager...\n";
    SessionManager session_manager =
        SessionManager::FromUrl(descriptive_name, json_url);

    // Authenticate
    std::cout << "Authenticating...\n";
    if (!session_manager.PasswordAuthentication("user", "password", "user")) {
      std::cerr << "Authentication failed!\n";
      return 1;
    }
    std::cout << "Authenticated successfully.\n";

    // Create a temporary PQ
    std::cout << "Creating temporary PQ...\n";
    PqConfigBuilder pq_builder =
        session_manager.MakeTempPqConfigBuilder("cpp_crash_course_pq");
    pq_builder.SetMaxHeapSizeGb(4);
    pq_builder.SetScriptLanguage("python");

    DndClient client =
        session_manager.AddQueryAndConnect(pq_builder.Build());
    std::cout << "Connected to PQ.\n";

    // Get table manager and run a script
    DndTableHandleManager table_manager = client.GetManager();

    std::cout << "Running script...\n";
    table_manager.RunScript(
        "from deephaven import time_table\n"
        "result = time_table('PT1S').update('X = i')");

    // Wait for some data
    sleep(3);

    // Fetch and display the table
    TableHandle table = table_manager.FetchTable("result");
    std::cout << "\n*** Result table:\n"
              << table.Stream(true) << "\n";

    // Clean up
    client.Close();
    session_manager.Close();
    std::cout << "Done.\n";

  } catch (const std::exception &e) {
    std::cerr << "Error: " << e.what() << "\n";
    return 1;
  }

  return 0;
}
```

To compile this program, use a command like:

```bash
g++ -std=c++20 -I$PREFIX/include -L$PREFIX/lib complete_example.cc -ldhcore -ldhclient -ldhe_client
```

## Debugging tips

If you experience connectivity issues, the client may appear to hang for up to 2 minutes (the default gRPC timeout) before reporting an error.

To debug network issues, set the `GRPC_VERBOSITY` environment variable:

```bash
export GRPC_VERBOSITY=debug  # or 'info' for less detail
./my_cpp_client
```

This logs gRPC connection details, including SSL authentication and certificate validation.

## Related documentation

- [C++ client installation guide](../../clients/install-cpp-client.md)
- [C++ client usage guide](../../clients/coreplus-cpp-client.md)
- [C++ API reference](/core/client-api/cpp/)
- [Code Studio](../../interfaces/web/code-studio.md)
- [Creating dashboards](../create-dashboard/by-hand.md)
- [Ingesting data](../data-in/streaming-kafka.md)
- [Writing queries](../develop-query/deephaven-ide.md)
