diff --git a/guides/databases/cdl-to-ddl.md b/guides/databases/cdl-to-ddl.md index d5e54522b..fcbad8d2a 100644 --- a/guides/databases/cdl-to-ddl.md +++ b/guides/databases/cdl-to-ddl.md @@ -13,7 +13,24 @@ Databases are deployed based on the entity definitions in your CDS models. This ## Using `cds compile`, ... -CDS compilation to database-specific DDLs is handled by the `cds compile` command, which is part of the [`cds` CLI](../../tools/cds-cli). When you run `cds deploy` or `cds watch`, this command is invoked automatically to generate the necessary DDL statements for your target database. +CDS compilation to database-specific DDLs is handled by the [`cds compile`](../../tools/cds-cli#cds-compile) command, which is part of the [`cds` CLI](../../tools/cds-cli). When you run `cds deploy` or `cds watch`, this command is invoked automatically to generate the necessary DDL statements for your target database. + +In CAP Java, the DDL is generated by the [Maven build](../../java/developing-applications/building#maven-build-options) which uses the [CDS Maven Plugin](../../java/developing-applications/building#cds-maven-plugin)'s [cds](../../java/assets/cds-maven-plugin-site/cds-mojo.html) goal to invoke `cds deploy --dry`. + +:::details +A build configuration to create the DDL specific for H2: + +```xml + + cds + + + deploy --to h2 --dry --out "${project.basedir}/src/main/resources/schema-h2.sql" + + + +``` +::: You can also run the command manually to see the generated DDL for your models. For example, to inspect what the SQL DDL for your entire model would look like, simply run: @@ -61,31 +78,9 @@ code --diff _out/c/sqlite.sql _out/c/h2.sql > CDS models are designed to be database-agnostic, allowing you to switch between different databases with minimal changes. The `--dialect` option helps you see how your models translate to different database-specific DDLs. \ -### Dialects by `cds env` Profiles - -The dialect is automatically inferred from your project configuration, and the current profile, so you typically don't need to specify it explicitly. For example, if your project is configured to use SAP HANA in production and SQLite in development, the respective dialects will be applied automatically. -Try this out using the `--profile` option: - -```shell -cds compile \* --to sql --profile development -cds compile \* --to sql --profile production -``` - - ::: details Use `cds env` to check your effective configurations: -```shell -cds env requires.db --profile development -cds env requires.db --profile production -``` -::: - -> [!tip] Dialects are inferred from profiles automatically -> You typically don't need to specify the `--dialect` option manually, as it is derived from your project configuration and the active profile. - - - ### Using `cds deploy` -We can use `cds deploy` to inspect the generated DDL without actually deploying it, by using the `--dry` option. This will print the ultimate DDL statements to the console instead of executing them against the database, for example: +We can use `cds deploy` to inspect the generated DDL without actually deploying it, by using the `--dry` option. This will print the DDL statements to the console instead of executing them against the database, for example: ```shell cds deploy --dry @@ -134,6 +129,24 @@ Essentially, `cds deploy` calls `cds compile --to sql` under the hood, but goe > [!note] Ad-hoc Deployments > Without the `--dry` option, `cds deploy` would not only compile your CDS models to DDL, but would also do an ad-hoc deployment to the target database, if available. How that works is explained in more detail in the database-specific guides for [_SAP HANA_](hana), [_SQLite_](sqlite), and [_PostgreSQL_](postgres). +### Dialects by `cds env` Profiles for CAP Node.js + +TThe dialect is automatically inferred from your project configuration, and the current profile, so you typically don't need to specify it explicitly. For example, if your project is configured to use SAP HANA in production and SQLite in development, the respective dialects will be applied automatically. Try this out using the `--profile` option: + +```shell +cds deploy --dry --profile development +cds deploy --dry --profile production +``` + + ::: details Use `cds env` to check your effective configurations: +```shell +cds env requires.db --profile development +cds env requires.db --profile production +``` +::: + +> [!tip] Dialects are inferred from profiles automatically +> You typically don't need to specify the `--dialect` option manually, as it is derived from your project configuration and the active profile. ## CDL ⇒ DDL Translation @@ -181,13 +194,16 @@ CREATE TABLE sap_capire_bookshop_Books_Details ( ... ); ``` ::: -> [!tip] Guaranteed & Stable Slugification -> The slugification effects are guaranteed and stable, which means that you can rely on it and use the slugified names in native SQL queries. For example, both of the following CQL queries are equivalent and will work as expected: +> [!tip] You may use slugified names in CAP Node.js +> In CAP Node.js, the slugification effects are guaranteed and stable, which means that you can rely on it and use the slugified names in _native SQL_ queries. For example, both of the following CQL queries are equivalent and will work as expected: +> +> ```js +> await cds.run `SELECT from sap.capire.bookshop.Books` +> await cds.run `SELECT from sap_capire_bookshop_Books` +> ``` -```js -await cds.run `SELECT from sap.capire.bookshop.Books` -await cds.run `SELECT from sap_capire_bookshop_Books` -``` +> [!warning] Don't use slugified names in CAP Java +In CAP Java, you can use fully qualified entity names with dots. The slugified names can't be used in CQL queries. > [!tip] > Prefer entity names like `Books.Details` over _CamelCase_ variants like `BooksDetails`. While both work equally, they show up differently in native tools of databases that don't preserve case, for example in SAP HANA: The former will show up as `BOOKS_DETAILS`, while the latter shows up as `BOOKSDETAILS`, which is harder to read. @@ -276,14 +292,23 @@ CREATE TABLE Books ( ``` ::: -> [!tip] Guaranteed & Stable Flattening -> The flattening effects are guaranteed and stable, which means that you can rely on it and use the flattened elements in native SQL queries. For example, both of the following CQL queries are equivalent and would work as expected: +The flattening effects for structured elements are guaranteed and stable. If a CDS model is compiled for usage with OData only the flattened elements are preserved in the CDS model. -```js -await cds.run `SELECT price.amount from Books` -await cds.run `SELECT price_amount from Books` -``` +> [!tip] Use flattening in runtime queries in CAP Node.js +> The flattening effects can also be used at runtime with CAP Node.js. For example, both of the following CQL queries are equivalent and would work as expected: +> +> ```js +> await cds.run `SELECT price.amount from Books` +> await cds.run `SELECT price_amount from Books` +> ``` +> [!warning] No flattening in runtime queries in CAP Java +> CAP Java does not perform an automatic flattening of path expressions: +> +> ```java +> Select.from("Books").columns("price_amount"); // valid +> Select.from("Books").columns("price.amount"); // invalid +> ``` ### Associations ⇒ JOINs @@ -349,7 +374,7 @@ LEFT JOIN Genres as genre on genre_ID = genre.ID; -- [!code ++] > Looking closely at the above compiled SQL code, we can regard > associations to be like _'Forward-declared' JOINs_, along these lines: > -> 1. Association names `a.name` appear in queries as standard _table aliases_ +> 1. Association names `a.name` appear in queries as _table aliases_ > 2. _JOINs_ are added automatically as per the following construction rule: > > _JOIN `a.target` as `a.name` on `a.on`_ @@ -467,6 +492,10 @@ However, even though CAP allows this, and handles all accesses correctly, it is > [!warning] DON'T use Database-Invalid Names! > It's **strongly discouraged** to use names that contain non-ASCII characters, or conflict with database reserved words. Even more avoid [delimited names](../../cds/cdl#keywords-identifiers) in CDS models in the first place, as that impacts readability of your models. +> [!warning] Avoid using reserved Java keywords +> A CAP Java project usually uses generated [accessor interfaces](../../java/cds-data#generated-accessor-interfaces). Avoid using reserved Java keywords as identifiers in a CDS model as using Java keywords might cause generated interfaces that don't compile. You may use the `@cds.java.name` annotation to mitigate such conflicts. + + ###### reserved-words > [!important] Lists of Reserved Words > Check out the reserved words for the databases you are targeting: \ @@ -474,6 +503,7 @@ However, even though CAP allows this, and handles all accesses correctly, it is > , [_SQLite_](https://www.sqlite.org/lang_keywords.html) > , [_H2_](https://www.h2database.com/html/advanced.html#keywords) > , [_PostgreSQL_](https://www.postgresql.org/docs/current/sql-keywords-appendix.html) +> , [_Java_](https://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html) diff --git a/guides/databases/cql-to-sql.md b/guides/databases/cql-to-sql.md index 02c72f569..55ecbf81b 100644 --- a/guides/databases/cql-to-sql.md +++ b/guides/databases/cql-to-sql.md @@ -10,36 +10,61 @@ CAP supports a number of portable functions and operators in CQL, which are auto Most native SQL operators are supported in CQL as-is, like these from the SQL92 standard: -- Arithmetic operators: `+`, `-`, `*`, `/`, `%` +- Arithmetic operators: `+`, `-`, `*`, `/` 1 - Comparison operators: `<`, `>`, `<=`, `>=`, `=`, `<>` - Logical operators: `AND`, `OR`, `NOT` - Other operators: `IN`, `LIKE`, `BETWEEN`, `IS NULL`, `IS NOT NULL`, etc. -In addition, CQL provides some extended operators as described below. +1 CAP Node.js additionally supports `%`. + +In addition, CQL provides some extended comparison operators as described below. ### Bivalent `==` and `!=` Operators -CQL supports `==` and `!=` operators as bivalent logic variants for SQL's three-valued logic `=` and `<>`. In essence, the differences are as follows: +CQL supports `==` and `!=` operators as two-valued logic variants for SQL's three-valued logic `=` and `<>`. -::: code-group -```SQL [CQL's Two-Valued Logic Operators] -SELECT 1 == null, 1 != null, null == null, null != null; ---> false, true, true, false -``` -::: -::: code-group -```SQL [SQL's Three-Valued Logic] -SELECT 1 = null, 1 <> null, null = null, null <> null; ---> null, null, null, null -``` +::: details +The differences are captured in these truth tables: + +#### two-valued equality (`==`, CQL) + +| == | 1 | 0 | `null` | +|---|---|---|---| +| 1 | `true` | `false` | `false` | +| 0 | `false` | `true` | `false` | +| `null` | `false` | `false` | `true` | + +#### three-valued equality (`=`, CQL & SQL) + +| = | 1 | 0 | `null` | +|---|---|---|---| +| 1 | `true` | `false` | `unknown` | +| 0 | `false` | `true` | `unknown` | +| `null` | `unknown` | `unknown` | `unknown` | + +#### two-valued inequality (`!=`, CQL) + +| == | 1 | 0 | `null` | +|---|---|---|---| +| 1 | `false` | `true` | `true` | +| 0 | `true` | `false` | `true` | +| `null` | `true` | `true` | `false` | + +#### three-valued inequality (`<>`, CQL & SQL) + +| = | 1 | 0 | `null` | +|---|---|---|---| +| 1 | `false` | `true` | `unknown` | +| 0 | `true` | `false` | `unknown` | +| `null` | `unknown` | `unknown` | `unknown` | ::: In other words: -- CQL's `x == null` -> `true` if `x` is `null`, otherwise `false` -- CQL's `x != null` -> `false` if `x` is `null`, otherwise `true` -- SQL's `x = null` -> `null` for all `x` (even if `x` is `null`) -- SQL's `x <> null` -> `null` for all `x` (even if `x` is not `null`) +- CQL's `x == null` -> `true` if `x` is `null` +- CQL's `x != null` -> `true` if `x` is not `null` +- SQL's `x = null` -> `unknown` for all `x` (even if `x` is `null`) +- SQL's `x <> null` -> `unknown` for all `x` (even if `x` is not `null`) A real-world example makes this clearer. Consider this CQL query: @@ -49,11 +74,20 @@ SELECT from Books where genre.name != 'Science Fiction'; The result set includes all books where genre is not 'Science Fiction', including the ones with an unspecified genre. In contrast, using SQL's `<>` operator, the ones with unspecified genre would be excluded. -The CQL behavior is consistent with common programming languages like JavaScript and Java, as well as with OData semantics. It is implemented in database by, the translation of `!=` to `IS NOT` in SQLite, or to `IS DISTINCT FROM` in standard SQL, and to an equivalent polyfill in SAP HANA. +The behavior of CQL two-valued comparison operators `==` and `!=` is consistent with common programming languages like JavaScript and Java, as well as with the semantics of the OData operators `eq` and `ne`. On the database `==` and `!=` are translated to `IS NOT DISTINCT FROM` and `IS DISTINCT FROM` in standard SQL, to `IS` and `IS NOT` on SQLite, and to an equivalent polyfill on SAP HANA. > [!tip] Usage Recommendation > Prefer using `==` and `!=` in the very most cases to avoid unexpected `null` results. Only use `=` and `<>` if you _really_ want SQL's three-valued logic behavior. +> [!tip] Avoid using `null` values +> Declare elements as `not null` where applicable. Or use a non-null value to represent "initial" state. + +> [!tip] Compare list values in CAP Java +> In CAP Java, you may use the comparison operators to compare [list values](../../java/working-with-cql/query-api#list-values) like in this CQL query: +> ```sql +> SELECT from Books where (year, month) > (2014, 7) +> ``` + ### Ternary `?:` Operator CQL supports the ternary conditional operator `condition ? expr1 : expr2`, similar to many programming languages like JavaScript and Java. It evaluates `condition`, and returns the value of `expr1` if `condition` is true, or the value of `expr2` otherwise. @@ -83,7 +117,7 @@ This operator is translated to the best-possible equivalent in the target databa Following are portable functions guaranteed by CAP. These can safely be used in CDS view definitions as well as in runtime queries expressed in CQL, and are translated to the best-possible database-specific native SQL equivalents. -String functions: +**String functions:** - `concat(x,y,...)` - `length(x)` @@ -97,23 +131,21 @@ String functions: - `substring(x,start, length)` - `matchespattern(x,pattern)` +**Numeric functions:** -Numeric functions: - -- `ceil(x)`, `ceiling(x)` +- `ceiling(x)`1 - `floor(x)` - `round(x)` -###### aggregate-functions -Aggregate functions: +**Aggregate functions:** - `avg(x)`, `average(x)` - `min(x)`, `max(x)` - `sum(x)` - `count(x)` - +- `countdistinct(x)`2 -Date / Time functions: +**Date/time functions:**3 - `date(x)` -> `yyyy-MM-dd` - `time(x)` -> `HH:mm:ss` @@ -123,11 +155,20 @@ Date / Time functions: - `hour(x)` - `minute(x)` - `second(x)` + +**SAP HANA date/time functions:**3 + - `years_between(x,y)` - `months_between(x,y)` - `days_between(x,y)` - `seconds_between(x,y)` +--- + +* 1 CAP Node.js also supports `ceil`. +* 2 `countdistinct` is only supported by CAP Java. +* 3 Date/time functions are not supported by CAP Java. + > [!note] Indexes and Substring Details > The return value of `indexof()` as well as the `start` parameter in `substring()` are zero-based index values. If the substring is not found, `indexof()` returns `-1`. If the `start` index in `substring()` is negative, it is counted from the end of the string. If the `length` parameter is omitted, the substring to the end of the string is returned. diff --git a/guides/databases/index.md b/guides/databases/index.md index 488cccb82..4ca4ca574 100644 --- a/guides/databases/index.md +++ b/guides/databases/index.md @@ -1,10 +1,10 @@ # CAP-level Database Integration -CAP application developers [focus on their domain](../../get-started/features#focus-on-domain), while CAP takes care of all aspects of database integration. This includes translating CDS models to native persistence models, schema evolution, deployment, as well as runtime querying – all of that in a database-agnostic way. [SQLite](./sqlite) 1 in-memory databases are automatically used in inner-loop development, while in production, [SAP HANA](./hana) 2 is used by default. +CAP application developers [focus on their domain](../../get-started/features#focus-on-domain), while CAP takes care of all aspects of database integration. This includes translating CDS models to native persistence models, schema evolution, deployment, as well as runtime querying – all of that in a database-agnostic way. An in-memory database1 is automatically used in inner-loop development, while in production, [SAP HANA](./hana) 2 is used by default. {.abstract} -> _1 or [H2](./h2) in case of CAP Java-based projects_.\ +> _1 [SQLite](./sqlite) or [H2](./h2) (for CAP Java)_.\ > _2 or [PostgreSQL](./postgres) in edge cases_.