diff --git a/.asf.yaml b/.asf.yaml
index 34d036e19b409..1307c8759bc32 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -68,6 +68,8 @@ github:
- "cargo check datafusion-functions features"
- "cargo check datafusion-spark features"
- "cargo test (amd64)"
+ - "cargo test 'extended_tests' (amd64)"
+ - "cargo test hash collisions (amd64)"
- "cargo test datafusion-cli (amd64)"
- "cargo examples (amd64)"
- "cargo test doc (amd64)"
@@ -76,6 +78,7 @@ github:
- "verify benchmark results (amd64)"
- "Run sqllogictest with Postgres runner"
- "Run sqllogictest in Substrait round-trip mode"
+ - "Run sqllogictests with the sqlite test suite"
- "cargo test (macos-aarch64)"
- "Verify Vendored Code"
- "Check cargo fmt"
@@ -84,6 +87,7 @@ github:
- "check Cargo.toml formatting"
- "check configs.md and ***_functions.md is up-to-date"
- "check example README is up-to-date"
+ - "Check datafusion crates used in datafusion-examples"
- "Verify MSRV (Min Supported Rust Version)"
# needs to be updated as part of the release process
# .asf.yaml doesn't support wildcard branch protection rules, only exact branch names
diff --git a/_downloads/1e336e540124589d1e27210fa4f805f6/rust_lint.sh b/_downloads/1e336e540124589d1e27210fa4f805f6/rust_lint.sh
index 73cab9c7f70bd..dbb64543028de 100644
--- a/_downloads/1e336e540124589d1e27210fa4f805f6/rust_lint.sh
+++ b/_downloads/1e336e540124589d1e27210fa4f805f6/rust_lint.sh
@@ -22,7 +22,9 @@
#
# Note: The installed checking tools (e.g., taplo) are not guaranteed to match
# the CI versions for simplicity, there might be some minor differences. Check
-# `.github/workflows` for the CI versions.
+# `.github/workflows` for the CI versions. When this script installs a missing
+# tool that has a pinned version in `ci/scripts/utils/tool_versions.sh`, it
+# installs that pinned version. An already installed tool is used as is.
#
#
#
@@ -84,10 +86,34 @@ while [[ $# -gt 0 ]]; do
done
SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# `ci/scripts/check_asf_yaml_status_checks.py` runs with `python3` from PATH
+# and imports PyYAML. Report a missing prerequisite before any tool is
+# installed or any formatter runs, and point at `uv run`, which sets up the
+# Python dependencies from the uv workspace.
+ensure_python_with_yaml() {
+ if ! command -v python3 &> /dev/null; then
+ echo "[${SCRIPT_NAME}] python3 was not found on PATH. Please run the suite through uv, which provides Python and its packages: uv run ./dev/rust_lint.sh" >&2
+ exit 1
+ fi
+ if ! python3 -c 'import yaml' &> /dev/null; then
+ echo "[${SCRIPT_NAME}] PyYAML is not installed for $(command -v python3). Please run the suite through uv, which installs it: uv run ./dev/rust_lint.sh" >&2
+ exit 1
+ fi
+}
+
+ensure_python_with_yaml
+
+# Load the tool versions shared with CI (for example, LYCHEE_VERSION).
+source "${SCRIPT_DIR}/../ci/scripts/utils/tool_versions.sh"
ensure_tool "taplo" "cargo install taplo-cli --locked"
ensure_tool "hawkeye" "cargo install hawkeye --locked"
ensure_tool "typos" "cargo install typos-cli --locked"
+ensure_tool "lychee" "cargo install lychee --locked --version ${LYCHEE_VERSION}"
+ensure_tool "cargo-audit" "cargo install cargo-audit --locked"
+ensure_tool "cargo-machete" "cargo install cargo-machete --locked --version ^${CARGO_MACHETE_VERSION}"
run_step() {
local name="$1"
@@ -103,11 +129,20 @@ declare -a WRITE_STEPS=(
"ci/scripts/license_header.sh|true"
"ci/scripts/typos_check.sh|true"
"ci/scripts/doc_prettier_check.sh|true"
+ "ci/scripts/check_examples_docs.sh|true"
+ "ci/scripts/check_generated_docs.sh|true"
)
declare -a READONLY_STEPS=(
"ci/scripts/check_no_cargo_install_in_workflows.sh|false"
+ "ci/scripts/check_asf_yaml_status_checks.py|false"
+ "ci/scripts/check_large_files.sh|false"
+ "ci/scripts/markdown_link_check.sh|false"
+ "ci/scripts/security_audit.sh|false"
+ "ci/scripts/check_circular_dependencies.sh|false"
+ "ci/scripts/check_unused_dependencies.sh|false"
"ci/scripts/rust_docs.sh|false"
+ "ci/scripts/check_docs_html.sh|false"
)
for entry in "${WRITE_STEPS[@]}" "${READONLY_STEPS[@]}"; do
diff --git a/_sources/contributor-guide/api-health.md.txt b/_sources/contributor-guide/api-health.md.txt
index a20bc284cf362..8737df280f4f8 100644
--- a/_sources/contributor-guide/api-health.md.txt
+++ b/_sources/contributor-guide/api-health.md.txt
@@ -43,6 +43,35 @@ Examples of non-breaking changes include:
- Marking a function as deprecated (`#[deprecated]`)
- Adding a new function to a `trait` with a default implementation
+### DataFusion-internal Public APIs
+
+Some internal implementation details require `pub` visibility because they are
+shared across DataFusion crates. These APIs are not intended as downstream
+extension points. They are hidden from generated documentation and are not part
+of DataFusion's supported public API, so they may be changed or removed without
+notice or a deprecation period. Examples include:
+
+1. Test helpers.
+2. Operator APIs required by the optimizer to inspect or rewrite execution plans
+ across crate boundaries.
+
+For APIs intended only for internal use, add `#[doc(hidden)]` and a doc comment
+section headed `# Public Only for Internal Use:`. Name the crate or component
+that requires access and explain why the API is not intended for downstream use.
+For example:
+
+```txt
+impl HashTableLookupExpr {
+ /// ...
+ ///
+ /// # Public Only for Internal Use:
+ /// `datafusion-proto` tests require this constructor, but it is not part of
+ /// the supported public API.
+ #[doc(hidden)]
+ pub fn new(...) {...}
+}
+```
+
### What is the public SQL API and what is a breaking SQL change?
DataFusion is also used as a SQL engine, so changes to SQL semantics (the
diff --git a/_sources/contributor-guide/development_environment.md.txt b/_sources/contributor-guide/development_environment.md.txt
index 2e4e00726580b..20cfd6edd0cec 100644
--- a/_sources/contributor-guide/development_environment.md.txt
+++ b/_sources/contributor-guide/development_environment.md.txt
@@ -108,7 +108,7 @@ DataFusion is written in Rust and it uses a standard rust toolkit:
- `rustup update stable` DataFusion generally uses the latest stable release of Rust, though it may lag when new Rust toolchains release
- See which toolchain is currently pinned in the [`rust-toolchain.toml`](https://github.com/apache/datafusion/blob/main/rust-toolchain.toml) file
- - This can cause issues such as not having the rust-analyzer component installed for the specified toolchain, in which case just install it manually, e.g. `rustup component add --toolchain 1.97.0 rust-analyzer`
+ - This can cause issues such as not having the rust-analyzer component installed for the specified toolchain, in which case just install it manually, e.g. `rustup component add --toolchain 1.98.1 rust-analyzer`
- `cargo build`
- `cargo fmt` to format the code
- etc.
@@ -130,3 +130,17 @@ Formatting instructions:
or run them all at once:
- [dev/rust_lint.sh](../../../dev/rust_lint.sh)
+
+Debugging:
+
+The standard dev profile, used by cargo build and cargo test, disables variable-level DWARF debug information that is required by interactive debuggers.
+
+If you need to step through the code with a debugger, build with:
+
+`CARGO_PROFILE_DEV_DEBUG=2 cargo build`
+
+Alternatively, you can set `CARGO_PROFILE_DEV_DEBUG=2` as an environment variable in your IDE.
+
+This enables the additional debug information required for source-level debugging.
+
+For more details, see the DataFusion [Cargo.toml](https://github.com/apache/datafusion/blob/main/Cargo.toml#L329) configuration.
diff --git a/_sources/contributor-guide/gsoc/gsoc_project_ideas_2025.md.txt b/_sources/contributor-guide/gsoc/gsoc_project_ideas_2025.md.txt
index d81d9eb9adab5..5366080ffe051 100644
--- a/_sources/contributor-guide/gsoc/gsoc_project_ideas_2025.md.txt
+++ b/_sources/contributor-guide/gsoc/gsoc_project_ideas_2025.md.txt
@@ -2,7 +2,7 @@
## Introduction
-Welcome to the Apache DataFusion Google Summer of Code (GSoC) 2025 project ideas list. Below you can find information about the projects. Please refer to [this page](https://datafusion.apache.org/contributor-guide/gsoc_application_guidelines.html) for application guidelines.
+Welcome to the Apache DataFusion Google Summer of Code (GSoC) 2025 project ideas list. Below you can find information about the projects. Please refer to [this page](https://datafusion.apache.org/contributor-guide/gsoc/gsoc_application_guidelines_2025.html) for application guidelines.
## Projects
diff --git a/_sources/contributor-guide/index.md.txt b/_sources/contributor-guide/index.md.txt
index 6f1a0f1c19907..d6a16680ddb79 100644
--- a/_sources/contributor-guide/index.md.txt
+++ b/_sources/contributor-guide/index.md.txt
@@ -122,7 +122,12 @@ before merge.
# ./dev/rust_lint.sh --write --allow-dirty
```
-You should also run any relevant commands from the [testing quick start](testing.md#testing-quick-start).
+Please ensure your PR follows the [testing guide](testing.md). In particular:
+
+- Prefer end-to-end Public API tests such as `sqllogictest` (`.slt`) and DataFrame API,
+ over Rust unit tests where possible. See
+ [Choosing What Kind of Test to Write](testing.md#choosing-what-kind-of-test-to-write).
+- Run any relevant commands from the [testing quick start](testing.md#testing-quick-start).
## Conventional Commits & Labeling PRs
diff --git a/_sources/contributor-guide/pr_review.md.txt b/_sources/contributor-guide/pr_review.md.txt
index 1154ae0e96b04..6166a741aa0a6 100644
--- a/_sources/contributor-guide/pr_review.md.txt
+++ b/_sources/contributor-guide/pr_review.md.txt
@@ -133,7 +133,8 @@ Guidelines for evaluating tests:
1. Prefer `sqllogictest` (`.slt`) tests or DataFrame API tests where
possible, as they exercise **user-visible behavior** and are less coupled
- to internal implementation details than unit tests.
+ to internal implementation details than unit tests (see
+ [Choosing What Kind of Test to Write](testing.md#choosing-what-kind-of-test-to-write)).
2. Verify tests cover edge cases and common failure scenarios, not just the
common successful path. However, it is NOT necessary to test every possible
error path, especially if it is difficult to trigger or unlikely to occur in
diff --git a/_sources/contributor-guide/testing.md.txt b/_sources/contributor-guide/testing.md.txt
index 3b644f610b90e..3e39ef2eb1af7 100644
--- a/_sources/contributor-guide/testing.md.txt
+++ b/_sources/contributor-guide/testing.md.txt
@@ -74,6 +74,30 @@ cargo nextest run
[the book]: https://doc.rust-lang.org/book/
[cargo-nextest]: https://nexte.st/
+## Choosing What Kind of Test to Write
+
+When adding tests, prefer tests that exercise **user-visible behavior** over
+tests of internal implementation details. Doing so means your tests are more
+likely to keep working (and keep catching regressions) while the code is
+refactored. In rough order of preference:
+
+1. Use [sqllogictest](#sqllogictests-tests) (`.slt`) tests for any behavior that can
+ be expressed in SQL.
+
+2. End-to-end tests that use public APIs such as the DataFrame API, for behavior
+ that cannot be expressed in SQL. For example, DataFrame tests live in
+ [`datafusion/core/tests/dataframe`] and run as part of the `core_integration`
+ test binary:
+
+ ```shell
+ cargo test -p datafusion --test core_integration -- dataframe
+ ```
+
+3. Rust unit tests for logic that cannot practically be reached through
+ SQL or DataFrame public APIs.
+
+[`datafusion/core/tests/dataframe`]: https://github.com/apache/datafusion/tree/main/datafusion/core/tests/dataframe
+
## Unit tests
Tests for code in an individual module are defined in the same source file with a `test` module, following Rust convention.
@@ -111,7 +135,7 @@ cargo test --profile=ci --test sqllogictests -- --complete
Like similar systems such as [DuckDB](https://duckdb.org/dev/testing), DataFusion has chosen to trade off a slightly higher barrier to contribution for longer term maintainability.
-DataFusion has integrated [sqlite's test suite](https://sqlite.org/sqllogictest/doc/trunk/about.wiki) as a supplemental test suite that is run whenever a PR is merged into DataFusion. To run it manually please refer to the [README](https://github.com/apache/datafusion/blob/main/datafusion/sqllogictest/README.md#running-tests-sqlite) file for instructions.
+DataFusion runs [sqlite's test suite](https://sqlite.org/sqllogictest/doc/trunk/about.wiki) in the merge queue before merging PRs into `main`. For local instructions, see [Running Tests: sqlite](https://github.com/apache/datafusion/blob/main/datafusion/sqllogictest/README.md#running-tests-sqlite).
## Snapshot testing (`cargo insta`)
@@ -127,15 +151,15 @@ cargo insta review
## Extended Tests
-In addition to the standard CI test suite that is run on all PRs prior to merge,
-DataFusion has "extended" tests (defined in [extended.yml]) that are run on each
-commit to `main`. These tests rarely fail but take significantly longer to run
-than the standard test suite and add important test coverage such as ensuring
-correctness when there are hash collisions and running the relevant portions of
-the entire [sqlite test suite]. You can run the extended tests
-locally by following the [instructions in the documentation].
+DataFusion has extended tests (defined in [extended.yml]) that take significantly
+longer to run than the standard suite. They provide additional correctness
+coverage and must pass in the merge queue before a PR merges into `main`.
+
+To conserve CI resources, these tests do not run on ordinary PR updates. They
+also run on pushes to release branches (`branch-*`). You can run them manually.
+
+For local SQLite test instructions, see the [instructions in the documentation].
-[sqlite test suite]: https://www.sqlite.org/sqllogictest/dir?ci=tip
[instructions in the documentation]: https://github.com/apache/datafusion/tree/main/datafusion/sqllogictest#running-tests-sqlite
[extended.yml]: https://github.com/apache/datafusion/blob/main/.github/workflows/extended.yml
@@ -164,7 +188,7 @@ contributions. Kudos to [@2010YOUY01] for the initial implementation.
## Documentation Examples
We use Rust [doctest] to verify examples from the documentation are correct and
-up-to-date. These tests are run as part of our CI and you can run them them
+up-to-date. These tests are run as part of our CI and you can run them
locally with the following command:
```shell
@@ -176,6 +200,20 @@ cargo test --doc
As with other Rust projects, examples in doc comments in `.rs` files are
automatically checked to ensure they work and evolve along with the code.
+Prefix a line with `# ` (a `#` followed by a space) to keep it compiled and
+run, but hidden from the rendered documentation. This is most useful for
+`use` statements, since readers care about the API being demonstrated, not
+its import boilerplate:
+
+````rust
+/// ```
+/// # use std::sync::Arc;
+/// let value = Arc::new(42);
+/// ```
+````
+
+Only the `let value = ...` line renders.
+
### User Guide Documentation
Rust example code from the user guide (anything marked with \`\`\`rust) is also
@@ -188,7 +226,12 @@ tested in the same way using the [doc_comment] crate. See the end of
## Documentation Link Checks
-Run the internal markdown link check locally:
+`./dev/rust_lint.sh` runs the internal markdown link check. If `lychee` is
+missing, the script installs the version pinned in
+`ci/scripts/utils/tool_versions.sh`. It uses an existing installation as is,
+even if the version differs from the pin.
+
+To run the check on its own:
```shell
source ci/scripts/utils/tool_versions.sh
@@ -200,6 +243,7 @@ Notes:
- The script is run with `bash` and is compatible with the default Bash on macOS (no `mapfile` dependency).
- The CI configuration currently checks internal markdown links only. External `http(s)` and `mailto` links are excluded to avoid flaky failures.
+- The check only reports broken links. `./dev/rust_lint.sh --write` does not change them.
When a link is broken, lychee prints the file and URL/path that failed. For example:
@@ -214,6 +258,119 @@ Rust doc comments are validated by rustdoc in CI and can be checked locally with
bash ci/scripts/rust_docs.sh
```
+## ASF Status Check Validation
+
+`ci/scripts/check_asf_yaml_status_checks.py` checks that every required status
+check in `.asf.yaml` matches a job in `.github/workflows`, and that `rust.yml`
+skips only its listed jobs on pushes to `main`. `./dev/rust_lint.sh` runs it
+and needs `python3` with [PyYAML]. The [uv] workspace provides both:
+
+```shell
+uv run ./dev/rust_lint.sh
+```
+
+To run the check on its own:
+
+```shell
+uv run python3 ci/scripts/check_asf_yaml_status_checks.py
+```
+
+[pyyaml]: https://pypi.org/project/PyYAML/
+[uv]: https://docs.astral.sh/uv/
+
+## Security Audit
+
+`ci/scripts/security_audit.sh` runs `cargo audit` on the root `Cargo.lock` with
+the advisory exceptions that CI uses. `./dev/rust_lint.sh` runs it and installs
+[cargo-audit] if it is missing. To run the audit on its own:
+
+```shell
+./ci/scripts/security_audit.sh
+```
+
+The audit fetches the RustSec advisory database. A new advisory or a different
+`cargo-audit` version can change the result without any change to the repository.
+
+[cargo-audit]: https://github.com/rustsec/rustsec/blob/main/cargo-audit/README.md
+
+## Large File Check
+
+`ci/scripts/check_large_files.sh` fails if any file committed between a base
+ref and a head ref is larger than 1.5 MB, the same check the "Large files PR
+check" workflow runs on pull requests. `./dev/rust_lint.sh` runs it against
+the merge base of `HEAD` and `main` on the remote that points at
+`apache/datafusion`, or on `origin` when there is no such remote. To run the
+check on its own, or against a different range:
+
+```shell
+./ci/scripts/check_large_files.sh
+./ci/scripts/check_large_files.sh --base upstream/main --head my-branch
+```
+
+Only committed files are checked. Commit a change before running it.
+
+## Dependency Checks
+
+CI runs two dependency checks, and `./dev/rust_lint.sh` runs both:
+
+- `ci/scripts/check_circular_dependencies.sh` builds and runs [`dev/depcheck`],
+ which fails on dependency cycles between DataFusion crates.
+- `ci/scripts/check_unused_dependencies.sh` runs `cargo machete --with-metadata`
+ from the repository root. The lint suite installs [cargo-machete] with the
+ version in `ci/scripts/utils/tool_versions.sh` if it is missing.
+
+To run either check on its own:
+
+```shell
+./ci/scripts/check_circular_dependencies.sh
+./ci/scripts/check_unused_dependencies.sh
+```
+
+[`dev/depcheck`]: https://github.com/apache/datafusion/tree/main/dev/depcheck
+[cargo-machete]: https://github.com/bnjbvr/cargo-machete
+
+## Examples README Check
+
+`datafusion-examples/README.md` is generated from the documentation comments in
+`datafusion-examples/examples//main.rs`. `ci/scripts/check_examples_docs.sh`
+regenerates it and fails if the committed file differs. `./dev/rust_lint.sh`
+runs it and needs `cargo` and `npx`. To run the check on its own, or to update
+the README:
+
+```shell
+./ci/scripts/check_examples_docs.sh
+./ci/scripts/check_examples_docs.sh --write
+```
+
+## Config and Function Docs Check
+
+[`configs.md`], [`aggregate_functions.md`], [`scalar_functions.md`], and
+[`window_functions.md`] are generated by [`dev/update_config_docs.sh`] and
+[`dev/update_function_docs.sh`]. To check that they are up to date, run the
+[`ci/scripts/check_generated_docs.sh`] script, which also runs as part of
+`./dev/rust_lint.sh`. Run it with `--write` to update the pages.
+
+[`configs.md`]: https://github.com/apache/datafusion/blob/main/docs/source/user-guide/configs.md
+[`aggregate_functions.md`]: https://github.com/apache/datafusion/blob/main/docs/source/user-guide/sql/aggregate_functions.md
+[`scalar_functions.md`]: https://github.com/apache/datafusion/blob/main/docs/source/user-guide/sql/scalar_functions.md
+[`window_functions.md`]: https://github.com/apache/datafusion/blob/main/docs/source/user-guide/sql/window_functions.md
+[`dev/update_config_docs.sh`]: https://github.com/apache/datafusion/blob/main/dev/update_config_docs.sh
+[`dev/update_function_docs.sh`]: https://github.com/apache/datafusion/blob/main/dev/update_function_docs.sh
+[`ci/scripts/check_generated_docs.sh`]: https://github.com/apache/datafusion/blob/main/ci/scripts/check_generated_docs.sh
+
+## Documentation HTML Build
+
+[`ci/scripts/check_docs_html.sh`] builds the documentation website, the same
+build the "Test doc build" job runs. Sphinx builds with `-W`, so one warning
+fails the check. `./dev/rust_lint.sh` runs it. Run the script with `--help`
+for the tools it needs and the files it writes.
+
+```shell
+./ci/scripts/check_docs_html.sh
+```
+
+[`ci/scripts/check_docs_html.sh`]: https://github.com/apache/datafusion/blob/main/ci/scripts/check_docs_html.sh
+
## Benchmarks
### Criterion Benchmarks
diff --git a/_sources/download.md.txt b/_sources/download.md.txt
index 34296262071c8..2a0cc8e6e3f6e 100644
--- a/_sources/download.md.txt
+++ b/_sources/download.md.txt
@@ -26,7 +26,7 @@ For example:
```toml
[dependencies]
-datafusion = "55.0.0"
+datafusion = "55.1.0"
```
While DataFusion is distributed via [crates.io] as a convenience, the
diff --git a/_sources/library-user-guide/catalogs.md.txt b/_sources/library-user-guide/catalogs.md.txt
index 3c8238b73edbb..dea4e413e2089 100644
--- a/_sources/library-user-guide/catalogs.md.txt
+++ b/_sources/library-user-guide/catalogs.md.txt
@@ -305,6 +305,74 @@ impl CatalogProviderList for MemoryCatalogProviderList {
Like other traits, it also maintains the mapping of the Catalog's name to the CatalogProvider.
+## Catalog Provider Factories
+
+The catalogs above are all registered programmatically, ahead of time,
+before a query ever runs. Sometimes it is useful to let users attach a
+catalog dynamically from SQL instead — for example, a catalog backed by a
+remote catalog service such as an Iceberg REST catalog. This is exactly
+analogous to how [`TableProviderFactory`] lets `CREATE EXTERNAL TABLE`
+create a `TableProvider` "on the fly": `CatalogProviderFactory` lets
+`CREATE EXTERNAL CATALOG ... STORED AS ...` create a
+`CatalogProvider` on the fly.
+
+To support `CREATE EXTERNAL CATALOG`, implement `CatalogProviderFactory`:
+
+```rust
+use std::sync::Arc;
+use async_trait::async_trait;
+use datafusion::catalog::{CatalogProvider, CatalogProviderFactory, MemoryCatalogProvider, Session};
+use datafusion::common::Result;
+use datafusion::logical_expr::CreateExternalCatalog;
+
+#[derive(Debug)]
+struct MyCatalogProviderFactory {}
+
+#[async_trait]
+impl CatalogProviderFactory for MyCatalogProviderFactory {
+ async fn create(
+ &self,
+ _state: &dyn Session,
+ cmd: &CreateExternalCatalog,
+ ) -> Result> {
+ // `cmd.location` and `cmd.options` carry whatever was supplied in the
+ // `LOCATION` and `OPTIONS` clauses of the SQL statement; a real
+ // implementation would use them to connect to the remote catalog
+ // service. This example just returns an empty in-memory catalog.
+ Ok(Arc::new(MemoryCatalogProvider::new()))
+ }
+}
+```
+
+Then register it on the `SessionState`, keyed by the `STORED AS` value that
+should resolve to it:
+
+```rust,ignore
+use datafusion::execution::session_state::SessionStateBuilder;
+
+let state = SessionStateBuilder::new()
+ .with_default_features()
+ .with_catalog_factory("MY_CATALOG_TYPE".to_string(), Arc::new(MyCatalogProviderFactory {}))
+ .build();
+```
+
+With the factory registered, users can attach and detach the catalog from
+SQL:
+
+```sql
+CREATE EXTERNAL CATALOG my_catalog
+STORED AS MY_CATALOG_TYPE
+LOCATION 's3://bucket/warehouse'
+OPTIONS ('warehouse' 'my_catalog');
+
+DROP CATALOG my_catalog;
+```
+
+See [DDL: `CREATE EXTERNAL CATALOG`](../user-guide/sql/ddl.md#create-external-catalog)
+for the full SQL syntax.
+
+[`tableproviderfactory`]: https://docs.rs/datafusion/latest/datafusion/catalog/trait.TableProviderFactory.html
+
## Recap
To recap, you need to:
diff --git a/_sources/library-user-guide/custom-table-providers.md.txt b/_sources/library-user-guide/custom-table-providers.md.txt
index dbbdf9d022716..30ffb2b5cf2f7 100644
--- a/_sources/library-user-guide/custom-table-providers.md.txt
+++ b/_sources/library-user-guide/custom-table-providers.md.txt
@@ -792,6 +792,19 @@ that a `FilterExec` is unnecessary for the `date` predicate, and the second
ensures that only the relevant directories are scanned. The actual file reading
happens later, in the stream produced by `execute()`.
+## Row-Level DML: DELETE and UPDATE
+
+A custom table provider can support `DELETE` and `UPDATE` by implementing the optional [`TableProvider::delete_from()`] and [`TableProvider::update()`] methods. Their default implementations return a "not implemented" error.
+
+Each method builds an [ExecutionPlan] that changes the matching rows and returns the number of affected rows in a `count` column. Your provider decides how to apply and persist the changes. Perform the changes when the returned plan executes: these methods run during physical planning, including for `EXPLAIN`.
+
+The method documentation describes the filters, assignments, SQL semantics, and result schema that an implementation must support. [MemTable] provides an implementation of both methods over in-memory batches.
+
+For SQL syntax and examples, see the [DML section](../user-guide/sql/dml.md) of the user guide.
+
+[`tableprovider::delete_from()`]: https://docs.rs/datafusion/latest/datafusion/catalog/trait.TableProvider.html#method.delete_from
+[`tableprovider::update()`]: https://docs.rs/datafusion/latest/datafusion/catalog/trait.TableProvider.html#method.update
+
## Putting It All Together
Here is a minimal but complete example of a custom table provider that generates
diff --git a/_sources/library-user-guide/extending-sql.md.txt b/_sources/library-user-guide/extending-sql.md.txt
index eea5b3b1acfc9..120bc8fab21a5 100644
--- a/_sources/library-user-guide/extending-sql.md.txt
+++ b/_sources/library-user-guide/extending-sql.md.txt
@@ -264,15 +264,38 @@ enables you to implement SQL constructs like:
When implementing [`RelationPlanner`], you receive a [`RelationPlannerContext`] that
provides utilities for planning:
-| Method | Purpose |
-| --------------------------- | ----------------------------------------------- |
-| `plan(relation)` | Recursively plan a nested relation |
-| `sql_to_expr(expr, schema)` | Convert SQL expression to DataFusion Expr |
-| `context_provider()` | Access session configuration, tables, functions |
+| Method | Purpose |
+| --------------------------- | ------------------------------------------------ |
+| `plan(relation)` | Recursively plan a nested relation |
+| `get_cte(name)` | Look up a CTE visible in the current query scope |
+| `sql_to_expr(expr, schema)` | Convert SQL expression to DataFusion Expr |
+| `context_provider()` | Access session configuration, tables, functions |
See the [RelationPlanner API documentation] for additional methods like
`normalize_ident()` and `object_name_to_table_reference()`.
+Relation planners are called before DataFusion's built-in CTE and catalog lookup.
+If your planner recognizes ordinary relations by name, check `get_cte()` after
+determining the relation is an ordinary name that your planner would otherwise
+handle. Deliberately reserved names and custom syntax can keep their existing
+precedence. Return `RelationPlanning::Original` when a CTE is visible so the
+next planner can handle the relation. When every ordinary name-based planner in
+the chain performs this check, planning reaches DataFusion's built-in CTE
+resolution. Normalize the parsed name first so the lookup follows DataFusion's
+existing name matching. Only do this for a table without function arguments: a
+CTE named `numbers` shadows `numbers`, but it does not shadow a call such as
+`numbers(10)`.
+
+```rust
+// Run this after recognizing `relation` as an ordinary name handled here.
+if let TableFactor::Table { name, args: None, .. } = &relation {
+ let table_ref = ctx.object_name_to_table_reference(name.clone())?;
+ if ctx.get_cte(&table_ref).is_some() {
+ return Ok(RelationPlanning::Original(Box::new(relation)));
+ }
+}
+```
+
#### Implementation Strategies
There are two main approaches when implementing a [`RelationPlanner`]:
diff --git a/_sources/library-user-guide/functions/adding-udfs.md.txt b/_sources/library-user-guide/functions/adding-udfs.md.txt
index c3a40557a006d..78e90dfa6b8d4 100644
--- a/_sources/library-user-guide/functions/adding-udfs.md.txt
+++ b/_sources/library-user-guide/functions/adding-udfs.md.txt
@@ -1116,6 +1116,24 @@ impl Accumulator for GeometricMean {
}
```
+### Declaring how an Aggregate UDF treats `DISTINCT`
+
+By default DataFusion assumes an aggregate is sensitive to the `DISTINCT` modifier, which means the accumulator is expected to
+read `AccumulatorArgs::is_distinct` and deduplicate its input. Override
+[`AggregateUDFImpl::distinct_handling`] when that is not what your function does:
+
+- Return `DistinctHandling::Insensitive` when duplicates cannot change the result, that is, when merging a value the
+ accumulator has already seen is a no-op. `min`, `max`, `bool_and` and `bit_or` are all in this group. The optimizer
+ then plans `f(DISTINCT x)` as `f(x)`, which skips both the per-group hash set and the extra grouping stage that
+ `SingleDistinctToGroupBy` would otherwise introduce.
+- Return `DistinctHandling::Unsupported` when the accumulator does not implement `DISTINCT`: it does not read
+ `is_distinct`, or it rejects `DISTINCT` with an error. The planner must then deduplicate the input first or reject
+ the query. Today this is a declaration only; rejecting such queries at planning time is a follow-up change.
+- Leave the default `DistinctHandling::Sensitive` when the accumulator reads `AccumulatorArgs::is_distinct` and
+ deduplicates its input itself.
+
+Getting this wrong changes query results, so only claim `Insensitive` if your merge is genuinely idempotent.
+
### Registering an Aggregate UDF
To register a Aggregate UDF, you need to wrap the function implementation in a [`AggregateUDF`] struct and then register
@@ -1370,6 +1388,7 @@ async fn main() -> Result<()> {
[`aggregateudf`]: https://docs.rs/datafusion/latest/datafusion/logical_expr/struct.AggregateUDF.html
[`create_udaf`]: https://docs.rs/datafusion/latest/datafusion/logical_expr/fn.create_udaf.html
+[`aggregateudfimpl::distinct_handling`]: https://docs.rs/datafusion/latest/datafusion/logical_expr/trait.AggregateUDFImpl.html#method.distinct_handling
[`advanced_udaf.rs`]: https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/udf/advanced_udaf.rs
## Adding a Table UDF
diff --git a/_sources/library-user-guide/upgrading/54.0.0.md.txt b/_sources/library-user-guide/upgrading/54.0.0.md.txt
index f8e7ac93c08d8..ce4d7c22a23de 100644
--- a/_sources/library-user-guide/upgrading/54.0.0.md.txt
+++ b/_sources/library-user-guide/upgrading/54.0.0.md.txt
@@ -335,44 +335,6 @@ This produces two user-visible changes:
`ScalarSubqueryExpr` expression. Code that walks or transforms `LogicalPlan` /
`ExecutionPlan` trees, as well as `EXPLAIN` output, may need updating.
-### Filter predicate evaluation order may differ from query text
-
-The logical optimizer now reorders filters so that cheap predicates (most binary
-comparisons, `IS NULL`, `Between`, `InList`, etc.) evaluate before expensive
-ones (`LIKE`, regex, scalar function calls, subqueries). For example,
-`WHERE col LIKE '%foo%' AND col2 = 5` may evaluate `col2 = 5` before
-`col LIKE '%foo%'`.
-
-**Evaluation order has never been guaranteed to match the order written in the
-query.** The SQL standard explicitly allows implementations to evaluate operands
-in any order; major engines (PostgreSQL, SQL Server, Oracle, MySQL) document the
-same. Queries should not rely on left-to-right evaluation or short-circuit
-semantics for `AND` or `OR`. Previous versions of DataFusion already reordered
-predicates (e.g., as part of expression simplification or predicate pushdown);
-the new reordering pass just increases the scenarios where the optimizer will
-change predicate evaluation order.
-
-**Fallible-predicate patterns are particularly affected.** For example:
-
-```sql
-WHERE s ~ '^[0-9]+$' AND CAST(s AS INT) > 0
-```
-
-The intent is likely to filter non-numeric strings before the `CAST` runs,
-but this depends on evaluation-order behavior the SQL standard does not
-guaranteed. The new reorder makes this kind of pattern more likely to fail
-at runtime if the optimizer moves the `CAST` ahead of the regex. To force
-conditional evaluation, rewrite using `CASE`, which has standardized
-short-circuit semantics:
-
-```sql
-WHERE CASE WHEN s ~ '^[0-9]+$' THEN CAST(s AS INT) > 0 ELSE false END
-```
-
-Volatile expressions (`random()`, `now()`, etc.) are exempt — their position
-in the conjunct list is preserved so the number of times they evaluate per
-query does not change.
-
### `datafusion-proto`: expression deserialization now takes a `TaskContext`
`Serializeable::from_bytes_with_registry` is renamed to `from_bytes_with_ctx`
@@ -928,8 +890,3 @@ match register_function {
RegisterFunction::Table(name, table) => {},
}
```
-
-### New `Dialect::Spark` variant
-
-The `Dialect` enum in `datafusion_common::config` now includes a `Spark` variant.
-If you match exhaustively on `Dialect`, add a `Dialect::Spark` arm.
diff --git a/_sources/library-user-guide/upgrading/55.0.0.md.txt b/_sources/library-user-guide/upgrading/55.0.0.md.txt
index 4483fe76059b2..abd4d0020e502 100644
--- a/_sources/library-user-guide/upgrading/55.0.0.md.txt
+++ b/_sources/library-user-guide/upgrading/55.0.0.md.txt
@@ -21,9 +21,43 @@
## DataFusion 55.0.0
-**Note:** DataFusion `55.0.0` has not been released yet. The information provided
-in this section pertains to features and changes that have already been merged
-to the main branch and are awaiting release in this version.
+### Filter predicate evaluation order may differ from query text
+
+The logical optimizer now reorders filters so that cheap predicates (most binary
+comparisons, `IS NULL`, `Between`, `InList`, etc.) evaluate before expensive
+ones (`LIKE`, regex, scalar function calls, subqueries). For example,
+`WHERE col LIKE '%foo%' AND col2 = 5` may evaluate `col2 = 5` before
+`col LIKE '%foo%'`.
+
+**Evaluation order has never been guaranteed to match the order written in the
+query.** The SQL standard explicitly allows implementations to evaluate operands
+in any order; major engines (PostgreSQL, SQL Server, Oracle, MySQL) document the
+same. Queries should not rely on left-to-right evaluation or short-circuit
+semantics for `AND` or `OR`. Previous versions of DataFusion already reordered
+predicates (e.g., as part of expression simplification or predicate pushdown);
+the new reordering pass just increases the scenarios where the optimizer will
+change predicate evaluation order.
+
+**Fallible-predicate patterns are particularly affected.** For example:
+
+```sql
+WHERE s ~ '^[0-9]+$' AND CAST(s AS INT) > 0
+```
+
+The intent is likely to filter non-numeric strings before the `CAST` runs,
+but this depends on evaluation-order behavior the SQL standard does not
+guaranteed. The new reorder makes this kind of pattern more likely to fail
+at runtime if the optimizer moves the `CAST` ahead of the regex. To force
+conditional evaluation, rewrite using `CASE`, which has standardized
+short-circuit semantics:
+
+```sql
+WHERE CASE WHEN s ~ '^[0-9]+$' THEN CAST(s AS INT) > 0 ELSE false END
+```
+
+Volatile expressions (`random()`, `now()`, etc.) are exempt — their position
+in the conjunct list is preserved so the number of times they evaluate per
+query does not change.
### Map casts with nested Structs use schema-evolution rules
@@ -215,6 +249,11 @@ Use `temp_file.size()` instead of [`RefCountedTempFile::current_disk_usage`].
[`refcountedtempfile::current_disk_usage`]: https://docs.rs/datafusion-execution/latest/datafusion_execution/disk_manager/struct.RefCountedTempFile.html#method.current_disk_usage
[`refcountedtempfile::update_disk_usage`]: https://docs.rs/datafusion-execution/latest/datafusion_execution/disk_manager/struct.RefCountedTempFile.html#method.update_disk_usage
+### New `Dialect::Spark` variant
+
+The `Dialect` enum in `datafusion_common::config` now includes a `Spark` variant.
+If you match exhaustively on `Dialect`, add a `Dialect::Spark` arm.
+
### `Dialect::AVAILABLE` replaced by `Dialect::available()`
`datafusion_common::config::Dialect::AVAILABLE` has been removed. Use
diff --git a/_sources/library-user-guide/upgrading/56.0.0.md.txt b/_sources/library-user-guide/upgrading/56.0.0.md.txt
index 1a6b983025e39..312668c485629 100644
--- a/_sources/library-user-guide/upgrading/56.0.0.md.txt
+++ b/_sources/library-user-guide/upgrading/56.0.0.md.txt
@@ -25,6 +25,279 @@
in this section pertains to features and changes that have already been merged
to the main branch and are awaiting release in this version.
+### Upgrade arrow/parquet to 60.0.0 and object_store to 0.14.2
+
+DataFusion 56.0.0 uses `arrow` and `parquet` 60.0.0, and `object_store` 0.14.2.
+This may require updates to your Cargo.toml if you have direct dependencies on
+these crates.
+
+See the [Arrow 60.0.0 release notes] and the [object_store 0.14.2 upgrade guide] for details on breaking changes in those versions.
+
+[arrow 60.0.0 release notes]: https://github.com/apache/arrow-rs/releases/tag/60.0.0
+[object_store 0.14.2 upgrade guide]: https://github.com/apache/arrow-rs-object-store/blob/v0.14.2/CHANGELOG.md
+
+#### Field and schema metadata now use arrow's `Metadata` type
+
+Arrow 60 introduced a dedicated [`Metadata`] type for field and schema metadata
+in place of `HashMap`. Following that change, several DataFusion
+APIs now use `Metadata` as well, such as `DFSchema::metadata` and
+`ExprSchema::metadata` return `&Metadata`. `CastExpr::target_metadata` and
+`TryCastExpr::target_metadata` return `Option<&Metadata>`.
+
+**Migration guide:**
+
+```rust,ignore
+// Before
+let meta: &HashMap = schema.metadata();
+let field = Field::new("a", DataType::Int64, true)
+ .with_metadata([("k".to_string(), "v".to_string())].into());
+
+// After
+let meta: &Metadata = schema.metadata();
+let field = Field::new("a", DataType::Int64, true)
+ .with_metadata(Metadata::new().with("k", "v"));
+```
+
+`Metadata` supports `.get()`, `.iter()`, `.is_empty()` and `.extend()` like
+`HashMap`, and converts to and from `HashMap` and
+`BTreeMap` via `From`, so most call sites need only a type
+change. Use `FieldMetadata::to_hashmap` where a `HashMap` is still required.
+
+[`metadata`]: https://docs.rs/arrow/60.0.0/arrow/datatypes/struct.Metadata.html
+
+### `ParquetAccessPlan::into_overall_row_selection` is deprecated
+
+`ParquetAccessPlan::into_overall_row_selection` is deprecated starting in 56.0.0.
+DataFusion now keeps selections local to each row group during Parquet scanning.
+The method remains available with its existing conversion and selection-length
+validation behavior, so direct callers continue to work but receive a deprecation
+warning.
+
+Users who attach a `ParquetAccessPlan` to a `PartitionedFile` for DataFusion to
+read need no changes.
+
+For custom readers, use `ParquetAccessPlan::into_inner()` to obtain the
+`RowGroupAccess` entries. Their positions are the original file row-group
+indexes, and each selection uses coordinates within its own row group. When
+migrating away from the deprecated method, callers must handle conversion and
+selection-length validation themselves. Parquet's push decoder and async reader
+accept `RowGroupSelection` values through `with_row_group_selections`; the
+synchronous reader still requires `with_row_groups` and an overall
+`with_row_selection`.
+
+### Missing Parquet null counts are treated as unknown
+
+DataFusion now preserves an omitted Parquet `null_count` statistic as unknown.
+Previously, it assumed zero nulls, which could discard matching NULL rows in
+`IS NULL` filters and `ORDER BY ... NULLS FIRST LIMIT` queries, or produce an
+incorrectly high `COUNT(column)` from metadata.
+
+Queries over affected files may read or sort more data because these optimizations
+require a known null count:
+
+- Pruning row groups for `IS NULL` filters.
+- Computing `COUNT(column)` using only file metadata.
+- Pruning row groups with a dynamic `NULLS FIRST` TopK filter.
+- Eliminating a sort over nullable columns in sorted, non-overlapping files.
+ Such queries may now retain a full `SortExec`, even when the data has no NULLs.
+
+parquet-rs versions before 53.1.0 omitted zero null counts. This includes files
+produced with the older parquet-rs dependency used by DataFusion releases before
+42.1.0. [Arrow #6490](https://github.com/apache/arrow-rs/pull/6490) changed the
+writer to record known zero counts. Files with explicit counts retain their
+existing behavior.
+
+To identify column chunks with bounds but no null count, run this query in the
+DataFusion CLI:
+
+```sql
+SELECT row_group_id, path_in_schema
+FROM parquet_metadata('data.parquet')
+WHERE (stats_min IS NOT NULL OR stats_max IS NOT NULL)
+ AND stats_null_count IS NULL;
+```
+
+Rewriting affected files with a current DataFusion version, for example using
+`COPY ... TO` with Parquet statistics enabled, records the missing counts and
+restores optimizations that depend on them. Preserve the required data ordering
+and ordering metadata when rewriting sorted files.
+
+### `Timestamp(u, Some(tz)) - Timestamp(u, None)` reads the naive operand in `tz`
+
+Subtracting a timezone-naive timestamp from a timezone-aware one _at the same
+time unit_ did not coerce at all in `55.0.0`: the naive operand was read as UTC,
+which differed both from `=` on the same pair of values and from every other
+pairing of time units. It now coerces like the rest, so the naive operand is
+read in the aware operand's time zone:
+
+```sql
+-- ts_tz is 2024-11-01T00:00:00-04:00 (America/New_York), ts is the naive
+-- 2024-11-01T00:00:00; ts_tz = ts is true in both versions
+-- 55.0.0: 0 days 4 hours 0 mins 0.000000000 secs
+-- 56.0.0: 0 days 0 hours 0 mins 0.000000000 secs
+SELECT ts_tz - ts FROM timestamps;
+```
+
+### `ForeignSession::create_physical_plan` is unsupported
+
+`ForeignSession::create_physical_plan` no longer forwards to the library that
+owns the session. It now returns a `NotImplemented` error because forwarding can
+re-enter an installed foreign planner, and the execution-plan handle returned by
+the old callback cannot restore local Rust type identities for downcasting.
+The original `FFI_SessionRef` callback slot remains in place for ABI compatibility
+with DataFusion 55 consumers, but calling that callback returns the same error.
+
+The session-owning library should instead export its original planner as a
+`datafusion_ffi::query_planner::FFI_QueryPlanner` before installing a foreign
+planner. The foreign planner can retain and invoke that handle to receive a
+serialized physical plan reconstructed with local type identities. See the
+`datafusion_ffi::query_planner` module documentation for the complete delegation
+pattern. `ForeignSession::query_planner`, `optimize`, and `physical_optimizers`
+continue to forward to the owning session across the FFI boundary.
+
+### Range partitioning supports retained samples and scaling
+
+`RangePartitioning::new` is deprecated. Prefer the validated
+`RangePartitioning::try_new_with_samples(ordering, samples, partition_count)`.
+For exact boundaries, pass `split_points.len() + 1` as the count, or keep using
+the validated `try_new` constructor. Retain additional samples when future
+scaling above that count is required; scaling does not create new sample values.
+
+`scale` returns `Option`. It returns `None` when the target
+partition count is zero or exceeds the retained sample capacity; callers can
+then retain the existing layout or choose another partitioning. Equality includes
+retained samples; use `has_same_layout` to compare the current key ordering and
+effective boundaries.
+
+`FFI_RangePartitioning` has a new layout; rebuild FFI consumers against the
+compatible release. The generated `PhysicalRangePartitioning` protobuf struct
+also gains fields, affecting exhaustive struct literals. Older protobuf payloads
+remain readable, and effective split points remain available to older readers.
+
+### `GroupColumn` now requires `values_preserving`
+
+Custom implementations of the public `GroupColumn` trait must implement
+`values_preserving`. This method returns selected rows without changing the stored
+values or their group indices. It preserves the requested order and supports
+repeated indices.
+
+**Migration guide:**
+
+Implement `values_preserving`, call
+`selection.validate_num_groups(self.len())?` before reading, and return rows in
+`selection.iter()` order without changing the builder state.
+
+### `datafusion-proto`: common option and constraint conversions are fallible
+
+Protobuf conversions for `CsvOptions`, `JsonOptions`, `ParquetCdcOptions`,
+`Constraint`, and `Constraints` now reject integer values that do not fit
+`usize`. Their infallible `From` implementations have been replaced with
+`TryFrom`. The existing `TryFrom` conversions for `ParquetOptions` and
+`TableParquetOptions` now also validate all `usize`-backed fields. A constraint
+without a `constraint_mode` returns an error instead of panicking.
+
+**Migration guide:**
+
+```rust,ignore
+// Before
+let csv = CsvOptions::from(&proto_csv);
+let cdc = ParquetCdcOptions::from(proto_cdc);
+let constraints: Constraints = proto_constraints.into();
+
+// After
+let csv = CsvOptions::try_from(&proto_csv)?;
+let cdc = ParquetCdcOptions::try_from(proto_cdc)?;
+let constraints = Constraints::try_from(proto_constraints)?;
+```
+
+See [issue #24170](https://github.com/apache/datafusion/issues/24170) for details.
+
+### `ExecutionOptions` has a new `enable_nlj_coordinated_fallback` field
+
+`ExecutionOptions` gained a public `enable_nlj_coordinated_fallback: bool` field
+(default `true`). It controls whether the memory-limited `NestedLoopJoinExec`
+fallback shares per-chunk build-side state across probe partitions, which is what
+lets `LEFT`, `LEFT SEMI`, `LEFT ANTI`, `LEFT MARK` and `FULL` joins spill instead
+of failing with `ResourcesExhausted` when the right side has several partitions.
+
+**Who is affected:**
+
+- Users constructing `ExecutionOptions` (or `ConfigOptions`) with an exhaustive
+ struct literal. Reading or `SET`-ing configuration is unaffected.
+- Distributed engines that run each output partition as an independent task.
+ The coordination assumes all probe partitions run in one process; with one
+ coordinator per task the shared probe-thread counter never reaches zero and the
+ fallback would stall. Such engines should set the flag to `false`, which keeps
+ the previous fail-fast behaviour for the affected join types.
+
+**Migration guide:**
+
+Set the new field, or fill it from `Default`:
+
+```rust,ignore
+// Before
+ExecutionOptions {
+ batch_size: 8192,
+ // ... every other field ...
+}
+
+// After: set it explicitly
+ExecutionOptions {
+ batch_size: 8192,
+ enable_nlj_coordinated_fallback: true,
+ // ... every other field ...
+}
+
+// After: or let the remaining fields come from Default, which also keeps
+// future field additions from breaking the literal
+ExecutionOptions {
+ batch_size: 8192,
+ ..Default::default()
+}
+```
+
+Distributed engines opting out:
+
+```rust,ignore
+let mut config = SessionConfig::new();
+config.options_mut().execution.enable_nlj_coordinated_fallback = false;
+```
+
+### `ExecutionOptions` has a new `soft_max_bytes_per_output_file` field
+
+`ExecutionOptions` gained a public `soft_max_bytes_per_output_file: ConfigNonZeroUsize`
+field (default 4 GiB minus one byte, or 4,294,967,295 bytes). When writing
+multiple output files, DataFusion starts a new file once a writer reports that
+the encoded size has reached this target or the existing
+`soft_max_rows_per_output_file` target has been reached. The byte limit is soft:
+buffered batches, in-flight batch serialization, individual batch sizes, and
+file metadata can make a completed file larger than the target. It does not
+apply to single-file output.
+
+**Who is affected:**
+
+- Users constructing `ExecutionOptions` (or `ConfigOptions`) with an exhaustive
+ struct literal must provide the new field.
+- Users writing multiple output files can set a smaller byte target to rotate
+ files before they reach the default size.
+
+**Migration guide:**
+
+Set the field explicitly, or fill it from `Default` as shown above. For example,
+to target 128 MiB output files in Rust:
+
+```rust,ignore
+let mut config = SessionConfig::new();
+config.options_mut().execution.soft_max_bytes_per_output_file =
+ ConfigNonZeroUsize::try_new(128 * 1024 * 1024)?;
+```
+
+The same setting can be changed with SQL:
+
+```sql
+SET datafusion.execution.soft_max_bytes_per_output_file = 134217728;
+```
+
### `datafusion.optimizer.use_statistics_registry` is deprecated and ignored
The `datafusion.optimizer.use_statistics_registry` config flag is deprecated and
@@ -49,6 +322,99 @@ previous default (`use_statistics_registry = false`).
`StatisticsRegistry::default_with_builtin_providers()`.
- To opt out, register nothing (the default).
+### Generated protobuf `JsonWriterOptions` gained a `compression_level` field
+
+The generated public protobuf `JsonWriterOptions` struct now carries an optional
+`compression_level` so JSON sink plans preserve explicitly configured
+compression levels across serialization.
+
+**Who is affected:**
+
+- Users constructing generated `JsonWriterOptions` values with an exhaustive
+ struct literal.
+
+**Migration guide:**
+
+Set `compression_level` explicitly, or fill it from `Default`:
+
+```rust,ignore
+// Before
+JsonWriterOptions { compression }
+
+// After
+JsonWriterOptions {
+ compression,
+ compression_level: None,
+}
+// or
+JsonWriterOptions {
+ compression,
+ ..Default::default()
+}
+```
+
+The protobuf wire format remains backward compatible.
+
+See [PR #24945](https://github.com/apache/datafusion/pull/24945) for details.
+
+### Generated protobuf Parquet structs gained state fields
+
+The generated public protobuf `ParquetScanExecNode` struct now carries an
+optional `metadata_size_hint`, and `ParquetSink` now carries optional
+`sorting_columns`. These fields preserve the corresponding Parquet source and
+sink settings across physical-plan serialization.
+
+**Who is affected:**
+
+- Users constructing either generated struct with an exhaustive struct literal.
+
+**Migration guide:**
+
+Add `metadata_size_hint: None` to `ParquetScanExecNode` literals and
+`sorting_columns: None` to `ParquetSink` literals to retain the previous
+behavior, or use `..Default::default()` for unspecified fields.
+
+The protobuf wire format remains backward compatible.
+
+See [PR #25057](https://github.com/apache/datafusion/pull/25057) for details.
+
+### Generated protobuf `CsvWriterOptions` changed
+
+The generated `CsvWriterOptions` now includes `compression_level`,
+`timestamp_tz_format`, and `terminator`. Its four existing format fields changed
+from `String` to `Option` to distinguish unset from explicitly empty
+formats. This affects exhaustive struct literals and direct format-field access.
+
+Wrap existing formats in `Some` or use `None`, and initialize the new fields
+(explicitly or through `Default`):
+
+```rust,ignore
+// Before (unchanged fields omitted)
+CsvWriterOptions {
+ date_format: "%Y-%m-%d".to_string(),
+ datetime_format: String::new(),
+ timestamp_format: String::new(),
+ time_format: String::new(),
+ // ...
+}
+
+// After
+CsvWriterOptions {
+ date_format: Some("%Y-%m-%d".to_string()),
+ datetime_format: None,
+ timestamp_format: None,
+ time_format: None,
+ compression_level: None,
+ timestamp_tz_format: None,
+ terminator: Vec::new(),
+ // ...
+}
+```
+
+The protobuf wire format remains backward compatible.
+
+See [PR #25058](https://github.com/apache/datafusion/pull/25058) for details.
+
### `DefaultStatisticsProvider` is deprecated
`datafusion_physical_plan::operator_statistics::DefaultStatisticsProvider` is
@@ -70,3 +436,262 @@ Use the walk instead:
StatisticsContext::new_with_registry(registry)
.compute_extended(plan, &StatisticsArgs::new())?; // or .compute(...) for core Statistics
```
+
+### API change for `floor` and `ceil` UDF
+
+The output type of the `floor` and `ceil` UDFs has been changed from the exact input type to a rescaled type with the same bit width. For example, for input `Decimal32(7,2)` `floor` now returns `Decimal32(6,0)`, where the new precision is `p - s + 1`, matching Spark's behaviour. See [#24703] for more details.
+
+**Who is affected:**
+
+- Users storing query result with these UDFs in a fixed schema
+- Users relying on `arrow_typeof` for these UDFs
+
+**Migration guide:**
+
+Change the expected type or wrap the expression in `CAST`. It's recommended to avoid relying on decimal's exact precision and scale.
+
+### `map_extract` / `element_at` return an empty list for absent keys
+
+`map_extract` (and its alias `element_at`) previously returned a single-element
+list containing `NULL` when the key was not present in the map. It now returns
+an empty list, matching the documented behavior and DuckDB. Two related cases
+changed at the same time, also matching DuckDB:
+
+- A `NULL` map input now yields `NULL` instead of `[NULL]`.
+- A `NULL` lookup key now yields `[]` instead of `[NULL]`.
+
+A key that is present with a `NULL` value still returns `[NULL]`, so absent
+keys and `NULL` values are now distinguishable.
+
+**Migration guide:**
+
+```sql
+-- Before
+SELECT map_extract(MAP {'a': 1}, 'missing'); -- [NULL]
+
+-- After
+SELECT map_extract(MAP {'a': 1}, 'missing'); -- []
+```
+
+Expressions that assumed the result always has exactly one element, for
+example by checking its length, unnesting it, or comparing it to `[NULL]`,
+should treat an empty list as the absent-key case instead.
+
+See [issue #24981](https://github.com/apache/datafusion/issues/24981) and
+[issue #24983](https://github.com/apache/datafusion/issues/24983) for details.
+
+### `DataFrame::from_columns` accepts `IntoIterator`
+
+`DataFrame::from_columns` now accepts any `IntoIterator`
+instead of specifically accepting a `Vec<(&str, ArrayRef)>`.
+
+```rust,ignore
+// Existing Vec usage continues to work
+let df = DataFrame::from_columns(vec![
+ ("id", id),
+ ("name", name),
+])?;
+
+// Arrays can now be used directly
+let df = DataFrame::from_columns([
+ ("id", id),
+ ("name", name),
+])?;
+```
+
+Most existing call sites using `Vec` require no changes. Code that relies on
+the exact non-generic function signature of `DataFrame::from_columns` may need
+to be updated to account for the new generic API.
+
+### Aggregate ordering state field names are now namespaced
+
+Ordering expressions exposed as top-level aggregate state fields now use names
+derived from the aggregate name and their ordering position.
+
+For example:
+
+```text
+first_value(value)[ordering_0]
+```
+
+is now used instead of an unqualified ordering field name such as:
+
+```text
+timestamp@0
+```
+
+This guarantees unique aggregate state field names and allows
+`DFSchema::check_names()` to be enforced.
+
+**Who is affected:**
+
+Users or integrations that inspect aggregate state field names directly,
+including custom UDAFs and FFI integrations.
+
+### Physical filter pushdown resolves columns by position
+
+`datafusion_physical_plan::filter_pushdown::ChildFilterDescription::from_child`
+and `FilterDescription::from_children` now resolve filter columns by position
+instead of looking them up by name. This prevents incorrect results when a
+child schema contains duplicate column names. `from_child` requires the child
+field at each referenced position to have the same name as the filter column.
+
+`ChildFilterDescription::from_child_with_allowed_indices` is deprecated but
+preserves its previous name-based mapping to the first matching child field.
+Migrate to `from_child_with_column_mapping` because name resolution is ambiguous
+when the child schema contains duplicate field names.
+
+**Migration guide:**
+
+Use `from_child` (or `from_children` for multiple children) when the parent and
+child schemas have matching column positions and names. When a node projects,
+reorders, or renames columns, use `from_child_with_column_mapping` with an
+explicit map from parent output indices to child input indices. Columns absent
+from the mapping cannot be pushed down.
+
+For example, if the parent outputs `[a, b]` and the child outputs `[b, a]`, a
+filter on `a@0` must map to child column `a@1`:
+
+```rust,ignore
+use std::collections::{HashMap, HashSet};
+use datafusion_physical_plan::filter_pushdown::ChildFilterDescription;
+
+// Before: allow parent column 0 and resolve "a" by name in the child.
+let description = ChildFilterDescription::from_child_with_allowed_indices(
+ &parent_filters,
+ HashSet::from([0]),
+ &child,
+)?;
+
+// After: explicitly map parent column 0 to child column 1.
+let description = ChildFilterDescription::from_child_with_column_mapping(
+ &parent_filters,
+ HashMap::from([(0, 1)]),
+ &child,
+)?;
+```
+
+### Default `datafusion.sql_parser.recursion_limit` raised from 50 to 51
+
+DataFusion now uses `sqlparser` 0.63.0, which adds recursion guards to more
+parse functions (for example, data type and `INTERVAL` parsing). As a result,
+the same SQL statement consumes slightly more of the parser recursion budget
+than it did with previous `sqlparser` versions. In particular, every expression
+now needs one additional level of depth.
+
+To avoid rejecting queries that previously parsed successfully, the default
+value of the `datafusion.sql_parser.recursion_limit` configuration option, and
+of `DFParserBuilder::with_recursion_limit`, has been raised from `50` to `51`.
+
+If you set `datafusion.sql_parser.recursion_limit` explicitly to a value close
+to the depth of your queries, you may see `RecursionLimitExceeded` errors after
+upgrading and should raise the limit accordingly.
+
+See [PR #25278](https://github.com/apache/datafusion/pull/25278) for details.
+
+### `ensure_distribution` is deprecated in favour of `ensure_distribution_with_stats`
+
+`datafusion_physical_optimizer::enforce_distribution::ensure_distribution` now
+takes its `StatisticsContext` from the caller, so one context (and its
+memoization cache) can be shared across a whole bottom-up traversal. The old
+two-argument form is kept as a deprecated wrapper that allocates a fresh
+context per call, which recomputes each shared subtree's statistics once per
+ancestor.
+
+```rust,ignore
+// Before
+let plan = DistributionContext::new_default(plan)
+ .transform_up(|ctx| ensure_distribution(ctx, config))
+ .data()?;
+
+// After: one context for the whole walk. `StatsCache` is keyed by raw plan-node
+// pointers, so reset it whenever a node's plan pointer actually changed.
+let stats_ctx = StatisticsContext::new();
+let plan = DistributionContext::new_default(plan)
+ .transform_up(|ctx| {
+ let before = Arc::clone(&ctx.plan);
+ let result = ensure_distribution_with_stats(ctx, config, &stats_ctx)?;
+ if !Arc::ptr_eq(&before, &result.data.plan) {
+ stats_ctx.reset_cache();
+ }
+ Ok(result)
+ })
+ .data()?;
+```
+
+Callers that only need the previous behaviour can keep using the deprecated
+form, or pass a freshly constructed `StatisticsContext` per call.
+
+### `MergeIntoOp` requires the SQL-visible target qualifier
+
+`MergeIntoOp` now stores the SQL-visible target qualifier separately from the
+target provider identity. This prevents an aliased target from being confused
+with a source relation that uses the target table's name.
+
+The struct is now non-exhaustive. Replace 55.0 struct literals with
+`MergeIntoOp::new`:
+
+```rust,ignore
+// DataFusion 55.0
+let op = MergeIntoOp { on, clauses };
+
+// DataFusion 56.0
+let op = MergeIntoOp::new(target_qualifier, on, clauses);
+```
+
+`target_qualifier` must be the relation name referenced by the MERGE expressions:
+the target alias when one is present, otherwise the target table reference.
+`DmlStatement::table_name` remains the provider/catalog identity.
+
+### `MergeIntoOpNode` protobuf literals require `target_qualifier`
+
+The generated `MergeIntoOpNode` type has a new optional field. Code constructing
+the generated type with a struct literal must provide it:
+
+```rust,ignore
+// DataFusion 55.0
+let node = protobuf::MergeIntoOpNode { on, clauses };
+
+// DataFusion 56.0
+let node = protobuf::MergeIntoOpNode {
+ on,
+ clauses,
+ target_qualifier: Some(protobuf::TableReference::from(target_qualifier)),
+};
+```
+
+Wire compatibility is directional:
+
+- A 56.0 reader accepts a 55.0 payload. When `target_qualifier` is absent, it
+ falls back to `DmlNode.table_name`, matching the 55.0 representation.
+- A 55.0 reader must not consume an alias-preserving 56.0 MERGE payload. It
+ ignores the unknown field but cannot preserve the qualifier required by the
+ expressions, which can cause resolution failure or incorrect rebinding.
+
+### `FileSource::exact_filter` controls scan equivalence properties
+
+`FileScanConfig` no longer derives equivalence properties (constant columns
+and equal columns) from `FileSource::filter`. It uses the new
+`FileSource::exact_filter` method instead. This method returns the part of the
+filter that every output row satisfies. A filter that the source uses only for
+pruning (for example, Parquet row group statistics when
+`datafusion.execution.parquet.pushdown_filters` is `false`) lets
+non-matching rows through, and equivalences derived from it gave wrong query
+results.
+
+`exact_filter` returns `None` by default. `ParquetSource` returns the pushed-down
+conjuncts when `pushdown_filters` is enabled.
+
+**Migration guide:**
+
+If your custom `FileSource` applies its filter to every row, implement
+`exact_filter` to keep the equivalence properties of the scan:
+
+```rust,ignore
+impl FileSource for MySource {
+ fn exact_filter(&self) -> Option> {
+ self.filter()
+ }
+ // ...
+}
+```
diff --git a/_sources/user-guide/concepts-readings-events.md.txt b/_sources/user-guide/concepts-readings-events.md.txt
index 366defa35eb5f..f6d4a19fbe0f6 100644
--- a/_sources/user-guide/concepts-readings-events.md.txt
+++ b/_sources/user-guide/concepts-readings-events.md.txt
@@ -53,13 +53,13 @@ This is a list of DataFusion related blog posts, articles, and other resources.
- **2026-03-31** [Blog: Writing Custom Table Providers in Apache DataFusion](https://datafusion.apache.org/blog/2026/03/31/writing-table-providers/)
-- **2026-03-20** [Blog: Turning LIMIT into an I/O Optimization: Inside DataFusion’s Multi-Layer Pruning Stack](https://datafusion.apache.org/blog/2026/03/20/multi-layer-pruning/)
+- **2026-03-20** [Blog: Turning LIMIT into an I/O Optimization: Inside DataFusion’s Multi-Layer Pruning Stack](https://datafusion.apache.org/blog/2026/03/20/limit-pruning/)
- **2026-02-23** [Blog: Apache DataFusion: A Data Engineer's Guide to the Query Engine Reshaping How We Build Data Systems](https://andrewmadson.substack.com/p/apache-datafusion-a-data-engineers)
- **2026-02-09** [Blog: Vector search using only Parquet and DataFusion](https://blog.xiangpeng.systems/posts/vector-search-with-parquet-datafusion/)
-- **2026-02-02** [Blog: Optimizing SQL CASE Expression Evaluation](https://datafusion.apache.org/blog/2026/02/02/case-expression/)
+- **2026-02-02** [Blog: Optimizing SQL CASE Expression Evaluation](https://datafusion.apache.org/blog/2026/02/02/datafusion_case/)
- **2026-01-12** [Blog: Extending SQL in DataFusion: from ->> to TABLESAMPLE](https://datafusion.apache.org/blog/2026/01/12/extending-sql)
@@ -223,6 +223,7 @@ regular virtual event where community members share what they are building with
# 🌎 Community Events
+- **2026-11-12** [San Francisco Apache DataFusion Meetup](https://github.com/apache/datafusion/discussions/25665) - [RSVP](https://luma.com/k04h0om1)
- **2026-09-30** [London Apache DataFusion Meetup](https://github.com/apache/datafusion/discussions/24512) - [RSVP](https://luma.com/r12f1t5o)
- **2026-09-03** [Boston Apache DataFusion Meetup](https://github.com/apache/datafusion/discussions/21541) - [RSVP](https://luma.com/yexgqifv)
- **2026-08-13** [San Francisco Apache DataFusion Meetup](https://github.com/apache/datafusion/discussions/24013) - [RSVP](https://luma.com/gk3s2vib)
diff --git a/_sources/user-guide/configs.md.txt b/_sources/user-guide/configs.md.txt
index 7c21103cd7818..ba8ea52bb0850 100644
--- a/_sources/user-guide/configs.md.txt
+++ b/_sources/user-guide/configs.md.txt
@@ -87,13 +87,13 @@ The following configuration settings are available:
| datafusion.execution.parquet.pushdown_filters | false | (reading) If true, filter expressions are be applied during the parquet decoding operation to reduce the number of rows decoded. This optimization is sometimes called "late materialization". |
| datafusion.execution.parquet.reorder_filters | false | (reading) If true, filter expressions evaluated during the parquet decoding operation will be reordered heuristically to minimize the cost of evaluation. If false, the filters are applied in the same order as written in the query |
| datafusion.execution.parquet.force_filter_selections | false | (reading) Force the use of RowSelections for filter results, when pushdown_filters is enabled. If false, the reader will automatically choose between a RowSelection and a Bitmap based on the number and pattern of selected rows. |
-| datafusion.execution.parquet.schema_force_view_types | true | (reading) If true, parquet reader will read columns of `Utf8/Utf8Large` with `Utf8View`, and `Binary/BinaryLarge` with `BinaryView`. |
-| datafusion.execution.parquet.binary_as_string | false | (reading) If true, parquet reader will read columns of `Binary/LargeBinary` with `Utf8`, and `BinaryView` with `Utf8View`. Parquet files generated by some legacy writers do not correctly set the UTF8 flag for strings, causing string columns to be loaded as BLOB instead. |
+| datafusion.execution.parquet.schema_force_view_types | true | (reading) If true, parquet reader will read columns of `Utf8/Utf8Large` with `Utf8View`, and `Binary/BinaryLarge` with `BinaryView`. The parquet reader is optimized for reading `Utf8View` and `BinaryView`, so such queries are significantly faster than reading `Utf8`/`Binary` and then casting to the view types. |
+| datafusion.execution.parquet.binary_as_string | false | (reading) If true, parquet reader will read columns of `Binary/LargeBinary` with `Utf8`, and `BinaryView` with `Utf8View`. Parquet files generated by some legacy writers do not correctly set the UTF8 flag for strings, causing string columns to be loaded as BLOB instead. The parquet reader has special optimizations for `Utf8` validation, so reading such columns as strings is significantly faster than reading them as binary and then casting to string. |
| datafusion.execution.parquet.coerce_int96 | NULL | (reading) If true, parquet reader will read columns of physical type int96 as originating from a different resolution than nanosecond. This is useful for reading data from systems like Spark which stores microsecond resolution timestamps in an int96 allowing it to write values with a larger date range than 64-bit timestamps with nanosecond resolution. |
| datafusion.execution.parquet.coerce_int96_tz | NULL | (reading) Optional timezone applied to INT96 columns when `coerce_int96` is set. When `Some`, INT96 columns coerce to `Timestamp(, Some())` instead of the default `Timestamp(, None)`. Spark and other systems write INT96 values as UTC-adjusted instants, so callers that need the resulting Arrow type to be timezone-aware (e.g. for Spark `TimestampType` semantics) should set this to `"UTC"`. No effect when `coerce_int96` is `None`. |
| datafusion.execution.parquet.bloom_filter_on_read | true | (reading) Use any available bloom filters when reading parquet files |
| datafusion.execution.parquet.max_predicate_cache_size | NULL | (reading) The maximum predicate cache size, in bytes. When `pushdown_filters` is enabled, sets the maximum memory used to cache the results of predicate evaluation between filter evaluation and output generation. Decreasing this value will reduce memory usage, but may increase IO and CPU usage. None means use the default parquet reader setting. 0 means no caching. |
-| datafusion.execution.parquet.max_in_list_size | 20 | Maximum number of input values in an `IN (...)` list eligible for min/max pruning. Lists above this cap, or a cap of 0, skip this rewrite; other predicates and Bloom-filter pruning remain available. Within the cap, nonempty lists of at most 20 values use the existing per-value rewrite. Larger positive, non-null literal string lists on a string column use a compact sorted domain. Other lists retain the existing per-value rewrite, so raising the cap can make those predicates expensive to build and evaluate. Defaults to 20. |
+| datafusion.execution.parquet.max_in_list_size | 20 | Maximum number of input values in an `IN (...)` list eligible for min/max pruning. Lists above this cap, or a cap of 0, skip this rewrite; other predicates and Bloom-filter pruning remain available. Within the cap, nonempty lists of at most 20 values use the existing per-value rewrite. Larger literal lists use a compact representation when the column type is string, variable-length binary, integer, decimal, date, time, timestamp, or duration. This applies to both `IN` and `NOT IN`, including lists with NULL members. `NOT IN` with NULL and all-NULL `IN` lists cannot match any rows. Compact lists containing NULL do not use the fully-matched-row-group optimization. Floating-point and other lists retain the existing per-value rewrite, so raising the cap can make those predicates expensive to build and evaluate. Defaults to 20. |
| datafusion.execution.parquet.data_pagesize_limit | 1048576 | (writing) Sets best effort maximum size of data page in bytes |
| datafusion.execution.parquet.write_batch_size | 1024 | (writing) Sets write_batch_size in rows |
| datafusion.execution.parquet.writer_version | 1.0 | (writing) Sets parquet writer version valid values are "1.0" and "2.0" |
@@ -104,7 +104,7 @@ The following configuration settings are available:
| datafusion.execution.parquet.statistics_enabled | page | (writing) Sets if statistics are enabled for any column Valid values are: "none", "chunk", and "page" These values are not case sensitive. If NULL, uses default parquet writer setting |
| datafusion.execution.parquet.max_row_group_size | 1048576 | (writing) Target maximum number of rows in each row group (defaults to 1M rows). Writing larger row groups requires more memory to write, but can get better compression and be faster to read. When `max_row_group_bytes` is also set, the writer flushes a row group when either limit is reached, whichever comes first. |
| datafusion.execution.parquet.max_row_group_bytes | NULL | (writing) Target maximum size of each row group in bytes. When set, the writer flushes whenever either this limit or `max_row_group_size` is reached, whichever comes first. Useful for bounding writer memory on wide schemas where a row-count limit can map to very different byte sizes. Matches the behavior of `parquet.block.size` in parquet-mr. If `None` (the default), only the row-count limit applies. Currently only honored when `allow_single_file_parallelism` is `false`; by default the parallel file writer ignores this limit. |
-| datafusion.execution.parquet.created_by | datafusion version 55.0.0 | (writing) Sets "created by" property |
+| datafusion.execution.parquet.created_by | datafusion version 55.1.0 | (writing) Sets "created by" property |
| datafusion.execution.parquet.column_index_truncate_length | 64 | (writing) Sets column index truncate length |
| datafusion.execution.parquet.statistics_truncate_length | 64 | (writing) Sets statistics truncate length. If NULL, uses default parquet writer setting |
| datafusion.execution.parquet.data_page_row_count_limit | 20000 | (writing) Sets best effort maximum number of rows in data page |
@@ -112,7 +112,7 @@ The following configuration settings are available:
| datafusion.execution.parquet.bloom_filter_on_write | false | (writing) Write bloom filters for all columns when creating parquet files |
| datafusion.execution.parquet.bloom_filter_fpp | NULL | (writing) Sets bloom filter false positive probability. If NULL, uses default parquet writer setting |
| datafusion.execution.parquet.bloom_filter_ndv | NULL | (writing) Sets bloom filter number of distinct values. If NULL, uses default parquet writer setting |
-| datafusion.execution.parquet.allow_single_file_parallelism | true | (writing) Controls whether DataFusion will attempt to speed up writing parquet files by serializing them in parallel. Each column in each row group in each output file are serialized in parallel leveraging a maximum possible core count of n_files*n_row_groups*n_columns. |
+| datafusion.execution.parquet.allow_single_file_parallelism | true | (writing) Controls whether DataFusion will attempt to speed up writing parquet files by serializing them in parallel. Each column in each row group in each output file are serialized in parallel leveraging a maximum possible core count of n_files\*n_row_groups\*n_columns. |
| datafusion.execution.parquet.maximum_parallel_row_group_writers | 1 | (writing) By default parallel parquet writer is tuned for minimum memory usage in a streaming execution plan. You may see a performance benefit when writing large parquet files by increasing maximum_parallel_row_group_writers and maximum_buffered_record_batches_per_stream if your system has idle cores and can tolerate additional memory usage. Boosting these values is likely worthwhile when writing out already in-memory data, such as from a cached data frame. |
| datafusion.execution.parquet.maximum_buffered_record_batches_per_stream | 2 | (writing) By default parallel parquet writer is tuned for minimum memory usage in a streaming execution plan. You may see a performance benefit when writing large parquet files by increasing maximum_parallel_row_group_writers and maximum_buffered_record_batches_per_stream if your system has idle cores and can tolerate additional memory usage. Boosting these values is likely worthwhile when writing out already in-memory data, such as from a cached data frame. |
| datafusion.execution.parquet.content_defined_chunking.enabled | false | (writing) EXPERIMENTAL: Enable content-defined chunking (CDC) when writing parquet files. When enabled, parallel writing is automatically disabled since the chunker state must persist across row groups. |
@@ -121,15 +121,17 @@ The following configuration settings are available:
| datafusion.execution.parquet.content_defined_chunking.norm_level | 0 | Normalization level. Increasing this improves deduplication ratio but increases fragmentation. Recommended range is [-3, 3], default is 0. |
| datafusion.execution.planning_concurrency | 0 | Fan-out during initial physical planning. This is mostly use to plan `UNION` children in parallel. Defaults to the number of CPU cores on the system |
| datafusion.execution.skip_physical_aggregate_schema_check | false | When set to true, skips verifying that the schema produced by planning the input of `LogicalPlan::Aggregate` exactly matches the schema of the input plan. When set to false, if the schema does not match exactly (including nullability and metadata), a planning error will be raised. This is used to workaround bugs in the planner that are now caught by the new schema verification step. |
-| datafusion.execution.enable_migration_aggregate | true | Temporary switch for aggregate stream implementations that are being migrated from `GroupedHashAggregateStream`. When set to true, DataFusion tries the migrated implementations when their preconditions are satisfied. When set to false, grouped aggregation falls back to `GroupedHashAggregateStream`. This option will be removed after the migration is finished. See for details. |
+| datafusion.execution.enable_migration_aggregate | true | Whether aggregation uses the implementation from the major refactor completed in the 56.0.0 release. When set to `false`, aggregation falls back to the implementation used before 55.0.0. The fallback exists only as a workaround for bugs in the new implementation and will be removed, together with this option, after the 56.0.0 release. See for details. |
| datafusion.execution.spill_compression | uncompressed | Sets the compression codec used when spilling data to disk. Since datafusion writes spill files using the Arrow IPC Stream format, only codecs supported by the Arrow IPC Stream Writer are allowed. Valid values are: uncompressed, lz4_frame, zstd. Note: lz4_frame offers faster (de)compression, but typically results in larger spill files. In contrast, zstd achieves higher compression ratios at the cost of slower (de)compression speed. |
| datafusion.execution.sort_spill_reservation_bytes | 10485760 | Specifies the reserved memory for each spillable sort operation to facilitate an in-memory merge. When a sort operation spills to disk, the in-memory data must be sorted and merged before being written to a file. This setting reserves a specific amount of memory for that in-memory sort/merge process. Note: This setting is irrelevant if the sort operation cannot spill (i.e., if there's no `DiskManager` configured). |
| datafusion.execution.sort_in_place_threshold_bytes | 1048576 | When sorting, below what size should data be concatenated and sorted in a single RecordBatch rather than sorted in batches and merged. |
| datafusion.execution.sort_pushdown_buffer_capacity | 1073741824 | Maximum buffer capacity (in bytes) per partition for BufferExec inserted during sort pushdown optimization. When PushdownSort eliminates a SortExec under SortPreservingMergeExec, a BufferExec is inserted to replace SortExec's buffering role. This prevents I/O stalls by allowing the scan to run ahead of the merge. This uses strictly less memory than the SortExec it replaces (which buffers the entire partition). The buffer respects the global memory pool limit. Setting this to a large value is safe — actual memory usage is bounded by partition size and global memory limits. |
| datafusion.execution.max_spill_file_size_bytes | 134217728 | Maximum size in bytes for individual spill files before rotating to a new file. When operators spill data to disk (e.g., RepartitionExec), they write multiple batches to the same file until this size limit is reached, then rotate to a new file. This reduces syscall overhead compared to one-file-per-batch while preventing files from growing too large. A larger value reduces file creation overhead but may hold more disk space. A smaller value creates more files but allows finer-grained space reclamation as files can be deleted once fully consumed. Now only `RepartitionExec` supports this spill file rotation feature, other spilling operators may create spill files larger than the limit. Default: 128 MB |
+| datafusion.execution.enable_nlj_coordinated_fallback | true | Enables the memory-limited fallback for `NestedLoopJoinExec` join types that emit unmatched left rows in the final output (LEFT, LEFT SEMI, LEFT ANTI, LEFT MARK, FULL) when the right side has multiple partitions. This fallback shares left-side state (the current left chunk, the visited bitmap and the probe-thread counter) across all right-side partitions, which assumes every partition runs in the same process. Distributed engines that execute each output partition as an independent task (e.g. Ballista, datafusion-distributed) give each task its own copy of this state and poll only one partition, so the cross-partition counter never reaches zero and the fallback would stall. Such engines should set this to `false`: the coordinated fallback is then disabled for left-emitting multi-partition joins, which instead fail with a resource-exhaustion error under memory pressure rather than deadlocking. Single-partition and non-left-emitting joins are unaffected and always keep the fallback. |
| datafusion.execution.meta_fetch_concurrency | 32 | Number of files to read in parallel when inferring schema and statistics |
-| datafusion.execution.minimum_parallel_output_files | 4 | Guarantees a minimum level of output files running in parallel. RecordBatches will be distributed in round robin fashion to each parallel writer. Each writer is closed and a new file opened once soft_max_rows_per_output_file is reached. |
+| datafusion.execution.minimum_parallel_output_files | 4 | Guarantees a minimum level of output files running in parallel. RecordBatches will be distributed in round robin fashion to each parallel writer. Each writer is closed and a new file opened once soft_max_rows_per_output_file or soft_max_bytes_per_output_file is reached. |
| datafusion.execution.soft_max_rows_per_output_file | 50000000 | Target number of rows in output files when writing multiple. This is a soft max, so it can be exceeded slightly. There also will be one file smaller than the limit if the total number of rows written is not roughly divisible by the soft max |
+| datafusion.execution.soft_max_bytes_per_output_file | 4294967295 | Target encoded size in bytes of output files when writing multiple. Writers asynchronously report the cumulative encoded size as they process RecordBatches. The final file size may exceed this limit due to batches buffered before the limit is observed, the size of a batch, and file metadata written when the file is finalized. |
| datafusion.execution.max_buffered_batches_per_output_file | 2 | This is the maximum number of RecordBatches buffered for each output file being worked. Higher values can potentially give faster write performance at the cost of higher peak memory consumption. This budget is split evenly between two independent points in the write pipeline (see the demuxer diagram in #7791): how many files can be in flight from the demuxer to a writer task, and how many RecordBatches are buffered for a single file's writer. Must be at least 2 so each half gets at least 1 unit of buffering - 0 or 1 would leave one side with a zero-capacity channel and panic at write time. |
| datafusion.execution.listing_table_ignore_subdirectory | true | Should sub directories be ignored when scanning directories for data files. Defaults to true (ignores subdirectories), consistent with Hive. Note that this setting does not affect reading partitioned tables (e.g. `/table/year=2021/month=01/data.parquet`). |
| datafusion.execution.listing_table_factory_infer_partitions | true | Should a `ListingTable` created through the `ListingTableFactory` infer table partitions from Hive compliant directories. Defaults to true (partition columns are inferred and will be represented in the table schema). |
@@ -140,7 +142,7 @@ The following configuration settings are available:
| datafusion.execution.skip_partial_aggregation_probe_ratio_threshold | 0.8 | Aggregation ratio (number of distinct groups / number of input rows) threshold for skipping partial aggregation. If the value is greater then partial aggregation will skip aggregation for further input |
| datafusion.execution.skip_partial_aggregation_probe_rows_threshold | 100000 | Number of input rows partial aggregation partition should process, before aggregation ratio check and trying to switch to skipping aggregation mode |
| datafusion.execution.use_row_number_estimates_to_optimize_partitioning | false | Should DataFusion use row number estimates at the input to decide whether increasing parallelism is beneficial or not. By default, only exact row numbers (not estimates) are used for this decision. Setting this flag to `true` will likely produce better plans. if the source of statistics is accurate. We plan to make this the default in the future. |
-| datafusion.execution.enforce_batch_size_in_joins | false | Should DataFusion enforce batch size in joins or not. By default, DataFusion will not enforce batch size in joins. Enforcing batch size in joins can reduce memory usage when joining large tables with a highly-selective join filter, but is also slightly slower. |
+| datafusion.execution.enforce_batch_size_in_joins | false | Should DataFusion enforce batch size in joins or not. By default, DataFusion will not enforce batch size in joins. Enforcing batch size in joins can reduce memory usage when joining large tables with a highly-selective join filter, but is also slightly slower. Note: this option currently only applies to the symmetric hash join. |
| datafusion.execution.objectstore_writer_buffer_size | 10485760 | Size (bytes) of data buffer DataFusion uses when writing output files. This affects the size of the data chunks that are uploaded to remote object stores (e.g. AWS S3). If very large (>= 100 GiB) output files are being written, it may be necessary to increase this size to avoid errors from the remote end point. |
| datafusion.execution.enable_ansi_mode | false | Whether to enable ANSI SQL mode. The flag is experimental and relevant only for DataFusion Spark built-in functions When `enable_ansi_mode` is set to `true`, the query engine follows ANSI SQL semantics for expressions, casting, and error handling. This means: - **Strict type coercion rules:** implicit casts between incompatible types are disallowed. - **Standard SQL arithmetic behavior:** operations such as division by zero, numeric overflow, or invalid casts raise runtime errors rather than returning `NULL` or adjusted values. - **Consistent ANSI behavior** for string concatenation, comparisons, and `NULL` handling. When `enable_ansi_mode` is `false` (the default), the engine uses a more permissive, non-ANSI mode designed for user convenience and backward compatibility. In this mode: - Implicit casts between types are allowed (e.g., string to integer when possible). - Arithmetic operations are more lenient — for example, `abs()` on the minimum representable integer value returns the input value instead of raising overflow. - Division by zero or invalid casts may return `NULL` instead of failing. # Default `false` — ANSI SQL mode is disabled by default. |
| datafusion.execution.hash_join_buffering_capacity | 0 | How many bytes to buffer in the probe side of hash joins while the build side is concurrently being built. Without this, hash joins will wait until the full materialization of the build side before polling the probe side. This is useful in scenarios where the query is not completely CPU bounded, allowing to do some early work concurrently and reducing the latency of the query. Note that when hash join buffering is enabled, the probe side will start eagerly polling data, not giving time for the producer side of dynamic filters to produce any meaningful predicate. Queries with dynamic filters might see performance degradation. Disabled by default, set to a number greater than 0 for enabling it. |
@@ -199,7 +201,7 @@ The following configuration settings are available:
| datafusion.sql_parser.support_varchar_with_length | true | If true, permit lengths for `VARCHAR` such as `VARCHAR(20)`, but ignore the length. If false, error if a `VARCHAR` with a length is specified. The Arrow type system does not have a notion of maximum string length and thus DataFusion can not enforce such limits. |
| datafusion.sql_parser.map_string_types_to_utf8view | true | If true, string types (VARCHAR, CHAR, Text, and String) are mapped to `Utf8View` during SQL planning. If false, they are mapped to `Utf8`. Default is true. |
| datafusion.sql_parser.collect_spans | false | When set to true, the source locations relative to the original SQL query (i.e. [`Span`](https://docs.rs/sqlparser/latest/sqlparser/tokenizer/struct.Span.html)) will be collected and recorded in the logical plan nodes. |
-| datafusion.sql_parser.recursion_limit | 50 | Specifies the recursion depth limit when parsing complex SQL Queries |
+| datafusion.sql_parser.recursion_limit | 51 | Specifies the recursion depth limit when parsing complex SQL Queries |
| datafusion.sql_parser.default_null_ordering | nulls_max | Specifies the default null ordering for query results. There are 4 options: - `nulls_max`: Nulls appear last in ascending order. - `nulls_min`: Nulls appear first in ascending order. - `nulls_first`: Nulls always be first in any order. - `nulls_last`: Nulls always be last in any order. By default, `nulls_max` is used to follow Postgres's behavior. postgres rule: |
| datafusion.sql_parser.enable_subquery_sort_elimination | true | When set to true, DataFusion may remove `ORDER BY` clauses from subqueries or CTEs during SQL planning when their ordering cannot affect the result, such as when no `LIMIT` or other order-sensitive operator depends on them. Disable this option to preserve explicit subquery ordering in the planned query. |
| datafusion.format.safe | true | If set to `true` any formatting errors will be written to the output instead of being converted into a [`std::fmt::Error`] |
diff --git a/_sources/user-guide/crate-configuration.md.txt b/_sources/user-guide/crate-configuration.md.txt
index 09c65107e58c8..75ac2fbdde939 100644
--- a/_sources/user-guide/crate-configuration.md.txt
+++ b/_sources/user-guide/crate-configuration.md.txt
@@ -156,7 +156,7 @@ By default, Datafusion returns errors as a plain text message. You can enable mo
such as backtraces by enabling the `backtrace` feature to your `Cargo.toml` file like this:
```toml
-datafusion = { version = "55.0.0", features = ["backtrace"]}
+datafusion = { version = "55.1.0", features = ["backtrace"]}
```
Set environment [variables](https://doc.rust-lang.org/std/backtrace/index.html#environment-variables)
diff --git a/_sources/user-guide/example-usage.md.txt b/_sources/user-guide/example-usage.md.txt
index 3d89405385c05..8c96b3e82dfc3 100644
--- a/_sources/user-guide/example-usage.md.txt
+++ b/_sources/user-guide/example-usage.md.txt
@@ -29,7 +29,7 @@ Find latest available Datafusion version on [DataFusion's
crates.io] page. Add the dependency to your `Cargo.toml` file:
```toml
-datafusion = "55.0.0"
+datafusion = "55.1.0"
tokio = { version = "1.0", features = ["rt-multi-thread"] }
```
diff --git a/_sources/user-guide/explain-usage.md.txt b/_sources/user-guide/explain-usage.md.txt
index 43ea6caac3a7a..b073313c6a0a4 100644
--- a/_sources/user-guide/explain-usage.md.txt
+++ b/_sources/user-guide/explain-usage.md.txt
@@ -233,6 +233,7 @@ When predicate pushdown is enabled, `DataSourceExec` with `ParquetSource` gains
- `row_groups_pruned_bloom_filter`: number of row groups evaluated by Bloom Filters, reporting both total checked groups and groups that matched.
- `row_groups_pruned_statistics`: number of row groups evaluated by row-group statistics (min/max), reporting both total checked groups and groups that matched.
- `limit_pruned_row_groups`: number of row groups pruned by the limit.
+- `limit_pruned_rows`: number of rows skipped by limit pruning when fully matched page ranges contain enough rows to satisfy the limit.
- `pushdown_rows_matched`: rows that were tested by any of the above filters, and passed all of them.
- `pushdown_rows_pruned`: rows that were tested by any of the above filters, and did not pass at least one of them.
- `predicate_evaluation_errors`: number of times evaluating the filter expression failed (expected to be zero in normal operation)
diff --git a/_sources/user-guide/expressions.md.txt b/_sources/user-guide/expressions.md.txt
index 3fbc11e0c92c0..55f64135dd0fb 100644
--- a/_sources/user-guide/expressions.md.txt
+++ b/_sources/user-guide/expressions.md.txt
@@ -191,7 +191,7 @@ select log(-1), log(0), sqrt(-1);
| lpad(text, length, [, fill]) | Extends the string to length (`length`) by prepending the characters (`fill`) (a space by default). Example: `lpad('bb', 5, 'a') → aaabb` |
| ltrim(text, text) | Removes all specified characters (`characters`) from the beginning of the string (`text`). Example: `ltrim('aabchelloccb', 'abc') -> helloccb` |
| md5(text) | Computes the MD5 hash of the argument (`text`). |
-| octet_length(text) | Returns number of bytes in the string (`text`). |
+| octet_length(text) | Returns number of bytes in the string or binary (`text`). |
| repeat(text, number) | Repeats the string the specified number of times. Example: `repeat('1', 4) -> 1111` |
| replace(string, from, to) | Replaces a specified string (`from`) with another specified string (`to`) in the string (`string`). Example: `replace('Hello', 'replace', 'el') -> Hola` |
| reverse(text) | Reverses the order of the characters in the string (`text`). Example: `reverse('hello') -> olleh` |
diff --git a/_sources/user-guide/metrics.md.txt b/_sources/user-guide/metrics.md.txt
index 306094c438eb7..111df66ccc08a 100644
--- a/_sources/user-guide/metrics.md.txt
+++ b/_sources/user-guide/metrics.md.txt
@@ -61,6 +61,146 @@ subsequent join processing time.
| avg_fanout | Average number of build-side join-key matches per matched probe-side row before applying any join filter. |
| array_map_created_count | Number of times `HashJoinExec` created an `ArrayMap` for perfect hash join lookup execution. |
+### AggregateExec
+
+`AggregateExec` exposes the common `BaselineMetrics`, the operator-level
+metrics below, and a timer per aggregate expression and execution phase.
+
+| Metric | Description |
+| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
+| time_calculating_group_ids | Time spent preparing group keys; see the note below for path-specific coverage. |
+| aggregate_arguments_time | Total time spent evaluating the inputs to the aggregate functions. `agg_expr_{index}_arguments_time` breaks this down per expression. |
+| aggregation_time | Time spent invoking accumulator `update` and `merge` operations. |
+| emitting_time | Time spent materializing group values and accumulator `state` or `evaluate` results. |
+| topk_maintenance_time | Time spent maintaining Grouped TopK's priority map, including batch setup, insertion, comparison, and NULL handling. |
+| skipped_aggregation_rows | Number of input rows passed through without aggregating them, when partial aggregation is skipped. |
+| reduction_factor | Rows emitted per row consumed by a partial aggregation, displayed as `66.67% (2/3)`. |
+| spill_count | Number of spill files written when the aggregation exceeds its memory budget. |
+| spilled_bytes | Total number of bytes written to spill files. |
+| spilled_rows | Total number of rows written to spill files. |
+| peak_mem_used | Peak tracked memory held by the grouped aggregation, in bytes; recorded by the fallback grouped hash path only. |
+
+These operator-level metrics are recorded by the grouped aggregation paths
+only: an `AggregateExec` without a `GROUP BY` reports just `BaselineMetrics`
+and the per-aggregate timers. `reduction_factor` and `skipped_aggregation_rows`
+are recorded in partial mode only. `skipped_aggregation_rows` is recorded only
+when partial-aggregation skipping is enabled for a single, non-grouping-sets
+`GROUP BY` whose input is not ordered by its grouping expressions; a
+`datafusion.execution.skip_partial_aggregation_probe_ratio_threshold` of `>= 1.0`
+disables the feature.
+
+`time_calculating_group_ids` covers both grouping-expression evaluation and
+resolving the resulting rows to group IDs, including interning and ordering
+setup. `aggregation_time` covers only accumulator `update` and `merge` calls.
+On accumulator-backed grouped aggregation paths, `state` and `evaluate` are
+included in `emitting_time`, including when partial aggregation materializes
+state under memory pressure. For an `AggregateExec` without a `GROUP BY`, the
+per-aggregate `state` and `evaluate` timers are recorded during
+`elapsed_compute`; it does not report grouped operator metrics such as
+`emitting_time`. Partial aggregation that skips aggregation reports
+`convert_to_state` instead of `aggregation_time` for those rows.
+
+When the specialized Grouped TopK path is selected for a limited grouped
+aggregate, it has no accumulators. Its group-key expression evaluation is
+included in `time_calculating_group_ids`, and its priority-map work is reported
+by `topk_maintenance_time`; it does not report accumulator phases. Planner
+selection is query-shape dependent: a limited `DISTINCT` query without
+ordering requirements uses the regular aggregate path instead.
+
+The per-aggregate timers are named `agg_expr_{index}_{phase}_time`, where
+`index` is the zero-based position of an aggregate expression in the operator
+and `phase` is one of the following:
+
+| Phase | Description |
+| ------------------ | --------------------------------------------------------------------------------------------- |
+| `arguments` | Evaluating the aggregate's argument expressions into input arrays. |
+| `update` | Updating an accumulator from raw input values. |
+| `merge` | Merging partial accumulator states. |
+| `state` | Obtaining an accumulator's intermediate state for partial output or aggregate spilling. |
+| `convert_to_state` | Converting raw aggregate inputs directly to partial state without normal accumulator updates. |
+| `evaluate` | Evaluating an accumulator to its final result. |
+
+For example, when a partial stage is planned, the partial `AggregateExec` for
+`SELECT SUM(a), SUM(b) FROM t` reports `agg_expr_0_arguments_time` and
+`agg_expr_0_update_time` for `SUM(a)`,
+and `agg_expr_1_arguments_time` and `agg_expr_1_update_time` for `SUM(b)`. The
+index is positional and refers to the same position in the `aggr=[...]` list
+printed on the operator's plan line, which is how an indexed timer is mapped
+back to an aggregate expression. Because the index is part of the metric name,
+otherwise identical functions over different columns stay distinct when
+per-partition metrics are combined.
+
+Each per-aggregate timer additionally carries an `aggregate` label holding the
+rendered aggregate expression (for example, `sum(t.a)`). Combining metrics
+across partitions drops labels, so this label is only shown in the "Plan with
+Full Metrics" section of `EXPLAIN ANALYZE VERBOSE`, which reports metrics per
+partition.
+
+`arguments` is recorded in every mode. The accumulator phases that are present
+depend on the aggregate mode and implementation. For non-grouped aggregation,
+partial mode records `update` and `state`, partial reduce mode records `merge`
+and `state`, final mode records `merge` and `evaluate`, and single mode records
+`update` and `evaluate`. Hash aggregation uses `update`, `state`, and
+`convert_to_state` in partial mode; `merge` and `state` in partial-reduce mode;
+`merge`, `state`, and `evaluate` in final mode; and `update`, `state`, `merge`,
+and `evaluate` in single mode. Its `state` timers measure intermediate-state
+emission, including during spilling. The grouped TopK aggregate path records
+only the per-aggregate `arguments` timer, because it maintains values directly
+rather than using accumulators.
+
+Where an aggregate has a `FILTER` clause, its evaluation is included in
+`aggregate_arguments_time`. Per-aggregate `arguments` timers include the filter
+when it is evaluated per aggregate. The legacy grouped hash path evaluates
+filters collectively, so its per-aggregate `arguments` timers cover argument
+expressions only; their sum need not equal `aggregate_arguments_time`.
+
+Aggregate implementations can also expose optional internal submetrics. These
+use the `agg_expr_{index}_internal_{subphase}_time` naming and `aggregate`
+label. The `internal` segment keeps them separate from call-boundary timers;
+`subphase` is a stable identifier owned and documented by the aggregate
+implementation. They are registered lazily only when an aggregate requests
+them, so aggregates without internal submetrics add no metrics. Registration
+is per `(aggregate expression index, subphase, partition)`: replacement
+accumulators in that partition share the same time, and normal metric display
+combines that time across partitions. An aggregate may request its submetric
+during accumulator construction, so it can appear even when its input is empty.
+For example, `array_agg(DISTINCT ...)` records the time spent deduplicating
+input values as `agg_expr_{index}_internal_distinct_time`. Grouped accumulation
+records this once per input batch, rather than once per group, to avoid making
+metric collection proportional to group cardinality. These submetrics complement
+the `update`, `merge`, `state`, and `evaluate` timers rather than subdividing or
+replacing them. An internal submetric may therefore overlap its enclosing phase
+timer; it is a supplementary diagnostic and must not be added to phase timings
+as a breakdown.
+
+Except for the `Summary` metric `reduction_factor`, these operator-level and
+per-aggregate metrics are `Dev` metrics. They appear in `EXPLAIN ANALYZE` when
+`datafusion.explain.analyze_level` includes `Dev` (the default), but are omitted
+at the `Summary` level. The normal display combines partitions; use `EXPLAIN ANALYZE VERBOSE` to additionally show the per-partition values together with
+each per-aggregate timer's `aggregate` label. For a query
+such as the following, the per-expression metrics stay readable, and the
+operator's `aggr=[...]` list names the aggregate behind each timer index:
+
+```sql
+EXPLAIN ANALYZE
+SELECT k, SUM(a), SUM(b), COUNT(c)
+FROM t
+GROUP BY k;
+```
+
+The abbreviated partial-aggregate plan line below shows that mapping (timings
+and unrelated metrics are omitted):
+
+```text
+AggregateExec: mode=Partial, gby=[k@0 as k], aggr=[sum(t.a), sum(t.b), count(t.c)],
+ metrics=[..., agg_expr_0_arguments_time=..., agg_expr_1_arguments_time=...,
+ agg_expr_2_arguments_time=...]
+```
+
+Thus `agg_expr_0_*` is `sum(t.a)`, `agg_expr_1_*` is `sum(t.b)`, and
+`agg_expr_2_*` is `count(t.c)`. In verbose output, the corresponding
+`aggregate` labels provide the same mapping per partition.
+
## TODO
Add metrics for the remaining operators
diff --git a/_sources/user-guide/sql/aggregate_functions.md.txt b/_sources/user-guide/sql/aggregate_functions.md.txt
index 4569a8850c076..2d59970b0067b 100644
--- a/_sources/user-guide/sql/aggregate_functions.md.txt
+++ b/_sources/user-guide/sql/aggregate_functions.md.txt
@@ -247,10 +247,10 @@ bool_and(expression)
### `bool_or`
-Returns true if all non-null input values are true, otherwise false.
+Returns true if any non-null input value is true, otherwise false.
```sql
-bool_and(expression)
+bool_or(expression)
```
#### Arguments
@@ -260,9 +260,9 @@ bool_and(expression)
#### Example
```sql
-> SELECT bool_and(column_name) FROM table_name;
+> SELECT bool_or(column_name) FROM table_name;
+----------------------------+
-| bool_and(column_name) |
+| bool_or(column_name) |
+----------------------------+
| true |
+----------------------------+
@@ -644,10 +644,10 @@ _Alias of [covar_samp](#covar_samp)._
### `covar_pop`
-Returns the sample covariance of a set of number pairs.
+Returns the population covariance of a set of number pairs.
```sql
-covar_samp(expression1, expression2)
+covar_pop(expression1, expression2)
```
#### Arguments
@@ -658,11 +658,11 @@ covar_samp(expression1, expression2)
#### Example
```sql
-> SELECT covar_samp(column1, column2) FROM table_name;
+> SELECT covar_pop(column1, column2) FROM table_name;
+-----------------------------------+
-| covar_samp(column1, column2) |
+| covar_pop(column1, column2) |
+-----------------------------------+
-| 8.25 |
+| 7.63333333333 |
+-----------------------------------+
```
diff --git a/_sources/user-guide/sql/data_types.md.txt b/_sources/user-guide/sql/data_types.md.txt
index 2e75fce6c7aa9..39442d38c497d 100644
--- a/_sources/user-guide/sql/data_types.md.txt
+++ b/_sources/user-guide/sql/data_types.md.txt
@@ -105,12 +105,42 @@ The maximum supported precision for `DECIMAL` types is 76.
## Date/Time Types
-| SQL DataType | Arrow DataType |
-| ------------ | :------------------------------- |
-| `DATE` | `Date32` |
-| `TIME` | `Time64(Nanosecond)` |
-| `TIMESTAMP` | `Timestamp(Nanosecond, None)` |
-| `INTERVAL` | `Interval(IntervalMonthDayNano)` |
+| SQL DataType | Arrow DataType |
+| ------------------------------------------------------------- | :--------------------------------------------------------- |
+| `DATE` | `Date32` |
+| `TIME` | `Time64(Nanosecond)` |
+| `TIMESTAMP`, `TIMESTAMP(p)`, `TIMESTAMP(p) WITHOUT TIME ZONE` | `Timestamp(unit, None)` |
+| `TIMESTAMPTZ(p)`, `TIMESTAMP(p) WITH TIME ZONE` | `Timestamp(unit, None)` by default — see the warning below |
+| `INTERVAL` | `Interval(MonthDayNano)` |
+
+:::{warning}
+`TIMESTAMPTZ` and `TIMESTAMP WITH TIME ZONE` do **not** give a timezone-aware
+type by default. The zone comes from the
+[`datafusion.execution.time_zone`] setting, and that setting is unset unless you
+set it. So `'2024-01-01T12:00:00Z'::timestamptz` gives `Timestamp(unit, None)`
+by default: the result type does not keep timezone metadata.
+
+An explicit offset in the input is still applied. DataFusion normalizes the
+value to UTC. For example, with the default setting,
+`'2024-01-01T12:00:00+07:00'::timestamptz` gives `2024-01-01T05:00:00`. It is
+not read as the local time `12:00:00`.
+
+This is a known bug. See [issue #25166]. PostgreSQL and DuckDB always give an
+aware type here, because their session time zone always has a value.
+
+Set `datafusion.execution.time_zone` to make these types aware. `'UTC'` is a
+good value.
+:::
+
+`unit` comes from the optional precision `p` on the two `TIMESTAMP` rows. Use
+`0`, `3`, `6` or `9` for `Second`, `Millisecond`, `Microsecond` or `Nanosecond`.
+DataFusion rejects each other value of `p`. If you omit `p`, the unit is
+`Nanosecond`. The precision goes after `TIMESTAMPTZ`, but before
+`WITH TIME ZONE`: use `TIMESTAMPTZ(3)` or `TIMESTAMP(3) WITH TIME ZONE`.
+`DATE`, `TIME` and `INTERVAL` do not accept a precision.
+
+[`datafusion.execution.time_zone`]: ../configs.md
+[issue #25166]: https://github.com/apache/datafusion/issues/25166
## Boolean Types
diff --git a/_sources/user-guide/sql/ddl.md.txt b/_sources/user-guide/sql/ddl.md.txt
index 0d76775bcc1c6..8382795e74306 100644
--- a/_sources/user-guide/sql/ddl.md.txt
+++ b/_sources/user-guide/sql/ddl.md.txt
@@ -22,17 +22,69 @@
DDL stands for "Data Definition Language" and relates to creating and
modifying catalog objects such as Tables.
-## CREATE DATABASE
+## CREATE CATALOG / CREATE DATABASE
-Create catalog with specified name.
+Create catalog with specified name. In DataFusion, `CREATE DATABASE` is an alias for `CREATE CATALOG`.
-CREATE DATABASE [ IF NOT EXISTS ] catalog
+CREATE CATALOG [ IF NOT EXISTS ] catalog
```sql
-- create catalog cat
-CREATE DATABASE cat;
+CREATE CATALOG cat;
+```
+
+## CREATE EXTERNAL CATALOG
+
+`CREATE EXTERNAL CATALOG` registers a catalog built by a registered
+[`CatalogProviderFactory`], such as a catalog backed by a remote catalog
+service (for example, an Iceberg REST catalog), so that it can be queried
+alongside DataFusion's built-in catalogs. A `CatalogProviderFactory` must
+first be registered on the `SessionState` with a key matching the
+`STORED AS` clause below — see the [Catalog Provider Factories] section of
+the Library User Guide for how to implement and register one.
+
+The supported syntax is:
+
+```sql
+CREATE [OR REPLACE] EXTERNAL CATALOG
+[ IF NOT EXISTS ]
+
+STORED AS
+[ LOCATION ]
+[ OPTIONS () ]
+
+ := (, , ...)
+```
+
+`catalog_type` identifies which registered `CatalogProviderFactory` to
+invoke; it is looked up the same way `file_type` is for
+[`CREATE EXTERNAL TABLE`](#create-external-table).
+
+```sql
+CREATE EXTERNAL CATALOG my_catalog
+STORED AS ICEBERG
+LOCATION 's3://bucket/warehouse'
+OPTIONS ('catalog.uri' 'http://rest-catalog:8181', 'warehouse' 'my_catalog');
+```
+
+[`catalogproviderfactory`]: https://docs.rs/datafusion/latest/datafusion/catalog/trait.CatalogProviderFactory.html
+[catalog provider factories]: ../../library-user-guide/catalogs.md#catalog-provider-factories
+
+## DROP CATALOG
+
+Removes a catalog previously registered with `CREATE EXTERNAL CATALOG` from
+DataFusion's catalog list.
+
+
+DROP CATALOG [ IF EXISTS ] catalog_name;
+
+
+```sql
+DROP CATALOG my_catalog;
+-- or use 'if exists' to silently ignore if the catalog doesn't exist
+DROP CATALOG IF EXISTS nonexistent_catalog;
```
## CREATE SCHEMA
diff --git a/_sources/user-guide/sql/dml.md.txt b/_sources/user-guide/sql/dml.md.txt
index 4934bc2674375..cd5947d983620 100644
--- a/_sources/user-guide/sql/dml.md.txt
+++ b/_sources/user-guide/sql/dml.md.txt
@@ -136,3 +136,94 @@ INSERT INTO table_name { VALUES ( expression [, ...]
| 2 |
+-------+
```
+
+## DELETE
+
+Removes rows from a table.
+
+
+DELETE FROM table_name [ WHERE condition ]
+
+
+`DELETE` returns the number of removed rows in a column named `count`.
+
+If you omit the `WHERE` clause, DataFusion removes all rows.
+
+DataFusion removes a row only if the condition is true for that row. SQL three-valued logic applies: if the condition evaluates to `NULL`, the row remains. For example, `WHERE value > 15` keeps a row with a `NULL` value, because `NULL > 15` is `NULL`.
+
+Not all tables support `DELETE`. See [Table support for DELETE and UPDATE](#table-support-for-delete-and-update).
+
+### Examples
+
+Remove the rows that match a condition:
+
+```sql
+> DELETE FROM target_table WHERE id > 1;
++-------+
+| count |
++-------+
+| 2 |
++-------+
+```
+
+Remove all rows:
+
+```sql
+> DELETE FROM target_table;
++-------+
+| count |
++-------+
+| 3 |
++-------+
+```
+
+## UPDATE
+
+Changes the values of existing rows.
+
+
+UPDATE table_name SET column = expression [, ...] [ WHERE condition ]
+
+
+`UPDATE` returns the number of affected rows in a column named `count`.
+
+If you omit the `WHERE` clause, DataFusion changes all rows. The three-valued logic of `DELETE` also applies here.
+
+Each assignment expression reads the row values from before the statement. `SET a = b, b = a` therefore exchanges the two values.
+
+Not all tables support `UPDATE`. See [Table support for DELETE and UPDATE](#table-support-for-delete-and-update).
+
+### Examples
+
+Set one column in the rows that match a condition:
+
+```sql
+> UPDATE target_table SET name = 'Baz' WHERE id = 2;
++-------+
+| count |
++-------+
+| 1 |
++-------+
+```
+
+Set two columns, one from an expression:
+
+```sql
+> UPDATE target_table SET value = value * 2, name = 'Doubled' WHERE id < 3;
++-------+
+| count |
++-------+
+| 2 |
++-------+
+```
+
+## Table support for DELETE and UPDATE
+
+Not all table providers support `DELETE` and `UPDATE`. In-memory tables created with `CREATE TABLE` support both statements. File-based tables created with `CREATE EXTERNAL TABLE` and views do not. Support for custom table providers depends on the provider.
+
+### Known limitations
+
+- Subqueries in `DELETE` and `UPDATE` conditions can affect unintended rows: [#24654](https://github.com/apache/datafusion/issues/24654).
+- `EXPLAIN DELETE` and `EXPLAIN UPDATE` can modify in-memory tables: [#24656](https://github.com/apache/datafusion/issues/24656).
+- `DELETE` ignores `LIMIT`: [#24998](https://github.com/apache/datafusion/issues/24998).
+- `UPDATE ... FROM` is not supported: [#19950](https://github.com/apache/datafusion/issues/19950).
diff --git a/_sources/user-guide/sql/scalar_functions.md.txt b/_sources/user-guide/sql/scalar_functions.md.txt
index bdc8efb1bd15d..1ba1e8c820005 100644
--- a/_sources/user-guide/sql/scalar_functions.md.txt
+++ b/_sources/user-guide/sql/scalar_functions.md.txt
@@ -1663,7 +1663,7 @@ trim(LEADING trim_str FROM str)
### `octet_length`
-Returns the length of a string in bytes.
+Returns the length of a string or binary in bytes.
```sql
octet_length(str)
@@ -1671,7 +1671,7 @@ octet_length(str)
#### Arguments
-- **str**: String expression to operate on. Can be a constant, column, or function, and any combination of operators.
+- **str**: String or binary expression to operate on. Can be a constant, column, or function, and any combination of operators.
#### Example
@@ -2563,6 +2563,11 @@ date_part(part, expression)
- doy (day of the year)
- epoch (seconds since Unix epoch for timestamps/dates, total seconds for intervals)
- isodow (ISO 8601 day of the week where Monday is 1 and Sunday is 7)
+ - timezone (UTC offset in seconds)
+ - timezone_hour (whole hours of the UTC offset)
+ - timezone_minute (whole minutes of the UTC offset, excluding the hours)
+
+ The `timezone`, `timezone_hour` and `timezone_minute` parts are only defined for timestamps that carry a timezone; extracting them from a timezone-naive timestamp, a date, a time or an interval is an error. They report the offset that applies at that instant, so they follow daylight saving time: `Europe/Brussels` yields `3600` in January and `7200` in July. For a negative offset each non-zero part carries the sign, so `America/St_Johns` in January yields `-3` hours and `-30` minutes. An offset smaller than one hour has a zero hour part, which cannot show a sign: `Africa/Monrovia` before 1972 yields `0` hours and `-43` minutes.
- **expression**: Time expression to operate on. Can be a constant, column, or function.
@@ -2581,6 +2586,12 @@ date_part(part, expression)
+----------------------------------------------------+
| 1 |
+----------------------------------------------------+
+> SELECT date_part('timezone', TIMESTAMP '2024-07-01T12:00:00' AT TIME ZONE 'Europe/Brussels') AS utc_offset_seconds;
++--------------------+
+| utc_offset_seconds |
++--------------------+
+| 7200 |
++--------------------+
```
#### Alternative Syntax
@@ -2659,7 +2670,13 @@ _Alias of [date_trunc](#date_trunc)._
### `from_unixtime`
-Converts an integer to RFC3339 timestamp format (`YYYY-MM-DDT00:00:00.000000000Z`). Integers and unsigned integers are interpreted as seconds since the unix epoch (`1970-01-01T00:00:00Z`) return the corresponding timestamp.
+Converts an integer to a timestamp with second precision (`Timestamp(Second)`).
+The integer is interpreted as the number of seconds since the unix epoch
+(`1970-01-01T00:00:00Z`).
+
+If the optional `timezone` argument is omitted, the timestamp is returned in the
+session time zone (`datafusion.execution.time_zone`), which is unset (i.e.
+timezone-naive) by default.
```sql
from_unixtime(expression[, timezone])
@@ -2668,7 +2685,7 @@ from_unixtime(expression[, timezone])
#### Arguments
- **expression**: The expression to operate on. Can be a constant, column, or function, and any combination of operators.
-- **timezone**: Optional timezone to use when converting the integer to a timestamp. If not provided, the default timezone is UTC.
+- **timezone**: Optional timezone to use when converting the integer to a timestamp. If not provided, the session time zone (`datafusion.execution.time_zone`) is used, which is unset (timezone-naive) by default.
#### Example
@@ -2679,6 +2696,15 @@ from_unixtime(expression[, timezone])
+-----------------------------------------------------------+
| 2020-09-08T09:42:29-04:00 |
+-----------------------------------------------------------+
+
+-- Without an explicit timezone the session time zone is used
+> SET datafusion.execution.time_zone = 'America/New_York';
+> select from_unixtime(1599572549);
++----------------------------------+
+| from_unixtime(Int64(1599572549)) |
++----------------------------------+
+| 2020-09-08T09:42:29-04:00 |
++----------------------------------+
```
### `make_date`
@@ -4832,7 +4858,7 @@ _Alias of [inner_product](#inner_product)._
### `empty`
-Returns 1 for an empty array or 0 for a non-empty array.
+Returns true for an empty array or false for a non-empty array.
```sql
empty(array)
@@ -4849,7 +4875,7 @@ empty(array)
+------------------+
| empty(List([1])) |
+------------------+
-| 0 |
+| false |
+------------------+
```
diff --git a/_sources/user-guide/sql/select.md.txt b/_sources/user-guide/sql/select.md.txt
index af442de6597c1..2cbe26fee3964 100644
--- a/_sources/user-guide/sql/select.md.txt
+++ b/_sources/user-guide/sql/select.md.txt
@@ -319,6 +319,7 @@ SELECT a FROM table_name WHERE a > 10;
```text
from_item [join_type] JOIN from_item [join_condition]
+from_item ASOF JOIN from_item MATCH_CONDITION (condition) [join_condition]
from_item CROSS JOIN from_item
from_item NATURAL JOIN from_item
from_item [join_type] JOIN LATERAL (query) AS alias [join_condition]
@@ -400,6 +401,48 @@ SELECT * FROM x LEFT JOIN x AS y ON x.column_1 = y.column_2;
+----------+----------+----------+----------+
```
+### ASOF JOIN
+
+DataFusion follows the
+[Snowflake `ASOF JOIN` syntax](https://docs.snowflake.com/en/sql-reference/constructs/asof-join).
+An `ASOF JOIN` matches each left row with at most one right row according to an
+ordered comparison. It preserves every left row and fills the right columns
+with `NULL` when no right row matches.
+
+```sql
+SELECT t.*, p.price
+FROM trades AS t
+ASOF JOIN prices AS p
+MATCH_CONDITION (t.ts >= p.ts)
+ON t.symbol = p.symbol;
+```
+
+`MATCH_CONDITION` must compare an expression from the left input with an
+expression from the right input using one of the following operators. Operand
+order is significant: the left input expression must appear on the left.
+
+| Condition | Selected right row |
+| --------- | ----------------------------------------- |
+| `l >= r` | Greatest `r` less than or equal to `l` |
+| `l > r` | Greatest `r` strictly less than `l` |
+| `l <= r` | Smallest `r` greater than or equal to `l` |
+| `l < r` | Smallest `r` strictly greater than `l` |
+
+An optional `ON` clause containing equality conditions combined with `AND`, or
+a `USING` clause, divides rows into equality groups before the ordered match.
+An unqualified `USING` key appears once in wildcard output, while both qualified
+input keys remain addressable.
+
+Without equality keys, all rows belong to one group. The initial execution
+strategy collects one ordered right partition and shares it across every left
+partition, so output partitioning follows the left input. The complete right
+input must fit in memory and may be scanned once per left partition; spilling
+and repartitioned ASOF execution are not yet supported.
+
+A `NULL` in either ordered expression or in any equality key does not match.
+Both inputs must be bounded. If multiple right rows have the same equality keys
+and ordered value, which tied row is selected is nondeterministic.
+
### RIGHT OUTER JOIN
The keywords `RIGHT JOIN` or `RIGHT OUTER JOIN` define a join that includes all rows from the right table even if there
diff --git a/contributor-guide/api-health.html b/contributor-guide/api-health.html
index d239b89b5e14f..b5c0f4a6d3d00 100644
--- a/contributor-guide/api-health.html
+++ b/contributor-guide/api-health.html
@@ -471,6 +471,34 @@
Some internal implementation details require pub visibility because they are
+shared across DataFusion crates. These APIs are not intended as downstream
+extension points. They are hidden from generated documentation and are not part
+of DataFusion’s supported public API, so they may be changed or removed without
+notice or a deprecation period. Examples include:
+
+
Test helpers.
+
Operator APIs required by the optimizer to inspect or rewrite execution plans
+across crate boundaries.
+
+
For APIs intended only for internal use, add #[doc(hidden)] and a doc comment
+section headed #PublicOnlyforInternalUse:. Name the crate or component
+that requires access and explain why the API is not intended for downstream use.
+For example:
+
impl HashTableLookupExpr {
+ /// ...
+ ///
+ /// # Public Only for Internal Use:
+ /// `datafusion-proto` tests require this constructor, but it is not part of
+ /// the supported public API.
+ #[doc(hidden)]
+ pub fn new(...) {...}
+}
+
+
+
What is the public SQL API and what is a breaking SQL change?#
DataFusion is also used as a SQL engine, so changes to SQL semantics (the
@@ -591,6 +619,7 @@
This can cause issues such as not having the rust-analyzer component installed for the specified toolchain, in which case just install it manually, e.g. rustupcomponentadd--toolchain1.97.0rust-analyzer
+
This can cause issues such as not having the rust-analyzer component installed for the specified toolchain, in which case just install it manually, e.g. rustupcomponentadd--toolchain1.98.1rust-analyzer
The standard dev profile, used by cargo build and cargo test, disables variable-level DWARF debug information that is required by interactive debuggers.
+
If you need to step through the code with a debugger, build with:
+
CARGO_PROFILE_DEV_DEBUG=2cargobuild
+
Alternatively, you can set CARGO_PROFILE_DEV_DEBUG=2 as an environment variable in your IDE.
+
This enables the additional debug information required for source-level debugging.
+
For more details, see the DataFusion Cargo.toml configuration.
Welcome to the Apache DataFusion Google Summer of Code (GSoC) 2025 project ideas list. Below you can find information about the projects. Please refer to this page for application guidelines.
+
Welcome to the Apache DataFusion Google Summer of Code (GSoC) 2025 project ideas list. Below you can find information about the projects. Please refer to this page for application guidelines.
Please ensure your PR follows the testing guide. In particular:
+
+
Prefer end-to-end Public API tests such as sqllogictest (.slt) and DataFrame API,
+over Rust unit tests where possible. See
+Choosing What Kind of Test to Write.
Verify tests cover edge cases and common failure scenarios, not just the
common successful path. However, it is NOT necessary to test every possible
error path, especially if it is difficult to trigger or unlikely to occur in
diff --git a/contributor-guide/testing.html b/contributor-guide/testing.html
index 8a3b2a9c7f8d6..44c5df3f9ad40 100644
--- a/contributor-guide/testing.html
+++ b/contributor-guide/testing.html
@@ -486,6 +486,27 @@
When adding tests, prefer tests that exercise user-visible behavior over
+tests of internal implementation details. Doing so means your tests are more
+likely to keep working (and keep catching regressions) while the code is
+refactored. In rough order of preference:
+
+
Use sqllogictest (.slt) tests for any behavior that can
+be expressed in SQL.
+
End-to-end tests that use public APIs such as the DataFrame API, for behavior
+that cannot be expressed in SQL. For example, DataFrame tests live in
+datafusion/core/tests/dataframe and run as part of the core_integration
+test binary:
Like similar systems such as DuckDB, DataFusion has chosen to trade off a slightly higher barrier to contribution for longer term maintainability.
-
DataFusion has integrated sqlite’s test suite as a supplemental test suite that is run whenever a PR is merged into DataFusion. To run it manually please refer to the README file for instructions.
In addition to the standard CI test suite that is run on all PRs prior to merge,
-DataFusion has “extended” tests (defined in extended.yml) that are run on each
-commit to main. These tests rarely fail but take significantly longer to run
-than the standard test suite and add important test coverage such as ensuring
-correctness when there are hash collisions and running the relevant portions of
-the entire sqlite test suite. You can run the extended tests
-locally by following the instructions in the documentation.
+
DataFusion has extended tests (defined in extended.yml) that take significantly
+longer to run than the standard suite. They provide additional correctness
+coverage and must pass in the merge queue before a PR merges into main.
+
To conserve CI resources, these tests do not run on ordinary PR updates. They
+also run on pushes to release branches (branch-*). You can run them manually.
We use Rust doctest to verify examples from the documentation are correct and
-up-to-date. These tests are run as part of our CI and you can run them them
+up-to-date. These tests are run as part of our CI and you can run them
locally with the following command:
As with other Rust projects, examples in doc comments in .rs files are
automatically checked to ensure they work and evolve along with the code.
+
Prefix a line with # (a # followed by a space) to keep it compiled and
+run, but hidden from the rendered documentation. This is most useful for
+use statements, since readers care about the API being demonstrated, not
+its import boilerplate:
+
///
+```
+/// # use std::sync::Arc;
+/// let value = Arc::new(42);
+/// ```
+
./dev/rust_lint.sh runs the internal markdown link check. If lychee is
+missing, the script installs the version pinned in
+ci/scripts/utils/tool_versions.sh. It uses an existing installation as is,
+even if the version differs from the pin.
ci/scripts/check_asf_yaml_status_checks.py checks that every required status
+check in .asf.yaml matches a job in .github/workflows, and that rust.yml
+skips only its listed jobs on pushes to main. ./dev/rust_lint.sh runs it
+and needs python3 with PyYAML. The uv workspace provides both:
ci/scripts/security_audit.sh runs cargoaudit on the root Cargo.lock with
+the advisory exceptions that CI uses. ./dev/rust_lint.sh runs it and installs
+cargo-audit if it is missing. To run the audit on its own:
+
./ci/scripts/security_audit.sh
+
+
+
The audit fetches the RustSec advisory database. A new advisory or a different
+cargo-audit version can change the result without any change to the repository.
ci/scripts/check_large_files.sh fails if any file committed between a base
+ref and a head ref is larger than 1.5 MB, the same check the “Large files PR
+check” workflow runs on pull requests. ./dev/rust_lint.sh runs it against
+the merge base of HEAD and main on the remote that points at
+apache/datafusion, or on origin when there is no such remote. To run the
+check on its own, or against a different range:
CI runs two dependency checks, and ./dev/rust_lint.sh runs both:
+
+
ci/scripts/check_circular_dependencies.sh builds and runs dev/depcheck,
+which fails on dependency cycles between DataFusion crates.
+
ci/scripts/check_unused_dependencies.sh runs cargomachete--with-metadata
+from the repository root. The lint suite installs cargo-machete with the
+version in ci/scripts/utils/tool_versions.sh if it is missing.
datafusion-examples/README.md is generated from the documentation comments in
+datafusion-examples/examples/<group>/main.rs. ci/scripts/check_examples_docs.sh
+regenerates it and fails if the committed file differs. ./dev/rust_lint.sh
+runs it and needs cargo and npx. To run the check on its own, or to update
+the README:
ci/scripts/check_docs_html.sh builds the documentation website, the same
+build the “Test doc build” job runs. Sphinx builds with -W, so one warning
+fails the check. ./dev/rust_lint.sh runs it. Run the script with --help
+for the tools it needs and the files it writes.
While DataFusion is distributed via crates.io as a convenience, the
diff --git a/library-user-guide/catalogs.html b/library-user-guide/catalogs.html
index 310a6a0dbfc64..c8d015299cc70 100644
--- a/library-user-guide/catalogs.html
+++ b/library-user-guide/catalogs.html
@@ -642,6 +642,65 @@
Implementing Me
Like other traits, it also maintains the mapping of the Catalog’s name to the CatalogProvider.
The catalogs above are all registered programmatically, ahead of time,
+before a query ever runs. Sometimes it is useful to let users attach a
+catalog dynamically from SQL instead — for example, a catalog backed by a
+remote catalog service such as an Iceberg REST catalog. This is exactly
+analogous to how TableProviderFactory lets CREATEEXTERNALTABLE
+create a TableProvider “on the fly”: CatalogProviderFactory lets
+CREATEEXTERNALCATALOG...STOREDAS<catalog_type>... create a
+CatalogProvider on the fly.
+
To support CREATEEXTERNALCATALOG, implement CatalogProviderFactory:
+
usestd::sync::Arc;
+useasync_trait::async_trait;
+usedatafusion::catalog::{CatalogProvider,CatalogProviderFactory,MemoryCatalogProvider,Session};
+usedatafusion::common::Result;
+usedatafusion::logical_expr::CreateExternalCatalog;
+
+#[derive(Debug)]
+structMyCatalogProviderFactory{}
+
+#[async_trait]
+implCatalogProviderFactoryforMyCatalogProviderFactory{
+asyncfncreate(
+&self,
+_state:&dynSession,
+cmd:&CreateExternalCatalog,
+)->Result<Arc<dynCatalogProvider>>{
+// `cmd.location` and `cmd.options` carry whatever was supplied in the
+// `LOCATION` and `OPTIONS` clauses of the SQL statement; a real
+// implementation would use them to connect to the remote catalog
+// service. This example just returns an empty in-memory catalog.
+Ok(Arc::new(MemoryCatalogProvider::new()))
+}
+}
+
+
+
Then register it on the SessionState, keyed by the STOREDAS value that
+should resolve to it:
A custom table provider can support DELETE and UPDATE by implementing the optional TableProvider::delete_from() and TableProvider::update() methods. Their default implementations return a “not implemented” error.
+
Each method builds an ExecutionPlan that changes the matching rows and returns the number of affected rows in a count column. Your provider decides how to apply and persist the changes. Perform the changes when the returned plan executes: these methods run during physical planning, including for EXPLAIN.
+
The method documentation describes the filters, assignments, SQL semantics, and result schema that an implementation must support. MemTable provides an implementation of both methods over in-memory batches.
+
For SQL syntax and examples, see the DML section of the user guide.
The RelationPlannerContextRelationPlanner API documentation for additional methods like
normalize_ident() and object_name_to_table_reference().
+
Relation planners are called before DataFusion’s built-in CTE and catalog lookup.
+If your planner recognizes ordinary relations by name, check get_cte() after
+determining the relation is an ordinary name that your planner would otherwise
+handle. Deliberately reserved names and custom syntax can keep their existing
+precedence. Return RelationPlanning::Original when a CTE is visible so the
+next planner can handle the relation. When every ordinary name-based planner in
+the chain performs this check, planning reaches DataFusion’s built-in CTE
+resolution. Normalize the parsed name first so the lookup follows DataFusion’s
+existing name matching. Only do this for a table without function arguments: a
+CTE named numbers shadows numbers, but it does not shadow a call such as
+numbers(10).
+
// Run this after recognizing `relation` as an ordinary name handled here.
+ifletTableFactor::Table{name,args:None,..}=&relation{
+lettable_ref=ctx.object_name_to_table_reference(name.clone())?;
+ifctx.get_cte(&table_ref).is_some(){
+returnOk(RelationPlanning::Original(Box::new(relation)));
+}
+}
+
By default DataFusion assumes an aggregate is sensitive to the DISTINCT modifier, which means the accumulator is expected to
+read AccumulatorArgs::is_distinct and deduplicate its input. Override
+AggregateUDFImpl::distinct_handling when that is not what your function does:
+
+
Return DistinctHandling::Insensitive when duplicates cannot change the result, that is, when merging a value the
+accumulator has already seen is a no-op. min, max, bool_and and bit_or are all in this group. The optimizer
+then plans f(DISTINCTx) as f(x), which skips both the per-group hash set and the extra grouping stage that
+SingleDistinctToGroupBy would otherwise introduce.
+
Return DistinctHandling::Unsupported when the accumulator does not implement DISTINCT: it does not read
+is_distinct, or it rejects DISTINCT with an error. The planner must then deduplicate the input first or reject
+the query. Today this is a declaration only; rejecting such queries at planning time is a follow-up change.
+
Leave the default DistinctHandling::Sensitive when the accumulator reads AccumulatorArgs::is_distinct and
+deduplicates its input itself.
+
+
Getting this wrong changes query results, so only claim Insensitive if your merge is genuinely idempotent.
Filter predicate evaluation order may differ from query text#
-
The logical optimizer now reorders filters so that cheap predicates (most binary
-comparisons, ISNULL, Between, InList, etc.) evaluate before expensive
-ones (LIKE, regex, scalar function calls, subqueries). For example,
-WHEREcolLIKE'%foo%'ANDcol2=5 may evaluate col2=5 before
-colLIKE'%foo%'.
-
Evaluation order has never been guaranteed to match the order written in the
-query. The SQL standard explicitly allows implementations to evaluate operands
-in any order; major engines (PostgreSQL, SQL Server, Oracle, MySQL) document the
-same. Queries should not rely on left-to-right evaluation or short-circuit
-semantics for AND or OR. Previous versions of DataFusion already reordered
-predicates (e.g., as part of expression simplification or predicate pushdown);
-the new reordering pass just increases the scenarios where the optimizer will
-change predicate evaluation order.
-
Fallible-predicate patterns are particularly affected. For example:
-
WHEREs~'^[0-9]+$'ANDCAST(sASINT)>0
-
-
-
The intent is likely to filter non-numeric strings before the CAST runs,
-but this depends on evaluation-order behavior the SQL standard does not
-guaranteed. The new reorder makes this kind of pattern more likely to fail
-at runtime if the optimizer moves the CAST ahead of the regex. To force
-conditional evaluation, rewrite using CASE, which has standardized
-short-circuit semantics:
Volatile expressions (random(), now(), etc.) are exempt — their position
-in the conjunct list is preserved so the number of times they evaluate per
-query does not change.
-
datafusion-proto: expression deserialization now takes a TaskContext#
Serializeable::from_bytes_with_registry is renamed to from_bytes_with_ctx
@@ -1284,11 +1252,6 @@
Note: DataFusion 55.0.0 has not been released yet. The information provided
-in this section pertains to features and changes that have already been merged
-to the main branch and are awaiting release in this version.
+
+
Filter predicate evaluation order may differ from query text#
+
The logical optimizer now reorders filters so that cheap predicates (most binary
+comparisons, ISNULL, Between, InList, etc.) evaluate before expensive
+ones (LIKE, regex, scalar function calls, subqueries). For example,
+WHEREcolLIKE'%foo%'ANDcol2=5 may evaluate col2=5 before
+colLIKE'%foo%'.
+
Evaluation order has never been guaranteed to match the order written in the
+query. The SQL standard explicitly allows implementations to evaluate operands
+in any order; major engines (PostgreSQL, SQL Server, Oracle, MySQL) document the
+same. Queries should not rely on left-to-right evaluation or short-circuit
+semantics for AND or OR. Previous versions of DataFusion already reordered
+predicates (e.g., as part of expression simplification or predicate pushdown);
+the new reordering pass just increases the scenarios where the optimizer will
+change predicate evaluation order.
+
Fallible-predicate patterns are particularly affected. For example:
+
WHEREs~'^[0-9]+$'ANDCAST(sASINT)>0
+
+
+
The intent is likely to filter non-numeric strings before the CAST runs,
+but this depends on evaluation-order behavior the SQL standard does not
+guaranteed. The new reorder makes this kind of pattern more likely to fail
+at runtime if the optimizer moves the CAST ahead of the regex. To force
+conditional evaluation, rewrite using CASE, which has standardized
+short-circuit semantics:
Volatile expressions (random(), now(), etc.) are exempt — their position
+in the conjunct list is preserved so the number of times they evaluate per
+query does not change.
+
Map casts with nested Structs use schema-evolution rules#
Casts of a Map whose key or value recursively contains a Struct now adapt
@@ -614,6 +643,11 @@
The Dialect enum in datafusion_common::config now includes a Spark variant.
+If you match exhaustively on Dialect, add a Dialect::Spark arm.
+
Dialect::AVAILABLE replaced by Dialect::available()#
datafusion_common::config::Dialect::AVAILABLE has been removed. Use
@@ -1791,11 +1825,13 @@
RANGE window frames with offsets now reject ORDER BY types without arithmeti
has not been released yet. The information provided
in this section pertains to features and changes that have already been merged
to the main branch and are awaiting release in this version.
+
+
Upgrade arrow/parquet to 60.0.0 and object_store to 0.14.2#
+
DataFusion 56.0.0 uses arrow and parquet 60.0.0, and object_store 0.14.2.
+This may require updates to your Cargo.toml if you have direct dependencies on
+these crates.
Field and schema metadata now use arrow’s Metadata type#
+
Arrow 60 introduced a dedicated Metadata type for field and schema metadata
+in place of HashMap<String,String>. Following that change, several DataFusion
+APIs now use Metadata as well, such as DFSchema::metadata and
+ExprSchema::metadata return &Metadata. CastExpr::target_metadata and
+TryCastExpr::target_metadata return Option<&Metadata>.
+
Migration guide:
+
// Before
+letmeta:&HashMap<String,String>=schema.metadata();
+letfield=Field::new("a",DataType::Int64,true)
+.with_metadata([("k".to_string(),"v".to_string())].into());
+
+// After
+letmeta:&Metadata=schema.metadata();
+letfield=Field::new("a",DataType::Int64,true)
+.with_metadata(Metadata::new().with("k","v"));
+
+
+
Metadata supports .get(), .iter(), .is_empty() and .extend() like
+HashMap, and converts to and from HashMap<String,String> and
+BTreeMap<String,String> via From, so most call sites need only a type
+change. Use FieldMetadata::to_hashmap where a HashMap is still required.
+
+
+
+
ParquetAccessPlan::into_overall_row_selection is deprecated#
+
ParquetAccessPlan::into_overall_row_selection is deprecated starting in 56.0.0.
+DataFusion now keeps selections local to each row group during Parquet scanning.
+The method remains available with its existing conversion and selection-length
+validation behavior, so direct callers continue to work but receive a deprecation
+warning.
+
Users who attach a ParquetAccessPlan to a PartitionedFile for DataFusion to
+read need no changes.
+
For custom readers, use ParquetAccessPlan::into_inner() to obtain the
+RowGroupAccess entries. Their positions are the original file row-group
+indexes, and each selection uses coordinates within its own row group. When
+migrating away from the deprecated method, callers must handle conversion and
+selection-length validation themselves. Parquet’s push decoder and async reader
+accept RowGroupSelection values through with_row_group_selections; the
+synchronous reader still requires with_row_groups and an overall
+with_row_selection.
+
+
+
Missing Parquet null counts are treated as unknown#
+
DataFusion now preserves an omitted Parquet null_count statistic as unknown.
+Previously, it assumed zero nulls, which could discard matching NULL rows in
+ISNULL filters and ORDERBY...NULLSFIRSTLIMIT queries, or produce an
+incorrectly high COUNT(column) from metadata.
+
Queries over affected files may read or sort more data because these optimizations
+require a known null count:
+
+
Pruning row groups for ISNULL filters.
+
Computing COUNT(column) using only file metadata.
+
Pruning row groups with a dynamic NULLSFIRST TopK filter.
+
Eliminating a sort over nullable columns in sorted, non-overlapping files.
+Such queries may now retain a full SortExec, even when the data has no NULLs.
+
+
parquet-rs versions before 53.1.0 omitted zero null counts. This includes files
+produced with the older parquet-rs dependency used by DataFusion releases before
+42.1.0. Arrow #6490 changed the
+writer to record known zero counts. Files with explicit counts retain their
+existing behavior.
+
To identify column chunks with bounds but no null count, run this query in the
+DataFusion CLI:
Rewriting affected files with a current DataFusion version, for example using
+COPY...TO with Parquet statistics enabled, records the missing counts and
+restores optimizations that depend on them. Preserve the required data ordering
+and ordering metadata when rewriting sorted files.
+
+
+
Timestamp(u,Some(tz))-Timestamp(u,None) reads the naive operand in tz#
+
Subtracting a timezone-naive timestamp from a timezone-aware one at the same
+time unit did not coerce at all in 55.0.0: the naive operand was read as UTC,
+which differed both from = on the same pair of values and from every other
+pairing of time units. It now coerces like the rest, so the naive operand is
+read in the aware operand’s time zone:
+
-- ts_tz is 2024-11-01T00:00:00-04:00 (America/New_York), ts is the naive
+-- 2024-11-01T00:00:00; ts_tz = ts is true in both versions
+-- 55.0.0: 0 days 4 hours 0 mins 0.000000000 secs
+-- 56.0.0: 0 days 0 hours 0 mins 0.000000000 secs
+SELECTts_tz-tsFROMtimestamps;
+
+
+
+
+
ForeignSession::create_physical_plan is unsupported#
+
ForeignSession::create_physical_plan no longer forwards to the library that
+owns the session. It now returns a NotImplemented error because forwarding can
+re-enter an installed foreign planner, and the execution-plan handle returned by
+the old callback cannot restore local Rust type identities for downcasting.
+The original FFI_SessionRef callback slot remains in place for ABI compatibility
+with DataFusion 55 consumers, but calling that callback returns the same error.
+
The session-owning library should instead export its original planner as a
+datafusion_ffi::query_planner::FFI_QueryPlanner before installing a foreign
+planner. The foreign planner can retain and invoke that handle to receive a
+serialized physical plan reconstructed with local type identities. See the
+datafusion_ffi::query_planner module documentation for the complete delegation
+pattern. ForeignSession::query_planner, optimize, and physical_optimizers
+continue to forward to the owning session across the FFI boundary.
+
+
+
Range partitioning supports retained samples and scaling#
+
RangePartitioning::new is deprecated. Prefer the validated
+RangePartitioning::try_new_with_samples(ordering,samples,partition_count).
+For exact boundaries, pass split_points.len()+1 as the count, or keep using
+the validated try_new constructor. Retain additional samples when future
+scaling above that count is required; scaling does not create new sample values.
+
scale returns Option<RangePartitioning>. It returns None when the target
+partition count is zero or exceeds the retained sample capacity; callers can
+then retain the existing layout or choose another partitioning. Equality includes
+retained samples; use has_same_layout to compare the current key ordering and
+effective boundaries.
+
FFI_RangePartitioning has a new layout; rebuild FFI consumers against the
+compatible release. The generated PhysicalRangePartitioning protobuf struct
+also gains fields, affecting exhaustive struct literals. Older protobuf payloads
+remain readable, and effective split points remain available to older readers.
Custom implementations of the public GroupColumn trait must implement
+values_preserving. This method returns selected rows without changing the stored
+values or their group indices. It preserves the requested order and supports
+repeated indices.
+
Migration guide:
+
Implement values_preserving, call
+selection.validate_num_groups(self.len())? before reading, and return rows in
+selection.iter() order without changing the builder state.
+
+
+
datafusion-proto: common option and constraint conversions are fallible#
+
Protobuf conversions for CsvOptions, JsonOptions, ParquetCdcOptions,
+Constraint, and Constraints now reject integer values that do not fit
+usize. Their infallible From implementations have been replaced with
+TryFrom. The existing TryFrom conversions for ParquetOptions and
+TableParquetOptions now also validate all usize-backed fields. A constraint
+without a constraint_mode returns an error instead of panicking.
+
Migration guide:
+
// Before
+letcsv=CsvOptions::from(&proto_csv);
+letcdc=ParquetCdcOptions::from(proto_cdc);
+letconstraints:Constraints=proto_constraints.into();
+
+// After
+letcsv=CsvOptions::try_from(&proto_csv)?;
+letcdc=ParquetCdcOptions::try_from(proto_cdc)?;
+letconstraints=Constraints::try_from(proto_constraints)?;
+
ExecutionOptions has a new enable_nlj_coordinated_fallback field#
+
ExecutionOptions gained a public enable_nlj_coordinated_fallback:bool field
+(default true). It controls whether the memory-limited NestedLoopJoinExec
+fallback shares per-chunk build-side state across probe partitions, which is what
+lets LEFT, LEFTSEMI, LEFTANTI, LEFTMARK and FULL joins spill instead
+of failing with ResourcesExhausted when the right side has several partitions.
+
Who is affected:
+
+
Users constructing ExecutionOptions (or ConfigOptions) with an exhaustive
+struct literal. Reading or SET-ing configuration is unaffected.
+
Distributed engines that run each output partition as an independent task.
+The coordination assumes all probe partitions run in one process; with one
+coordinator per task the shared probe-thread counter never reaches zero and the
+fallback would stall. Such engines should set the flag to false, which keeps
+the previous fail-fast behaviour for the affected join types.
+
+
Migration guide:
+
Set the new field, or fill it from Default:
+
// Before
+ExecutionOptions{
+batch_size:8192,
+// ... every other field ...
+}
+
+// After: set it explicitly
+ExecutionOptions{
+batch_size:8192,
+enable_nlj_coordinated_fallback:true,
+// ... every other field ...
+}
+
+// After: or let the remaining fields come from Default, which also keeps
+// future field additions from breaking the literal
+ExecutionOptions{
+batch_size:8192,
+..Default::default()
+}
+
ExecutionOptions has a new soft_max_bytes_per_output_file field#
+
ExecutionOptions gained a public soft_max_bytes_per_output_file:ConfigNonZeroUsize
+field (default 4 GiB minus one byte, or 4,294,967,295 bytes). When writing
+multiple output files, DataFusion starts a new file once a writer reports that
+the encoded size has reached this target or the existing
+soft_max_rows_per_output_file target has been reached. The byte limit is soft:
+buffered batches, in-flight batch serialization, individual batch sizes, and
+file metadata can make a completed file larger than the target. It does not
+apply to single-file output.
+
Who is affected:
+
+
Users constructing ExecutionOptions (or ConfigOptions) with an exhaustive
+struct literal must provide the new field.
+
Users writing multiple output files can set a smaller byte target to rotate
+files before they reach the default size.
+
+
Migration guide:
+
Set the field explicitly, or fill it from Default as shown above. For example,
+to target 128 MiB output files in Rust:
datafusion.optimizer.use_statistics_registry is deprecated and ignored#
The datafusion.optimizer.use_statistics_registry config flag is deprecated and
@@ -480,6 +719,86 @@
datafusion.opti
To opt out, register nothing (the default).
+
+
Generated protobuf JsonWriterOptions gained a compression_level field#
+
The generated public protobuf JsonWriterOptions struct now carries an optional
+compression_level so JSON sink plans preserve explicitly configured
+compression levels across serialization.
+
Who is affected:
+
+
Users constructing generated JsonWriterOptions values with an exhaustive
+struct literal.
+
+
Migration guide:
+
Set compression_level explicitly, or fill it from Default:
+
// Before
+JsonWriterOptions{compression}
+
+// After
+JsonWriterOptions{
+compression,
+compression_level:None,
+}
+// or
+JsonWriterOptions{
+compression,
+..Default::default()
+}
+
+
+
The protobuf wire format remains backward compatible.
Generated protobuf Parquet structs gained state fields#
+
The generated public protobuf ParquetScanExecNode struct now carries an
+optional metadata_size_hint, and ParquetSink now carries optional
+sorting_columns. These fields preserve the corresponding Parquet source and
+sink settings across physical-plan serialization.
+
Who is affected:
+
+
Users constructing either generated struct with an exhaustive struct literal.
+
+
Migration guide:
+
Add metadata_size_hint:None to ParquetScanExecNode literals and
+sorting_columns:None to ParquetSink literals to retain the previous
+behavior, or use ..Default::default() for unspecified fields.
+
The protobuf wire format remains backward compatible.
The generated CsvWriterOptions now includes compression_level,
+timestamp_tz_format, and terminator. Its four existing format fields changed
+from String to Option<String> to distinguish unset from explicitly empty
+formats. This affects exhaustive struct literals and direct format-field access.
+
Wrap existing formats in Some or use None, and initialize the new fields
+(explicitly or through Default):
The output type of the floor and ceil UDFs has been changed from the exact input type to a rescaled type with the same bit width. For example, for input Decimal32(7,2)floor now returns Decimal32(6,0), where the new precision is p-s+1, matching Spark’s behaviour. See [#24703] for more details.
+
Who is affected:
+
+
Users storing query result with these UDFs in a fixed schema
+
Users relying on arrow_typeof for these UDFs
+
+
Migration guide:
+
Change the expected type or wrap the expression in CAST. It’s recommended to avoid relying on decimal’s exact precision and scale.
+
+
+
map_extract / element_at return an empty list for absent keys#
+
map_extract (and its alias element_at) previously returned a single-element
+list containing NULL when the key was not present in the map. It now returns
+an empty list, matching the documented behavior and DuckDB. Two related cases
+changed at the same time, also matching DuckDB:
+
+
A NULL map input now yields NULL instead of [NULL].
+
A NULL lookup key now yields [] instead of [NULL].
+
+
A key that is present with a NULL value still returns [NULL], so absent
+keys and NULL values are now distinguishable.
+
Migration guide:
+
-- Before
+SELECTmap_extract(MAP{'a':1},'missing');-- [NULL]
+
+-- After
+SELECTmap_extract(MAP{'a':1},'missing');-- []
+
+
+
Expressions that assumed the result always has exactly one element, for
+example by checking its length, unnesting it, or comparing it to [NULL],
+should treat an empty list as the absent-key case instead.
DataFrame::from_columns now accepts any IntoIterator<Item=(&str,ArrayRef)>
+instead of specifically accepting a Vec<(&str,ArrayRef)>.
+
// Existing Vec usage continues to work
+letdf=DataFrame::from_columns(vec![
+("id",id),
+("name",name),
+])?;
+
+// Arrays can now be used directly
+letdf=DataFrame::from_columns([
+("id",id),
+("name",name),
+])?;
+
+
+
Most existing call sites using Vec require no changes. Code that relies on
+the exact non-generic function signature of DataFrame::from_columns may need
+to be updated to account for the new generic API.
+
+
+
Aggregate ordering state field names are now namespaced#
+
Ordering expressions exposed as top-level aggregate state fields now use names
+derived from the aggregate name and their ordering position.
+
For example:
+
first_value(value)[ordering_0]
+
+
+
is now used instead of an unqualified ordering field name such as:
+
timestamp@0
+
+
+
This guarantees unique aggregate state field names and allows
+DFSchema::check_names() to be enforced.
+
Who is affected:
+
Users or integrations that inspect aggregate state field names directly,
+including custom UDAFs and FFI integrations.
+
+
+
Physical filter pushdown resolves columns by position#
+
datafusion_physical_plan::filter_pushdown::ChildFilterDescription::from_child
+and FilterDescription::from_children now resolve filter columns by position
+instead of looking them up by name. This prevents incorrect results when a
+child schema contains duplicate column names. from_child requires the child
+field at each referenced position to have the same name as the filter column.
+
ChildFilterDescription::from_child_with_allowed_indices is deprecated but
+preserves its previous name-based mapping to the first matching child field.
+Migrate to from_child_with_column_mapping because name resolution is ambiguous
+when the child schema contains duplicate field names.
+
Migration guide:
+
Use from_child (or from_children for multiple children) when the parent and
+child schemas have matching column positions and names. When a node projects,
+reorders, or renames columns, use from_child_with_column_mapping with an
+explicit map from parent output indices to child input indices. Columns absent
+from the mapping cannot be pushed down.
+
For example, if the parent outputs [a,b] and the child outputs [b,a], a
+filter on a@0 must map to child column a@1:
+
usestd::collections::{HashMap,HashSet};
+usedatafusion_physical_plan::filter_pushdown::ChildFilterDescription;
+
+// Before: allow parent column 0 and resolve "a" by name in the child.
+letdescription=ChildFilterDescription::from_child_with_allowed_indices(
+&parent_filters,
+HashSet::from([0]),
+&child,
+)?;
+
+// After: explicitly map parent column 0 to child column 1.
+letdescription=ChildFilterDescription::from_child_with_column_mapping(
+&parent_filters,
+HashMap::from([(0,1)]),
+&child,
+)?;
+
+
+
+
+
Default datafusion.sql_parser.recursion_limit raised from 50 to 51#
+
DataFusion now uses sqlparser 0.63.0, which adds recursion guards to more
+parse functions (for example, data type and INTERVAL parsing). As a result,
+the same SQL statement consumes slightly more of the parser recursion budget
+than it did with previous sqlparser versions. In particular, every expression
+now needs one additional level of depth.
+
To avoid rejecting queries that previously parsed successfully, the default
+value of the datafusion.sql_parser.recursion_limit configuration option, and
+of DFParserBuilder::with_recursion_limit, has been raised from 50 to 51.
+
If you set datafusion.sql_parser.recursion_limit explicitly to a value close
+to the depth of your queries, you may see RecursionLimitExceeded errors after
+upgrading and should raise the limit accordingly.
ensure_distribution is deprecated in favour of ensure_distribution_with_stats#
+
datafusion_physical_optimizer::enforce_distribution::ensure_distribution now
+takes its StatisticsContext from the caller, so one context (and its
+memoization cache) can be shared across a whole bottom-up traversal. The old
+two-argument form is kept as a deprecated wrapper that allocates a fresh
+context per call, which recomputes each shared subtree’s statistics once per
+ancestor.
+
// Before
+letplan=DistributionContext::new_default(plan)
+.transform_up(|ctx|ensure_distribution(ctx,config))
+.data()?;
+
+// After: one context for the whole walk. `StatsCache` is keyed by raw plan-node
+// pointers, so reset it whenever a node's plan pointer actually changed.
+letstats_ctx=StatisticsContext::new();
+letplan=DistributionContext::new_default(plan)
+.transform_up(|ctx|{
+letbefore=Arc::clone(&ctx.plan);
+letresult=ensure_distribution_with_stats(ctx,config,&stats_ctx)?;
+if!Arc::ptr_eq(&before,&result.data.plan){
+stats_ctx.reset_cache();
+}
+Ok(result)
+})
+.data()?;
+
+
+
Callers that only need the previous behaviour can keep using the deprecated
+form, or pass a freshly constructed StatisticsContext per call.
+
+
+
MergeIntoOp requires the SQL-visible target qualifier#
+
MergeIntoOp now stores the SQL-visible target qualifier separately from the
+target provider identity. This prevents an aliased target from being confused
+with a source relation that uses the target table’s name.
+
The struct is now non-exhaustive. Replace 55.0 struct literals with
+MergeIntoOp::new:
target_qualifier must be the relation name referenced by the MERGE expressions:
+the target alias when one is present, otherwise the target table reference.
+DmlStatement::table_name remains the provider/catalog identity.
A 56.0 reader accepts a 55.0 payload. When target_qualifier is absent, it
+falls back to DmlNode.table_name, matching the 55.0 representation.
+
A 55.0 reader must not consume an alias-preserving 56.0 MERGE payload. It
+ignores the unknown field but cannot preserve the qualifier required by the
+expressions, which can cause resolution failure or incorrect rebinding.
FileScanConfig no longer derives equivalence properties (constant columns
+and equal columns) from FileSource::filter. It uses the new
+FileSource::exact_filter method instead. This method returns the part of the
+filter that every output row satisfies. A filter that the source uses only for
+pruning (for example, Parquet row group statistics when
+datafusion.execution.parquet.pushdown_filters is false) lets
+non-matching rows through, and equivalences derived from it gave wrong query
+results.
+
exact_filter returns None by default. ParquetSource returns the pushed-down
+conjuncts when pushdown_filters is enabled.
+
Migration guide:
+
If your custom FileSource applies its filter to every row, implement
+exact_filter to keep the equivalence properties of the scan:
The timezone, timezone_hour and timezone_minute parts are only defined for timestamps that carry a timezone; extracting them from a timezone-naive timestamp, a date, a time or an interval is an error. They report the offset that applies at that instant, so they follow daylight saving time: Europe/Brussels yields 3600 in January and 7200 in July. For a negative offset each non-zero part carries the sign, so America/St_Johns in January yields -3 hours and -30 minutes. An offset smaller than one hour has a zero hour part, which cannot show a sign: Africa/Monrovia before 1972 yields 0 hours and -43 minutes.
expression: Time expression to operate on. Can be a constant, column, or function.
Converts an integer to RFC3339 timestamp format (YYYY-MM-DDT00:00:00.000000000Z). Integers and unsigned integers are interpreted as seconds since the unix epoch (1970-01-01T00:00:00Z) return the corresponding timestamp.
+
Converts an integer to a timestamp with second precision (Timestamp(Second)).
+The integer is interpreted as the number of seconds since the unix epoch
+(1970-01-01T00:00:00Z).
+
If the optional timezone argument is omitted, the timestamp is returned in the
+session time zone (datafusion.execution.time_zone), which is unset (i.e.
+timezone-naive) by default.
expression: The expression to operate on. Can be a constant, column, or function, and any combination of operators.
-
timezone: Optional timezone to use when converting the integer to a timestamp. If not provided, the default timezone is UTC.
+
timezone: Optional timezone to use when converting the integer to a timestamp. If not provided, the session time zone (datafusion.execution.time_zone) is used, which is unset (timezone-naive) by default.
-----------------------------------------------------------+|2020-09-08T09:42:29-04:00|+-----------------------------------------------------------+
+
+-- Without an explicit timezone the session time zone is used
+>SETdatafusion.execution.time_zone='America/New_York';
+>selectfrom_unixtime(1599572549);
++----------------------------------+
+|from_unixtime(Int64(1599572549))|
++----------------------------------+
+|2020-09-08T09:42:29-04:00|
++----------------------------------+
@@ -5508,7 +5532,7 @@
DataFusion follows the
+Snowflake ASOFJOIN syntax.
+An ASOFJOIN matches each left row with at most one right row according to an
+ordered comparison. It preserves every left row and fills the right columns
+with NULL when no right row matches.
MATCH_CONDITION must compare an expression from the left input with an
+expression from the right input using one of the following operators. Operand
+order is significant: the left input expression must appear on the left.
+
+
+
Condition
+
Selected right row
+
+
+
+
l>=r
+
Greatest r less than or equal to l
+
+
l>r
+
Greatest r strictly less than l
+
+
l<=r
+
Smallest r greater than or equal to l
+
+
l<r
+
Smallest r strictly greater than l
+
+
+
+
+
An optional ON clause containing equality conditions combined with AND, or
+a USING clause, divides rows into equality groups before the ordered match.
+An unqualified USING key appears once in wildcard output, while both qualified
+input keys remain addressable.
+
Without equality keys, all rows belong to one group. The initial execution
+strategy collects one ordered right partition and shares it across every left
+partition, so output partitioning follows the left input. The complete right
+input must fit in memory and may be scanned once per left partition; spilling
+and repartitioned ASOF execution are not yet supported.
+
A NULL in either ordered expression or in any equality key does not match.
+Both inputs must be bounded. If multiple right rows have the same equality keys
+and ordered value, which tied row is selected is nondeterministic.
diff --git a/versions/55.0.0/_downloads/1e336e540124589d1e27210fa4f805f6/rust_lint.sh b/versions/55.0.0/_downloads/1e336e540124589d1e27210fa4f805f6/rust_lint.sh
new file mode 100644
index 0000000000000..73cab9c7f70bd
--- /dev/null
+++ b/versions/55.0.0/_downloads/1e336e540124589d1e27210fa4f805f6/rust_lint.sh
@@ -0,0 +1,126 @@
+#!/usr/bin/env bash
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# This script runs all the Rust lints locally the same way the
+# DataFusion CI does
+#
+# Note: The installed checking tools (e.g., taplo) are not guaranteed to match
+# the CI versions for simplicity, there might be some minor differences. Check
+# `.github/workflows` for the CI versions.
+#
+#
+#
+# For each lint scripts:
+#
+# By default, they run in check mode:
+# ./ci/scripts/rust_fmt.sh
+#
+# With `--write`, scripts perform best-effort auto fixes:
+# ./ci/scripts/rust_fmt.sh --write
+#
+# The `--write` flag assumes a clean git repository (no uncommitted changes); to force
+# auto fixes even if there are unstaged changes, use `--allow-dirty`:
+# ./ci/scripts/rust_fmt.sh --write --allow-dirty
+#
+# New scripts can use `rust_fmt.sh` as a reference.
+
+set -euo pipefail
+
+usage() {
+ cat >&2 < /dev/null; then
+ echo "Installing $cmd using: $install_cmd"
+ eval "$install_cmd"
+ fi
+}
+
+MODE="check"
+ALLOW_DIRTY=0
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ --write)
+ MODE="write"
+ ;;
+ --allow-dirty)
+ ALLOW_DIRTY=1
+ ;;
+ -h|--help)
+ usage
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ shift
+done
+
+SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
+
+ensure_tool "taplo" "cargo install taplo-cli --locked"
+ensure_tool "hawkeye" "cargo install hawkeye --locked"
+ensure_tool "typos" "cargo install typos-cli --locked"
+
+run_step() {
+ local name="$1"
+ shift
+ echo "[${SCRIPT_NAME}] Running ${name}"
+ "$@"
+}
+
+declare -a WRITE_STEPS=(
+ "ci/scripts/rust_fmt.sh|true"
+ "ci/scripts/rust_clippy.sh|true"
+ "ci/scripts/rust_toml_fmt.sh|true"
+ "ci/scripts/license_header.sh|true"
+ "ci/scripts/typos_check.sh|true"
+ "ci/scripts/doc_prettier_check.sh|true"
+)
+
+declare -a READONLY_STEPS=(
+ "ci/scripts/check_no_cargo_install_in_workflows.sh|false"
+ "ci/scripts/rust_docs.sh|false"
+)
+
+for entry in "${WRITE_STEPS[@]}" "${READONLY_STEPS[@]}"; do
+ IFS='|' read -r script_path supports_write <<<"$entry"
+ script_name="$(basename "$script_path")"
+ args=()
+ if [[ "$supports_write" == "true" && "$MODE" == "write" ]]; then
+ args+=(--write)
+ [[ $ALLOW_DIRTY -eq 1 ]] && args+=(--allow-dirty)
+ fi
+ if [[ ${#args[@]} -gt 0 ]]; then
+ run_step "$script_name" "$script_path" "${args[@]}"
+ else
+ run_step "$script_name" "$script_path"
+ fi
+done
diff --git a/versions/55.0.0/_downloads/3cce4d737d8c5814f5b50d859d21ba53/capitalized_example.csv b/versions/55.0.0/_downloads/3cce4d737d8c5814f5b50d859d21ba53/capitalized_example.csv
new file mode 100644
index 0000000000000..dbc8f5c5a0a60
--- /dev/null
+++ b/versions/55.0.0/_downloads/3cce4d737d8c5814f5b50d859d21ba53/capitalized_example.csv
@@ -0,0 +1,5 @@
+A,b,c
+1,2,3
+1,10,5
+2,5,6
+2,1,4
\ No newline at end of file
diff --git a/versions/55.0.0/_downloads/4a91b8629bd17ce8ae200ee0b5345f19/rust_fmt.sh b/versions/55.0.0/_downloads/4a91b8629bd17ce8ae200ee0b5345f19/rust_fmt.sh
new file mode 100644
index 0000000000000..16c87cea5e0fa
--- /dev/null
+++ b/versions/55.0.0/_downloads/4a91b8629bd17ce8ae200ee0b5345f19/rust_fmt.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
+source "${SCRIPT_DIR}/utils/git.sh"
+
+MODE="check"
+ALLOW_DIRTY=0
+
+usage() {
+ cat >&2 <&2 <&2 < 0;
+select distinct dict_10_required from t where dict_1000_optional is not NULL and i64_optional > 0;
+select distinct dict_10_required from t where dict_1000_optional is not NULL and i64_required > 0;
+select distinct dict_10_required from t where dict_1000_optional is not NULL and i64_required > 0;
+
+-- Test basic aggregations
+select dict_10_optional, count(*) from t group by dict_10_optional;
+select dict_10_optional, dict_100_optional, count(*) from t group by dict_10_optional, dict_100_optional;
+
+-- Test float aggregations
+select dict_10_optional, dict_100_optional, MIN(f64_required), MAX(f64_required), AVG(f64_required) from t group by dict_10_optional, dict_100_optional;
+select dict_10_optional, dict_100_optional, MIN(f64_optional), MAX(f64_optional), AVG(f64_optional) from t group by dict_10_optional, dict_100_optional;
+select dict_10_required, dict_100_required, MIN(f64_optional), MAX(f64_optional), AVG(f64_optional) from t group by dict_10_required, dict_100_required;
diff --git a/versions/55.0.0/_images/flamegraph.svg b/versions/55.0.0/_images/flamegraph.svg
new file mode 100644
index 0000000000000..951cbb1ff3664
--- /dev/null
+++ b/versions/55.0.0/_images/flamegraph.svg
@@ -0,0 +1,491 @@
+
\ No newline at end of file
diff --git a/versions/55.0.0/_images/original.svg b/versions/55.0.0/_images/original.svg
new file mode 100644
index 0000000000000..6ba0ece995a3c
--- /dev/null
+++ b/versions/55.0.0/_images/original.svg
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/versions/55.0.0/_images/original_dark.svg b/versions/55.0.0/_images/original_dark.svg
new file mode 100644
index 0000000000000..532434f9214a6
--- /dev/null
+++ b/versions/55.0.0/_images/original_dark.svg
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/versions/55.0.0/_images/samply_profiler.png b/versions/55.0.0/_images/samply_profiler.png
new file mode 100644
index 0000000000000..08b9907458568
Binary files /dev/null and b/versions/55.0.0/_images/samply_profiler.png differ
diff --git a/versions/55.0.0/_sources/contributor-guide/api-health.md.txt b/versions/55.0.0/_sources/contributor-guide/api-health.md.txt
new file mode 100644
index 0000000000000..a20bc284cf362
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/api-health.md.txt
@@ -0,0 +1,126 @@
+
+
+# API health policy
+
+DataFusion is used extensively as a library in other applications and has a
+large public API. We try to keep the API well maintained and minimize breaking
+changes to avoid issues for downstream users.
+
+## Breaking API Changes
+
+### What is the public Rust API and what is a breaking API change?
+
+An item is part of the public Rust API if it appears on the [docs.rs page].
+
+Breaking changes _require_ users to modify their code for it to compile and
+run, and are listed as "Major Changes" in the [SemVer Compatibility Section of
+the Cargo Book]. Common examples include:
+
+- Adding new required parameters to a function (`foo(a: i32, b: i32)` -> `foo(a: i32, b: i32, c: i32)`)
+- Removing a `pub` function
+- Changing the return type of a function
+- Adding a new function to a `trait` without a default implementation
+
+Examples of non-breaking changes include:
+
+- Marking a function as deprecated (`#[deprecated]`)
+- Adding a new function to a `trait` with a default implementation
+
+### What is the public SQL API and what is a breaking SQL change?
+
+DataFusion is also used as a SQL engine, so changes to SQL semantics (the
+results returned for a given query) are a form of breaking change. Even with
+no Rust API change, altering the behavior of an existing SQL construct can
+silently break downstream applications, dashboards, and tests.
+
+We apply the same caution to SQL semantics changes as to Rust API changes:
+the benefit must be weighed against the cost of breaking downstream users.
+
+### When to make breaking API changes?
+
+When possible, we prefer to avoid making breaking API changes. One common way to
+avoid such changes is to deprecate the old API, as described in the [Deprecation
+Guidelines](#deprecation-guidelines) section below.
+
+If you do want to propose a breaking API change, we must weigh the benefits of the
+change with the cost (impact on downstream users). It is often frustrating for
+downstream users to change their applications, and it is even more so if they
+do not gain improved capabilities.
+
+Examples of good reasons for a breaking API or SQL change:
+
+- It enables new use cases that were not possible before
+- It significantly improves performance
+- The previous behavior is clearly wrong (e.g. produces incorrect results)
+
+Examples of potentially weak reasons:
+
+- An internal refactor to make DataFusion more consistent
+- Removing an API that is not widely used but has not been marked as deprecated
+- Slightly improving compatibility with another database (for example,
+ PostgreSQL or DuckDB)
+
+### What to do when making breaking API changes?
+
+When making breaking Rust API changes, please:
+
+1. Add the `api-change` label so the change is highlighted in the release notes.
+2. Document non-trivial changes in the version-specific [Upgrade Guide].
+
+For breaking SQL changes, also describe the previous and new behavior in the PR
+description, ideally including example queries and results where appropriate.
+This makes review easier and helps downstream users discover the affected
+semantics.
+
+[docs.rs page]: https://docs.rs/datafusion/latest/datafusion/index.html
+[semver compatibility section of the cargo book]: https://doc.rust-lang.org/cargo/reference/semver.html#change-categories
+
+## Upgrade Guides
+
+When a change requires DataFusion users to modify their code as part of an
+upgrade, please consider documenting it in the version-specific [Upgrade Guide].
+
+[upgrade guide]: ../library-user-guide/upgrading/index.rst
+
+## Deprecation Guidelines
+
+When deprecating a method:
+
+- Mark the API as deprecated using `#[deprecated]` and specify the exact DataFusion version in which it was deprecated
+- Concisely describe the preferred API to help the user transition
+
+The deprecated version is the next version that introduces the deprecation. For
+example, if the current version listed in [`Cargo.toml`] is `43.0.0`, then the next
+version will be `44.0.0`.
+
+[`cargo.toml`]: https://github.com/apache/datafusion/blob/main/Cargo.toml
+
+To mark the API as deprecated, use the `#[deprecated(since = "...", note = "...")]` attribute.
+
+For example:
+
+```rust
+#[deprecated(since = "41.0.0", note = "Use new API instead")]
+pub fn api_to_deprecated(a: usize, b: usize) {}
+```
+
+Deprecated methods will remain in the codebase for a period of 6 major versions or 6 months, whichever is longer, to provide users ample time to transition away from them.
+
+Please refer to [DataFusion releases](https://crates.io/crates/datafusion/versions) to plan API migration ahead of time.
diff --git a/versions/55.0.0/_sources/contributor-guide/architecture.md.txt b/versions/55.0.0/_sources/contributor-guide/architecture.md.txt
new file mode 100644
index 0000000000000..8197e0cd00a08
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/architecture.md.txt
@@ -0,0 +1,91 @@
+
+
+# Architecture
+
+DataFusion's code structure and organization is described in the
+[crates.io documentation], to keep it as close to the source as
+possible. You can find the most up to date version in the [source code].
+
+[crates.io documentation]: https://docs.rs/datafusion/latest/datafusion/index.html#architecture
+[source code]: https://github.com/apache/datafusion/blob/main/datafusion/core/src/lib.rs
+
+## Forks vs Extension APIs
+
+DataFusion is a fast moving project, which results in frequent internal changes.
+This benefits DataFusion by allowing it to evolve and respond quickly to
+requests, but also means that maintaining a fork with major modifications
+sometimes requires non trivial work.
+
+The public API (what is accessible if you use the DataFusion releases from
+crates.io) is typically much more stable (though it does change from release to
+release as well).
+
+Thus, rather than forks, we recommend using one of the many extension APIs (such
+as `TableProvider`, `OptimizerRule`, or `ExecutionPlan`) to customize
+DataFusion. If you can not do what you want with the existing APIs, we would
+welcome you working with us to add new APIs to enable your use case, as
+described in the next section.
+
+Please see the [Extensions] section to find out more about existing DataFusion
+extensions and how to contribute your extension to the community.
+
+[extensions]: ../library-user-guide/extensions.md
+
+## Creating new Extension APIs
+
+DataFusion aims to be a general-purpose query engine, and thus the core crates
+contain features that are useful for a wide range of use cases. Use case specific
+functionality (such as very specific time series or stream processing features)
+are typically implemented using the extension APIs.
+
+If you have a use case that is not covered by the existing APIs, we would love to
+work with you to design a new general purpose API. There are often others who are
+interested in similar extensions and the act of defining the API often improves
+the code overall for everyone.
+
+Extension APIs that provide "safe" default behaviors are more likely to be
+suitable for inclusion in DataFusion, while APIs that require major changes to
+built-in operators are less likely. For example, it might make less sense
+to add an API to support a stream processing feature if that would result in
+slower performance for built-in operators. It may still make sense to add
+extension APIs for such features, but leave implementation of such operators in
+downstream projects.
+
+The process to create a new extension API is typically:
+
+- Look for an existing issue describing what you want to do, and file one if it
+ doesn't yet exist.
+- Discuss what the API would look like. Feel free to ask contributors (via `@`
+ mentions) for feedback (you can find such people by looking at the most
+ recently changed PRs and issues)
+- Prototype the new API, typically by adding an example (in
+ `datafusion-examples` or refactoring existing code) to show how it would work
+- Create a PR with the new API, and work with the community to get it merged
+
+Some benefits of using an example based approach are
+
+- Any future API changes will also keep your example going ensuring no
+ regression in functionality
+- There will be a blue print of any needed changes to your code if the APIs do change
+ (just look at what changed in your example)
+
+An example of this process was [creating a SQL Extension Planning API].
+
+[creating a sql extension planning api]: https://github.com/apache/datafusion/issues/11207
diff --git a/versions/55.0.0/_sources/contributor-guide/architecture/dependency-graph.md.txt b/versions/55.0.0/_sources/contributor-guide/architecture/dependency-graph.md.txt
new file mode 100644
index 0000000000000..be3502f48beda
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/architecture/dependency-graph.md.txt
@@ -0,0 +1,180 @@
+
+
+# Workspace Dependency Graph
+
+This page shows the dependency relationships between DataFusion's workspace
+crates. This only includes internal dependencies, external crates like `Arrow` are not included
+
+The dependency graph is auto-generated by `docs/scripts/generate_dependency_graph.sh` to ensure it stays up-to-date, and the script now runs automatically as part of `docs/build.sh`.
+
+## Dependency Graph for Workspace Crates
+
+
+
+```{raw} html
+
+
+```
+
+```{eval-rst}
+.. raw:: html
+ :file: ../../_static/data/deps.svg
+```
+
+```{raw} html
+
+
+```
+
+### Legend
+
+- black lines: normal dependency
+- blue lines: dev-dependency
+- green lines: build-dependency
+- dotted lines: optional dependency (could be removed by disabling a cargo feature)
+
+Transitive dependencies are intentionally ignored to keep the graph readable.
+
+The dependency graph is generated through `cargo depgraph` by `docs/scripts/generate_dependency_graph.sh`.
diff --git a/versions/55.0.0/_sources/contributor-guide/communication.md.txt b/versions/55.0.0/_sources/contributor-guide/communication.md.txt
new file mode 100644
index 0000000000000..b7d93d726a6bc
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/communication.md.txt
@@ -0,0 +1,106 @@
+
+
+# Community Communication
+
+We welcome participation from everyone and encourage you to join us, ask
+questions, and get involved.
+All participation in the Apache DataFusion project is governed by the
+Apache Software Foundation's [code of
+conduct](https://www.apache.org/foundation/policies/conduct.html).
+
+## GitHub
+
+The primary means of communication is the
+[GitHub repository](https://github.com/apache/datafusion) in the form of issues, discussions, and Pull Requests.
+Our repository is open to everyone. We encourage you to
+participate by reporting issues, asking questions, and contributing code.
+
+## Chat
+
+We also use the Discord and Slack platforms for lower latency, informal discussions and coordination.
+These are great places to
+meet other members of the community, ask questions, and brainstorm ideas.
+However, to ensure technical discussions are archived and accessible to everyone,
+all technical designs are recorded and formalized in GitHub issues.
+
+### Discord
+
+Historically, the most active discussion forum has been the [Arrow Rust Discord
+server][discord-link] which has specific channels for Arrow, DataFusion, and
+DataFusion subprojects such as Ballista, Comet, Java, Python, etc.
+DataFusion specific channels are prefixed with the `#datafusion-` tag.
+We recommend new users join this server for real-time discussions with the community.
+
+### Slack
+
+Some of the community also uses the [ASF Slack workspace] for discussions. This
+has historically been much less active than the Discord server.
+Unfortunately, due to spammers, the ASF Slack workspace [requires an invitation]
+to join. We are happy to invite any community member -- please ask for an
+invitation in the Discord server.
+
+[asf slack workspace]: https://the-asf.slack.com/
+[requires an invitation]: https://s.apache.org/slack-invite
+
+In Slack, we use these channels:
+
+- `#arrow`
+- `#arrow-rust`
+- `#datafusion`
+- `#datafusion-ballista`
+- `#datafusion-comet`
+- `#datafusion-python`
+
+## Weekly Video Call Syncs
+
+The DataFusion community also holds a weekly video call sync for real-time
+discussion and coordination. You can join the meeting using the Google Meet
+link below, and use the shared meeting document for agenda items and notes:
+
+- [Video call link](https://meet.google.com/nfg-eviu-qrm)
+- [Meeting details and notes](https://docs.google.com/document/d/1NBpkIAuU7O9h8Br5CbFksDhX-L9TyO9wmGLPMe0Plc8)
+
+### Job Board
+
+There are plenty of opportunities to work with DataFusion advertised on the
+#hiring channel on the [Arrow Rust Discord Server][discord-link].
+Please feel free to post links to DataFusion related jobs there.
+
+## Mailing Lists
+
+Like other Apache projects, we use [mailing lists] for certain purposes, most
+importantly release coordination and announcing new committers and PMC members.
+Other than these processes, most DataFusion mailing list traffic will link to a GitHub issue or PR where
+the actual discussion occurs. The project mailing lists are:
+
+- [`dev@datafusion.apache.org`](mailto:dev@datafusion.apache.org): the main
+ mailing list for release coordination and other project-wide discussions. Links:
+ [archives](https://lists.apache.org/list.html?dev@datafusion.apache.org),
+ [subscribe](mailto:dev-subscribe@datafusion.apache.org),
+ [unsubscribe](mailto:dev-unsubscribe@datafusion.apache.org)
+- `github@datafusion.apache.org`: read-only mailing list that receives all GitHub notifications for the project. Links:
+ [archives](https://lists.apache.org/list.html?github@datafusion.apache.org)
+- `commits@datafusion.apache.org`: read-only mailing list that receives all GitHub commits for the project. Links:
+ [archives](https://lists.apache.org/list.html?commits@datafusion.apache.org)
+- `private@datafusion.apache.org`: private mailing list for PMC members. This list has very little traffic, almost exclusively discussions on growing the committer and PMC membership. Links:
+ [archives](https://lists.apache.org/list.html?private@datafusion.apache.org)
+
+[mailing lists]: https://www.apache.org/foundation/mailinglists
+[discord-link]: https://discord.gg/Qw5gKqHxUM
diff --git a/versions/55.0.0/_sources/contributor-guide/development_environment.md.txt b/versions/55.0.0/_sources/contributor-guide/development_environment.md.txt
new file mode 100644
index 0000000000000..2e4e00726580b
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/development_environment.md.txt
@@ -0,0 +1,132 @@
+
+
+# Development Environment
+
+This section describes how you can get started at developing DataFusion.
+
+## Quick Start
+
+For the fastest path to a working local environment, follow these steps
+from the repository root:
+
+```shell
+# 1. Install Rust (https://rust-lang.org/tools/install/) and verify the active toolchain with
+rustup show
+
+# 2. Install protoc 3.15+ (see details below)
+protoc --version
+
+# 3. Download test data used by examples and many tests
+git submodule update --init --recursive
+
+# 4. Build the workspace
+cargo build
+
+# 5. Verify that Rust integration tests can be run
+cargo test -p datafusion --test parquet_integration
+
+# 6. Verify that sqllogictests can run
+cargo test --profile=ci --test sqllogictests
+```
+
+Notes:
+
+- The pinned Rust version is defined in `rust-toolchain.toml`.
+- `protoc` is required to compile DataFusion from source.
+- Some tests and examples rely on git submodule data being present locally.
+
+## Windows Setup
+
+```shell
+wget https://az792536.vo.msecnd.net/vms/VMBuild_20190311/VirtualBox/MSEdge/MSEdge.Win10.VirtualBox.zip
+choco install -y git rustup.install visualcpp-build-tools
+git-bash.exe
+cargo build
+```
+
+## Dev Container setup
+
+DataFusion has support for [dev containers](https://containers.dev/) which may be used for
+developing DataFusion in an isolated environment either locally or remote if desired. Using dev containers for developing
+DataFusion is not a requirement but is available where doing local development could be tricky
+such as with Windows and WSL2, those with older hardware, etc.
+
+For specific details on IDE support for dev containers see the documentation for [Visual Studio Code](https://code.visualstudio.com/docs/devcontainers/containers),
+[IntelliJ IDEA](https://www.jetbrains.com/help/idea/connect-to-devcontainer.html),
+[Rust Rover](https://www.jetbrains.com/help/rust/connect-to-devcontainer.html), and
+[GitHub Codespaces](https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers).
+
+## `protoc` Installation
+
+Compiling DataFusion from sources requires an installed version of the protobuf compiler, `protoc`.
+
+On most platforms this can be installed from your system's package manager. For example:
+
+```
+# Ubuntu
+$ sudo apt install -y protobuf-compiler
+
+# Fedora
+$ dnf install -y protobuf-devel
+
+# Arch Linux
+$ pacman -S protobuf
+
+# macOS
+$ brew install protobuf
+```
+
+You will want to verify the version installed is `3.15` or greater, which has support for explicit [field presence](https://github.com/protocolbuffers/protobuf/blob/v3.15.0/docs/field_presence.md). Older versions may fail to compile.
+
+```shell
+$ protoc --version
+libprotoc 3.15.0
+```
+
+Alternatively a binary release can be downloaded from the [Release Page](https://github.com/protocolbuffers/protobuf/releases) or [built from source](https://github.com/protocolbuffers/protobuf/blob/main/src/README.md).
+
+## Bootstrap Environment
+
+DataFusion is written in Rust and it uses a standard rust toolkit:
+
+- `rustup update stable` DataFusion generally uses the latest stable release of Rust, though it may lag when new Rust toolchains release
+ - See which toolchain is currently pinned in the [`rust-toolchain.toml`](https://github.com/apache/datafusion/blob/main/rust-toolchain.toml) file
+ - This can cause issues such as not having the rust-analyzer component installed for the specified toolchain, in which case just install it manually, e.g. `rustup component add --toolchain 1.97.0 rust-analyzer`
+- `cargo build`
+- `cargo fmt` to format the code
+- etc.
+
+Testing setup:
+
+- `git submodule init`
+- `git submodule update --init --remote --recursive`
+- `cargo test` to run tests
+
+Note that running `cargo test` requires significant memory resources, due to cargo running many tests in parallel by default. If you run into issues with slow tests or system lock ups, you can significantly reduce the memory required by instead running `cargo test -- --test-threads=1`. For more information see [this issue](https://github.com/apache/datafusion/issues/5347).
+
+Formatting instructions:
+
+- [ci/scripts/rust_fmt.sh](../../../ci/scripts/rust_fmt.sh)
+- [ci/scripts/rust_clippy.sh](../../../ci/scripts/rust_clippy.sh)
+- [ci/scripts/rust_toml_fmt.sh](../../../ci/scripts/rust_toml_fmt.sh)
+
+or run them all at once:
+
+- [dev/rust_lint.sh](../../../dev/rust_lint.sh)
diff --git a/versions/55.0.0/_sources/contributor-guide/governance.md.txt b/versions/55.0.0/_sources/contributor-guide/governance.md.txt
new file mode 100644
index 0000000000000..c0208c9de1476
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/governance.md.txt
@@ -0,0 +1,179 @@
+
+
+# Governance
+
+## Overview
+
+DataFusion is part of the [Apache Software Foundation] and is governed following
+the [Apache Way] and [project management guidelines], [independently of
+commercial interests].
+
+[apache software foundation]: https://www.apache.org/
+[apache way]: https://www.apache.org/theapacheway/
+[project management guidelines]: https://www.apache.org/foundation/how-it-works.html#management
+[independently of commercial interests]: https://community.apache.org/projectIndependence.html
+
+As much as practicable, we strive to make decisions by consensus, and anyone in
+the community is encouraged to propose ideas, start discussions, and contribute
+to the project.
+
+## People
+
+DataFusion is currently governed by the following individuals
+
+
+
+
+
+| Name | Apache ID | github | Affiliation | Role |
+| ------------------------- | ---------------- | ------------------------------------------------------- | -------------- | --------- |
+| Andrew Lamb | alamb | [alamb](https://github.com/alamb) | InfluxData | PMC Chair |
+| Adrian Garcia Badaracco | adriangb | [adriangb](https://github.com/adriangb) | Pydantic | PMC |
+| Andrew Grove | agrove | [andygrove](https://github.com/andygrove) | Apple | PMC |
+| Mustafa Akur | akurmustafa | [akurmustafa](https://github.com/akurmustafa) | OHSU | PMC |
+| Berkay Şahin | berkay | [berkaysynnada](https://github.com/berkaysynnada) | Synnada | PMC |
+| Oleksandr Voievodin | comphead | [comphead](https://github.com/comphead) | Apple | PMC |
+| Daniël Heres | dheres | [Dandandan](https://github.com/Dandandan) | | PMC |
+| QP Hou | houqp | [houqp](https://github.com/houqp) | | PMC |
+| Jie Wen | jakevin | [jackwener](https://github.com/jackwener) | | PMC |
+| Jay Zhan | jayzhan | [jayzhan211](https://github.com/jayzhan211) | | PMC |
+| Jeffrey Vo | jeffreyvo | [Jefffrey](https://github.com/Jefffrey) | | PMC |
+| Jonah Gao | jonah | [jonahgao](https://github.com/jonahgao) | | PMC |
+| Kun Liu | liukun | [liukun4515](https://github.com/liukun4515) | | PMC |
+| Matt Butrovich | mbutrovich | [mbutrovich](https://github.com/mbutrovich) | Apple | PMC |
+| Marko Milenković | milenkovicm | [milenkovicm](https://github.com/milenkovicm) | | PMC |
+| Mehmet Ozan Kabak | ozankabak | [ozankabak](https://github.com/ozankabak) | Synnada, Inc | PMC |
+| Tim Saucer | timsaucer | [timsaucer](https://github.com/timsaucer) | | PMC |
+| L. C. Hsieh | viirya | [viirya](https://github.com/viirya) | Databricks | PMC |
+| Ruihang Xia | wayne | [waynexia](https://github.com/waynexia) | Greptime | PMC |
+| Wes McKinney | wesm | [wesm](https://github.com/wesm) | Posit | PMC |
+| Will Jones | wjones127 | [wjones127](https://github.com/wjones127) | LanceDB | PMC |
+| Xudong Wang | xudong963 | [xudong963](https://github.com/xudong963) | Polygon.io | PMC |
+| Yongting You | ytyou | [2010YOUY01](https://github.com/2010YOUY01) | Independent | PMC |
+| Brent Gardner | avantgardner | [avantgardnerio](https://github.com/avantgardnerio) | Coralogix | Committer |
+| Bhargava Vadlamani | bhargava | [coderfender](https://github.com/coderfender) | | Committer |
+| Dmitrii Blaginin | blaginin | [blaginin](https://github.com/blaginin) | SpiralDB | Committer |
+| Piotr Findeisen | findepi | [findepi](https://github.com/findepi) | dbt Labs | Committer |
+| Gabriel Musat | gabotechs | [gabotechs](https://github.com/gabotechs) | DataDog | Committer |
+| Jax Liu | goldmedal | [goldmedal](https://github.com/goldmedal) | Canner | Committer |
+| Huaxin Gao | huaxingao | [huaxingao](https://github.com/huaxingao) | | Committer |
+| Ifeanyi Ubah | iffyio | [iffyio](https://github.com/iffyio) | Validio | Committer |
+| Liu Jiayu | jiayuliu | [jimexist](https://github.com/jimexist) | | Committer |
+| Ruiqiu Cao | kamille | [Rachelint](https://github.com/Rachelint) | Tencent | Committer |
+| Kazuyuki Tanimura | kazuyukitanimura | [kazuyukitanimura](https://github.com/kazuyukitanimura) | | Committer |
+| Eduard Karacharov | korowa | [korowa](https://github.com/korowa) | | Committer |
+| Siew Kam Onn | kosiew | [kosiew](https://github.com/kosiew) | | Committer |
+| Kumar Ujjawal | kumarujjawal | [kumarUjjawal](https://github.com/kumarUjjawal) | | Committer |
+| Lewis Zhang | linwei | [lewiszlw](https://github.com/lewiszlw) | diit.cn | Committer |
+| Metehan Yildirim | mete | [metegenez](https://github.com/metegenez) | | Committer |
+| Martin Tzvetanov Grigorov | mgrigorov | [martin-g](https://github.com/martin-g) | | Committer |
+| Wang Mingming | mingmwang | [mingmwang](https://github.com/mingmwang) | | Committer |
+| Michael Ward | mjward | [Michael-J-Ward ](https://github.com/Michael-J-Ward) | | Committer |
+| Marco Neumann | mneumann | [crepererum](https://github.com/crepererum) | InfluxData | Committer |
+| Neil Conway | neilc | [neilconway](https://github.com/neilconway) | | Committer |
+| Zhong Yanghong | nju_yaho | [yahoNanJing](https://github.com/yahoNanJing) | | Committer |
+| Nuno Faria | nunofaria | [nuno-faria](https://github.com/nuno-faria) | | Committer |
+| Paddy Horan | paddyhoran | [paddyhoran](https://github.com/paddyhoran) | Assured Allies | Committer |
+| Parth Chandra | parthc | [parthchandra](https://github.com/parthchandra) | Apple | Committer |
+| Rémi Dettai | rdettai | [rdettai](https://github.com/rdettai) | | Committer |
+| Raz Luvaton | rluvaton | [rluvaton](https://github.com/rluvaton) | | Committer |
+| Chao Sun | sunchao | [sunchao](https://github.com/sunchao) | OpenAI | Committer |
+| Daniel Harris | thinkharderdev | [thinkharderdev](https://github.com/thinkharderdev) | Coralogix | Committer |
+| Raphael Taylor-Davies | tustvold | [tustvold](https://github.com/tustvold) | | Committer |
+| Zhen Wang | wangzhen | [wForget](https://github.com/wForget) | | Committer |
+| Weijun Huang | weijun | [Weijun-H](https://github.com/Weijun-H) | OrbDB | Committer |
+| Yang Jiang | yangjiang | [Ted-jiang](https://github.com/Ted-jiang) | Ebay | Committer |
+| Yoav Cohen | ycohen | [yoavcloud](https://github.com/yoavcloud) | | Committer |
+| Yijie Shen | yjshen | [yjshen](https://github.com/yjshen) | DataPelago | Committer |
+| Qi Zhu | zhuqi | [zhuqi-lucas](https://github.com/zhuqi-lucas) | Polygon.io | Committer |
+
+
+
+Note that the authoritative list of PMC and committers is the [Apache Phonebook]
+
+[apache phonebook]: https://projects.apache.org/committee.html?datafusion
+
+## Roles
+
+- **Contributors**: Anyone who contributes to the project, whether it be code,
+ documentation, testing, issue reports, code, or some other forms.
+
+- **Committers**: Contributors who have been granted write access to the
+ project's source code repository. Committers are responsible for reviewing and
+ merging pull requests. Committers are chosen by the PMC.
+
+- **Project Management Committee (PMC)**: The PMC is responsible for the
+ oversight of the project. The PMC is responsible for making decisions about the
+ project, including the addition of new committers and PMC members. The PMC is
+ also responsible for [voting] on releases and ensuring that the project follows
+ the [Apache Way].
+
+[voting]: https://www.apache.org/foundation/voting.html
+
+## Becoming a Committer
+
+Contributors with sustained, high-quality activity may be invited to become
+committers by the PMC as a recognition of their contribution to the project and
+their shared commitment. Committers have the significant responsibility of using
+their status and access to improve the project for the entire community.
+
+When considering inviting someone to be a committer, the PMC looks for
+contributors who are already doing the work and exercising the judgment expected
+of a committer. After all, any contributor can do all of the things a committer
+does except for merge a PR. While there is no set list of requirements, nor a
+checklist that entitles one to commit privileges, typical behaviors include:
+
+- Contributions beyond pull requests, such as reviewing other pull requests,
+ fixing bugs and documentation, triaging issues, answering community questions,
+ improving usability, helping with CI, verifying releases, etc.
+
+- Contributions that are consistent in quality and sustained
+ over time, typically on the order of 6 months or more.
+
+- Assistance growing the size and health of the community via constructive,
+ respectful, and consensus driven interactions, as described in our [Code of
+ Conduct] and the [Apache Way].
+
+If you feel you should be offered committer privileges, but have not been, you
+can reach out to one of the PMC members or the private@datafusion.apache.org mailing
+list.
+
+[code of conduct]: https://www.apache.org/foundation/policies/conduct.html
+
+## Becoming a PMC Member
+
+Committers with long term sustained contributions to the project may be invited
+to join the PMC. This is a recognition of a significant contribution to growing
+the community, improving the project, and helping to guide the project's
+direction, typically over the course of a year or more.
diff --git a/versions/55.0.0/_sources/contributor-guide/gsoc/gsoc_application_guidelines_2025.md.txt b/versions/55.0.0/_sources/contributor-guide/gsoc/gsoc_application_guidelines_2025.md.txt
new file mode 100644
index 0000000000000..c127b4231b8e1
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/gsoc/gsoc_application_guidelines_2025.md.txt
@@ -0,0 +1,105 @@
+# GSoC Application Guidelines (2025)
+
+## Introduction
+
+Welcome to the Apache DataFusion Google Summer of Code (GSoC) application guidelines. We are excited to support contributors who are passionate about open-source data processing technologies and eager to contribute to DataFusion. This document provides detailed instructions on how to apply, what we expect from applicants, and how you can increase your chances of selection.
+
+## Why Contribute to Apache DataFusion?
+
+Apache DataFusion is a high-performance, extensible query engine for data processing, written in Rust and designed for modern analytical workloads. GSoC offers a fantastic opportunity for students and early-career developers to work with experienced mentors, learn about open-source development, and make meaningful contributions.
+
+## Prerequisites
+
+Before applying, ensure you:
+
+- Have read and understood the [Apache DataFusion Contributor Guide](https://datafusion.apache.org/contributor-guide/index.html).
+- Have basic familiarity with Rust programming and SQL-based data processing.
+- Have explored DataFusion’s GitHub repository and tried running sample queries.
+- Have introduced yourself on our mailing list or Discord to discuss project ideas with potential mentors.
+
+## Application Process
+
+To apply, follow these steps:
+
+1. **Choose a Project Idea**
+ - Review the list of proposed GSoC projects for Apache DataFusion.
+ - If you have your own project idea, discuss it with potential mentors before submitting your proposal.
+2. **Engage with the Community**
+ - Join our [mailing list](mailto:dev@datafusion.apache.org) and [Discord](https://discord.gg/jHzkpK4em5) to introduce yourself and ask questions.
+ - Optional: Submit a small pull request (PR) for an issue marked with the **good first issue** tag to understand/test whether you enjoy working on Apache DataFusion, get comfortable with navigating the codebase and demonstrate your ability.
+3. **Write a Clear Proposal**
+ - You can use the template below to structure your proposal.
+ - Ensure it is has sufficient details and is feasible.
+ - Seek feedback from mentors before submission.
+
+## Application Template
+
+```
+# Apache DataFusion GSoC Application
+
+## Personal Information
+
+- **Name:**
+- **GitHub ID:**
+- **Email:**
+- **LinkedIn/Personal Website (if any):**
+- **Time Zone & Available Hours Per Week:**
+
+## Project Proposal
+
+### Title
+
+Provide a concise and descriptive project title.
+
+### Synopsis
+
+Summarize the project in a few sentences. What problem does it solve? Why is it important? If you choose an idea proposed by us, this can simply be a summary of your research on the problem and/or your understanding of it.
+
+### Benefits to the Community
+
+Explain how this project will improve Apache DataFusion and its ecosystem. If you choose an idea proposed by us, this can simply be a summary of your understanding of potential benefits.
+
+### Deliverables & Milestones
+
+Consult with project mentors to come up with a rough roadmap for what you plan to accomplish, ensuring it aligns with GSoC’s timeline.
+
+### Technical Details
+
+Discuss the technologies, tools, and methodologies you plan to use. Mention any potential challenges and how you plan to address them.
+
+### Related Work & References
+
+List any relevant research, documentation, or prior work that informs your proposal.
+
+## Personal Experience
+
+### Relevant Skills & Background
+
+Describe your experience with Rust, databases, and open-source contributions.
+
+### Past Open-Source Contributions
+
+List any prior contributions (links to PRs, issues, repositories).
+
+### Learning Plan
+
+Explain how you will learn new skills required for this project.
+
+## Mentor & Communication
+
+- **Preferred Communication Channels:** (Email, Discord, etc.)
+- **Weekly Progress Updates Plan:** Describe how you plan to remain in sync with your mentor(s).
+
+## Additional Information
+
+Add anything else you believe strengthens your application.
+
+```
+
+## Final Steps
+
+- Review your proposal for clarity and completeness.
+- Submit your proposal via the GSoC portal before the deadline.
+- Stay active in the community and be ready to discuss your application with mentors.
+
+We look forward to your application and your contributions to Apache DataFusion!
diff --git a/versions/55.0.0/_sources/contributor-guide/gsoc/gsoc_project_ideas_2025.md.txt b/versions/55.0.0/_sources/contributor-guide/gsoc/gsoc_project_ideas_2025.md.txt
new file mode 100644
index 0000000000000..d81d9eb9adab5
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/gsoc/gsoc_project_ideas_2025.md.txt
@@ -0,0 +1,112 @@
+# GSoC Project Ideas (2025)
+
+## Introduction
+
+Welcome to the Apache DataFusion Google Summer of Code (GSoC) 2025 project ideas list. Below you can find information about the projects. Please refer to [this page](https://datafusion.apache.org/contributor-guide/gsoc_application_guidelines.html) for application guidelines.
+
+## Projects
+
+### [Implement Continuous Monitoring of DataFusion Performance](https://github.com/apache/datafusion/issues/5504)
+
+- **Description and Outcomes:** DataFusion lacks continuous monitoring of how performance evolves over time -- we do this somewhat manually today. Even though performance has been one of our top priorities for a while now, we didn't build a continuous monitoring system yet. This linked issue contains a summary of all the previous efforts that made us inch closer to having such a system, but a functioning system needs to built on top of that progress. A student successfully completing this project would gain experience in building an end-to-end monitoring system that integrates with GitHub, scheduling/running benchmarks on some sort of a cloud infrastructure, and building a versatile web UI to expose the results. The outcome of this project will benefit Apache DataFusion on an ongoing basis in its quest for ever-more performance.
+- **Category:** Tooling
+- **Difficulty:** Medium
+- **Possible Mentor(s) and/or Helper(s):** [alamb](https://github.com/alamb) and [mertak-synnada](https://github.com/mertak-synnada)
+- **Skills:** DevOps, Cloud Computing, Web Development, Integrations
+- **Expected Project Size:** 175 to 350 hours\*
+
+### [Supporting Correlated Subqueries](https://github.com/apache/datafusion/issues/5483)
+
+- **Description and Outcomes:** Correlated subqueries are an important SQL feature that enables some users to express their business logic more intuitively without thinking about "joins". Even though DataFusion has decent join support, it doesn't fully support correlated subqueries. The linked epic contains bite-size pieces of the steps necessary to achieve full support. For students interested in internals of data systems and databases, this project is a good opportunity to apply and/or improve their computer science knowledge. The experience of adding such a feature to a widely-used foundational query engine can also serve as a good opportunity to kickstart a career in the area of databases and data systems.
+- **Category:** Core
+- **Difficulty:** Advanced
+- **Possible Mentor(s) and/or Helper(s):** [jayzhan-synnada](https://github.com/jayzhan-synnada) and [xudong963](https://github.com/xudong963)
+- **Skills:** Databases, Algorithms, Data Structures, Testing Techniques
+- **Expected Project Size:** 350 hours
+
+### Improving DataFusion DX (e.g. [1](https://github.com/apache/datafusion/issues/9371) and [2](https://github.com/apache/datafusion/issues/14429))
+
+- **Description and Outcomes:** While performance, extensibility and customizability is DataFusion's strong aspects, we have much work to do in terms of user-friendliness and ease of debug-ability. This project aims to make strides in these areas by improving terminal visualizations of query plans and increasing the "deployment" of the newly-added diagnostics framework. This project is a potential high-impact project with high output visibility, and reduce the barrier to entry to new users.
+- **Category:** DX
+- **Difficulty:** Medium
+- **Possible Mentor(s) and/or Helper(s):** [eliaperantoni](https://github.com/eliaperantoni) and [mkarbo](https://github.com/mkarbo)
+- **Skills:** Software Engineering, Terminal Visualizations
+- **Expected Project Size:** 175 to 350 hours\*
+
+### [Robust WASM Support](https://github.com/apache/datafusion/issues/13815)
+
+- **Description and Outcomes:** DataFusion can be compiled today to WASM with some care. However, it is somewhat tricky and brittle. Having robust WASM support improves the _embeddability_ aspect of DataFusion, and can enable many practical use cases. A good conclusion of this project would be the addition of a live demo sub-page to the DataFusion homepage.
+- **Category:** Build
+- **Difficulty:** Medium
+- **Possible Mentor(s) and/or Helper(s):** [alamb](https://github.com/alamb) and [waynexia](https://github.com/waynexia)
+- **Skills:** WASM, Advanced Rust, Web Development, Software Engineering
+- **Expected Project Size:** 175 to 350 hours\*
+
+### [High Performance Aggregations](https://github.com/apache/datafusion/issues/7000)
+
+- **Description and Outcomes:** An aggregation is one of the most fundamental operations within a query engine. Practical performance in many use cases, and results in many well-known benchmarks (e.g. [ClickBench](https://benchmark.clickhouse.com/)), depend heavily on aggregation performance. DataFusion community has been working on improving aggregation performance for a while now, but there is still work to do. A student working on this project will get the chance to hone their skills on high-performance, low(ish) level coding, intricacies of measuring performance, data structures and others.
+- **Category:** Core
+- **Difficulty:** Advanced
+- **Possible Mentor(s) and/or Helper(s):** [jayzhan-synnada](https://github.com/jayzhan-synnada) and [Rachelint](https://github.com/Rachelint)
+- **Skills:** Algorithms, Data Structures, Advanced Rust, Databases, Benchmarking Techniques
+- **Expected Project Size:** 350 hours
+
+### [Improving Python Bindings](https://github.com/apache/datafusion-python)
+
+- **Description and Outcomes:** DataFusion offers Python bindings that enable users to build data systems using Python. However, the Python bindings are still relatively low-level, and do not expose all APIs libraries like [Pandas](https://pandas.pydata.org/) and [Polars](https://pola.rs/) with a end-user focus offer. This project aims to improve DataFusion's Python bindings to make progress towards moving it closer to such libraries in terms of built-in APIs and functionality.
+- **Category:** Python Bindings
+- **Difficulty:** Medium
+- **Possible Mentor(s) and/or Helper(s):** [timsaucer](https://github.com/timsaucer)
+- **Skills:** APIs, FFIs, DataFrame Libraries
+- **Expected Project Size:** 175 to 350 hours\*
+
+### [Optimizing DataFusion Binary Size](https://github.com/apache/datafusion/issues/13816)
+
+- **Description and Outcomes:** DataFusion is a foundational library with a large feature set. Even though we try to avoid adding too many dependencies and implement many low-level functionalities inside the codebase, the fast moving nature of the project results in an accumulation of dependencies over time. This inflates DataFusion's binary size over time, which reduces portability and embeddability. This project involves a study of the codebase, using compiler tooling, to understand where code bloat comes from, simplifying/reducing the number of dependencies by efficient in-house implementations, and avoiding code duplications.
+- **Category:** Core/Build
+- **Difficulty:** Medium
+- **Possible Mentor(s) and/or Helper(s):** [comphead](https://github.com/comphead) and [alamb](https://github.com/alamb)
+- **Skills:** Software Engineering, Refactoring, Dependency Management, Compilers
+- **Expected Project Size:** 175 to 350 hours\*
+
+### [Ergonomic SQL Features](https://github.com/apache/datafusion/issues/14514)
+
+- **Description and Outcomes:** [DuckDB](https://duckdb.org/) has many innovative features that significantly improve the SQL UX. Even though some of those features are already implemented in DataFusion, there are many others we can implement (and get inspiration from). [This page](https://duckdb.org/docs/sql/dialect/friendly_sql.html) contains a good summary of such features. Each such feature will serve as a bite-size, achievable milestone for a cool GSoC project that will have user-facing impact improving the UX on a broad basis. The project will start with a survey of what is already implemented, what is missing, and kick off with a prioritization proposal/implementation plan.
+- **Category:** SQL FE
+- **Difficulty:** Medium
+- **Possible Mentor(s) and/or Helper(s):** [berkaysynnada](https://github.com/berkaysynnada)
+- **Skills:** SQL, Planning, Parsing, Software Engineering
+- **Expected Project Size:** 350 hours
+
+### [Advanced Interval Analysis](https://github.com/apache/datafusion/issues/14515)
+
+- **Description and Outcomes:** DataFusion implements interval arithmetic and utilizes it for range estimations, which enables use cases in data pruning, optimizations and statistics. However, the current implementation only works efficiently for forward evaluation; i.e. calculating the output range of an expression given input ranges (ranges of columns). When propagating constraints using the same graph, the current approach requires multiple bottom-up and top-down traversals to narrow column bounds fully. This project aims to fix this deficiency by utilizing a better algorithmic approach. Note that this is a _very advanced_ project for students with a deep interest in computational methods, expression graphs, and constraint solvers.
+- **Category:** Core
+- **Difficulty:** Advanced
+- **Possible Mentor(s) and/or Helper(s):** [ozankabak](https://github.com/ozankabak) and [berkaysynnada](https://github.com/berkaysynnada)
+- **Skills:** Algorithms, Data Structures, Applied Mathematics, Software Engineering
+- **Expected Project Size:** 350 hours
+
+### [Spark-Compatible Functions Crate](https://github.com/apache/datafusion/issues/5600)
+
+- **Description and Outcomes:** In general, DataFusion aims to be compatible with PostgreSQL in terms of functions and behaviors. However, there are many users (and downstream projects, such as [DataFusion Comet](https://datafusion.apache.org/comet/)) that desire compatibility with [Apache Spark](https://spark.apache.org/). This project aims to collect Spark-compatible functions into a separate crate to help such users and/or projects. The project will be an exercise in creating the right APIs, explaining how to use them, and then telling the world about them (e.g. via creating a compatibility-tracking page cataloging such functions, writing blog posts etc.).
+- **Category:** Extensions
+- **Difficulty:** Medium
+- **Possible Mentor(s) and/or Helper(s):** [alamb](https://github.com/alamb) and [andygrove](https://github.com/andygrove)
+- **Skills:** SQL, Spark, Software Engineering
+- **Expected Project Size:** 175 to 350 hours\*
+
+### [SQL Fuzzing Framework in Rust](https://github.com/apache/datafusion/issues/14535)
+
+- **Description and Outcomes:** Fuzz testing is a very important technique we utilize often in DataFusion. Having SQL-level fuzz testing enables us to battle-test DataFusion in an end-to-end fashion. Initial version of our fuzzing framework is Java-based, but the time has come to migrate to Rust-native solution. This will simplify the overall implementation (by avoiding things like JDBC), enable us to implement more advanced algorithms for query generation, and attract more contributors over time. This project is a good blend of software engineering, algorithms and testing techniques (i.e. fuzzing techniques).
+- **Category:** Extensions
+- **Difficulty:** Advanced
+- **Possible Mentor(s) and/or Helper(s):** [2010YOUY01](https://github.com/2010YOUY01)
+- **Skills:** SQL, Testing Techniques, Advanced Rust, Software Engineering
+- **Expected Project Size:** 175 to 350 hours\*
+
+\*_There is enough material to make this a 350-hour project, but it is granular enough to make it a 175-hour project as well._
+
+## Contact Us
+
+You can join our [mailing list](mailto:dev%40datafusion.apache.org) and [Discord](https://discord.gg/jHzkpK4em5) to introduce yourself and ask questions.
diff --git a/versions/55.0.0/_sources/contributor-guide/gsoc/index.rst.txt b/versions/55.0.0/_sources/contributor-guide/gsoc/index.rst.txt
new file mode 100644
index 0000000000000..10b0013e9b169
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/gsoc/index.rst.txt
@@ -0,0 +1,36 @@
+.. Licensed to the Apache Software Foundation (ASF) under one
+.. or more contributor license agreements. See the NOTICE file
+.. distributed with this work for additional information
+.. regarding copyright ownership. The ASF licenses this file
+.. to you under the Apache License, Version 2.0 (the
+.. "License"); you may not use this file except in compliance
+.. with the License. You may obtain a copy of the License at
+
+.. http://www.apache.org/licenses/LICENSE-2.0
+
+.. Unless required by applicable law or agreed to in writing,
+.. software distributed under the License is distributed on an
+.. "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+.. KIND, either express or implied. See the License for the
+.. specific language governing permissions and limitations
+.. under the License.
+
+Google Summer of Code (GSOC)
+============================
+
+DataFusion has participated in
+`Google Summer of Code (GSOC) `_
+since 2025. GSOC is a global program that offers students stipends to
+write code for open source projects.
+
+If you are a interested in contributing to DataFusion, we encourage you
+to apply. You can find more information about the application process and
+project ideas in the sections below.
+
+
+.. toctree::
+ :maxdepth: 1
+
+ gsoc_application_guidelines_2025
+ gsoc_project_ideas_2025
+
diff --git a/versions/55.0.0/_sources/contributor-guide/howtos.md.txt b/versions/55.0.0/_sources/contributor-guide/howtos.md.txt
new file mode 100644
index 0000000000000..18d9391d24bbe
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/howtos.md.txt
@@ -0,0 +1,190 @@
+
+
+# HOWTOs
+
+## How to update the version of Rust used in CI tests
+
+Make a PR to update the [rust-toolchain] file in the root of the repository.
+
+[rust-toolchain]: https://github.com/apache/datafusion/blob/main/rust-toolchain.toml
+
+## Adding new functions
+
+**Implementation**
+
+| Function type | Location to implement | Trait to implement | Macros to use | Example |
+| ------------- | ------------------------- | ---------------------------------------------- | ------------------------------------------------ | -------------------- |
+| Scalar | [functions][df-functions] | [`ScalarUDFImpl`] | `make_udf_function!()` and `export_functions!()` | [`advanced_udf.rs`] |
+| Nested | [functions-nested] | [`ScalarUDFImpl`] | `make_udf_expr_and_func!()` | |
+| Aggregate | [functions-aggregate] | [`AggregateUDFImpl`] and an [`Accumulator`] | `make_udaf_expr_and_func!()` | [`advanced_udaf.rs`] |
+| Window | [functions-window] | [`WindowUDFImpl`] and a [`PartitionEvaluator`] | `define_udwf_and_expr!()` | [`advanced_udwf.rs`] |
+| Table | [functions-table] | [`TableFunctionImpl`] and a [`TableProvider`] | `create_udtf_function!()` | [`simple_udtf.rs`] |
+
+- The macros are to simplify some boilerplate such as ensuring a DataFrame API compatible function is also created
+- Ensure new functions are properly exported through the subproject
+ `mod.rs` or `lib.rs`.
+- Functions should preferably provide documentation via the `#[user_doc(...)]` attribute so their documentation
+ can be included in the SQL reference documentation (see below section)
+- Scalar functions are further grouped into modules for families of functions (e.g. string, math, datetime).
+ Functions should be added to the relevant module; if a new module needs to be created then a new [Rust feature]
+ should also be added to allow DataFusion users to conditionally compile the modules as needed
+- Aggregate functions can optionally implement a [`GroupsAccumulator`] for better performance
+
+Spark compatible functions are [located in separate crate][df-spark] but otherwise follow the same steps, though all
+function types (e.g. scalar, nested, aggregate) are grouped together in the single location.
+
+[df-functions]: https://github.com/apache/datafusion/tree/main/datafusion/functions
+[functions-nested]: https://github.com/apache/datafusion/tree/main/datafusion/functions-nested
+[functions-aggregate]: https://github.com/apache/datafusion/tree/main/datafusion/functions-aggregate
+[functions-window]: https://github.com/apache/datafusion/tree/main/datafusion/functions-window
+[functions-table]: https://github.com/apache/datafusion/tree/main/datafusion/functions-table
+[df-spark]: https://github.com/apache/datafusion/tree/main/datafusion/spark
+[`scalarudfimpl`]: https://docs.rs/datafusion/latest/datafusion/logical_expr/trait.ScalarUDFImpl.html
+[`aggregateudfimpl`]: https://docs.rs/datafusion/latest/datafusion/logical_expr/trait.AggregateUDFImpl.html
+[`accumulator`]: https://docs.rs/datafusion/latest/datafusion/logical_expr/trait.Accumulator.html
+[`groupsaccumulator`]: https://docs.rs/datafusion/latest/datafusion/logical_expr/trait.GroupsAccumulator.html
+[`windowudfimpl`]: https://docs.rs/datafusion/latest/datafusion/logical_expr/trait.WindowUDFImpl.html
+[`partitionevaluator`]: https://docs.rs/datafusion/latest/datafusion/logical_expr/trait.PartitionEvaluator.html
+[`tablefunctionimpl`]: https://docs.rs/datafusion/latest/datafusion/catalog/trait.TableFunctionImpl.html
+[`tableprovider`]: https://docs.rs/datafusion/latest/datafusion/catalog/trait.TableProvider.html
+[`advanced_udf.rs`]: https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/udf/advanced_udf.rs
+[`advanced_udaf.rs`]: https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/udf/advanced_udaf.rs
+[`advanced_udwf.rs`]: https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/udf/advanced_udwf.rs
+[`simple_udtf.rs`]: https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/udf/simple_udtf.rs
+[rust feature]: https://doc.rust-lang.org/cargo/reference/features.html
+
+**Testing**
+
+Prefer adding `sqllogictest` integration tests where the function is called via SQL against
+well known data and returns an expected result. See the existing [test files][slt-test-files] if
+there is an appropriate file to add test cases to, otherwise create a new file. See the
+[`sqllogictest` documentation][slt-readme] for details on how to construct these tests.
+Ensure edge case, `null` input cases are considered in these tests.
+
+If a behaviour cannot be tested via `sqllogictest` (e.g. testing `simplify()`, needs to be
+tested in isolation from the optimizer, difficult to construct exact input via `sqllogictest`)
+then tests can be added as Rust unit tests in the implementation module, though these should be
+kept minimal where possible
+
+[slt-test-files]: https://github.com/apache/datafusion/tree/main/datafusion/sqllogictest/test_files
+[slt-readme]: https://github.com/apache/datafusion/blob/main/datafusion/sqllogictest/README.md
+
+**Documentation**
+
+Run documentation update script `./dev/update_function_docs.sh` which will update the relevant
+markdown document [here][fn-doc-home] (see the documents for [scalar][fn-doc-scalar],
+[aggregate][fn-doc-aggregate] and [window][fn-doc-window] functions)
+
+- You _should not_ manually update the markdown document after running the script as those manual
+ changes would be overwritten on next execution
+- Reference [GitHub issue] which introduced this behaviour
+
+[fn-doc-home]: https://github.com/apache/datafusion/blob/main/docs/source/user-guide/sql
+[fn-doc-scalar]: https://github.com/apache/datafusion/blob/main/docs/source/user-guide/sql/scalar_functions.md
+[fn-doc-aggregate]: https://github.com/apache/datafusion/blob/main/docs/source/user-guide/sql/aggregate_functions.md
+[fn-doc-window]: https://github.com/apache/datafusion/blob/main/docs/source/user-guide/sql/window_functions.md
+[github issue]: https://github.com/apache/datafusion/issues/12740
+
+## How to display plans graphically
+
+The query plans represented by `LogicalPlan` nodes can be graphically
+rendered using [Graphviz](https://www.graphviz.org/).
+
+To do so, save the output of the `display_graphviz` function to a file.:
+
+```rust
+// Create plan somehow...
+let mut output = File::create("/tmp/plan.dot")?;
+write!(output, "{}", plan.display_graphviz());
+```
+
+Then, use the `dot` command line tool to render it into a file that
+can be displayed. For example, the following command creates a
+`/tmp/plan.pdf` file:
+
+```bash
+dot -Tpdf < /tmp/plan.dot > /tmp/plan.pdf
+```
+
+## How to format `.md` documents
+
+We use [`prettier`] to format `.md` files.
+
+You can either use `npm i -g prettier` to install it globally or use `npx` to run it as a standalone binary.
+Using `npx` requires a working node environment. Upgrading to the latest prettier is recommended (by adding
+`--upgrade` to the `npm` command).
+
+```bash
+$ prettier --version
+2.3.0
+```
+
+After you've confirmed your prettier version, you can format all the `.md` files:
+
+```bash
+prettier -w {datafusion,datafusion-cli,datafusion-examples,dev,docs}/**/*.md
+```
+
+[`prettier`]: https://prettier.io/
+
+## How to format `.toml` files
+
+We use [`taplo`] to format `.toml` files.
+
+To install via cargo:
+
+```sh
+cargo install taplo-cli --locked
+```
+
+> Refer to the [taplo installation documentation][taplo-install] for other ways to install it.
+
+```bash
+$ taplo --version
+taplo 0.9.0
+```
+
+After you've confirmed your `taplo` version, you can format all the `.toml` files:
+
+```bash
+taplo fmt
+```
+
+[`taplo`]: https://taplo.tamasfe.dev/
+[taplo-install]: https://taplo.tamasfe.dev/cli/installation/binary.html
+
+## How to update protobuf/gen dependencies
+
+For the `proto` and `proto-common` crates, the prost/tonic code is generated by running their respective `./regen.sh` scripts,
+which in turn invokes the Rust binary located in `./gen`.
+
+This is necessary after modifying the protobuf definitions or altering the dependencies of `./gen`, and requires a
+valid installation of [protoc] (see [installation instructions] for details).
+
+```bash
+# From repository root
+# proto-common
+./datafusion/proto-common/regen.sh
+# proto
+./datafusion/proto/regen.sh
+```
+
+[protoc]: https://github.com/protocolbuffers/protobuf#protocol-compiler-installation
+[installation instructions]: https://datafusion.apache.org/contributor-guide/development_environment.html#protoc-installation
diff --git a/versions/55.0.0/_sources/contributor-guide/index.md.txt b/versions/55.0.0/_sources/contributor-guide/index.md.txt
new file mode 100644
index 0000000000000..6f1a0f1c19907
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/index.md.txt
@@ -0,0 +1,244 @@
+
+
+# Introduction
+
+We welcome and encourage contributions of all kinds, from all levels, such as:
+
+1. Tickets with issue reports or feature requests
+2. Discussions
+3. Documentation improvements
+4. Code, both PR and (especially) PR Review.
+
+In addition to submitting new PRs, we have a healthy tradition of community
+members reviewing each other's PRs. Doing so is a great way to help the
+community as well as get more familiar with Rust and the relevant codebases.
+
+## Development Environment
+
+Start with the [Development Environment Quick Start](development_environment.md#quick-start).
+
+For more detail, see the full [development environment guide](development_environment.md)
+and the [testing guide](testing.md).
+
+## Finding and Creating Issues to Work On
+
+You can find a curated [good-first-issue] list to help you get started.
+You can read about how we plan larger projects in the [Roadmap and Improvement Proposals](roadmap.md) section.
+
+[good-first-issue]: https://github.com/apache/datafusion/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22
+
+### Open Contribution and Assigning tickets
+
+DataFusion is an open contribution project, and thus there is no particular
+project imposed deadline for completing issues or restrictions on who can
+work on an issue, nor limits to how many people can work on an issue at the same time.
+
+Contributors drive the project forward based on their own priorities and
+interests and thus you are free to work on any issue that interests you.
+
+If someone is already working on an issue that you want or need but hasn't
+been able to finish it yet, you should feel free to work on it as well. In
+general it is both polite and will help avoid unnecessary duplication of work if
+you leave a note on an issue when you start working on it.
+
+If you want to work on an issue which is not already assigned to someone else
+and there are no comment indicating that someone is already working on that
+issue then you can assign the issue to yourself by submitting a single word
+comment `take`. This will assign the issue to yourself. However, if you are
+unable to make progress you should unassign the issue by commenting a single
+word `untake`.
+
+# Developer's guide
+
+## Pull Request Overview
+
+We welcome pull requests (PRs) from anyone in the community.
+
+DataFusion is a rapidly evolving project and we try to review and merge PRs quickly.
+
+Review bandwidth is currently our most limited resource, and we highly encourage reviews by the broader community. If you are waiting for your PR to be reviewed, consider helping review other PRs that are waiting. Such review both helps the reviewer to learn the codebase and become more expert, as well as helps identify issues in the PR (such as lack of test coverage), that can be addressed and make future reviews faster and more efficient.
+
+The lifecycle of a PR is:
+
+1. Create a PR targeting the `main` branch.
+2. For new contributors a committer must first trigger the CI tasks. Please mention the members from committers list in the PR to help trigger the CI
+3. Your PR will be reviewed. Please respond to all feedback on the PR: you don't have to change the code, but you should acknowledge the feedback. PRs waiting for the feedback for more than a few days will be marked as draft.
+4. Once the PR is approved, one of the [committers] will merge your PR, typically within 24 hours. We leave approved "major" changes (see below) open for 24 hours prior to merging, and sometimes leave "minor" PRs open for the same time to permit additional feedback.
+
+Note that the above time frames are estimates. Due to limited committer
+bandwidth, it may take longer to merge your PR. Please wait
+patiently. If it has been several days you can friendly ping the
+committer who approved your PR to help remind them to merge it.
+
+[committers]: https://people.apache.org/phonebook.html?unix=datafusion
+
+## Creating Pull Requests
+
+When possible, we recommend splitting your contributions into multiple smaller focused PRs rather than large PRs (500+ lines) because:
+
+1. The PR is more likely to be reviewed quickly -- our reviewers struggle to find the contiguous time needed to review large PRs.
+2. The PR discussions tend to be more focused and less likely to get lost among several different threads.
+3. It is often easier to accept and act on feedback when it comes early on in a small change, before a particular approach has been polished too much.
+
+If you are concerned that a larger design will be lost in a string of small PRs, creating a large draft PR that shows how they all work together can help.
+
+Note all commits in a PR are squashed when merged to the `main` branch so there is one commit per PR after merge.
+
+For larger PRs, it is often helpful to leave a review on your own PR with
+comments calling out important changes or specific important choices. These
+annotations can help reviewers quickly find areas they should focus on, thus
+speeding up review.
+
+## Release Management and Backports
+
+Contributor-facing guidance for release branches, patch releases, and backports
+is documented in the [Release Management](release_management.md) guide.
+
+## Before Submitting a PR
+
+Before submitting a PR, run the standard non-functional checks. PRs must pass
+before merge.
+
+```bash
+./dev/rust_lint.sh
+# use `--write` to automatically fix some formatting and lint errors
+# ./dev/rust_lint.sh --write --allow-dirty
+```
+
+You should also run any relevant commands from the [testing quick start](testing.md#testing-quick-start).
+
+## Conventional Commits & Labeling PRs
+
+We generate change logs for each release using an automated process that will categorize PRs based on the title
+and/or the GitHub labels attached to the PR.
+
+We follow the [Conventional Commits] specification to categorize PRs based on the title. This most often simply means
+looking for titles starting with prefixes such as `fix:`, `feat:`, `docs:`, or `chore:`. We do not enforce this
+convention but encourage its use if you want your PR to feature in the correct section of the changelog.
+
+The change log generator will also look at GitHub labels such as `bug`, `enhancement`, or `api change`, and labels
+do take priority over the conventional commit approach, allowing maintainers to re-categorize PRs after they have been merged.
+
+[conventional commits]: https://www.conventionalcommits.org/en/v1.0.0/
+
+## Reviewing Pull Requests
+
+See the [Reviewing Pull Requests](pr_review.md) guide for what we look for
+when reviewing PRs and how to prepare your own for review.
+
+## Performance Improvements
+
+Performance improvements are always welcome: performance is a key DataFusion
+feature.
+
+In general, the performance improvement from a change should be "enough" to
+justify any added code complexity. How much is "enough" is a judgement made by
+the committers, but generally means that the improvement should be noticeable in
+a real-world scenario and is greater than the noise of the benchmarking system.
+
+To help committers evaluate the potential improvement, performance PRs should
+in general be accompanied by benchmark results that demonstrate the improvement.
+
+The best way to demonstrate a performance improvement is with the existing
+benchmarks:
+
+- [System level SQL Benchmarks](https://github.com/apache/datafusion/tree/main/benchmarks)
+- Microbenchmarks such as those in [functions/benches](https://github.com/apache/datafusion/tree/main/datafusion/functions/benches)
+
+If there is no suitable existing benchmark, you can create a new one. It helps
+to isolate the effects of your change by creating a separate PR with the
+benchmark, and then a PR with the code change that improves the benchmark.
+
+[system level sql benchmarks]: https://github.com/apache/datafusion/tree/main/benchmarks
+[functions/benches]: https://github.com/apache/datafusion/tree/main/datafusion/functions/benches
+
+## "Major" and "Minor" PRs
+
+Since we are a worldwide community, we have contributors in many timezones who review and comment. To ensure anyone who wishes has an opportunity to review a PR, our committers try to ensure that at least 24 hours passes between when a "major" PR is approved and when it is merged.
+
+A "major" PR means there is a substantial change in design or a change in the API. Committers apply their best judgment to determine what constitutes a substantial change. A "minor" PR might be merged without a 24 hour delay, again subject to the judgment of the committer. Examples of potential "minor" PRs are:
+
+1. Documentation improvements/additions
+2. Small bug fixes
+3. Non-controversial build-related changes (clippy, version upgrades etc.)
+4. Smaller non-controversial feature additions
+
+The good thing about open code and open development is that any issues in one change can almost always be fixed with a follow on PR.
+
+## Stale PRs
+
+Pull requests will be marked with a `stale` label after 60 days of inactivity and then closed 7 days after that.
+Commenting on the PR will remove the `stale` label.
+
+## AI-Assisted contributions
+
+DataFusion has the following policy for AI-assisted PRs:
+
+- The PR author should **understand the core ideas** behind the implementation **end-to-end**, and be able to justify the design and code during review.
+- **Calls out unknowns and assumptions**. It's okay to not fully understand some bits of AI generated code. You should comment on these cases and point them out to reviewers so that they can use their knowledge of the codebase to clear up any concerns. For example, you might comment "calling this function here seems to work but I'm not familiar with how it works internally, I wonder if there's a race condition if it is called concurrently".
+
+### Why fully AI-generated PRs without understanding are not helpful
+
+Today, AI tools cannot reliably make complex changes to DataFusion on their own, which is why we rely on pull requests and code review.
+
+The purposes of code review are:
+
+1. Finish the intended task.
+2. Share knowledge between authors and reviewers, as a long-term investment in the project. For this reason, even if someone familiar with the codebase can finish a task quickly, we're still happy to help a new contributor work on it even if it takes longer.
+
+An AI dump for an issue doesn’t meet these purposes. Maintainers could finish the task faster by using AI directly, and the submitters gain little knowledge if they act only as a pass through AI proxy without understanding.
+
+Please understand the reviewing capacity is **very limited** for the project, so large PRs which appear to not have the requisite understanding might not get reviewed, and eventually closed or redirected.
+
+### Better ways to contribute than an “AI dump”
+
+It's recommended to write a high-quality issue with a clear problem statement and a minimal, reproducible example. This can make it easier for others to contribute.
+
+### CI Runners
+
+#### Runs-On
+
+We use [Runs-On](https://runs-on.com/) for some actions in the main repository, which run in the ASF AWS account to speed up CI. In forks, these actions run on the default GitHub runners since forks do not have access to ASF infrastructure.
+
+To configure them, we use the following format:
+
+`runs-on: ${{ github.repository_owner == 'apache' && format('runs-on={0},family=m8a,cpu=16,image=ubuntu24-full-x64,extras=s3-cache,disk=large,tag=datafusion', github.run_id) || 'ubuntu-latest' }}`
+
+This is a conditional expression that uses Runs-On custom runners for the main repository and falls back to the standard GitHub runners for forks. Runs-On configuration follows the [Runs-On pattern](https://runs-on.com/configuration/job-labels/).
+
+For those actions we also use the [Runs-On action](https://runs-on.com/caching/magic-cache/#how-to-use), which adds support for external caching and reports job metrics:
+
+`- uses: runs-on/action@cd2b598b0515d39d78c38a02d529db87d2196d1e`
+
+For the standard GitHub runners, this action will do nothing.
+
+##### Spot Instances
+
+By default, Runs-On actions run as [spot instances](https://runs-on.com/configuration/spot-instances/), which means they might occasionally be interrupted. In the CI you would see:
+
+```
+Error: The operation was canceled.
+```
+
+According to Runs-On, spot instance termination is extremely rare for instances running for less than 1h. Those actions will be restarted automatically.
+
+#### GitHub Runners
+
+We also use standard GitHub runners for some actions in the main repository; these are also runnable in forks.
diff --git a/versions/55.0.0/_sources/contributor-guide/inviting.md.txt b/versions/55.0.0/_sources/contributor-guide/inviting.md.txt
new file mode 100644
index 0000000000000..75ef7c1e98d6d
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/inviting.md.txt
@@ -0,0 +1,418 @@
+
+
+# Inviting New Committers and PMC Members
+
+This is a cookbook of the recommended DataFusion specific process for inviting
+new committers and PMC members. It is intended to follow the [Apache Project
+Management Committee guidelines], which takes precedence over this document if
+there is a conflict.
+
+This process is intended for PMC members. While the process is open, the actual
+discussions and invitations are not (one of the very few things that we do not
+do in the open).
+
+When following this process, in doubt, check the `private@datafusion.apache.org`
+[mailing list archive] for examples of previous emails.
+
+The general process is:
+
+1. A PMC member starts a discussion on `private@datafusion.apache.org`
+ about a candidate they feel should be considered who would use the additional
+ trust granted to a committer or PMC member to help the community grow and thrive.
+2. When consensus is reached a formal [vote] occurs
+3. Assuming the vote is successful, that person is granted the appropriate
+ access via ASF systems.
+
+[apache project management committee guidelines]: https://www.apache.org/dev/pmc.html
+[mailing list archive]: https://lists.apache.org/list.html?dev@datafusion.apache.org
+[vote]: https://www.apache.org/foundation/voting
+
+## New Committers
+
+### Step 1: Start a Discussion Thread
+
+The goal of this step is to allow free form discussion prior to calling a vote.
+This helps the other PMC members understand why you are proposing to invite the
+person to become a committer and makes the voting process easier.
+
+Best practice is to include some details about why you are proposing to invite
+the person. Here is an example:
+
+```
+To: private@datafusion.apache.org
+Subject: [DISCUSS] $PERSONS_NAME for Committer
+
+$PERSONS_NAME has been an active contributor to the DataFusion community for the
+last 6 months[1][2], helping others, answering questions, and improving the
+project's code.
+
+Are there any thoughts about inviting $PERSONS_NAME to become a committer?
+
+Thanks,
+Your Name
+
+[1]: https://github.com/apache/datafusion/issues?q=commenter%3A
+[2]: https://github.com/apache/datafusion/commits?author=
+```
+
+### Step 2: Formal Vote
+
+Assuming the discussion thread goes well, start a formal vote, with an email like:
+
+```
+To: private@datafusion.apache.org
+Subject: [VOTE] $PERSONS_NAME for DataFusion Committer
+I propose to invite $PERSONS_NAME to be a committer. See discussion here [1].
+
+[ ] +1 : Invite $PERSONS_NAME to become a committer
+[ ] +0: ...
+[ ] -1: I disagree because ...
+
+The vote will be open for at least 7 days.
+
+My vote: +1
+
+Thanks,
+Your Name
+
+[1] LINK TO DISCUSSION THREAD (e.g. https://lists.apache.org/thread/7rocc026wckknrjt9j6bsqk3z4c0g5yf)
+```
+
+If the vote passes (requires 3 `+1`, and no `-1` votes) , send a result email
+like the following (substitute `N` with the number of `+1` votes)
+
+```
+to: private@datafusion.apache.org
+subject: [RESULT][VOTE] $PERSONS_NAME for DataFusion Committer
+
+The vote carries with N +1 votes.
+```
+
+### Step 3: Send Invitation to the Candidate
+
+Once the vote on `private@` has passed and the `[RESULT]` e-mail sent, send an
+invitation to the new committer and cc: `private@datafusion.apache.org`
+
+In order to be given write access, the committer needs an apache.org account (e.g. `name@apache.org`). To get one they need:
+
+1. An [ICLA] on file. Note that Sending an ICLA to `secretary@apache.org` will trigger account creation. If they already have an ICLA on file, but no Apache account, see instructions below.
+2. Add GitHub username to the account at [id.apache.org](http://id.apache.org/)
+3. Connect [gitbox.apache.org] to their GitHub account
+4. Follow the instructions at [gitbox.apache.org] to link your GitHub account with your
+
+[gitbox.apache.org]: https://gitbox.apache.org
+
+If the new committer is already a committer on another Apache project (so they
+already had an Apache account), The PMC Chair (or an ASF member) simply needs to
+explicitly add them to the roster on the [Whimsy Roster Tool].
+
+### Step 4: Announce and Celebrate the New Committer
+
+Email to Send an email such as the following to
+[dev@datafusion.apache.org](mailto:dev@datafusion.apache.org) to celebrate and
+acknowledge the new committer to the community.
+
+```
+To: dev@datafusion.apache.org
+Subject: [ANNOUNCE] New DataFusion committer: $NEW_COMMITTER
+
+On behalf of the DataFusion PMC, I'm happy to announce that $NEW_COMMITTER
+has accepted an invitation to become a committer on Apache
+DataFusion. Welcome, and thank you for your contributions!
+
+
+```
+
+[icla]: http://www.apache.org/licenses/#clas
+
+## Email Templates for Inviting New Committers
+
+### Committers WITHOUT an Apache account and WITHOUT ICLA on file
+
+You can check here to see if someone has an Apache account: http://people.apache.org/committer-index.html
+
+If you aren't sure whether someone has an ICLA on file, ask the DataFusion PMC
+chair or an ASF Member to check [the ICLA file list].
+
+[the icla file list]: https://whimsy.apache.org/officers/unlistedclas.cgi
+
+```
+To: $EMAIL
+Cc: private@datafusion.apache.org
+Subject: Invitation to become a DataFusion Committer
+
+Dear $NEW_COMMITTER,
+
+The DataFusion Project Management Committee (PMC) hereby offers you
+committer privileges to the project. These privileges are offered on
+the understanding that you'll use them reasonably and with common
+sense. We like to work on trust rather than unnecessary constraints.
+
+Being a committer enables you to merge PRs to DataFusion git repositories.
+
+Being a committer does not require you to participate any more than
+you already do. It does tend to make one even more committed. You will
+probably find that you spend more time here.
+
+Of course, you can decline and instead remain as a contributor,
+participating as you do now.
+
+A. This personal invitation is a chance for you to accept or decline
+in private. Either way, please let us know in reply to this email, make sure to reply-all (it should send a copy to
+private@datafusion.apache.org) for record keeping / log of the project.
+
+B. If you accept, the next step is to register an ICLA:
+
+Details of the iCLA and how to submit them are found through this link:
+https://www.apache.org/licenses/contributor-agreements.html#clas
+
+When you transmit the completed ICLA, request to notify Apache
+DataFusion and choose a unique Apache id. Look to see if your preferred id
+is already taken at http://people.apache.org/committer-index.html This
+will allow the Secretary to notify the PMC when your ICLA has been
+recorded.
+
+Once you are notified that your Apache account has been created, you must then:
+
+1. Add your GitHub username to your account at id.apache.org
+
+2. Follow the instructions at gitbox.apache.org to link your GitHub account
+with your Apache account.
+
+You will then have write (but not admin) access to the DataFusion repositories.
+If you have questions or run into issues, please reply-all to this e-mail.
+```
+
+After the new account has been created, you can announce the new committer on `dev@`
+
+### Committers WITHOUT an Apache account but WITH an ICLA on file
+
+In this scenario, an officer (the project VP or an Apache Member) needs only to
+request an account to be created for the new committer, since through the
+ordinary process the ASF Secretary will do it automatically. This is done at
+https://whimsy.apache.org/officers/acreq. Before requesting the new account,
+send an e-mail to the new committer (cc'ing `private@`) like this:
+
+```
+To: $EMAIL
+Cc: private@datafusion.apache.org
+Subject: Invitation to become a DataFusion Committer
+
+Dear $NEW_COMMITTER,
+
+The DataFusion Project Management Committee (PMC) hereby offers you
+committer privileges to the project. These privileges are offered on
+the understanding that you'll use them reasonably and with common
+sense. We like to work on trust rather than unnecessary constraints.
+
+Being a committer enables you to merge PRs to DataFusion git repositories.
+
+Being a committer does not require you to participate any more than
+you already do. It does tend to make one even more committed. You will
+probably find that you spend more time here.
+
+Of course, you can decline and instead remain as a contributor,
+participating as you do now.
+
+This personal invitation is a chance for you to accept or decline
+in private. Either way, please let us know in reply to this email, make sure to reply-all (it should send a copy to
+private@datafusion.apache.org) for record keeping / log of the project. We will have to request an
+Apache account be created for you, so please let us know what user id
+you would prefer.
+
+Once you are notified that your Apache account has been created, you must then:
+
+1. Add your GitHub username to your account at id.apache.org
+
+2. Follow the instructions at gitbox.apache.org to link your GitHub account
+with your Apache account.
+
+You will then have write (but not admin) access to the DataFusion repositories.
+If you have questions or run into issues, please reply-all to this e-mail.
+```
+
+### Committers WITH an existing Apache account
+
+In this scenario, an officer (the project PMC Chair or an ASF Member) can simply add
+the new committer on the [Whimsy Roster Tool]. Before doing this, e-mail the new
+committer inviting them to be a committer like so (cc private@):
+
+```
+To: $EMAIL
+Cc: private@datafusion.apache.org
+Subject: Invitation to become a DataFusion Committer
+
+Dear $NEW_COMMITTER,
+
+The DataFusion Project Management Committee (PMC) hereby offers you
+committer privileges to the project. These privileges are offered on
+the understanding that you'll use them reasonably and with common
+sense. We like to work on trust rather than unnecessary constraints.
+
+Being a committer enables you to merge PRs to DataFusion git repositories.
+
+Being a committer does not require you to participate any more than
+you already do. It does tend to make one even more committed. You will
+probably find that you spend more time here.
+
+Of course, you can decline and instead remain as a contributor,
+participating as you do now.
+
+If you accept, please let us know in reply to this email, make sure to reply-all (it should send a copy to
+private@datafusion.apache.org) for record keeping / log of the project.
+```
+
+## New PMC Members
+
+This is a DataFusion specific cookbook for the Apache Software Foundation
+instructions on [how to add a PMC member].
+
+[how to add a pmc member]: https://www.apache.org/dev/pmc.html#pmcmembers
+
+### Step 1: Start a Discussion Thread
+
+As for committers, start a discussion thread on the `private@` mailing list
+
+```
+To: private@datafusion.apache.org
+Subject: [DISCUSS] $NEW_PMC_MEMBER for PMC
+
+I would like to propose adding $NEW_PMC_MEMBER[1] to the DataFusion PMC.
+
+$NEW_PMC_MEMBER has been a committer since $COMMITTER_MONTH [2], has a
+strong and sustained contribution record for more than a year, and focused on
+helping the community and the project grow[3].
+
+Are there any thoughts about inviting $NEW_PMC_MEMBER to become a PMC member?
+
+[1] https://github.com/$NEW_PMC_MEMBERS_GITHUB_ACCOUNT
+[2] LINK TO COMMITTER VOTE RESULT THREAD (e.g. https://lists.apache.org/thread/ovgp8z97l1vh0wzjkgn0ktktggomxq9t)
+[3]: https://github.com/apache/datafusion/pulls?q=commenter%3A<$NEW_PMC_MEMBERS_GITHUB_ACCOUNT>+
+
+Thanks,
+YOUR NAME
+```
+
+### Step 2: Formal Vote
+
+Assuming the discussion thread goes well, start a formal vote with an email like:
+
+```
+To: private@datafusion.apache.org
+Subject: [VOTE] $NEW_PMC_MEMBER for PMC
+
+I propose inviting $NEW_PMC_MEMBER to join the DataFusion PMC. We previously
+discussed the merits of inviting $NEW_PMC_MEMBER to join the PMC [1].
+
+The vote will be open for at least 7 days.
+
+[ ] +1 : Invite $NEW_PMC_MEMBER to become a PMC member
+[ ] +0: ...
+[ ] -1: I disagree because ...
+
+My vote: +1
+
+[1] LINK TO DISCUSSION THREAD (e.g. https://lists.apache.org/thread/x2zno2hs1ormvfy13n7h82hmsxp3j66c)
+
+Thanks,
+Your Name
+```
+
+If this vote succeeds, send a "RESULT" email to `private@` like this:
+
+```
+To: private@datafusion.apache.org
+Subject: [RESULT][VOTE] $NEW_PMC_MEMBER for PMC
+
+The vote carries with N +1 votes and no -1 votes. I will send an invitation
+```
+
+### Step 3: Send invitation email
+
+Assuming the vote passes, the Chair sends an invitation e-mail to the new PMC
+member (cc'ing `private@`) like this:
+
+```
+To: $EMAIL
+Cc: private@datafusion.apache.org
+Subject: Invitation to join the DataFusion PMC
+Dear $NEW_PMC_MEMBER,
+
+In recognition of your demonstrated commitment to, and alignment with, the
+goals of the Apache DataFusion project, the DataFusion PMC has voted to offer you
+membership in the DataFusion PMC ("Project Management Committee").
+
+Please let us know if you accept by subscribing to the private alias [by
+sending mail to private-subscribe@datafusion.apache.org], and posting
+a message to private@datafusion.apache.org.
+
+The PMC for every top-level project is tasked by the Apache Board of
+Directors with official oversight and binding votes in that project.
+
+As a PMC member, you are responsible for continuing the general project, code,
+and community oversight that you have exhibited so far. The votes of the PMC
+are legally binding.
+
+All PMC members are subscribed to the project's private mail list, which is
+used to discuss issues unsuitable for an open, public forum, such as people
+issues (e.g. new committers, problematic community members, etc.), security
+issues, and the like. It can't be emphasized enough that care should be taken
+to minimize the use of the private list, discussing everything possible on the
+appropriate public list.
+
+The private PMC list is *private* - it is strictly for the use of the
+PMC. Messages are not to be forwarded to anyone else without the express
+permission of the PMC. Also note that any Member of the Foundation has the
+right to review and participate in any PMC list, as a PMC is acting on behalf
+of the Membership.
+
+Finally, the PMC is not meant to create a hierarchy within the committership or
+the community. Therefore, in our day-to-day interactions with the rest of the
+community, we continue to interact as peers, where every reasonable opinion is
+considered, and all community members are invited to participate in our public
+voting. If there ever is a situation where the PMC's view differs significantly
+from that of the rest of the community, this is a symptom of a problem that
+needs to be addressed.
+
+With the expectation of your acceptance, welcome!
+
+The Apache DataFusion PMC
+```
+
+### Step 4: Chair Promotes the Committer to PMC
+
+The PMC chair adds the user to the PMC using the [Whimsy Roster Tool].
+
+### Step 5: Announce and Celebrate the New PMC Member
+
+Send an email such as the following to `dev@datafusion.apache.org` to celebrate:
+
+```
+To: dev@datafusion.apache.org
+Subject: [ANNOUNCE] New DataFusion PMC member: $NEW_PMC_MEMBER
+
+The Project Management Committee (PMC) for Apache DataFusion has invited
+$NEW_PMC_MEMBER to become a PMC member and we are pleased to announce
+that $NEW_PMC_MEMBER has accepted.
+
+Congratulations and welcome!
+```
+
+[whimsy roster tool]: https://whimsy.apache.org/roster/committee/datafusion
diff --git a/versions/55.0.0/_sources/contributor-guide/pr_review.md.txt b/versions/55.0.0/_sources/contributor-guide/pr_review.md.txt
new file mode 100644
index 0000000000000..1154ae0e96b04
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/pr_review.md.txt
@@ -0,0 +1,240 @@
+
+
+# Reviewing Pull Requests
+
+When reviewing PRs, our primary goal is to improve DataFusion and its community
+together. PR feedback should be constructive and help improve the code as well
+as the understanding of the contributor.
+
+Review bandwidth is currently our most limited resource, and reviews from the
+broader community are both welcomed and encouraged. Reviewing PRs is a great way
+to learn the codebase, and you do not need to be a committer to leave valuable
+review feedback. In fact, one of the best ways to become a committer is to
+thoughtfully review other PRs.
+
+Please ensure any comments you leave contain a rationale and suggested
+alternative -- it is frustrating to be told "don't do it this way" without any
+clear reason or alternative provided.
+
+The criteria in this guide are also a useful checklist when preparing your own
+PR for review.
+
+## PR Review Mechanics
+
+Some helpful links:
+
+- [PRs Waiting for Review] on GitHub
+- [Approved PRs Waiting for Merge] on GitHub
+
+[prs waiting for review]: https://github.com/apache/datafusion/pulls?q=is%3Apr+is%3Aopen+-review%3Aapproved+-is%3Adraft+
+[approved prs waiting for merge]: https://github.com/apache/datafusion/pulls?q=is%3Apr+is%3Aopen+review%3Aapproved+-is%3Adraft
+
+The overall PR lifecycle (CI triggering, approval, the 24-hour rule for
+"major" PRs, and merging) is described in the
+[Pull Request Overview](index.md#pull-request-overview) section of the
+contributor guide.
+
+Practical tips:
+
+1. Check out the changes locally to explore them in your IDE or with an
+ agent, e.g. `gh pr checkout ` using the [GitHub CLI].
+2. There is normally no need to rerun locally any tests that CI has already run.
+3. Leave comments on specific lines of the diff where possible, so the
+ discussion has context.
+4. If you review a PR but don't feel confident approving it, leaving comments
+ is still valuable: a partial review (e.g. "I reviewed the tests and they
+ look good") helps the next reviewer focus their time.
+5. Anything that does not need to block the current PR can be noted as a
+ potential follow-up (ideally by filing an issue), keeping the PR focused
+ and quick to merge.
+
+[github cli]: https://cli.github.com/
+
+## Review the PR Description
+
+The PR description is often what users and contributors will find when they have
+a question about the intention behind a change, or when the code itself is not
+clear. The PR description also becomes the extended commit message.
+
+Check that the description:
+
+1. Concisely describes the **problem being solved from the user's point of
+ view**.
+
+2. Follows the [PR template], and answers the template's questions.
+
+3. Accurately describes the content of the PR, including any relevant context or
+ background.
+ Great descriptions have a high signal-to-noise ratio, summarizing
+ important implementation changes without repeating technical minutiae that
+ are already present in the code itself.
+
+4. Explicitly calls out any user-facing or API changes (see
+ [Review the Code](#review-the-code) below).
+
+[pr template]: https://github.com/apache/datafusion/blob/main/.github/pull_request_template.md
+
+## Review the Code Comments
+
+The goal of code comments is to help future readers of the code understand what
+is not obvious from reading the code itself. Great comments make the code easier
+to reason about for readers with the expected background, and help future
+maintainers.
+
+Some practical guidelines for reviewing comments:
+
+1. The code has adequate comments focused on the **rationale** for any
+ non-obvious change (the "why"), not a restatement of what the code does
+ (the "what"), which is typically clear from reading the code itself.
+2. Comments do not narrate irrelevant internal implementation details or the
+ history of how the change was developed (this is common in LLM-assisted
+ code, e.g. "// changed to use a HashMap" or "// this handles the case
+ mentioned above"). Such comments become irrelevant as soon as the PR merges.
+3. When comments refer to other structs, functions, or modules, they should use
+ [rustdoc intra-doc links] (e.g. `` [`SessionContext`] ``) rather than plain
+ text names, so that `cargo doc` link checking ensures the references stay
+ valid as the code evolves.
+4. New public APIs have doc comments, including examples where appropriate
+ (doc examples are also tested by CI, so they double as test coverage).
+5. When documenting modules, functions, or fields, start with simple examples
+ and intuitive explanations, and optionally add formal, math-like
+ definitions when necessary. This makes the implementation easier to reason
+ about.
+6. When something is confusing on first read, treat that as a good
+ opportunity to improve the comments.
+
+[rustdoc intra-doc links]: https://doc.rust-lang.org/rustdoc/write-documentation/linking-to-items-by-name.html
+
+## Review the Test Coverage
+
+Check that the feature or fix is covered sufficiently with tests (see the
+[Testing](testing.md) guide for more details): the PR should include tests for
+any new functionality, and a bug fix should include a test that reproduces the
+reported problem.
+
+Guidelines for evaluating tests:
+
+1. Prefer `sqllogictest` (`.slt`) tests or DataFrame API tests where
+ possible, as they exercise **user-visible behavior** and are less coupled
+ to internal implementation details than unit tests.
+2. Verify tests cover edge cases and common failure scenarios, not just the
+ common successful path. However, it is NOT necessary to test every possible
+ error path, especially if it is difficult to trigger or unlikely to occur in
+ practice.
+3. Verify test coverage of changed code using the `codecov` check on the PR,
+ or by running [`cargo llvm-cov`] locally for an HTML report. Use judgment
+ about any uncovered lines -- the goal is confidence in the change, not
+ slavishly hitting some coverage number.
+4. Avoid tests with lots of repeated boilerplate: when many tests share
+ near-identical setup, it is hard to understand what is different
+ (and thus what is actually being tested) between them. Make the _difference_
+ between cases obvious.
+5. Check that tests assert on specific expected values or plans (e.g. via
+ `insta` snapshots or `.slt` expected output) rather than merely checking
+ "no error occurred".
+6. Verify tests actually cover the bug ("Ablation Testing"): For bug fixes, revert
+ the fix locally and check that the new test fails without it (i.e. the test
+ actually reproduces the bug or covers the new feature).
+
+[`cargo llvm-cov`]: https://github.com/taiki-e/cargo-llvm-cov
+
+## Review the Code
+
+Check that:
+
+1. The code is clear and fits the style of the existing codebase.
+2. New functions and tests are placed near similar functions and
+ tests. For example, helper functions should be defined close to where they are used,
+ and new tests should be placed in the same module as the code they test.
+ SLT tests should be placed in an existing .slt file with related functionality,
+ unless the new tests are large enough to justify their own file.
+3. New APIs are consistent with existing public APIs and patterns; where a
+ similar mechanism already exists, the PR should extend it rather than
+ introduce a parallel one.
+4. Any changes to the public API follow the [API health policy].
+5. The change is appropriately scoped: unrelated refactoring, formatting
+ churn, or drive-by changes make review longer and are better as separate
+ PRs.
+6. New errors are actionable, mention the offending item, and use
+ the right error variant (e.g. `plan_err!` for user-triggerable errors vs
+ `internal_err!` for invariant violations).
+
+[api health policy]: api-health.md
+
+## Review the Performance
+
+Performance is a key feature of DataFusion. See [Performance Improvements](index.md#performance-improvements)
+for the project policy: an improvement should be "enough" to justify any
+added code complexity, and performance PRs should come with benchmark
+results.
+
+When reviewing:
+
+1. Find any relevant existing benchmarks and run them against `main`:
+ the [system-level SQL benchmarks] are run with `bench.sh` (see the
+ [benchmarks README]), and microbenchmarks (e.g. in
+ `datafusion/functions/benches`) are run with `cargo bench`.
+2. Be aware that benchmarking on a machine where other
+ work is being done will make results hard to reproduce. Prefer a quiet,
+ dedicated machine and repeated runs.
+3. If the PR claims a performance improvement, check that the reported
+ results are reproducible and that the benchmark exercises the changed
+ code path.
+
+[system-level sql benchmarks]: https://github.com/apache/datafusion/tree/main/benchmarks
+[benchmarks readme]: https://github.com/apache/datafusion/blob/main/benchmarks/README.md
+
+## Best Practices for Reviewers
+
+Here are some suggested best practices to follow when reviewing PRs.
+
+### Review Tone: Thank Contributors and Praise Good Work Specifically
+
+Open reviews by thanking the author by name, and when a PR is well done, say
+specifically what makes it good -- positive feedback encourages people to keep
+contributing and helps them understand what is valued in the project.
+
+### State Approval Conditions Explicitly
+
+If you are not ready to approve, list concretely what you would need to see
+before approving (e.g. "benchmark results and an upgrade guide entry") so
+the author has a clear path to merge.
+
+### Defer Non-Blocking Work to Follow-On Issues
+
+Explicitly defer non-critical suggestions to a follow-on PR and file
+(or ask the author to file) issues for them, so good PRs merge quickly
+without scope creep.
+
+Similarly, when a PR mixes refactoring with behavior changes or fixes a narrow
+problem with a broad mechanism, ask for it to be split or scoped down rather
+than reviewing it as-is.
+
+### Narrate What You Verified When Approving
+
+Rather than a bare "LGTM", say what you actually checked ("traced the state
+transitions by hand", "confirmed the hasher change cannot affect ordering")
+so it is clear what was verified and what was not.
+
+### Invite Additional Committers on Core Changes
+
+For changes to core, widely shared code, leave the PR open for other
+committers to look at and cc those who know the area, even after you have
+approved.
diff --git a/versions/55.0.0/_sources/contributor-guide/release_management.md.txt b/versions/55.0.0/_sources/contributor-guide/release_management.md.txt
new file mode 100644
index 0000000000000..7053d0f994559
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/release_management.md.txt
@@ -0,0 +1,202 @@
+
+
+# Release Management
+
+This page describes DataFusion release branches and backports. For the
+maintainer release guide, including release candidate artifacts, voting, and
+publication, see [the release process README in `dev/release`].
+
+## Overview
+
+DataFusion typically has a major release about once per month, including
+breaking API changes. Patch releases are made on an ad hoc basis, but we try to
+avoid them because major releases are frequent.
+
+New development happens on the [`main` branch]. Releases are made from release
+branches named `branch-NN`, such as [`branch-50`] for the `50.x.y` release
+series.
+
+In general:
+
+- New features land on [`main`]
+- Patch releases are cut from the corresponding `branch-NN`
+- Only targeted, low-risk fixes should be added to a release branch
+
+Changes reach a release branch in one of two ways:
+
+- (Most common) Fix the issue on `main` and then backport the merged change to the release branch
+- Fix the issue on the release branch and then forward-port the change to `main`
+
+Releases are coordinated using GitHub issues. Each planned release is listed in
+the [DataFusion Releases tracking issue], and each release is coordinated in a
+dedicated issue, such as the [release issue for 50.3.0]. If you think a fix
+should be included in a patch release, discuss it on the relevant tracking issue
+or open a backport PR and link it there.
+
+To prepare for a new release series, maintainers:
+
+- Create a new branch from `main`, such as `branch-50`, in the Apache repository
+- Continue merging new features to `main`
+- Prepare the release branch for release by updating versions, changelog content,
+ and any additional release-specific fixes via the
+ [Backport Workflow](#backport-workflow)
+- Create release candidate artifacts from the release branch
+- After approval, publish to crates.io, ASF distribution servers, and Git tags
+
+## Backport Criteria
+
+A release branch is a stabilization branch for an imminent or recent patch
+release. The bar for landing a change on a release branch is therefore
+_higher_ than the bar for landing on `main`, not lower. These criteria define
+what is eligible for backport; the [Backport Workflow](#backport-workflow)
+below describes the mechanics.
+
+DataFusion follows Cargo SemVer, with breaking changes allowed at major
+version boundaries — see the [API health policy] for the full framing of
+public Rust and SQL API stability. Patch releases (`x.y.z`, `z ≥ 1`) carry
+fixes only and never introduce new features or breaking changes.
+
+### Eligible for backport
+
+- **Security fixes.** Fixes for known or reported security issues should be
+ backported to every actively maintained release branch.
+- **Correctness fixes.** Fixes for queries that produce incorrect results,
+ panics, data loss, or crashes. If the fix itself changes user-visible SQL
+ semantics to make a wrong result right, follow [Behavior changes] below.
+- **Stability and regression fixes.** Fixes for regressions introduced in the
+ current release line, hangs, deadlocks, memory leaks, or other availability
+ issues.
+- **Build, CI, and test fixes** required to keep the branch buildable and
+ releasable.
+- **Documentation fixes** for behavior already in the release. Documentation
+ for behavior that exists only on `main` does not belong on a release branch.
+
+### Not recommended for backport
+
+- **New features**, including new SQL functions, new optimizer rules, new
+ configuration options, new public APIs, and new file-format support. Land
+ on `main` and ship in the next major release.
+- **Breaking API changes** of any kind, Rust or SQL. DataFusion makes
+ breaking changes only at major version boundaries — see [API health policy].
+- **Refactors and cleanup** that do not fix a bug, even if they are correct.
+- **Performance improvements** that are not also correctness or stability
+ fixes. Land on `main`.
+- **Dependency upgrades**, except when the upgrade itself is the security or
+ correctness fix and there is no narrower alternative.
+
+### Behavior changes
+
+A "behavior change" is any fix that alters user-visible results: SQL
+semantics (values, ordering, types, null handling), error messages that
+downstream users may rely on, plan output, or default configuration values.
+
+Behavior-changing fixes need extra scrutiny on a release branch because
+users upgrading between patch versions do not expect their queries to start
+returning different results. When proposing one for backport, state on the
+release tracking issue _why_ the change should ship in this patch release
+rather than wait for the next major. The previous and new behavior should
+already be documented on the original issue or PR — link to that rather
+than restating it.
+
+If in doubt, default to "land on `main`, ship in the next major."
+
+### Who decides
+
+The release manager for the active release line is the final reviewer of
+what goes into the patch release. They coordinate via the release tracking
+issue (for example, the [release issue for 50.3.0]). Anyone may propose a
+backport by opening a backport PR and linking it from the tracking issue;
+inclusion is the release manager's call.
+
+### Active release branches
+
+DataFusion does not maintain Long-Term Support branches. In general only the
+most recent `branch-NN` is actively maintained for backports, but if you need
+fixes in older releases, we are open to discussion.
+
+Security fixes are an exception: a maintainer may choose to backport a
+critical security fix to an older branch even after it would otherwise be
+closed. Discuss on the dev list or in a tracking issue before doing so.
+
+## Backport Workflow
+
+The usual workflow is:
+
+1. Fix on `main` first, and merge the fix via a normal PR workflow.
+2. Cherry-pick the merged commit onto the release branch.
+3. Open a backport PR targeting the release branch (examples below).
+
+- [Example backport PR]
+- [Additional backport PR example]
+
+### Inputs
+
+To backport a change, gather the following information:
+
+- Target branch, such as `apache/branch-52`
+- The release tracking issue URL, such as https://github.com/apache/datafusion/issues/19692
+- The original PR URL, such as https://github.com/apache/datafusion/pull/20192
+- Optional explicit commit SHA to backport
+
+### Apply the Backport
+
+Start from the target release branch, create a dedicated backport branch, and
+use `git cherry-pick`. For example, to backport PR #1234 to `branch-52` when
+the commit SHA is `abc123`, run:
+
+```bash
+git checkout apache/branch-52
+git checkout -b alamb/backport_1234
+git cherry-pick abc123
+```
+
+### Test
+
+Run tests as described in the [testing documentation].
+
+### Open the PR
+
+Create a PR against the release branch, not `main`, and prefix it with
+`[branch-NN]` to show which release branch the backport targets. For example:
+
+- `[branch-52] fix: validate inter-file ordering in eq_properties() (#20329)`
+
+Use a PR description that links the tracking issue, original PR, and target
+branch, for example:
+
+```markdown
+- Part of
+- Closes on
+
+This PR:
+
+- Backports from @ to the line
+```
+
+[`main` branch]: https://github.com/apache/datafusion/tree/main
+[`branch-50`]: https://github.com/apache/datafusion/tree/branch-50
+[the release process readme in `dev/release`]: https://github.com/apache/datafusion/blob/main/dev/release/README.md
+[datafusion releases tracking issue]: https://github.com/apache/datafusion/issues/19783
+[release issue for 50.3.0]: https://github.com/apache/datafusion/issues/18072
+[example backport pr]: https://github.com/apache/datafusion/pull/18131
+[additional backport pr example]: https://github.com/apache/datafusion/pull/20792
+[testing documentation]: testing.md
+[api health policy]: api-health.md
+[behavior changes]: #behavior-changes
diff --git a/versions/55.0.0/_sources/contributor-guide/roadmap.md.txt b/versions/55.0.0/_sources/contributor-guide/roadmap.md.txt
new file mode 100644
index 0000000000000..903b2c7b7ef38
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/roadmap.md.txt
@@ -0,0 +1,156 @@
+
+
+# Roadmap and Improvement Proposals
+
+The [project introduction](../user-guide/introduction.md) explains the
+overview and goals of DataFusion, and our development efforts largely
+align to that vision.
+
+## Planning `EPIC`s
+
+DataFusion uses [GitHub issues] to track planned work. We collect related
+tickets using tracking issues marked with the `EPIC` label, containing
+discussion and links to more detailed items:
+
+[github issues]: https://github.com/apache/datafusion/issues
+
+- [The current list of `EPIC`s can be found here.](https://github.com/apache/datafusion/issues?q=is%3Aissue%20state%3Aopen%20label%3AEPIC)
+
+- [The current list of `PROPOSAL EPIC` (that are not yet underway) can be found here.](https://github.com/apache/datafusion/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22PROPOSAL%20EPIC%22)
+
+Epics offer a high level roadmap of what the DataFusion community is thinking
+about. The epics are not meant to restrict possibilities, but rather help
+organize the community and make it easier to see where development is headed,
+align our work, and inspire additional contributions.
+
+We also welcome contributions for items not covered by epics. However, before
+submitting a large PR, we strongly suggest and request you start a conversation as described in [Discussing New Features](#discussing-new-features) below.
+
+[dev@arrow.apache.org]: mailto:dev@arrow.apache.org
+
+## Quarterly Roadmap
+
+The DataFusion roadmap is driven by the priorities of contributors rather than
+any single organization or coordinating committee. We typically discuss our
+roadmap using GitHub issues, approximately quarterly, and invite you to join the
+discussion.
+
+The current roadmap discussion is
+[DataFusion 2026 Q3-Q4 Roadmap Discussion](https://github.com/apache/datafusion/issues/22882).
+
+For more information:
+
+1. [Search for issues labeled `roadmap`](https://github.com/apache/datafusion/issues?q=is%3Aissue%20%20%20roadmap)
+2. [DataFusion 2026 Q3-Q4 Roadmap Discussion](https://github.com/apache/datafusion/issues/22882)
+3. [DataFusion Road Map: Q1 2026](https://github.com/apache/datafusion/issues/18494)
+4. [DataFusion Road Map: Q3-Q4 2025](https://github.com/apache/datafusion/issues/15878)
+5. [2024 Q4 / 2025 Q1 Roadmap](https://github.com/apache/datafusion/issues/13274)
+
+## Improvement Proposals
+
+### Discussing New Features
+
+If you plan to work on a new feature that doesn't have an existing ticket, it is
+a good idea to open one for discussion. Advanced discussion helps avoid wasted
+effort by determining if the feature is a good fit for DataFusion before too
+much time is invested. Discussion on a ticket can help gather feedback from the
+community and is likely easier to discuss than a 1000 line PR.
+
+Maintainers will mark major proposals as `PROPOSED EPIC` to make them more
+visible, but we are very limited on review bandwidth. If you open a ticket and it
+doesn't get any response, try `@`-mentioning recently active community members
+in the ticket, or [posting to the mailing list or Discord](communication.md).
+
+### Supervising Maintainers
+
+We have found that most successful epics have one or more "supervising
+maintainers", a committer ([see here for current list]) who take the lead on
+reviewing and committing PRs, helps with design, and coordinates and
+communicates with the community. If you want to ship a large feature, we
+recommend finding such maintainer upfront; otherwise, your PRs may
+remain unreviewed for a very long time.
+
+Supervising maintainers have no additional formal authority and there is
+currently no formal process for appointing, approving or tracking who has that
+role for a given epic. Instead, we rely on discussion on the ticket or PR.
+Helping complete an epic is a significant time commitment, so maintainers are
+more likely to help features they are particularly interested in or align with
+their own project's use of DataFusion.
+
+If you are willing to be a supervising maintainer for a feature, please say so
+explicitly. If you are unsure, we suggest asking directly who is willing to take
+the role, as it can be hard to tell sometimes whether a committer is simply
+participating and giving general feedback.
+
+[see here for current list]: governance.md
+
+### What Contributions are Good Fits?
+
+DataFusion is designed to be highly extensible, and many features can be
+implemented as extensions without changes or additions to the core. Support for
+new functions, data formats, and similar functionality can be added using those
+extension APIs, and there are already many existing community supported
+extensions listed in the [extensions list].
+
+Query engines are complex pieces of software to develop and maintain. Given our
+limited maintenance bandwidth, we try to keep the DataFusion core as simple and
+focused as possible, while still satisfying the [design goal] of an easy to
+start initial experience.
+
+With that in mind, contributions that meet the following criteria are more likely
+to be accepted:
+
+1. Bug fixes for existing features
+2. Test coverage for existing features
+3. Documentation improvements / examples
+4. Performance improvements to existing features (with benchmarks)
+5. "Small" functional improvements to existing features (if they don't change existing behavior)
+6. Additional APIs for extending DataFusion's capabilities
+7. CI improvements
+
+Contributions that will likely involve more discussion (see Discussing New
+Features above) prior to acceptance include:
+
+1. Major new functionality (even if it is part of the "standard SQL")
+2. New functions, especially if they aren't part of "standard SQL"
+3. New data sources (e.g. support for Apache ORC)
+
+[extensions list]: ../library-user-guide/extensions.md
+[design goal]: https://docs.rs/datafusion/latest/datafusion/index.html#design-goals
+
+### Design Build vs. Big Up Front Design
+
+Typically, the DataFusion community attacks large problems by solving them bit
+by bit and refining a solution iteratively on the `main` branch as a series of
+Pull Requests. This is different from projects which front-load the effort
+with a more comprehensive design process.
+
+By "advancing the front" the community always makes tangible progress, and the strategy is
+especially effective in a project that relies on individual contributors who may
+not have the time or resources to invest in a large upfront design effort.
+However, this "bit by bit approach" doesn't always succeed, and sometimes we get
+stuck or go down the wrong path and then change directions.
+
+Our process necessarily results in imperfect solutions being the "state of the
+code" in some cases, and larger visions are not yet fully realized. However, the
+community is good at driving things to completion in the long run. If you see
+something that needs improvement or an area that is not yet fully realized,
+please consider submitting an issue or PR to improve it. We are always looking
+for more contributions.
diff --git a/versions/55.0.0/_sources/contributor-guide/specification/index.rst.txt b/versions/55.0.0/_sources/contributor-guide/specification/index.rst.txt
new file mode 100644
index 0000000000000..a34f0b19e4dea
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/specification/index.rst.txt
@@ -0,0 +1,35 @@
+.. Licensed to the Apache Software Foundation (ASF) under one
+.. or more contributor license agreements. See the NOTICE file
+.. distributed with this work for additional information
+.. regarding copyright ownership. The ASF licenses this file
+.. to you under the Apache License, Version 2.0 (the
+.. "License"); you may not use this file except in compliance
+.. with the License. You may obtain a copy of the License at
+
+.. http://www.apache.org/licenses/LICENSE-2.0
+
+.. Unless required by applicable law or agreed to in writing,
+.. software distributed under the License is distributed on an
+.. "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+.. KIND, either express or implied. See the License for the
+.. specific language governing permissions and limitations
+.. under the License.
+
+Specifications
+==============
+
+We formalize some DataFusion semantics and behaviors through specification
+documents. These specifications are useful to be used as references to help
+resolve ambiguities during development or code reviews.
+
+You are also welcome to propose changes to existing specifications or create
+new specifications as you see fit. All specifications are stored in the
+`docs/source/specification` folder. Here is the list current active
+specifications:
+
+
+.. toctree::
+ :maxdepth: 1
+
+ invariants
+ output-field-name-semantic
diff --git a/versions/55.0.0/_sources/contributor-guide/specification/invariants.md.txt b/versions/55.0.0/_sources/contributor-guide/specification/invariants.md.txt
new file mode 100644
index 0000000000000..c8de4e1d4e21d
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/specification/invariants.md.txt
@@ -0,0 +1,327 @@
+
+
+# Invariants
+
+This document enumerates invariants of DataFusion's logical and physical planes
+(functions, and nodes). Some of these invariants are currently not enforced.
+This document assumes that the reader is familiar with some of the codebase,
+including rust arrow's RecordBatch and Array.
+
+## Rational
+
+DataFusion's computational model is built on top of a dynamically typed arrow
+object, Array, that offers the interface `Array::as_any` to downcast itself to
+its statically typed versions (e.g. `Int32Array`). DataFusion uses
+`Array::data_type` to perform the respective downcasting on its physical
+operations. DataFusion uses a dynamic type system because the queries being
+executed are not always known at compile time: they are only known during the
+runtime (or query time) of programs built with DataFusion. This document is
+built on top of this principle.
+
+In dynamically typed interfaces, it is up to developers to enforce type
+invariances. This document declares some of these invariants, so that users
+know what they can expect from a query in DataFusion, and DataFusion developers
+know what they need to enforce at the coding level.
+
+## Notation
+
+- Field or physical field: the tuple name, `arrow::DataType` and nullability flag (a bool whether values can be null), represented in this document by `PF(name, type, nullable)`
+- Logical field: Field with a relation name. Represented in this document by `LF(relation, name, type, nullable)`
+- Projected plan: plan with projection as the root node.
+- Logical schema: a vector of logical fields, used by logical plan.
+- Physical schema: a vector of physical fields, used by both physical plan and Arrow record batch.
+
+### Logical
+
+#### Function
+
+An object that knows its valid incoming logical fields and how to derive its
+output logical field from its arguments' logical fields. A functions' output
+field is itself a function of its input fields:
+
+```
+logical_field(lf1: LF, lf2: LF, ...) -> LF
+```
+
+Examples:
+
+- `plus(a,b) -> LF(None, "{a} Plus {b}", d(a.type,b.type), a.nullable | b.nullable)` where d is the function mapping input types to output type (`get_supertype` in our current implementation).
+- `length(a) -> LF(None, "length({a})", u32, a.nullable)`
+
+#### Plan
+
+A tree composed of other plans and functions (e.g. `Projection c1 + c2, c1 - c2 AS sum12; Scan c1 as u32, c2 as u64`)
+that knows how to derive its schema.
+
+Certain plans have a frozen schema (e.g. Scan), while others derive their
+schema from their child nodes.
+
+#### Column
+
+An identifier in a logical plan consists of field name and relation name.
+
+### Physical
+
+#### Function
+
+An object that knows how to derive its physical field from its arguments'
+physical fields, and also how to actually perform the computation on data. A
+functions' output physical field is a function of its input physical fields:
+
+```
+physical_field(PF1, PF2, ...) -> PF
+```
+
+Examples:
+
+- `plus(a,b) -> PF("{a} Plus {b}", d(a.type,b.type), a.nullable | b.nullable)` where d is a complex function (`get_supertype` in our current implementation) whose computation is for each element in the columns, sum the two entries together and return it in the same type as the smallest type of both columns.
+- `length(&str) -> PF("length({a})", u32, a.nullable)` whose computation is "count number of bytes in the string".
+
+#### Plan
+
+A tree (e.g. `Projection c1 + c2, c1 - c2 AS sum12; Scan c1 as u32, c2 as u64`)
+that knows how to derive its metadata and compute itself.
+
+Note how the physical plane does not know how to derive field names: field
+names are solely a property of the logical plane, as they are not needed in the
+physical plane.
+
+#### Column
+
+A type of physical node in a physical plan consists of a field name and unique index.
+
+### Data Sources' registry
+
+A map of source name/relation -> Schema plus associated properties necessary to read data from it (e.g. file path).
+
+### Functions' registry
+
+A map of function name -> logical + physical function.
+
+### Physical Planner
+
+A function that knows how to derive a physical plan from a logical plan:
+
+```
+plan(LogicalPlan) -> PhysicalPlan
+```
+
+### Logical Optimizer
+
+A function that accepts a logical plan and returns an (optimized) logical plan
+which computes the same results, but in a more efficient manner:
+
+```
+optimize(LogicalPlan) -> LogicalPlan
+```
+
+### Physical Optimizer
+
+A function that accepts a physical plan and returns an (optimized) physical
+plan which computes the same results, but may differ based on the actual
+hardware or execution environment being run:
+
+```
+optimize(PhysicalPlan) -> PhysicalPlan
+```
+
+### Builder
+
+A function that knows how to build a new logical plan from an existing logical
+plan and some extra parameters.
+
+```
+build(logical_plan, params...) -> logical_plan
+```
+
+## Invariants
+
+The following subsections describe invariants. Since functions' output schema
+depends on its arguments' schema (e.g. min, plus), the resulting schema can
+only be derived based on a known set of input schemas (TableProvider).
+Likewise, schemas of functions depend on the specific registry of functions
+registered (e.g. does `my_op` return u32 or u64?). Thus, in this section, the
+wording "same schema" is understood to mean "same schema under a given registry
+of data sources and functions".
+
+### (relation, name) tuples in logical fields and logical columns are unique
+
+Every logical field's (relation, name) tuple in a logical schema MUST be unique.
+Every logical column's (relation, name) tuple in a logical plan MUST be unique.
+
+This invariant guarantees that `SELECT t1.id, t2.id FROM t1 JOIN t2...`
+unambiguously selects the field `t1.id` and `t2.id` in a logical schema in the
+logical plane.
+
+#### Responsibility
+
+It is the logical builder and optimizer's responsibility to guarantee this
+invariant.
+
+#### Validation
+
+Builder and optimizer MUST error if this invariant is violated on any logical
+node that creates a new schema (e.g. scan, projection, aggregation, join, etc.).
+
+### Physical schema is consistent with data
+
+The contents of every Array in every RecordBatch in every partition returned by
+a physical plan MUST be consistent with RecordBatch's schema, in that every
+Array in the RecordBatch must be downcastable to its corresponding type
+declared in the RecordBatch.
+
+#### Responsibility
+
+Physical functions MUST guarantee this invariant. This is particularly
+important in aggregate functions, whose aggregating type may be different from
+the intermediary types during calculations (e.g. sum(i32) -> i64).
+
+#### Validation
+
+Since the validation of this invariant is computationally expensive, execution
+contexts CAN validate this invariant. It is acceptable for physical nodes to
+`panic!` if their input does not satisfy this invariant.
+
+### Physical schema is consistent in physical functions
+
+The schema of every Array returned by a physical function MUST match the
+DataType reported by the physical function itself.
+
+This ensures that when a physical function claims that it returns a type
+(e.g. Int32), users can safely downcast its resulting Array to the
+corresponding type (e.g. Int32Array), as well as to write data to formats that
+have a schema with nullability flag (e.g. parquet).
+
+#### Responsibility
+
+It is the responsibility of the developer that writes a physical function to
+guarantee this invariant.
+
+In particular:
+
+- The derived DataType matches the code it uses to build the array for every branch of valid input type combinations.
+- The nullability flag matches how the values are built.
+
+#### Validation
+
+Since the validation of this invariant is computationally expensive, execution
+contexts CAN validate this invariant.
+
+### The physical schema is invariant under planning
+
+The physical schema derived by a physical plan returned by the planner MUST be
+equivalent to the physical schema derived by the logical plan passed to the
+planner. Specifically:
+
+```
+plan(logical_plan).schema === logical_plan.physical_schema
+```
+
+Logical plan's physical schema is defined as logical schema with relation
+qualifiers stripped for all logical fields:
+
+```
+logical_plan.physical_schema = vector[ strip_relation(f) for f in logical_plan.logical_fields ]
+```
+
+This is used to ensure that the physical schema of its (logical) plan is what
+it gets in record batches, so that users can rely on the optimized logical plan
+to know the resulting physical schema.
+
+Note that since a logical plan can be as simple as a single projection with a
+single function, `Projection f(c1,c2)`, a corollary of this is that the
+physical schema of every `logical function -> physical function` must be
+invariant under planning.
+
+#### Responsibility
+
+Developers of physical and logical plans and planners MUST guarantee this
+invariant for every triplet (logical plan, physical plan, conversion rule).
+
+#### Validation
+
+Planners MUST validate this invariant. In particular they MUST return an error
+when, during planning, a physical function's derived schema does not match the
+logical functions' derived schema.
+
+### The output schema equals the physical plan schema
+
+The schema of every RecordBatch in every partition outputted by a physical plan
+MUST be equal to the schema of the physical plan. Specifically:
+
+```
+physical_plan.evaluate(batch).schema = physical_plan.schema
+```
+
+Together with other invariants, this ensures that the consumers of record
+batches do not need to know the output schema of the physical plan; they can
+safely rely on the record batch's schema to perform downscaling and naming.
+
+#### Responsibility
+
+Physical nodes MUST guarantee this invariant.
+
+#### Validation
+
+Execution Contexts CAN validate this invariant.
+
+### Logical schema is invariant under logical optimization
+
+The logical schema derived by a projected logical plan returned by the logical
+optimizer MUST be equivalent to the logical schema derived by the logical plan
+passed to the planner:
+
+```
+optimize(logical_plan).schema === logical_plan.schema
+```
+
+This is used to ensure that plans can be optimized without jeopardizing future
+referencing logical columns (name and index) or assumptions about their
+schemas.
+
+#### Responsibility
+
+Logical optimizers MUST guarantee this invariant.
+
+#### Validation
+
+Users of logical optimizers SHOULD validate this invariant.
+
+### Physical schema is invariant under physical optimization
+
+The physical schema derived by a projected physical plan returned by the
+physical optimizer MUST match the physical schema derived by the physical plan
+passed to the planner:
+
+```
+optimize(physical_plan).schema === physical_plan.schema
+```
+
+This is used to ensure that plans can be optimized without jeopardizing future
+references of logical columns (name and index) or assumptions about their
+schemas.
+
+#### Responsibility
+
+Optimizers MUST guarantee this invariant.
+
+#### Validation
+
+Users of optimizers SHOULD validate this invariant.
diff --git a/versions/55.0.0/_sources/contributor-guide/specification/output-field-name-semantic.md.txt b/versions/55.0.0/_sources/contributor-guide/specification/output-field-name-semantic.md.txt
new file mode 100644
index 0000000000000..1a3c373c9bbd5
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/specification/output-field-name-semantic.md.txt
@@ -0,0 +1,212 @@
+
+
+# Output field name semantics
+
+This specification documents how field names in output record batches should be
+generated based on given user queries. The field name rules apply to
+DataFusion queries planned from both SQL queries and Dataframe APIs.
+
+## Field name rules
+
+- All bare column field names MUST not contain relation/table qualifier.
+ - Both `SELECT t1.id`, `SELECT id` and `df.select_columns(&["id"])` SHOULD result in field name: `id`
+- All compound column field names MUST contain relation/table qualifier.
+ - `SELECT foo + bar` SHOULD result in field name: `table.foo PLUS table.bar`
+- Function names MUST be converted to lowercase.
+ - `SELECT AVG(c1)` SHOULD result in field name: `avg(table.c1)`
+- Literal string MUST not be wrapped with quotes or double quotes.
+ - `SELECT 'foo'` SHOULD result in field name: `foo`
+- Operator expressions MUST be wrapped with parentheses.
+ - `SELECT -2` SHOULD result in field name: `(- 2)`
+- Operator and operand MUST be separated by spaces.
+ - `SELECT 1+2` SHOULD result in field name: `(1 + 2)`
+- Function arguments MUST be separated by a comma `,` and a space.
+ - `SELECT f(c1,c2)` and `df.select(vec![f.udf("f")?.call(vec![col("c1"), col("c2")])])` SHOULD result in field name: `f(table.c1, table.c2)`
+
+## Appendices
+
+### Examples and comparison with other systems
+
+Data schema for test sample queries:
+
+```
+CREATE TABLE t1 (id INT, a VARCHAR(5));
+INSERT INTO t1 (id, a) VALUES (1, 'foo');
+INSERT INTO t1 (id, a) VALUES (2, 'bar');
+
+CREATE TABLE t2 (id INT, b VARCHAR(5));
+INSERT INTO t2 (id, b) VALUES (1, 'hello');
+INSERT INTO t2 (id, b) VALUES (2, 'world');
+```
+
+#### Projected columns
+
+Query:
+
+```
+SELECT t1.id, a, t2.id, b
+FROM t1
+JOIN t2 ON t1.id = t2.id
+```
+
+DataFusion Arrow record batches output:
+
+| id | a | id | b |
+| --- | --- | --- | ----- |
+| 1 | foo | 1 | hello |
+| 2 | bar | 2 | world |
+
+Spark, MySQL 8 and PostgreSQL 13 output:
+
+| id | a | id | b |
+| --- | --- | --- | ----- |
+| 1 | foo | 1 | hello |
+| 2 | bar | 2 | world |
+
+SQLite 3 output:
+
+| id | a | b |
+| --- | --- | ----- |
+| 1 | foo | hello |
+| 2 | bar | world |
+
+#### Function transformed columns
+
+Query:
+
+```
+SELECT ABS(t1.id), abs(-id) FROM t1;
+```
+
+DataFusion Arrow record batches output:
+
+| abs(t1.id) | abs((- t1.id)) |
+| ---------- | -------------- |
+| 1 | 1 |
+| 2 | 2 |
+
+Spark output:
+
+| abs(id) | abs((- id)) |
+| ------- | ----------- |
+| 1 | 1 |
+| 2 | 2 |
+
+MySQL 8 output:
+
+| ABS(t1.id) | abs(-id) |
+| ---------- | -------- |
+| 1 | 1 |
+| 2 | 2 |
+
+PostgreSQL 13 output:
+
+| abs | abs |
+| --- | --- |
+| 1 | 1 |
+| 2 | 2 |
+
+SQlite 3 output:
+
+| ABS(t1.id) | abs(-id) |
+| ---------- | -------- |
+| 1 | 1 |
+| 2 | 2 |
+
+#### Function with operators
+
+Query:
+
+```
+SELECT t1.id + ABS(id), ABS(id * t1.id) FROM t1;
+```
+
+DataFusion Arrow record batches output:
+
+| t1.id + abs(t1.id) | abs(t1.id \* t1.id) |
+| ------------------ | ------------------- |
+| 2 | 1 |
+| 4 | 4 |
+
+Spark output:
+
+| id + abs(id) | abs(id \* id) |
+| ------------ | ------------- |
+| 2 | 1 |
+| 4 | 4 |
+
+MySQL 8 output:
+
+| t1.id + ABS(id) | ABS(id \* t1.id) |
+| --------------- | ---------------- |
+| 2 | 1 |
+| 4 | 4 |
+
+PostgreSQL output:
+
+| ?column? | abs |
+| -------- | --- |
+| 2 | 1 |
+| 4 | 4 |
+
+SQLite output:
+
+| t1.id + ABS(id) | ABS(id \* t1.id) |
+| --------------- | ---------------- |
+| 2 | 1 |
+| 4 | 4 |
+
+#### Project literals
+
+Query:
+
+```
+SELECT 1, 2+5, 'foo_bar';
+```
+
+DataFusion Arrow record batches output:
+
+| 1 | (2 + 5) | foo_bar |
+| --- | ------- | ------- |
+| 1 | 7 | foo_bar |
+
+Spark output:
+
+| 1 | (2 + 5) | foo_bar |
+| --- | ------- | ------- |
+| 1 | 7 | foo_bar |
+
+MySQL output:
+
+| 1 | 2+5 | foo_bar |
+| --- | --- | ------- |
+| 1 | 7 | foo_bar |
+
+PostgreSQL output:
+
+| ?column? | ?column? | ?column? |
+| -------- | -------- | -------- |
+| 1 | 7 | foo_bar |
+
+SQLite 3 output:
+
+| 1 | 2+5 | 'foo_bar' |
+| --- | --- | --------- |
+| 1 | 7 | foo_bar |
diff --git a/versions/55.0.0/_sources/contributor-guide/testing.md.txt b/versions/55.0.0/_sources/contributor-guide/testing.md.txt
new file mode 100644
index 0000000000000..3b644f610b90e
--- /dev/null
+++ b/versions/55.0.0/_sources/contributor-guide/testing.md.txt
@@ -0,0 +1,270 @@
+
+
+# Testing
+
+Tests are critical to ensure that DataFusion is working properly and
+is not accidentally broken during refactorings. All new features
+should have test coverage and the entire test suite is run as part of CI.
+
+## Testing Quick Start
+
+While developing a feature or bug fix, best practice is to run the smallest set
+of tests that gives confidence for your change, then expand as needed.
+
+Initially, run the tests in the crates you changed. For example, if you made changes
+to files in `datafusion-optimizer/src`, run the corresponding crate tests:
+
+```shell
+cargo test -p datafusion-optimizer
+```
+
+Then, run the `sqllogictest` suite, which provides a strong speed–coverage tradeoff for development: it runs quickly while offering broad regression coverage across most SQL behavior in DataFusion.
+
+```shell
+cargo test --profile=ci --test sqllogictests
+```
+
+Finally, before submitting a PR, run the tests for the core `datafusion` and
+`datafusion-cli` crates:
+
+```shell
+cargo test -p datafusion
+cargo test -p datafusion-cli
+```
+
+Some integration tests require optional external services such as Docker-backed
+containers and may skip when unavailable.
+
+## Testing Overview
+
+DataFusion has several levels of tests in its [Test Pyramid] and tries to follow
+the Rust standard [Testing Organization] described in [The Book].
+
+Run tests using `cargo`:
+
+```shell
+cargo test
+```
+
+You can also use other runners such as [cargo-nextest].
+
+```shell
+cargo nextest run
+```
+
+[test pyramid]: https://martinfowler.com/articles/practical-test-pyramid.html
+[testing organization]: https://doc.rust-lang.org/book/ch11-03-test-organization.html
+[the book]: https://doc.rust-lang.org/book/
+[cargo-nextest]: https://nexte.st/
+
+## Unit tests
+
+Tests for code in an individual module are defined in the same source file with a `test` module, following Rust convention.
+
+For example, to run tests in the `datafusion` crate:
+
+```shell
+cargo test -p datafusion
+```
+
+The [test_util] module provides useful macros to write unit tests effectively, such as [`assert_batches_sorted_eq`] and [`assert_batches_eq`] for RecordBatches and [`assert_contains`] / [`assert_not_contains`] which are used extensively in the codebase.
+
+[test_util]: https://github.com/apache/datafusion/tree/main/datafusion/common/src/test_util.rs
+[`assert_batches_sorted_eq`]: https://docs.rs/datafusion/latest/datafusion/macro.assert_batches_sorted_eq.html
+[`assert_batches_eq`]: https://docs.rs/datafusion/latest/datafusion/macro.assert_batches_eq.html
+[`assert_contains`]: https://docs.rs/datafusion/latest/datafusion/common/macro.assert_contains.html
+[`assert_not_contains`]: https://docs.rs/datafusion/latest/datafusion/common/macro.assert_not_contains.html
+
+## sqllogictests Tests
+
+DataFusion's SQL implementation is tested using [sqllogictest](https://github.com/apache/datafusion/tree/main/datafusion/sqllogictest). You can run these tests with commands like:
+
+```shell
+# Run all tests
+cargo test --profile=ci --test sqllogictests
+# Run a specific test file
+cargo test --profile=ci --test sqllogictests -- aggregate.slt
+# Run a specific test file and update expected outputs
+cargo test --profile=ci --test sqllogictests -- aggregate.slt --complete
+# Run and update expected outputs for all test files
+cargo test --profile=ci --test sqllogictests -- --complete
+```
+
+`sqllogictests` may be less convenient for new contributors who are familiar with writing `.rs` tests as they require learning another tool. However, `sqllogictest` based tests are much easier to develop and maintain as they 1) do not require a slow recompile/link cycle and 2) can be automatically updated.
+
+Like similar systems such as [DuckDB](https://duckdb.org/dev/testing), DataFusion has chosen to trade off a slightly higher barrier to contribution for longer term maintainability.
+
+DataFusion has integrated [sqlite's test suite](https://sqlite.org/sqllogictest/doc/trunk/about.wiki) as a supplemental test suite that is run whenever a PR is merged into DataFusion. To run it manually please refer to the [README](https://github.com/apache/datafusion/blob/main/datafusion/sqllogictest/README.md#running-tests-sqlite) file for instructions.
+
+## Snapshot testing (`cargo insta`)
+
+[Insta](https://github.com/mitsuhiko/insta) is used for snapshot testing. Snapshots are generated
+and compared on each test run. If the output changes, tests will fail.
+
+To review the changes, you can use Insta CLI:
+
+```shell
+cargo install cargo-insta
+cargo insta review
+```
+
+## Extended Tests
+
+In addition to the standard CI test suite that is run on all PRs prior to merge,
+DataFusion has "extended" tests (defined in [extended.yml]) that are run on each
+commit to `main`. These tests rarely fail but take significantly longer to run
+than the standard test suite and add important test coverage such as ensuring
+correctness when there are hash collisions and running the relevant portions of
+the entire [sqlite test suite]. You can run the extended tests
+locally by following the [instructions in the documentation].
+
+[sqlite test suite]: https://www.sqlite.org/sqllogictest/dir?ci=tip
+[instructions in the documentation]: https://github.com/apache/datafusion/tree/main/datafusion/sqllogictest#running-tests-sqlite
+[extended.yml]: https://github.com/apache/datafusion/blob/main/.github/workflows/extended.yml
+
+## Rust Integration Tests
+
+There are several public interface tests for the DataFusion library in the [tests](https://github.com/apache/datafusion/tree/main/datafusion/core/tests) directory.
+
+You can run these tests individually using `cargo` as normal command such as
+
+```shell
+cargo test -p datafusion --test parquet_integration
+```
+
+## SQL "Fuzz" testing
+
+DataFusion uses the [SQLancer] for "fuzz" testing: it generates random SQL
+queries and execute them against DataFusion to find bugs.
+
+The code is in the [datafusion-sqllancer] repository, and we welcome further
+contributions. Kudos to [@2010YOUY01] for the initial implementation.
+
+[sqlancer]: https://github.com/sqlancer/sqlancer
+[datafusion-sqllancer]: https://github.com/datafusion-contrib/datafusion-sqllancer
+[@2010youy01]: https://github.com/2010YOUY01
+
+## Documentation Examples
+
+We use Rust [doctest] to verify examples from the documentation are correct and
+up-to-date. These tests are run as part of our CI and you can run them them
+locally with the following command:
+
+```shell
+cargo test --doc
+```
+
+### API Documentation Examples
+
+As with other Rust projects, examples in doc comments in `.rs` files are
+automatically checked to ensure they work and evolve along with the code.
+
+### User Guide Documentation
+
+Rust example code from the user guide (anything marked with \`\`\`rust) is also
+tested in the same way using the [doc_comment] crate. See the end of
+[core/src/lib.rs] for more details.
+
+[doctest]: https://doc.rust-lang.org/rust-by-example/testing/doc_testing.html
+[doc_comment]: https://docs.rs/doc-comment/latest/doc_comment
+[core/src/lib.rs]: https://github.com/apache/datafusion/blob/main/datafusion/core/src/lib.rs#L583
+
+## Documentation Link Checks
+
+Run the internal markdown link check locally:
+
+```shell
+source ci/scripts/utils/tool_versions.sh
+cargo install lychee --locked --version "${LYCHEE_VERSION}"
+bash ci/scripts/markdown_link_check.sh
+```
+
+Notes:
+
+- The script is run with `bash` and is compatible with the default Bash on macOS (no `mapfile` dependency).
+- The CI configuration currently checks internal markdown links only. External `http(s)` and `mailto` links are excluded to avoid flaky failures.
+
+When a link is broken, lychee prints the file and URL/path that failed. For example:
+
+```text
+[docs/source/user-guide/cli/overview.md]:
+ [ERROR] file:///.../docs/source/user-guide/cli/missing-page.md | Cannot find file: File not found. Check if file exists and path is correct
+```
+
+Rust doc comments are validated by rustdoc in CI and can be checked locally with:
+
+```shell
+bash ci/scripts/rust_docs.sh
+```
+
+## Benchmarks
+
+### Criterion Benchmarks
+
+[Criterion](https://docs.rs/criterion/latest/criterion/index.html) is a statistics-driven micro-benchmarking framework used by DataFusion for evaluating the performance of specific code-paths. In particular, the criterion benchmarks help to both guide optimisation efforts, and prevent performance regressions within DataFusion.
+
+Criterion integrates with Cargo's built-in [benchmark support](https://doc.rust-lang.org/cargo/commands/cargo-bench.html) and a given benchmark can be run with
+
+```
+cargo bench --bench BENCHMARK_NAME
+```
+
+A full list of benchmarks can be found [here](https://github.com/apache/datafusion/tree/main/datafusion/core/benches).
+
+_[cargo-criterion](https://github.com/bheisler/cargo-criterion) may also be used for more advanced reporting._
+
+### Parquet SQL Benchmarks
+
+The parquet SQL benchmarks can be run with
+
+```
+ cargo bench --bench parquet_query_sql
+```
+
+These randomly generate a parquet file, and then benchmark queries sourced from [parquet_query_sql.sql](../../../datafusion/core/benches/parquet_query_sql.sql) against it. This can therefore be a quick way to add coverage of particular query and/or data paths.
+
+If the environment variable `PARQUET_FILE` is set, the benchmark will run queries against this file instead of a randomly generated one. This can be useful for performing multiple runs, potentially with different code, against the same source data, or for testing against a custom dataset.
+
+The benchmark will automatically remove any generated parquet file on exit, however, if interrupted (e.g. by CTRL+C) it will not. This can be useful for analysing the particular file after the fact, or preserving it to use with `PARQUET_FILE` in subsequent runs.
+
+### Comparing Baselines
+
+By default, Criterion.rs will compare the measurements against the previous run (if any). Sometimes it's useful to keep a set of measurements around for several runs. For example, you might want to make multiple changes to the code while comparing against the master branch. For this situation, Criterion.rs supports custom baselines.
+
+```
+ git checkout main
+ cargo bench --bench sql_planner -- --save-baseline main
+ git checkout YOUR_BRANCH
+ cargo bench --bench sql_planner -- --baseline main
+```
+
+Note: For MacOS it may be required to run `cargo bench` with `sudo`
+
+```
+sudo cargo bench ...
+```
+
+More information on [Baselines](https://bheisler.github.io/criterion.rs/book/user_guide/command_line_options.html#baselines)
+
+### Upstream Benchmark Suites
+
+Instructions and tooling for running upstream benchmark suites against DataFusion can be found in [benchmarks](https://github.com/apache/datafusion/tree/main/benchmarks).
+
+These are valuable for comparative evaluation against alternative Arrow implementations and query engines.
diff --git a/versions/55.0.0/_sources/download.md.txt b/versions/55.0.0/_sources/download.md.txt
new file mode 100644
index 0000000000000..34296262071c8
--- /dev/null
+++ b/versions/55.0.0/_sources/download.md.txt
@@ -0,0 +1,77 @@
+
+
+# Download
+
+Most users use DataFusion as a library in their Rust projects by adding it as a dependency
+in their `Cargo.toml` file and downloading it from the Rust [crates.io] package registry.
+
+For example:
+
+```toml
+[dependencies]
+datafusion = "55.0.0"
+```
+
+While DataFusion is distributed via [crates.io] as a convenience, the
+official Apache DataFusion releases are provided as source artifacts.
+
+[crates.io]: https://crates.io/crates/datafusion
+
+## Releases
+
+You can find the latest releases, signatures and checksums on
+the [ASF Release Page](https://dist.apache.org/repos/dist/release/datafusion)
+
+For previous releases, please check the [archive](https://archive.apache.org/dist/datafusion/).
+
+For releases earlier than 37.0.0, please check [Arrow's archive](https://archive.apache.org/dist/arrow/).
+
+## Notes
+
+- When downloading a release, please verify the OpenPGP compatible signature (or failing that, check the SHA-512); these should be fetched from the main Apache site.
+- The [KEYS] file contains the public keys used for signing release. It is recommended that (when possible) a web of trust is used to confirm the identity of these keys.
+- Please download the [KEYS] file as well as the .asc signature files.
+
+[keys]: https://downloads.apache.org/datafusion/KEYS
+
+### To verify the signature of the release artifact
+
+You will need to download both the release artifact and the .asc signature file for that artifact. Then verify the signature by:
+
+- Download the KEYS file and the .asc signature files for the relevant release artifacts.
+- Import the KEYS file to your GPG keyring:
+
+ ```shell
+ gpg --import KEYS
+ ```
+
+- Verify the signature of the release artifact using the following command:
+
+ ```shell
+ gpg --verify .asc
+ ```
+
+### To verify the checksum of the release artifact
+
+You will need to download both the release artifact and the .sha512 checksum file for that artifact. Then verify the checksum by:
+
+```shell
+shasum -a 512 -c .sha512
+```
diff --git a/versions/55.0.0/_sources/index.rst.txt b/versions/55.0.0/_sources/index.rst.txt
new file mode 100644
index 0000000000000..ea6ebb74c08b1
--- /dev/null
+++ b/versions/55.0.0/_sources/index.rst.txt
@@ -0,0 +1,186 @@
+.. Licensed to the Apache Software Foundation (ASF) under one
+.. or more contributor license agreements. See the NOTICE file
+.. distributed with this work for additional information
+.. regarding copyright ownership. The ASF licenses this file
+.. to you under the Apache License, Version 2.0 (the
+.. "License"); you may not use this file except in compliance
+.. with the License. You may obtain a copy of the License at
+
+.. http://www.apache.org/licenses/LICENSE-2.0
+
+.. Unless required by applicable law or agreed to in writing,
+.. software distributed under the License is distributed on an
+.. "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+.. KIND, either express or implied. See the License for the
+.. specific language governing permissions and limitations
+.. under the License.
+
+.. image:: _static/images/original.svg
+ :alt: DataFusion Logo
+ :class: light-logo
+
+.. image:: _static/images/original_dark.svg
+ :alt: DataFusion Logo
+ :class: dark-logo
+
+=================
+Apache DataFusion
+=================
+
+.. raw:: html
+
+
+
+
+DataFusion is an extensible query engine written in `Rust `_ that
+uses `Apache Arrow `_ as its in-memory format.
+
+The documentation on this site is for the `core DataFusion project `_, which contains
+libraries and binaries for developers building fast and feature rich database and analytic systems,
+customized to particular workloads. See `use cases `_ for examples.
+
+The following related subprojects target end users and have separate documentation.
+
+- `DataFusion Python `_ offers a Python interface for SQL and DataFrame
+ queries.
+- `DataFusion Java `_ offers a Java interface for SQL and DataFrame
+ queries.
+- `DataFusion Comet `_ is an accelerator for Apache Spark based on
+ DataFusion.
+- `DataFusion Ballista `_ is distributed processing extension for DataFusion.
+
+"Out of the box," DataFusion offers `SQL `_
+and `Dataframe `_ APIs,
+excellent `performance `_, built-in support for CSV, Parquet, JSON, and Avro,
+extensive customization, and a great `community`_.
+`Python Bindings `_ are also available.
+`Ballista `_ is Apache DataFusion extension enabling the parallelized execution of workloads across multiple nodes in a distributed environment.
+
+DataFusion features a full query planner, a columnar, streaming, multi-threaded,
+vectorized execution engine, and partitioned data sources. You can
+customize DataFusion at almost all points including additional data sources,
+query languages, functions, custom operators and more.
+See the `Architecture `_ section for more details.
+
+To get started, see
+
+* The `example usage`_ section of the user guide and the `datafusion-examples`_ directory.
+* The `library user guide`_ for examples of using DataFusion's extension APIs
+* The `developer’s guide`_ for contributing and `communication`_ for getting in touch with us.
+
+.. _example usage: user-guide/example-usage.html
+.. _datafusion-examples: https://github.com/apache/datafusion/tree/main/datafusion-examples
+.. _developer’s guide: contributor-guide/index.html#developer-s-guide
+.. _library user guide: library-user-guide/index.html
+.. _community: contributor-guide/communication.html
+.. _communication: contributor-guide/communication.html
+
+.. _toc.asf-links:
+.. toctree::
+ :maxdepth: 1
+ :caption: ASF Links
+
+ Apache Software Foundation
+ License
+ Donate
+ Thanks
+ Security
+
+.. _toc.links:
+.. toctree::
+ :maxdepth: 1
+ :caption: Links
+
+ GitHub and Issue Tracker
+ crates.io
+ API Docs
+ Blog
+ Code of conduct
+ Download
+
+.. _toc.guide:
+.. toctree::
+ :maxdepth: 1
+ :caption: User Guide
+
+ user-guide/introduction
+ user-guide/example-usage
+ user-guide/features
+ user-guide/concepts-readings-events
+ user-guide/crate-configuration
+ user-guide/cli/index
+ user-guide/dataframe
+ user-guide/arrow-introduction
+ user-guide/expressions
+ user-guide/sql/index
+ user-guide/configs
+ user-guide/explain-usage
+ user-guide/parquet-content-defined-chunking
+ user-guide/metrics
+ user-guide/faq
+
+.. _toc.library-user-guide:
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Library User Guide
+
+ library-user-guide/index
+ library-user-guide/upgrading/index
+ library-user-guide/extensions
+ library-user-guide/using-the-sql-api
+ library-user-guide/extending-sql
+ library-user-guide/working-with-exprs
+ library-user-guide/using-the-dataframe-api
+ library-user-guide/building-logical-plans
+ library-user-guide/catalogs
+ library-user-guide/functions/index
+ library-user-guide/custom-table-providers
+ library-user-guide/table-constraints
+ library-user-guide/extending-operators
+ library-user-guide/profiling
+ library-user-guide/query-optimizer
+
+.. .. _toc.contributor-guide:
+
+.. toctree::
+ :maxdepth: 1
+ :caption: Contributor Guide
+
+ contributor-guide/index
+ contributor-guide/pr_review
+ contributor-guide/communication
+ contributor-guide/development_environment
+ contributor-guide/architecture
+ contributor-guide/architecture/dependency-graph
+ contributor-guide/testing
+ contributor-guide/api-health
+ contributor-guide/howtos
+ contributor-guide/release_management
+ contributor-guide/roadmap
+ contributor-guide/governance
+ contributor-guide/inviting
+ contributor-guide/specification/index
+ contributor-guide/gsoc/index
+
+.. _toc.subprojects:
+
+.. toctree::
+ :maxdepth: 1
+ :caption: DataFusion Subprojects
+
+ DataFusion Ballista
+ DataFusion Comet
+ DataFusion Java
+ DataFusion Python
diff --git a/versions/55.0.0/_sources/library-user-guide/building-logical-plans.md.txt b/versions/55.0.0/_sources/library-user-guide/building-logical-plans.md.txt
new file mode 100644
index 0000000000000..6efd97879ac4d
--- /dev/null
+++ b/versions/55.0.0/_sources/library-user-guide/building-logical-plans.md.txt
@@ -0,0 +1,226 @@
+
+
+# Building Logical Plans
+
+A logical plan is a structured representation of a database query that describes the high-level operations and
+transformations needed to retrieve data from a database or data source. It abstracts away specific implementation
+details and focuses on the logical flow of the query, including operations like filtering, sorting, and joining tables.
+
+This logical plan serves as an intermediate step before generating an optimized physical execution plan. This is
+explained in more detail in the [Query Planning and Execution Overview] section of the [Architecture Guide].
+
+## Building Logical Plans Manually
+
+DataFusion's [LogicalPlan] is an enum containing variants representing all the supported operators, and also
+contains an `Extension` variant that allows projects building on DataFusion to add custom logical operators.
+
+It is possible to create logical plans by directly creating instances of the [LogicalPlan] enum as shown, but it is
+much easier to use the [LogicalPlanBuilder], which is described in the next section.
+
+Here is an example of building a logical plan directly:
+
+```rust
+use datafusion::common::DataFusionError;
+use datafusion::arrow::datatypes::{DataType, Field, Schema, SchemaRef};
+use datafusion::logical_expr::{Filter, LogicalPlan, TableScan, LogicalTableSource};
+use datafusion::prelude::*;
+use std::sync::Arc;
+
+fn main() -> Result<(), DataFusionError> {
+ // create a logical table source
+ let schema = Schema::new(vec![
+ Field::new("id", DataType::Int32, true),
+ Field::new("name", DataType::Utf8, true),
+ ]);
+ let table_source = LogicalTableSource::new(SchemaRef::new(schema));
+
+ // create a TableScan plan
+ let projection = None; // optional projection
+ let filters = vec![]; // optional filters to push down
+ let fetch = None; // optional LIMIT
+ let table_scan = LogicalPlan::TableScan(TableScan::try_new(
+ "person",
+ Arc::new(table_source),
+ projection,
+ filters,
+ fetch,
+ )?
+ );
+
+ // create a Filter plan that evaluates `id > 500` that wraps the TableScan
+ let filter_expr = col("id").gt(lit(500));
+ let plan = LogicalPlan::Filter(Filter::try_new(filter_expr, Arc::new(table_scan)) ? );
+
+ // print the plan
+ println!("{}", plan.display_indent_schema());
+ Ok(())
+}
+```
+
+This example produces the following plan:
+
+```text
+Filter: person.id > Int32(500) [id:Int32;N, name:Utf8;N]
+ TableScan: person [id:Int32;N, name:Utf8;N]
+```
+
+## Building Logical Plans with LogicalPlanBuilder
+
+DataFusion logical plans can be created using the [LogicalPlanBuilder] struct. There is also a [DataFrame] API which is
+a higher-level API that delegates to [LogicalPlanBuilder].
+
+There are several functions that can be used to create a new builder, such as
+
+- `empty` - create an empty plan with no fields
+- `values` - create a plan from a set of literal values
+- `scan` - create a plan representing a table scan
+- `scan_with_filters` - create a plan representing a table scan with filters
+
+Once the builder is created, transformation methods can be called to declare that further operations should be
+performed on the plan. Note that all we are doing at this stage is building up the logical plan structure. No query
+execution will be performed.
+
+Here are some examples of transformation methods, but for a full list, refer to the [LogicalPlanBuilder] API documentation.
+
+- `filter`
+- `limit`
+- `sort`
+- `distinct`
+- `join`
+
+The following example demonstrates building the same simple query plan as the previous example, with a table scan followed by a filter.
+
+
+
+```rust
+use datafusion::common::DataFusionError;
+use datafusion::arrow::datatypes::{DataType, Field, Schema, SchemaRef};
+use datafusion::logical_expr::{LogicalPlanBuilder, LogicalTableSource};
+use datafusion::prelude::*;
+use std::sync::Arc;
+
+fn main() -> Result<(), DataFusionError> {
+ // create a logical table source
+ let schema = Schema::new(vec![
+ Field::new("id", DataType::Int32, true),
+ Field::new("name", DataType::Utf8, true),
+ ]);
+ let table_source = LogicalTableSource::new(SchemaRef::new(schema));
+
+ // optional projection
+ let projection = None;
+
+ // create a LogicalPlanBuilder for a table scan
+ let builder = LogicalPlanBuilder::scan("person", Arc::new(table_source), projection)?;
+
+ // perform a filter operation and build the plan
+ let plan = builder
+ .filter(col("id").gt(lit(500)))? // WHERE id > 500
+ .build()?;
+
+ // print the plan
+ println!("{}", plan.display_indent_schema());
+ Ok(())
+}
+```
+
+This example produces the following plan:
+
+```text
+Filter: person.id > Int32(500) [id:Int32;N, name:Utf8;N]
+ TableScan: person [id:Int32;N, name:Utf8;N]
+```
+
+## Translating Logical Plan to Physical Plan
+
+Logical plans can not be directly executed. They must be "compiled" into an
+[`ExecutionPlan`], which is often referred to as a "physical plan".
+
+Compared to `LogicalPlan`s, `ExecutionPlan`s have many more details such as
+specific algorithms and detailed optimizations. Given a
+`LogicalPlan`, the easiest way to create an `ExecutionPlan` is using
+[`SessionState::create_physical_plan`] as shown below
+
+```rust
+use datafusion::datasource::{provider_as_source, MemTable};
+use datafusion::common::DataFusionError;
+use datafusion::physical_plan::display::DisplayableExecutionPlan;
+use datafusion::arrow::datatypes::{DataType, Field, Schema, SchemaRef};
+use datafusion::logical_expr::{LogicalPlanBuilder, LogicalTableSource};
+use datafusion::prelude::*;
+use std::sync::Arc;
+
+// Creating physical plans may access remote catalogs and data sources
+// thus it must be run with an async runtime.
+#[tokio::main]
+async fn main() -> Result<(), DataFusionError> {
+
+ // create a default table source
+ let schema = Schema::new(vec![
+ Field::new("id", DataType::Int32, true),
+ Field::new("name", DataType::Utf8, true),
+ ]);
+ // To create an ExecutionPlan we must provide an actual
+ // TableProvider. For this example, we don't provide any data
+ // but in production code, this would have `RecordBatch`es with
+ // in memory data
+ let table_provider = Arc::new(MemTable::try_new(Arc::new(schema), vec![vec![]])?);
+ // Use the provider_as_source function to convert the TableProvider to a table source
+ let table_source = provider_as_source(table_provider);
+
+ // create a LogicalPlanBuilder for a table scan without projection or filters
+ let logical_plan = LogicalPlanBuilder::scan("person", table_source, None)?.build()?;
+
+ // Now create the physical plan by calling `create_physical_plan`
+ let ctx = SessionContext::new();
+ let physical_plan = ctx.state().create_physical_plan(&logical_plan).await?;
+
+ // print the plan
+ println!("{}", DisplayableExecutionPlan::new(physical_plan.as_ref()).indent(true));
+ Ok(())
+}
+```
+
+This example produces the following physical plan:
+
+```text
+DataSourceExec: partitions=0, partition_sizes=[]
+```
+
+## Table Sources
+
+The previous examples use a [LogicalTableSource], which is used for tests and documentation in DataFusion, and is also
+suitable if you are using DataFusion to build logical plans but do not use DataFusion's physical planner.
+
+However, it is more common to use a [TableProvider]. To get a [TableSource] from a
+[TableProvider], use [provider_as_source] or [DefaultTableSource].
+
+[query planning and execution overview]: https://docs.rs/datafusion/latest/datafusion/index.html#query-planning-and-execution-overview
+[architecture guide]: https://docs.rs/datafusion/latest/datafusion/index.html#architecture
+[logicalplan]: https://docs.rs/datafusion-expr/latest/datafusion_expr/logical_plan/enum.LogicalPlan.html
+[logicalplanbuilder]: https://docs.rs/datafusion-expr/latest/datafusion_expr/logical_plan/builder/struct.LogicalPlanBuilder.html
+[dataframe]: using-the-dataframe-api.md
+[logicaltablesource]: https://docs.rs/datafusion-expr/latest/datafusion_expr/logical_plan/builder/struct.LogicalTableSource.html
+[defaulttablesource]: https://docs.rs/datafusion/latest/datafusion/datasource/default_table_source/struct.DefaultTableSource.html
+[provider_as_source]: https://docs.rs/datafusion/latest/datafusion/datasource/default_table_source/fn.provider_as_source.html
+[tableprovider]: https://docs.rs/datafusion/latest/datafusion/datasource/trait.TableProvider.html
+[tablesource]: https://docs.rs/datafusion-expr/latest/datafusion_expr/trait.TableSource.html
+[`executionplan`]: https://docs.rs/datafusion/latest/datafusion/physical_plan/trait.ExecutionPlan.html
+[`sessionstate::create_physical_plan`]: https://docs.rs/datafusion/latest/datafusion/execution/session_state/struct.SessionState.html#method.create_physical_plan
diff --git a/versions/55.0.0/_sources/library-user-guide/catalogs.md.txt b/versions/55.0.0/_sources/library-user-guide/catalogs.md.txt
new file mode 100644
index 0000000000000..fc1d0abb7823a
--- /dev/null
+++ b/versions/55.0.0/_sources/library-user-guide/catalogs.md.txt
@@ -0,0 +1,315 @@
+
+
+# Catalogs, Schemas, and Tables
+
+This section describes how to create and manage catalogs, schemas, and tables in DataFusion. For those wanting to dive into the code quickly please see the [example](https://github.com/apache/datafusion/blob/main/datafusion-examples/examples/data_io/catalog.rs).
+
+## General Concepts
+
+Catalog providers, catalogs, schemas, and tables are organized in a hierarchy. A `CatalogProviderList` contains `CatalogProvider`s, a `CatalogProvider` contains `SchemaProviders` and a `SchemaProvider` contains `TableProvider`s.
+
+DataFusion comes with a basic in memory catalog functionality in the [`catalog` module]. You can use these in memory implementations as is, or extend DataFusion with your own catalog implementations, for example based on local files or files on remote object storage.
+
+DataFusion supports DDL queries (e.g. `CREATE TABLE`) using the catalog API described in this section. See the [TableProvider] section for information on DML queries (e.g. `INSERT INTO`).
+
+[`catalog` module]: https://docs.rs/datafusion/latest/datafusion/catalog/index.html
+[tableprovider]: ./custom-table-providers.md
+
+Similarly to other concepts in DataFusion, you'll implement various traits to create your own catalogs, schemas, and tables. The following sections describe the traits you'll need to implement.
+
+The `CatalogProviderList` trait has methods to register new catalogs, get a catalog by name and list all catalogs .The `CatalogProvider` trait has methods to set a schema to a name, get a schema by name, and list all schemas. The `SchemaProvider`, which can be registered with a `CatalogProvider`, has methods to set a table to a name, get a table by name, list all tables, deregister a table, and check for a table's existence. The `TableProvider` trait has methods to scan underlying data and use it in DataFusion. The `TableProvider` trait is covered in more detail [here](./custom-table-providers.md).
+
+In the following example, we'll implement an in memory catalog, starting with the `SchemaProvider` trait as we need one to register with the `CatalogProvider`. Finally we will implement `CatalogProviderList` to register the `CatalogProvider`.
+
+## Implementing `MemorySchemaProvider`
+
+The `MemorySchemaProvider` is a simple implementation of the `SchemaProvider` trait. It stores state (i.e. tables) in a `DashMap`, which then underlies the `SchemaProvider` trait.
+
+```rust
+use std::sync::Arc;
+use dashmap::DashMap;
+use datafusion::catalog::{TableProvider, SchemaProvider};
+
+#[derive(Debug)]
+pub struct MemorySchemaProvider {
+ tables: DashMap>,
+}
+```
+
+`tables` is the key-value pair described above. The underlying state could also be another data structure or other storage mechanism such as a file or transactional database.
+
+Then we implement the `SchemaProvider` trait for `MemorySchemaProvider`.
+
+```rust
+# use std::sync::Arc;
+# use dashmap::DashMap;
+# use datafusion::catalog::TableProvider;
+#
+# #[derive(Debug)]
+# pub struct MemorySchemaProvider {
+# tables: DashMap>,
+# }
+
+use std::any::Any;
+use datafusion::catalog::SchemaProvider;
+use async_trait::async_trait;
+use datafusion::common::{Result, exec_err};
+
+#[async_trait]
+impl SchemaProvider for MemorySchemaProvider {
+ fn table_names(&self) -> Vec {
+ self.tables
+ .iter()
+ .map(|table| table.key().clone())
+ .collect()
+ }
+
+ async fn table(&self, name: &str) -> Result