mirror of
https://github.com/lancedb/lancedb.git
synced 2026-09-04 20:48:50 +00:00
e639b1b650
## Summary
Add SQL execution to remote LanceDB connections. On the standard
synchronous connection, `execute_query` waits for the initial result
stream and returns its Arrow reader. `execute_query_async` is called
without Python `await` and immediately returns a query handle for status
inspection, streaming, or cancellation. Local databases report that SQL
is not supported.
The transport and query lifecycle live in Rust. Python exposes
native-backed synchronous and asynchronous connection methods and query
wrappers; it does not use PyArrow's Flight client.
## User experience
The standard synchronous connection supports both direct reads and
background query execution:
```python
db = lancedb.connect(
"db://analytics",
api_key="ldb_...",
sql_host_override="grpc+tls://sql.example.com:10026",
)
# Direct execution waits only until the initial result stream is available.
# Later batches continue streaming as the query progresses.
reader = db.execute_query(
"SELECT * FROM events",
default_namespace_path=["production"],
)
for batch in reader:
print(batch.num_rows)
# Background execution returns a query handle immediately. Despite the
# `_async` suffix, no Python `await` is needed on a synchronous connection.
query = db.execute_query_async("SELECT * FROM events")
print(query.id)
description = db.describe_query(query.id)
print(description.status)
print(description.progress)
print(description.expires_at)
# Start reading as soon as the service advertises partial results. The reader
# continues polling and yields newly available record batches until the query
# and all result endpoints are complete.
reader = query.reader()
for batch in reader:
print(batch.num_rows)
# Or cancel a different still-running query. Its status becomes "cancelling"
# while the server is still working, then "cancelled" once confirmed.
cancelled_query = db.execute_query_async("SELECT * FROM large_events")
cancelled_query.cancel()
```
The less commonly used asynchronous connection exposes the same
operations as coroutines:
```python
async_db = await lancedb.connect_async(
"db://analytics",
api_key="ldb_...",
sql_host_override="grpc+tls://sql.example.com:10026",
)
query = await async_db.execute_query_async("SELECT * FROM events")
async for batch in await query.reader():
print(batch.num_rows)
```
The UUIDv7 query id is scoped to the connection that submitted it. The
connection retains lightweight shared query state used by
`query.describe()` and `db.describe_query(query.id)`; the id does not
encode SQL or a Flight continuation token and is not a cross-connection
resume token. Abandoned state has bounded retention, and terminal state
remains available briefly.
Unqualified table names use the connected database and the `public`
namespace by default. `default_namespace_path` accepts a list such as
`["production", "events"]`. SQL can still use qualified names to
reference other databases and namespaces available to the deployment.
## Design
- Uses Arrow Flight `PollFlightInfo` for submission and long polling,
`DoGet` for results, and `CancelFlightInfo` for cancellation. Each
`PollInfo.info` is treated as the cumulative set of currently available
endpoints, so advertised tickets are consumed once and batches can be
delivered before execution is complete.
- Serializes result completion and cancellation into one lifecycle. A
server-accepted request reports `cancelling` and wakes blocked
status/result work; a later retry can confirm `cancelled`. Result
retrieval is rejected after cancellation is accepted, while cancellation
after a result was already delivered is a no-op.
- Assigns a time-ordered UUIDv7 connection-scoped query id and retains
only shared evolving lifecycle state, keeping SQL, Flight continuation
tokens, and Arrow result data out of public ids and the registry.
- Leaves admission control to the server while honoring server
expiration and a local fallback retention window for abandoned entries.
- Retains terminal ids for five minutes so they remain available for
connection-level description.
- Keeps one lazily initialized SQL client on each remote database
connection and attaches fresh authentication, routing, namespace, and
request metadata to every operation.
- Applies the configured overall timeout to each execution, description,
reader, and cancellation operation. A result reader carries one absolute
deadline from `reader()` through the end of streaming; connect and read
timeouts continue to bound their individual phases.
- Returns a bounded, backpressured, single-consumer Arrow stream rather
than collecting the full result in memory. Dropping the reader stops
downloading but does not implicitly cancel the server query.
- Preserves typed schemas for empty result sets through the stream
schema.
- Accepts Flight result messages up to 1 GiB so a valid row containing a
large blob, string, or vector is not rejected by tonic's 4 MiB default
receive limit.
- Supports the Python client first while keeping the authoritative
implementation in the Rust core.
348 lines
13 KiB
YAML
348 lines
13 KiB
YAML
name: Rust
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
pull_request:
|
|
paths:
|
|
- Cargo.toml
|
|
- Cargo.lock
|
|
- rust-toolchain.toml
|
|
- deny.toml
|
|
- rust/**
|
|
- nodejs/Cargo.toml
|
|
- python/Cargo.toml
|
|
- .github/workflows/rust.yml
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
# This env var is used by Swatinem/rust-cache@v2 for the cache
|
|
# key, so we set it to make sure it is always consistent.
|
|
CARGO_TERM_COLOR: always
|
|
RUST_BACKTRACE: "1"
|
|
|
|
jobs:
|
|
lint:
|
|
timeout-minutes: 30
|
|
runs-on: ubuntu-24.04
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
env:
|
|
# Need up-to-date compilers for kernels
|
|
CC: clang-18
|
|
CXX: clang++-18
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 0
|
|
lfs: true
|
|
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
|
with:
|
|
components: rustfmt, clippy
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
# Restore everywhere, but only save from main. Per-PR saves are
|
|
# unreadable outside their own branch anyway, since GitHub scopes
|
|
# caches to the creating ref.
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
- name: Install dependencies
|
|
run: |
|
|
sudo apt update
|
|
sudo apt install -y protobuf-compiler libssl-dev
|
|
- name: Run format
|
|
run: cargo fmt --all -- --check
|
|
- name: Run clippy
|
|
run: cargo clippy --profile ci --workspace --tests --all-features -- -D warnings
|
|
- name: Run clippy (without remote feature)
|
|
run: cargo clippy --profile ci --workspace --tests -- -D warnings
|
|
|
|
deny:
|
|
# Supply-chain checks: advisories, licenses, banned crates, and source
|
|
# restrictions. Configuration lives in `deny.toml` at the workspace root.
|
|
timeout-minutes: 10
|
|
runs-on: ubuntu-24.04
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
- uses: EmbarkStudios/cargo-deny-action@v2
|
|
with:
|
|
command: check advisories bans licenses sources
|
|
|
|
build-no-lock:
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 30
|
|
env:
|
|
# Need up-to-date compilers for kernels
|
|
CC: clang
|
|
CXX: clang++
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
# Building without a lock file often requires the latest Rust version since downstream
|
|
# dependencies may have updated their minimum Rust version.
|
|
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
|
with:
|
|
toolchain: "stable"
|
|
# Remove cargo.lock to force a fresh build
|
|
- name: Remove Cargo.lock
|
|
run: rm -f Cargo.lock
|
|
- uses: rui314/setup-mold@v1
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
# Restore everywhere, but only save from main. Per-PR saves are
|
|
# unreadable outside their own branch anyway, since GitHub scopes
|
|
# caches to the creating ref.
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
- name: Install dependencies
|
|
run: |
|
|
sudo apt update
|
|
sudo apt install -y protobuf-compiler libssl-dev
|
|
- name: Build all
|
|
run: |
|
|
cargo build --profile ci --benches --all-features --tests
|
|
|
|
linux:
|
|
timeout-minutes: 60
|
|
# To build all features, we need more disk space than is available
|
|
# on the free OSS github runner. This is mostly due to the the
|
|
# sentence-transformers feature.
|
|
runs-on: ubuntu-2404-4x-x64
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
working-directory: rust
|
|
env:
|
|
# Need up-to-date compilers for kernels
|
|
CC: clang-18
|
|
CXX: clang++-18
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 0
|
|
lfs: true
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
# Restore everywhere, but only save from main. Per-PR saves are
|
|
# unreadable outside their own branch anyway, since GitHub scopes
|
|
# caches to the creating ref.
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
- name: Install dependencies
|
|
run: |
|
|
sudo apt update
|
|
sudo apt install -y protobuf-compiler libssl-dev
|
|
- uses: rui314/setup-mold@v1
|
|
- name: Make Swap
|
|
run: |
|
|
swapfile=/swapfile
|
|
min_swap_bytes=$((15 * 1024 * 1024 * 1024))
|
|
active_swap_bytes="$(sudo swapon --show=NAME,SIZE --bytes --noheadings | awk '$1 == "/swapfile" { print $2 }')"
|
|
if [ -n "$active_swap_bytes" ]; then
|
|
if [ "$active_swap_bytes" -ge "$min_swap_bytes" ]; then
|
|
echo "/swapfile is already active with enough space; skipping swap creation"
|
|
exit 0
|
|
fi
|
|
echo "/swapfile is already active but smaller than 16G; using /mnt/lancedb-swapfile"
|
|
swapfile=/mnt/lancedb-swapfile
|
|
fi
|
|
if sudo swapon --show=NAME --noheadings | grep -Fxq "$swapfile"; then
|
|
echo "$swapfile is already active; skipping swap creation"
|
|
exit 0
|
|
fi
|
|
sudo rm -f "$swapfile"
|
|
sudo fallocate -l 16G "$swapfile"
|
|
sudo chmod 600 "$swapfile"
|
|
sudo mkswap "$swapfile"
|
|
sudo swapon "$swapfile"
|
|
- name: Build
|
|
run: cargo build --profile ci --all-features --tests --locked --examples
|
|
- name: Run feature tests
|
|
run: CARGO_ARGS="--profile ci" make -C ./lancedb feature-tests
|
|
- name: Run examples
|
|
run: cargo run --profile ci --all-features --example simple --locked
|
|
|
|
remote:
|
|
timeout-minutes: 30
|
|
# Running this requires access to secrets, so skip if this is a PR from a
|
|
# fork. Keep it separate from the all-features build so Cargo does not
|
|
# retain both dependency graphs in one target directory.
|
|
if: github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork
|
|
runs-on: ubuntu-2404-4x-x64
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
working-directory: rust
|
|
env:
|
|
CC: clang-18
|
|
CXX: clang++-18
|
|
GH_TOKEN: ${{ secrets.SOPHON_READ_TOKEN }}
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 0
|
|
lfs: true
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
# Remote tests use a different feature graph from the main Linux
|
|
# job. Cache downloads, but build into a fresh target directory.
|
|
cache-targets: false
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
- name: Install dependencies
|
|
run: |
|
|
sudo apt update
|
|
sudo apt install -y protobuf-compiler libssl-dev
|
|
- uses: rui314/setup-mold@v1
|
|
- name: Run remote tests
|
|
run: CARGO_ARGS="--profile ci" make -C ./lancedb remote-tests
|
|
|
|
macos:
|
|
timeout-minutes: 60
|
|
strategy:
|
|
matrix:
|
|
mac-runner: ["macos-14", "macos-15"]
|
|
runs-on: "${{ matrix.mac-runner }}"
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
working-directory: rust
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 0
|
|
lfs: true
|
|
- name: CPU features
|
|
run: sysctl -a | grep cpu
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
# Restore everywhere, but only save from main. Per-PR saves are
|
|
# unreadable outside their own branch anyway, since GitHub scopes
|
|
# caches to the creating ref.
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
- name: Install dependencies
|
|
run: brew install protobuf
|
|
- name: Run tests
|
|
run: |
|
|
# Don't run the s3 integration tests since docker isn't available
|
|
# on this image.
|
|
ALL_FEATURES=`cargo metadata --format-version=1 --no-deps \
|
|
| jq -r '.packages[] | .features | keys | .[]' \
|
|
| grep -v s3-test | sort | uniq | paste -s -d "," -`
|
|
# Run doctests before test binaries fill the runner disk. Examples are
|
|
# already built by the Linux job, so avoid retaining them here.
|
|
cargo test --profile ci --features $ALL_FEATURES --locked --doc
|
|
cargo test --profile ci --features $ALL_FEATURES --locked --lib --tests
|
|
|
|
windows:
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- target: x86_64-pc-windows-msvc
|
|
runner: windows-2022
|
|
# windows-11-arm is a standard runner, so it is free on public repos.
|
|
# Running natively lets the aarch64 tests actually execute -- this
|
|
# job used to cross-compile them and then skip the test step, paying
|
|
# full codegen and link cost for a compile check.
|
|
- target: aarch64-pc-windows-msvc
|
|
runner: windows-11-arm
|
|
runs-on: ${{ matrix.runner }}
|
|
defaults:
|
|
run:
|
|
working-directory: rust/lancedb
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
- name: Set target
|
|
run: rustup target add ${{ matrix.target }}
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
# Restore everywhere, but only save from main. Per-PR saves are
|
|
# unreadable outside their own branch anyway, since GitHub scopes
|
|
# caches to the creating ref.
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
- name: Install Protoc v21.12
|
|
run: choco install --no-progress protoc
|
|
- name: Build
|
|
run: |
|
|
$env:VCPKG_ROOT = $env:VCPKG_INSTALLATION_ROOT
|
|
cargo build --profile ci --features aws,remote --tests --locked --target ${{ matrix.target }}
|
|
- name: Run tests
|
|
run: |
|
|
$env:VCPKG_ROOT = $env:VCPKG_INSTALLATION_ROOT
|
|
# `--target` has to match the build step above. Without it cargo uses
|
|
# target/ci/ rather than target/<triple>/ci/ and rebuilds the entire
|
|
# dependency graph a second time.
|
|
cargo test --profile ci --features aws,remote --locked --target ${{ matrix.target }}
|
|
|
|
msrv:
|
|
# Check the minimum supported Rust version
|
|
name: MSRV Check - Rust v${{ matrix.msrv }}
|
|
runs-on: ubuntu-24.04
|
|
strategy:
|
|
matrix:
|
|
msrv: ["1.91.0"] # This should match up with rust-version in Cargo.toml
|
|
env:
|
|
# Need up-to-date compilers for kernels
|
|
CC: clang-18
|
|
CXX: clang++-18
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
with:
|
|
submodules: true
|
|
- name: Install dependencies
|
|
run: |
|
|
sudo apt update
|
|
sudo apt install -y protobuf-compiler libssl-dev
|
|
- name: Install ${{ matrix.msrv }}
|
|
uses: dtolnay/rust-toolchain@master
|
|
with:
|
|
toolchain: ${{ matrix.msrv }}
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
# Restore everywhere, but only save from main. Per-PR saves are
|
|
# unreadable outside their own branch anyway, since GitHub scopes
|
|
# caches to the creating ref.
|
|
save-if: ${{ github.ref == 'refs/heads/main' }}
|
|
- name: Downgrade dependencies
|
|
# These packages have newer requirements for MSRV
|
|
run: |
|
|
cargo update -p aws-sdk-bedrockruntime --precise 1.77.0
|
|
cargo update -p aws-sdk-dynamodb --precise 1.68.0
|
|
cargo update -p aws-config --precise 1.6.0
|
|
cargo update -p aws-sdk-kms --precise 1.63.0
|
|
cargo update -p aws-sdk-s3 --precise 1.79.0
|
|
cargo update -p aws-sdk-sso --precise 1.62.0
|
|
cargo update -p aws-sdk-ssooidc --precise 1.63.0
|
|
cargo update -p aws-sdk-sts --precise 1.63.0
|
|
# aws-runtime/sigv4/credential-types/types and the aws-smithy-*
|
|
# crates bumped their MSRV to 1.91.1 in late 2026; pin to the last
|
|
# 1.91.0-compatible versions. The order matters — each downgrade
|
|
# only succeeds once everything that still pins it at a higher
|
|
# version has itself been downgraded.
|
|
cargo update -p aws-runtime --precise 1.5.12
|
|
cargo update -p aws-types --precise 1.3.9
|
|
cargo update -p aws-sigv4 --precise 1.3.5
|
|
cargo update -p aws-credential-types --precise 1.2.8
|
|
# aws-smithy-checksums must stay at or above 0.63.13: OpenDAL's S3
|
|
# service needs crc-fast ~1.9, and older releases pin it to ~1.3.
|
|
cargo update -p aws-smithy-checksums --precise 0.63.13
|
|
cargo update -p aws-smithy-runtime --precise 1.9.3
|
|
cargo update -p aws-smithy-http --precise 0.62.6
|
|
cargo update -p aws-smithy-eventstream --precise 0.60.14
|
|
cargo update -p aws-smithy-http-client --precise 1.1.3
|
|
cargo update -p aws-smithy-observability --precise 0.1.4
|
|
cargo update -p aws-smithy-query --precise 0.60.8
|
|
cargo update -p aws-smithy-runtime-api --precise 1.9.3
|
|
cargo update -p aws-smithy-async --precise 1.2.7
|
|
cargo update -p aws-smithy-types --precise 1.3.6
|
|
cargo update -p aws-smithy-xml --precise 0.60.11
|
|
cargo update -p home --precise 0.5.9
|
|
- name: cargo +${{ matrix.msrv }} check
|
|
env:
|
|
RUSTUP_TOOLCHAIN: ${{ matrix.msrv }}
|
|
run: cargo check --profile ci --workspace --tests --benches --all-features
|