Skip to content

Runtime Views: CTE mode #1880

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions java/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ Some property defaults have been adjusted:
| `cds.security.authorization.instanceBased.rejectSelectedUnauthorizedEntity.enabled` | false | true | Requests that violate instance-based authorization conditions now fail with 403, instead of 404. |
| `cds.security.authorization.instanceBased.checkInputData.enabled` | false | true | [Authorization Checks On Input Data](./security#input-data-auth) are now enabled by default. |
| `cds.errors.defaultTranslations.enabled` | false | true | [Translations for Validation Error Messages](./event-handlers/indicating-errors#ootb-translated-messages) are now enabled by default. |
| `cds.sql.runtimeView.mode` | resolve | cte | [Runtime views](./working-with-cql/query-execution#runtimeviews) are now by default translated into Common Table Expressions |

### Deprecated Properties

Expand Down
64 changes: 42 additions & 22 deletions java/working-with-cql/query-execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -400,11 +400,17 @@ The `lock()` method has an optional parameter `timeout` that indicates the maxim

The parameter `mode` allows to specify whether an `EXCLUSIVE` or a `SHARED` lock should be set.

## Runtime Views { #runtimeviews}
## Runtime Views { #runtimeviews }

The CDS compiler generates [SQL DDL](../../guides/databases?impl-variant=java#generating-sql-ddl) statements based on your CDS model, which include SQL views for all CDS [views and projections](../../cds/cdl#views-projections). This means adding or changing CDS views requires a deployment of the database schema changes.
The CDS compiler generates [SQL DDL](../../guides/databases?impl-variant=java#generating-sql-ddl) statements from your CDS model, including SQL views for all CDS [views and projections](../../cds/cdl#views-projections). As a result, adding or modifying CDS views typically requires redeploying the database schema.

To avoid schema updates due to adding or updating CDS views, annotate them with [@cds.persistence.skip](../../guides/databases#cds-persistence-skip). In this case the CDS compiler won't generate corresponding static database views. Instead, the CDS views are dynamically resolved by the CAP Java runtime.
To avoid schema redeployments when you add or update CDS views, annotate them with [@cds.persistence.skip](../../guides/databases#cds-persistence-skip). This annotation tells the CDS compiler to skip generating database views for these entities. Instead, the CAP Java runtime dynamically resolves such views at runtime.

::: warning Limitations
Runtime views support only simple [CDS projections](../../cds/cdl#as-projection-on). They do not support complex views that use aggregations, unions, joins, or subqueries in the `FROM` clause. To read [draft-enabled](../fiori-drafts#reading-drafts) entities, set `cds.drafts.persistence` to `split`. [Calculated elements](../../cds/cdl#calculated-elements) are not yet supported in runtime views.
:::

For example, consider the following CDS model and query:

```cds
entity Books {
Expand All @@ -413,33 +419,47 @@ entity Books {
stock : Integer;
author : Association to one Authors;
}
@cds.persistence.skip // [!code focus]
entity BooksWithLowStock as projection on Books { // [!code focus]
id, title, author.name as author // [!code focus]
} where stock < 10; // [!code focus]
@cds.persistence.skip
entity BooksWithLowStock as projection on Books {
id, title, author.name as author
} where stock < 10;
```

At runtime, CAP Java resolves queries against runtime views until an entity is reached that isn't annotated with *@cds.persistence.skip*. For example, the CQL query

```sql
Select BooksWithLowStock where author = 'Kafka'
```

is executed against SQL databases as

```SQL
SELECT B.ID, B.TITLE, A.NAME as "author" FROM BOOKS AS B
LEFT OUTER JOIN AUTHORS AS A ON B.AUTHOR_ID = A.ID
WHERE B.STOCK < 10 AND A.NAME = ?
```
CAP Java provides two modes for resolving runtime views:

::: warning Limitations
Runtime views are supported for simple [CDS projections](../../cds/cdl#as-projection-on). Expands of [filtered associations](../../cds/cdl#publish-associations-with-filter) are only supported since `3.7.0`. Constant values and expressions in runtime views are supported since `3.8.0`.
**`cte` mode**: The runtime translates the view definition into a _Common Table Expression_ (CTE) and sends it with the query to the database.

Complex views using aggregations or union/join/subqueries in `FROM` are not supported and for reading [draft-enabled](../fiori-drafts#reading-drafts) entities, `cds.drafts.persistence` needs to be set to `split`.
```sql
WITH BOOKSWITHLOWSTOCK_CTE AS (
SELECT B.ID,
B.TITLE,
A.NAME AS "AUTHOR"
FROM BOOKS B
LEFT OUTER JOIN AUTHOR A ON B.AUTHOR_ID = A.ID
WHERE B.STOCK < 10
)
SELECT ID, TITLE, AUTHOR AS "author"
FROM BOOKSWITHLOWSTOCK_CTE
WHERE A.NAME = ?
```

::: tip
CAP Java 4.x uses `cte` mode by default. In 3.10, enable it with **cds.sql.runtimeView.mode: cte**.
:::

### Using I/O Streams in Queries
**`resolve` mode**: The runtime _resolves_ the view definition to the underlying persistence entities and executes the query directly against them.

```sql
SELECT B.ID, B.TITLE, A.NAME AS "author"
FROM BOOKS AS B
LEFT OUTER JOIN AUTHORS AS A ON B.AUTHOR_ID = A.ID
WHERE B.STOCK < 10 AND A.NAME = ?
```

## Using I/O Streams in Queries

As described in section [Predefined Types](../cds-data#predefined-types) it's possible to stream the data, if the element is annotated with `@Core.MediaType`. The following example demonstrates how to allocate the stream for element `coverImage`, pass it through the API to an underlying database and close the stream.

Expand Down Expand Up @@ -473,7 +493,7 @@ try (InputStream resource = getResource("IMAGE.PNG")) {
// Transaction finished
```

### Using Native SQL
## Using Native SQL

CAP Java doesn't have a dedicated API to execute native SQL Statements. However, when using Spring as application framework you can leverage Spring's features to execute native SQL statements. See [Execute SQL statements with Spring's JdbcTemplate](../cqn-services/persistence-services#jdbctemplate) for more details.

Expand Down