


Work on a C++ Analytical Database Engine and Pass the Required Tests
Use when changing the code of a C++ analytical database engine. The AI traces the change from SQL parsing to execution, edits generated files through their source, follows the C++ style and error rules, and runs SQL logic tests and every required build before calling it done.
To use this AI rule
## Choose the Build Type and Tests to Run at Each Stage
Choose a build configuration that provides meaningful assertions and diagnostics without making routine iteration unnecessarily slow.
### Build Strategy
- Use an optimized build with debug symbols as the normal development configuration when it preserves the required checks.
- Use a fully instrumented debug build when investigating memory safety, assertion failures, or behavior that optimization may affect.
- Run the repository formatter before committing.
- Regenerate source-derived files through the approved generation target, which should also apply required formatting.
### Test Strategy
- Run the fast unit suite during normal iteration.
- Scope a run to one test file or case while diagnosing a focused change.
- Run the complete suite, including slow tests, before a broad handoff when the change can affect shared behavior.
- When fixing continuous-integration failures, reproduce each required configuration in the documented order.
- Include configuration-matrix, vectorized-execution, sanitizer, and assertion builds when the affected boundary requires them.
- Do not substitute a faster local configuration for a failing authoritative gate without evidence that the difference is irrelevant.
## Trace a Query from SQL Parsing to Results Before Fixing It
Trace behavior through the complete query lifecycle instead of patching the first module that exposes a symptom.
### Pipeline Stages
1. Parse SQL text into statement, expression, and table-reference syntax trees.
2. Bind names and types against the catalog while creating a logical plan.
3. Optimize the logical plan with semantic-preserving rules and cost-based choices.
4. Convert logical operators into physical operators.
5. Execute physical operators through vectorized, parallel pipelines.
6. Return results through the connection and client context.
### Component Ownership
- Keep grammar and parser transformations synchronized; every grammar rule needs the corresponding transformation.
- Let the planner own binding, type resolution, subqueries, and logical operators.
- Let the optimizer transform plans without changing observable semantics.
- Let the execution layer own physical planning, operators, and expression evaluation.
- Keep persistent storage, buffering, compression, checkpoints, and write-ahead logging in the storage layer.
- Treat the catalog as the single source of truth for schemas, tables, functions, and types.
- Keep transactions, undo state, and multi-version concurrency control separate from task scheduling and parallel pipelines.
## Process Data in Column Batches and Follow Ownership Rules
An analytical engine depends on clear distinctions between parsed syntax, bound expressions, column identity, physical vectors, and ownership.
### Data Flow
- Process data in columnar batches rather than one row at a time.
- Represent each batch column with the engine's vector abstraction.
- Carry a stable pair of table and column indexes through planning and execution.
- Keep parsed expressions unbound and separate from typed, bound expressions.
- Evaluate bound expressions through the vectorized expression executor.
### Ownership and Types
- Use exclusive smart ownership by default.
- Use shared ownership only when multiple lifetimes genuinely require it.
- Distinguish nullable non-owning references from guaranteed non-null references.
- Never use raw owning pointers.
- Route type promotion and casts through one authoritative rule set.
- Add custom types through the extension mechanism rather than bypassing the type system.
- Use visitors for tree traversal, factories for deserialization, and typed subclasses for operator, entry, and expression hierarchies.
## Edit Extensions and Generated Files at Their Source
Treat in-tree extensions, externally maintained extensions, generated code, and release artifacts as different ownership classes.
### Extension Boundaries
- Edit in-tree extensions directly in their declared source directory.
- Keep externally maintained extensions in separate repositories and apply repository-owned changes through the designated patch mechanism.
- Support building either the full extension set or an explicit subset.
- Test extension changes against the same core interfaces and type rules used by built-in functionality.
### Generated Artifacts
- Identify the source files that generate API bindings, registrations, settings, serialization code, storage metadata, metrics, and enum utilities.
- Edit the source of a generated artifact, never only its generated output.
- Run the approved generation target after source changes.
- Inspect generated diffs for unrelated churn and format them through the standard formatter.
## Follow the C++ Coding Style and Keep Comments Short
Consistency in low-level code reduces ambiguity around ownership, indexes, public interfaces, and control flow.
### Code Style
- Use the repository's indentation and alignment rules and enforce its line-width limit through the formatter.
- Prefer fixed-width integer types over platform-dependent integer widths.
- Use the project's designated index type for offsets, indexes, and counts.
- Pass non-trivial read-only objects by constant reference.
- Prefer range-based loops when they express the traversal clearly.
- Always use braces for conditionals and loops.
- Never use `const_cast`.
- Follow established file, type, variable, and function naming conventions.
### Comments
- Keep comments short and let clear code carry the ordinary explanation.
- Comment enduring intent, constraints, or non-obvious invariants.
- Do not leave issue-specific repair history in the code.
- Put change narratives, such as an off-by-one repair, in the change description or commit message.
- Use longer comments only when the invariant cannot be made clear through code structure and naming.
## Choose Exceptions or Assertions by Error Type and Write SQL Logic Tests
Choose error channels according to whether a query must terminate, can recover, or has encountered an internal programmer defect.
### Error Policy
- Use exceptions for query-terminating failures such as parsing errors, missing objects, or exhausted memory.
- Use return values for conditions that can be recovered from during the same query.
- Use debug assertions for programmer errors that user input must never trigger.
- Make assertions specific enough to reveal the violated invariant.
- Do not turn expected invalid input into an internal assertion failure.
### SQL Logic Tests
- Prefer declarative SQL logic tests over C++ tests for query behavior.
- Mark statements that must succeed separately from statements that must fail.
- Declare the expected result-column types for queries.
- Separate query text from expected rows with the framework's canonical delimiter.
- Use regex expectations for error text only when exact wording is intentionally unstable.
- Declare required environment variables explicitly.
- Give slow tests the framework's slow-test designation so default runs remain practical.
- Cover numeric, string, and nested types, plus invalid and unexpected usage rather than only the happy path.
- Require the complete authoritative suite to pass before submission.
## Find What to Change from Existing Tests, Then Finish Every Required Check
Use tests and architectural ownership to locate a feature before editing, then verify every derived surface affected by the change.
### Investigation Sequence
1. Find existing tests to learn supported syntax and expected behavior.
2. Trace the feature from parser through binder, optimizer, physical planning, and execution.
3. Locate the corresponding statement, operator, expression, catalog, or function types.
4. Check where the feature is registered and where its public declaration lives.
5. Search implementation files and public headers with the repository's standard code-search tool.
6. Identify generated files and extension surfaces that depend on the changed source.
### Completion Checks
- Add or update focused regression tests before broad testing.
- Run formatting and source generation.
- Run the focused test, then the required unit, slow, sanitizer, assertion, configuration, and vector suites.
- Build the affected executable and extensions.
- Review generated diffs and documentation ownership.
- Do not claim completion until every required gate has an actual result.
