Connection contract
x-tenant-slug is accepted as an alias for x-tenant.
Send the authorization metadata on every call. The Flight Handshake RPC is
accepted and does nothing, so a client cannot authenticate through it.
Pools each role reaches
A query that names a pool the caller’s role does not reach fails with
INVALID_ARGUMENT, the message Query references an unknown relation, and
error code QL-PL-002. Catalog discovery leaves that pool out.
Inside the pools a role reaches, the Workspace’s
Provider Policies decide which rows of each
Provider table it reads. Table metadata leaves out the row count and
validation rates of a table they narrow for the caller.
Tokens
A SQL tool authenticates with apat_ token
(API tokens). A SQL token a
member creates in Protection → Access Tokens reaches that Workspace only
and queries with its owner’s Workspace roles at the time of each query; a
staff role never counts. Flight SQL refuses a call with:
Connect with ADBC
PARABLE_FLIGHT_URL to grpc+tls://sql.parable.work:443. The public
endpoints use TLS. A local development stack can serve cleartext HTTP/2 at a
grpc:// URL.
Request lifecycle
For a statement query:GetFlightInfovalidates and plans the SQL, then returns an opaque ticket.DoGetexecutes from that ticket and streams Arrow record batches.- The client releases the result stream when it has consumed or abandoned it.
Limits
A query may run for up to one hour. The clock starts when Parable admits the query and covers planning and the whole result stream, including the time your client spends reading it. A query that runs longer fails withDEADLINE_EXCEEDED, Parable error code QL-TO-002 (QUERY_TIMEOUT), and the
message query <id> exceeded timeout of 3600s.
The server sets this limit. A longer deadline on your client does not extend
it, and a shorter one ends the call early, so set your driver’s timeout to at
least an hour before running a long query.
Row limit
A query may return up to 2,000,000 rows.DoGet sends them batch by batch as
Query Layer produces them, and the Workspace API forwards each batch without
collecting the result.
A query whose result has more rows fails. Nothing is truncated: the stream
ends with RESOURCE_EXHAUSTED, Parable error code QL-SQ-005
(RESULT_ROW_CAP_EXCEEDED), and this message:
LIMIT, filter with WHERE, or
aggregate in SQL. To read more rows than the limit, run one query per range of
a column, such as one month at a time.
Each IP address may send 600 calls a minute. A query takes at least two calls,
GetFlightInfo and DoGet. Calls over the limit are refused with HTTP status
429 at Parable’s edge, which gRPC clients report as UNAVAILABLE.
Metadata discovery
Flight SQL supports catalog, schema, table, table-type, SQL capability, and logical key discovery.GetTables can include an Arrow IPC schema for every
matching table, including optional Parable semantic metadata.
Discover tables and columns
shows how to use those operations.
Semantic types in comparisons
A column can carry a semantic scalar, such asContact.Email or
Contact.PhoneNumber, in its parable.scalar.canonical_name field metadata.
Parable uses it when a query plans:
- Two columns with different scalars can be compared only when scalar-lib
declares them comparable, such as
Temporal.DateandTemporal.DateTime.contacts.email = people.phonefails withINVALID_ARGUMENTand error codeQL-PL-007(INCOMPARABLE_SCALARS). The message names both columns and both scalars. The check covers comparison operators,BETWEEN,IN, subquery comparisons, join keys, andUNION,INTERSECTandEXCEPTcolumns. - To compare across scalars on purpose, cast one side where it is compared:
CAST(contacts.email AS VARCHAR) = people.phone. A column without a scalar compares with any column. - A value you supply is never refused and needs no cast. A string literal or
bound parameter compared with an
Identity.UUIDorContact.Emailcolumn is converted to that scalar’s canonical form, soemail = 'Jane@Example.com'matches the storedjane@example.com. A value that is not valid for the scalar is compared as written:email = ''returns no rows, andemail <> ''returns every row with an email.
Embedding vectors in comparisons
embed() stamps its model identity (provider, name, variant, version,
dimensions, normalization) in its output field’s parable.model_* metadata.
Vectors are comparable only within one identity, so array_distance over two
vectors stamped with different identities fails with
INVALID_ARGUMENT and error code QL-PL-008
(INCOMPARABLE_EMBEDDING_MODELS), even when their dimensions match. The
message names the function and both models. A Plot’s embed() column carries
the identity of the model that wrote it. A vector without an identity, such as
a literal vector, is compared on its dimensions alone; see
Embed.
Recursive queries
WITH RECURSIVE walks a hierarchy, such as everyone below each manager at any
depth. Join its two terms with UNION: it stops when an iteration adds no new
row, so a loop in the data, such as a person listed as their own manager,
ends. UNION ALL fails with INVALID_ARGUMENT and error code QL-PL-014
(RECURSIVE_UNION_ALL), because nothing else would stop it.
Errors and retries
Unsupported commands return gRPCUNIMPLEMENTED. Invalid authentication and
Workspace selection return gRPC authentication, permission, or argument
statuses rather than HTTP JSON errors.
A Parable error code, such as QL-PL-002, arrives in the
parable-error-code response metadata beside the gRPC status. Facts a
refusal names for you, when it names any, arrive as a JSON object of strings in
the binary parable-error-details-bin metadata.
When query concurrency is saturated, Parable returns RESOURCE_EXHAUSTED with
error code QL-IN-008. A client can retry a
read-only query with bounded exponential backoff. Do not retry invalid SQL,
authentication failures, or permission failures without changing the request.
QL-PL-007 (INCOMPARABLE_SCALARS) is deterministic: change the comparison or
add a CAST rather than retrying. QL-PL-008 (INCOMPARABLE_EMBEDDING_MODELS)
is too: embed both sides with the same model. So is QL-PL-015
(FILTER_POLICY_COLUMN_MISSING, FAILED_PRECONDITION): a Plot that reads
Provider data lacks a column a Parable filter Policy that binds you reads,
usually identity_account_id; the Plot’s author adds the column.
SQL the query engine cannot run is the query’s to fix. It returns
INVALID_ARGUMENT with one of these codes, and the message never repeats the
SQL or its values. Change the query rather than retrying:
Casts and some unsupported expressions are checked when the result is read,
so
QL-PL-009 and QL-PL-012 can arrive from DoGet after GetFlightInfo
succeeded. Other engine failures keep INTERNAL with QL-IN-001
(DATAFUSION_ERROR) and the message Query execution failed. That includes
an error raised by a row while the query runs, such as a string value that
does not cast to a number, because its description carries the value. A Jev
argument read from a column, rather than written in the query, is checked on
each row, so a row it refuses fails this way under the default
on_error = fail. A row a Plot returns that its declared contract does not
allow, read through parables.*, fails with FAILED_PRECONDITION and error
code PA-AU-047, naming the Plot and never the value.
When a workspace table is briefly unavailable, Parable returns UNAVAILABLE
with error code QL-IN-005 (UPSTREAM_UNAVAILABLE), and the message names the
table. Retry the query with the same backoff.
Three error codes arrive with RESOURCE_EXHAUSTED, and each one needs a
different response. Read the error code before you retry:
RESOURCE_EXHAUSTED can also arrive with no error code, for example when a
workspace table returns more rows than one query may read: do not retry
it, because the message says why the query was refused.
Like QL-SQ-005, QL-IN-009 can arrive after some record batches. Discard
the rows your driver returned before the error: they are not the result.
QL-TO-002 (QUERY_TIMEOUT) is a query past the time limit. Filter,
aggregate, or split it before running it again.