Skip to main content
Parable implements the read-only subset of Arrow Flight SQL needed to discover Workspace data and execute queries. Clients should inspect GetSqlInfo capability metadata instead of assuming that the server implements every Flight SQL operation.

Query and metadata commands

GetFlightInfo validates and plans a SQL statement, then returns an opaque ticket. DoGet executes that ticket and streams Arrow record batches.

Prepared statements

A prepared statement is read-only and has this lifecycle:
  • The CreatePreparedStatement action returns a handle.
  • DoPut on CommandPreparedStatementQuery binds parameter values. Its DoPutPreparedStatementResult returns a new handle that carries them. Send that handle on every later call.
  • The ClosePreparedStatement action ends the statement.
The handle carries the statement, so each call can go to any Parable server. It works only for the Workspace and the person that prepared it. Flight SQL clients from Arrow 15 onward, such as ADBC and the Arrow Flight SQL JDBC driver, use the handle that DoPut returns. An older client that keeps the first handle runs the statement without its values, and the statement fails. Use prepared statements when query values come from users or another untrusted source. Transactions, savepoints, and prepared writes are not supported.

Sample a table

TABLESAMPLE reads a sample of a table or a subquery, in the form Postgres, Snowflake and Databricks share:
  • A row is kept when a hash of all its values and the seed, read as a fraction from 0 to 1, is below the percentage. The same seed keeps the same rows of the same data, whatever the query reads around it, so two samples of one table in one query keep the same rows.
  • BERNOULLI, ROW, SYSTEM and BLOCK all sample rows. A size without a unit is a percentage.
  • (n ROWS) keeps the n rows with the lowest hash. BUCKET k OUT OF n keeps the rows in the k-th of n equal ranges, so the n buckets hold every row once.
  • Without REPEATABLE or SEED, the seed is 0, so a query that samples returns the same rows each time. Postgres picks a new seed each time instead.
  • OFFSET and BUCKET ... ON are refused.
A join between two sampled tables keeps about the product of their percentages of its matches: 10 percent of each keeps about 1 percent.

LATERAL subqueries

A LATERAL subquery reads columns of the tables before it in FROM. The engine plans it as a join, so it works when the join is clear:
  • Write it as JOIN LATERAL (...) x ON ..., LEFT JOIN LATERAL (...) x ON ..., or after a comma, as in FROM teams t, LATERAL (...) x.
  • Use the outer columns only in comparisons in the subquery’s own WHERE clause. The comparison can be =, >, or another operator, and it can use AND and OR.
  • The subquery can use DISTINCT, GROUP BY, HAVING with GROUP BY, ORDER BY, and aggregates such as count(*). A team with no people gets the count 0, as in Postgres.
The query fails with INVALID_ARGUMENT and error code QL-PL-012 when:
  • The subquery reads an outer column in its SELECT list, in GROUP BY, in a UNION branch, or in a subquery nested inside it.
  • The subquery has a LIMIT.
  • LATERAL is in a RIGHT or FULL join.
  • The subquery’s own SELECT has an aggregate and a HAVING clause but no GROUP BY, and the join is not LEFT. A table that the subquery joins, or a scalar subquery in its WHERE clause, can still use HAVING with no GROUP BY.
Move the comparison into the subquery’s WHERE clause, or join the tables directly. For a HAVING clause, move its condition into the join’s ON clause, as in JOIN LATERAL (SELECT count(*) AS n ...) x ON x.n > 1, or add GROUP BY.

Show the plan of a query

EXPLAIN followed by a SELECT returns the plan Parable would use for the query, and runs nothing:
  • The answer has two columns, plan_type and plan, and two rows: one logical_plan row and one physical_plan row.
  • The physical plan names each step, its partitions and its keys. It shows no storage path and no filter condition, because a filter can hold a Policy’s condition.
  • The plan holds no cost information.
  • EXPLAIN ANALYZE runs the query, so it fails with INVALID_ARGUMENT and error code QL-SQ-008.
  • EXPLAIN VERBOSE, a FORMAT option, EXPLAIN QUERY PLAN and DESCRIBE of a query fail with INVALID_ARGUMENT and error code QL-SQ-009.

Unsupported operations

The SQL surface does not support:
  • Writes, ingestion, or transactions.
  • DoExchange, or DoPut for anything but binding prepared statement parameters.
  • ListFlights or PollFlightInfo.
  • Transaction, savepoint, or cancellation actions.
Unsupported commands return gRPC UNIMPLEMENTED. ListActions returns an empty stream because the server does not advertise actions proactively. Handshake is accepted and does nothing, so JDBC drivers that call it on connect work; authentication comes from the authorization metadata on every call. Primary and foreign-key commands return logical metadata. They do not make the underlying tables enforce constraints.