Trino HTTP compatibility
SQE speaks enough of the Trino HTTP protocol that Trino clients, JDBC drivers,
and BI tools can point at it unchanged. The coordinator exposes the
/v1/statement endpoint with nextUri pagination, /v1/info, and
/v1/info/state. This is a compatibility surface, not a re-implementation of
Trino; it covers the query-submission path that clients actually use.
Single server
Prerequisites
docker compose -f docker-compose.test.yml up -d
./scripts/bootstrap-test.sh
Configuration
The Trino HTTP listener runs alongside Flight SQL. The default port is 8080
(the test/distributed compose files map it to 28080):
[coordinator]
trino_http_port = 8080 # 0 to disable
HTTPS inside the cluster
trino-python-client and dbt-trino refuse to send a password or token over
plain HTTP. An in-cluster client that calls the service directly needs TLS
on the listener itself. Set trino_https_port and point [coordinator.trino_tls]
at a PEM certificate and key:
[coordinator]
trino_http_port = 8080 # plain, for clients that do not need TLS (0 to disable)
trino_https_port = 8443 # same endpoints over TLS (0, the default, disables it)
[coordinator.trino_tls]
cert_file = "/etc/sqe/trino-tls/tls.crt"
key_file = "/etc/sqe/trino-tls/tls.key"
# ca_file = "/etc/sqe/trino-tls/ca.crt" # optional: require client certificates
Both listeners serve the same queries and share sessions. A request on the
HTTPS port gets https:// nextUri and infoUri values on that port, so the
client never drops back to plain HTTP mid-query. For TLS only, set
trino_http_port = 0 and trino_https_port = 8080. Health checks and metrics
stay plain on their own ports either way.
The certificate fits a cert-manager Certificate issued by an internal CA.
Mount its secret at the paths above. SQE polls the files every 60 seconds and
swaps the certificate for new handshakes, so a renewal needs no restart.
Clients trust the issuer through the CA bundle trust-manager distributes, for
example verify="/etc/ssl/internal/ca.crt" in trino-python-client. The
certificate must name the service host the clients use, such as
sqe.sqe.svc.cluster.local.
Startup fails when trino_https_port is set without a certificate, when a
certificate file is missing, or when the port collides with another listener.
The OAuth2 external-auth URLs (/oauth2/...) are built from the configured
redirect_uri, not from the listener a request arrives on. Give it the
https address clients use.
Behind a TLS-terminating ingress
The plain listener speaks HTTP. Every response carries a nextUri that the
client follows with its bearer token, so that URI must point at the public
https address, not at the plain listener. SQE builds it from the request in
one of two ways.
Trust the ingress by address. List its IPs or its range in
[security] trusted_proxies. A trusted peer’s X-Forwarded-Proto,
X-Forwarded-Host and X-Forwarded-Port then shape the URI, and a forwarded
https always yields https:
[security]
trusted_proxies = ["10.42.0.0/16"] # exact IPs or CIDR ranges, IPv4 or IPv6
Name the public URL instead, when the ingress IPs cannot be pinned:
[coordinator]
public_base_url = "https://sql.example.org"
SQE uses public_base_url only for requests addressed to its host. A client
inside the cluster calling http://sqe.sqe:8080 keeps getting URIs on
http://sqe.sqe:8080. Without either setting, a proxied request gets an
http:// URI, and clients send their token in cleartext to port 80 before
the ingress redirects them.
Trusting a range trusts every peer in it. Any of them can set
X-Forwarded-For, which becomes the audited client IP, and the forwarded
scheme and host. Keep the range as narrow as the ingress allows. Invalid
entries and a malformed public_base_url stop the server at startup.
Run
# Submit a query. Basic auth carries the user; the password is the OIDC secret
# (empty for the local root client).
curl -s -u root: \
-H "X-Trino-User: root" \
-d "SELECT 1 AS one" \
http://localhost:28080/v1/statement
Trino clients follow the nextUri field until results are exhausted. A JDBC
client connects with the Trino driver against http://localhost:28080.
Expected output
The first response carries a nextUri; following it returns the data:
{
"columns": [{"name": "one", "type": "bigint"}],
"data": [[1]],
"stats": {"state": "FINISHED"}
}
How it is tested
crates/sqe-coordinator/tests/integration_test.rs::test_trino_http_query: server startup, Basic auth,/v1/statementPOST, pagination.test_trino_type_mapping,test_trino_batches_to_json: Arrow to Trino JSON.scripts/trino-parity-test.shandscripts/trino-compat-test.sh: run the same SQL against SQE and a real Trino and diff the results.
Distributed
The Trino HTTP endpoint lives on the coordinator. Distribution across workers is identical to the Flight path: the coordinator plans, workers execute. The client sees a single Trino-compatible endpoint regardless of worker count.
Prerequisites
docker compose -f docker-compose.test.yml -f docker-compose.distributed.yml up --build -d
./scripts/bootstrap-test.sh
Run
scripts/test.sh scenario distributed
The scenario exercises the Trino HTTP endpoint on 28080 alongside the
Flight path and confirms worker dispatch.
Expected output
The distributed scenario’s Trino check submits a query to the HTTP endpoint on the
coordinator (28080) and follows nextUri to completion, alongside the Flight
path on the same cluster. This is covered by the suite; the docker-dependent
re-run was not repeated this round (see the validation matrix note on local
Docker capacity).
Trino SQL parity
SQE adds a Trino-compatibility function layer (date/time helpers like year(),
month(), day_of_week(), JSON casts, and more) so dbt models and Trino SQL
run with fewer rewrites. The current parity surface is tracked in
Trino Compatibility. The parity scripts
above are the regression guard.
Notes
- Authentication needs Basic auth (
-u user:password) to populate the session, not just theX-Trino-Userheader. For the local root client the password is empty (-u root:). - The Trino HTTP endpoint is enabled by default on
[coordinator] trino_http_port = 8080; set the port to0to disable it. Flight SQL is the recommended protocol for SQE-native clients.