Introduction to SAP Hana CDS Development
- 1. Introduction to CDS
- 2. CDS VIEW creation template
-
- 1. Define a simple view of a single data source
- 2. Define the JOIN view of two data sources
- 3. Define views with associated relationships
- 4. Define the view of the parent class association relationship
- 5. Define the view of a single input parameter
- 6. Define a simple projection view entity
- 7. Define inherited views
- 8. Define table functions with input parameters
- 9. Define abstract entities with input parameters
- 10. Define parent-child hierarchical view
- 11. Define a single input customer entity
- 3. CDS VIEW ENTITY creation template
1. Introduction to CDS
To leverage SAP HANA for application development, SAP has introduced a new underlying data modeling called Core Data Services (CDS). With CDS, the data model is defined and used on the database server, not the application server. CDS also provides capabilities beyond traditional data modeling tools, including support for conceptual modeling and relationship definitions, built-in functions, and extensions.
Initially, CDS is only available in the design-time and run-time environments of SAP HANA. Now, the CDS concept is also fully implemented in SAP NetWeaver for ABAP, enabling developers to use ABAP development tools to work at the ABAP layer while pushing code execution down to the database.
CDS simplifies and unifies the way you define and use data models, regardless of the consumption technology you are using. Technically, it is an enhancement to SQL that provides you with a data definition language (DDL) for defining semantically rich database tables/views (CDS entities) and user-defined types in your database.
include:
- Expressions used in calculations and queries in the data model
- Associations at a conceptual level, using simple path expressions instead of joins in queries
- Enrich data model annotations with additional (domain specific) metadata. [Metadata is "data that describes data". Metadata can describe the data's elements or attributes (name, size, data type, etc.), or its structure (length, fields, data columns), or its related data (where it is located, how to contact it, who owns it). ]
CDS version change history:
2. CDS VIEW creation template
1. Define a simple view of a single data source
template:
/*
template 1: Define View
Defines a simple CDS view with one data source.
*/
@AbapCatalog.sqlViewName: '${sql_view_name}'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: '${ddl_source_description}'
define view ${ddl_source_name_editable} as select from ${data_source_name} {
${
cursor}
}
Example (CDS standard writing method):
@AbapCatalog.sqlViewName: 'YV_DEMO01_SCARR'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS_DEMO01_SCARR'
define view YCDS_DEMO01_SCARR as
select from scarr
{
--key mandt, -- CDS会自动添加
key carrid,
carrname,
url
};
Or (traditional SQL writing):
@AbapCatalog.sqlViewName: 'YV_DEMO01_SCARR'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS_DEMO01_SCARR'
define view YCDS_DEMO01_SCARR as
select
--key mandt, -- CDS会自动添加
key carrid,
carrname,
url
from scarr;
ABAP program call (Open SQL):
REPORT yz_cds_demo.
SELECT *
FROM ycds_demo01_scarr
INTO TABLE @DATA(itab).
cl_demo_output=>display( itab ).
ABAP program call (SALV IDA):
REPORT YZ_IDA_DEMO.
CL_SALV_GUI_TABLE_IDA=>CREATE_FOR_CDS_VIEW( iv_cds_view_name = 'YCDS_DEMO01_SCARR' )->FULLSCREEN( )->DISPLAY( ).
Example (define field alias):
@AbapCatalog.sqlViewName: 'YV_DEMO01_SCARR2'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS_DEMO01_SCARR2'
define view YCDS_DEMO02_SCARR
(id, name, url) --field alias
as
select from scarr
{
--key mandt,
key carrid as id, --alias
carrname,
url
};
2. Define the JOIN view of two data sources
template:
/*
template 2: Define View with Join
Defines a CDS view which combines two data sources using a left outer join.
The join conditions are specified in the on clause.
*/
@AbapCatalog.sqlViewName: '${sql_view_name}'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: '${ddl_source_description}'
define view ${ddl_source_name_editable} as select from ${data_source_name}
left outer join ${joined_data_source_name}
on ${data_source_name}.${element_name} = ${joined_data_source_name}.${joined_element_name} {
${
cursor}
}
Example:
@AbapCatalog.sqlViewName: 'YV_DEMO02_JOIN'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS_DEMO02_JOIN'
define view YCDS_DEMO02_JOIN as
select from spfli
left outer join scarr
on scarr.carrid = spfli.carrid
{
key spfli.carrid,
key spfli.connid,
scarr.carrname
};
ABAP caller:
REPORT yz_cds_demo.
SELECT *
FROM ycds_demo02_join
INTO TABLE @DATA(itab).
cl_demo_output=>display( itab ).
3. Define views with associated relationships
template:
/*
template 3: Define View with Association
Defines a CDS view with a public association to another data source.
The association can be used in the select list as well as by other CDS views which use this CDS view as a data source.
*/
@AbapCatalog.sqlViewName: '${sql_view_name}'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: '${ddl_source_description}'
define view ${ddl_source_name_editable} as select from ${data_source_name}
association [${
1}] to ${target_data_source_name} as ${_association_name}
on $$projection.${element_name} = ${_association_name}.${target_element_name} {
${
cursor}
${_association_name} // Make association public
}
Example:
@AbapCatalog.sqlViewName: 'YV_DEMO03_ASSOCI'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS_DEMO03_ASSOCIATION'
define view YCDS_DEMO03_ASSOCIATION as
select from spfli
association to scarr as _scarr
on $projection.carrid = _scarr.carrid
{
key spfli.carrid,
key spfli.connid,
--_scarr.carrname,
_scarr // Make association public, joined on demand
}
Preview data in HanaStudio:
HANA access data:
select * from YV_DEMO03_ASSOCI; -- 未访问关联
ABAP access data:
REPORT yz_cds_demo.
PARAMETERS: p_carrid TYPE scarr-carrid.
SELECT carrid, connid, \_scarr-carrname AS flightname "访问关联
FROM YCDS_DEMO03_ASSOCIATION
where carrid = @p_carrid
INTO TABLE @DATA(itab).
cl_demo_output=>display( itab ).
4. Define the view of the parent class association relationship
template:
/*
template 4: Define View with To-Parent Association
Defines a CDS view with a specialized association to its parent CDS entity.
Compositions and to-parent associations are used to define the structure of a business object which can be used in the ABAP RESTful Programming Model.
*/
@AbapCatalog.sqlViewName: '${sql_view_name}'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: '${ddl_source_description}'
define view ${ddl_source_name_editable} as select from ${data_source_name}
association to parent ${target_data_source_name} as ${_association_name}
on $$projection.${element_name} = ${_association_name}.${target_element_name} {
${
cursor}
${_association_name} // Make association public
}
Example:
@AbapCatalog.sqlViewName: 'YV_DEMO04_TOPARE'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS_DEMO04_TOPARENT'
define view YCDS_DEMO04_TOPARENT as
select from spfli
association to parent YCDS_DEMO01_SCARR as _scarr
on $projection.carrid = _scarr.id {
key spfli.carrid,
key spfli.connid,
_scarr.id, // Make association public
_scarr
}
5. Define the view of a single input parameter
template:
/*
template 5: Define View with Parameters
Defines a CDS view with a single input parameter.
The input parameter can be used as an element in the select list
or as an operand in conditional or arithmetic expressions.
*/
@AbapCatalog.sqlViewName: '${sql_view_name}'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: '${ddl_source_description}'
define view ${ddl_source_name_editable}
with parameters ${parameter_name} : ${parameter_type}
as select from ${data_source_name} {
${
cursor}
}
Example:
@AbapCatalog.sqlViewName: 'YV_DEMO05_PARAM'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS_DEMO05_PARAMETERS'
define view YCDS_DEMO05_PARAMETERS
with parameters p_carrid : s_carr_id
as select from spfli {
key connid,
cityfrom,
cityto
}
where carrid = $parameters.p_carrid;
SE11 diagram (does not support viewing table data):
SE16N diagram (can be executed, parameters need to be entered):
ABAP program call:
REPORT yz_cds_demo.
PARAMETERS: p_carrid TYPE scarr-carrid.
SELECT *
FROM ycds_demo05_parameters( p_carrid = @p_carrid )
INTO TABLE @DATA(itab).
cl_demo_output=>display( itab ).
HANA query data:
select * from YV_DEMO05_PARAM('AA') where mandt = 200;
--或者
select * from YV_DEMO05_PARAM( p_carrid => 'AA' ) where mandt = 200;
6. Define a simple projection view entity
Template: used to shield some fields (generally used to protect data).
/*
template 6: Define Projection View
Defines a simple CDS projection view.
*/
@EndUserText.label: '${ddl_source_description}'
@AccessControl.authorizationCheck: #CHECK
define view entity ${ddl_source_name_editable} as projection on ${data_source_name} {
${
cursor}
}
Example:
@EndUserText.label: 'CDS_DEMO06_PROJECTION'
@AccessControl.authorizationCheck: #NOT_REQUIRED
define view entity YCDS_DEMO06_PROJECTION
as projection on YCDS_DEMO04_TOPARENT {
key carrid,
key connid
}
7. Define inherited views
/*
template 7: Extend View
Extends an existing CDS view by adding the specified elements
to the select list of the CDS view using a view enhancement.
*/
@AbapCatalog.sqlViewAppendName: '${sql_view_append_name}'
@EndUserText.label: '${ddl_source_description}'
extend view ${view_name} with ${ddl_source_name_editable} {
${data_source_name}.${element_name}
}
Example:
@AbapCatalog.sqlViewAppendName: 'YV_DEMO07_EXTEND'
@EndUserText.label: 'CDS_DEMO07_EXTEND'
extend view YCDS_DEMO02_JOIN //原CDS,有三个字段
with YCDS_DEMO07_EXTEND //新CDS,追加一个字段
{
scarr.currcode
}
8. Define table functions with input parameters
Template: AMDP FUNCTION implementation.
/*
template 8: Define Table Function with Parameters
Defines the type signature of a client dependent CDS table function with importing parameters.
The CDS table function is implemented in the specified ABAP method.
The CDS table function can be used in Open SQL and as a data source
in other CDS view definitions.
*/
@EndUserText.label: '${ddl_source_description}'
define table function ${ddl_source_name_editable}
with parameters ${parameter_name} : ${parameter_type}
returns {
${client_element_name} : abap.clnt;
${element_name} : ${element_type};
${
cursor}
}
implemented by method ${class_name}=>${method_name};
Example:
@EndUserText.label: 'ADMP_DEMO_SCARR'
define table function YCDS_ADMP_DEMO_SCARR
with parameters
@Environment.systemField: #CLIENT
p_clnt : abap.clnt
returns {
mandt : abap.clnt;
carrid : s_carr_id;
carrname : s_carrname;
url : s_carrurl;
}
implemented by method ycl_amdp_hdb_demo=>get_scarr_for_cds;
Specific reference: X-File: Introduction and implementation method of AMDP in SAP ABAP
9. Define abstract entities with input parameters
Template: A CDS entity that only describes type properties and does not instantiate any database objects.
/*
template 9: Define Abastract Entity with Parameters
Defines an abstract CDS entity with a single input parameter.
*/
@EndUserText.label: '${ddl_source_description}'
define abstract entity ${ddl_source_name_editable}
with parameters ${parameter_name} : ${parameter_type} {
${element_name} : ${element_type};
${
cursor}
}
Example:
@EndUserText.label: 'CDS_DEMO09_ABSTRACT'
define abstract entity YCDS_DEMO09_ABSTRACT
with parameters p_carrid : s_carr_id
{
connid : s_conn_id;
cityfrom : s_from_cit;
cityto : s_to_city;
}
10. Define parent-child hierarchical view
template:
/*
template 10: Define Parent Child Hierarchy
Defines a simple CDS parent child hierarchy.
*/
define hierarchy ${ddl_source_name_editable}
as parent child hierarchy (
source ${data_source_name}
child to parent association ${_association_name}
start where ${element_name} = ${
value}
siblings order by ${order_by_element_name}
)
{
${element_name}
${
cursor}
}
Define parent-child hierarchical table: YTB_DEMO_HIER
insert data:
CREATE COLUMN TABLE "SAPHANADB"."YTB_DEMO_HIER"
(
"MANDT" NVARCHAR(3) DEFAULT '000' NOT NULL ,
"ID" INTEGER CS_INT DEFAULT 0 NOT NULL ,
"PID" INTEGER CS_INT DEFAULT 0 NOT NULL ,
"NAME" NVARCHAR(20) DEFAULT '' NOT NULL ,
CONSTRAINT "YTB_DEMO_HIER~0" PRIMARY KEY ("MANDT","ID")
);
insert into YTB_DEMO_HIER values('200', 1, 0, '图书');
insert into YTB_DEMO_HIER values('200', 2, 1, '教材类');
insert into YTB_DEMO_HIER values('200', 3, 1, '计算机类');
insert into YTB_DEMO_HIER values('200', 4, 3, 'Java');
insert into YTB_DEMO_HIER values('200', 5, 3, '.Net');
insert into YTB_DEMO_HIER values('200', 6, 3, 'SAP');
insert into YTB_DEMO_HIER values('200', 7, 1, '文学类');
insert into YTB_DEMO_HIER values('200', 8, 1, '科幻类');
insert into YTB_DEMO_HIER values('200', 9, 8, '三体');
insert into YTB_DEMO_HIER values('200', 10, 8, '流浪地球');
Define parent-child hierarchical data source: CDS View
@AbapCatalog.sqlViewName: 'YTB_DEMO_HIER_S'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS_DEMO10_HIERARCHY_SOURCE'
define view YCDS_DEMO10_HIERARCHY_SOURCE
as select from ytb_demo_hier
association[1..1] to YCDS_DEMO10_HIERARCHY_SOURCE as _tree
on $projection.parent= _tree.id
{
_tree,
key id,
pid as parent,
name
}
Or: CDS View entity
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS_DEMO10_HIERARCHY_VIEW'
define view entity YCDS_DEMO10_HIERARCHY_VIEW
as select from ytb_demo_hier
association[1..1] to YCDS_DEMO10_HIERARCHY_VIEW as _tree
on $projection.parent= _tree.id
{
_tree,
key id,
pid as parent,
name
}
Define the parent-child hierarchical relationship view:
define hierarchy YCDS_DEMO10_HIERARCHY
with parameters
p_id : abap.int4
as parent child hierarchy (
source
--YCDS_DEMO10_HIERARCHY_SOURCE --两者都可以
YCDS_DEMO10_HIERARCHY_VIEW --两者都可以
child to parent association _tree
start where
id = :p_id
siblings order by
id ascending
)
{
id,
parent,
name
}
Preview data in Hana:
Query data in Hana SQL:
select * from YTB_DEMO_HIER_S; --sql view,可以访问,有数据
select * from YCDS_DEMO10_HIERARCHY_SOURCE; --cds view,无法访问
select * from YCDS_DEMO10_HIERARCHY_VIEW; --cds view entity,可以访问,没有数据
select * from YCDS_DEMO10_HIERARCHY( p_id => 3 ); --可以访问,没有数据
Access in ABAP:
REPORT YZ_CDS_DEMO.
PARAMETERS: p_id type YCDS_DEMO10_HIERARCHY_VIEW-id.
SELECT FROM YCDS_DEMO10_HIERARCHY( p_id = @p_id )
FIELDS id,
parent,
name,
hierarchy_rank,
hierarchy_tree_size,
hierarchy_parent_rank,
hierarchy_level,
hierarchy_is_cycle,
hierarchy_is_orphan,
node_id,
parent_id
INTO TABLE @DATA( cds_result ).
cl_demo_output=>display( cds_result ).
11. Define a single input customer entity
template:
/*
template 11: Define Custom Entity with Parameters
Defines a custom CDS entity with a single input parameter.
*/
@EndUserText.label: '${ddl_source_description}'
define custom entity ${ddl_source_name_editable}
with parameters ${parameter_name} : ${parameter_type} {
key ${key_element_name} : ${key_element_type};
${element_name} : ${element_type};
${
cursor}
}
Example:
(1) Define CDS customer entity: YCDS_DEMO11_CUSTOM_ENTITY
@ObjectModel.query.implementedBy : 'ABAP:YCL_CUSTOM_ENTITY'
@EndUserText.label: 'CDS_DEMO11_CUSTOM_ENTITY'
define custom entity YCDS_DEMO11_CUSTOM_ENTITY
with parameters p_id : abap.char(3)
{
key carrid : abap.char(3); // Returning fields are mentioned between {} just like ordinary CDS
carrname : abap.char(20); // Returning field set must contain a key or key combination
url : abap.char(255);
}
(2) Define ABAP implementation class: YCL_CUSTOM_ENTITY
class YCL_CUSTOM_ENTITY definition
public
final
create public .
public section.
interfaces IF_RAP_QUERY_PROVIDER .
protected section.
private section.
ENDCLASS.
CLASS YCL_CUSTOM_ENTITY IMPLEMENTATION.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method YCL_CUSTOM_ENTITY->IF_RAP_QUERY_PROVIDER~SELECT
* +-------------------------------------------------------------------------------------------------+
* | [--->] IO_REQUEST TYPE REF TO IF_RAP_QUERY_REQUEST
* | [--->] IO_RESPONSE TYPE REF TO IF_RAP_QUERY_RESPONSE
* | [!CX!] CX_RAP_QUERY_PROV_NOT_IMPL
* | [!CX!] CX_RAP_QUERY_PROVIDER
* +--------------------------------------------------------------------------------------</SIGNATURE>
method IF_RAP_QUERY_PROVIDER~SELECT.
data:IT_RESULT type table of YCDS_DEMO11_CUSTOM_ENTITY. "Internal table to be returned , easier to handle return if internal table is as same type of our data definition
data: LV_PARAM type STRING."Local variable to fetch and save parameter value
try.
try.
if IO_REQUEST->IS_DATA_REQUESTED( ). "Fetching incoming data
IO_REQUEST->GET_PAGING( ).
data(LT_FILTER_COND) = IO_REQUEST->GET_PARAMETERS( ). "Setting the filter condition, fetching parameter names from data definition
LV_PARAM = value #( LT_FILTER_COND[ PARAMETER_NAME = 'p_id' ]-VALUE optional ). "Fetching the parameter value
"Using the parameter we could do whatever we want , like selecting from a table , doing certain calculations etc
select * from scarr where carrID = @LV_PARAM into CORRESPONDING FIELDS OF TABLE @IT_RESULT.
IO_RESPONSE->SET_TOTAL_NUMBER_OF_RECORDS( LINES( IT_RESULT ) ). "setting the total number of records which will be sent
IO_RESPONSE->SET_DATA( IT_RESULT ). "returning the data as internal table
endif.
catch CX_RAP_QUERY_PROVIDER into data(LX_EXC). "CX_A4C_RAP_QUERY_PROVIDER is now deprecated so use CX_RAP_QUERY_PROVIDER
endtry.
catch CX_RFC_DEST_PROVIDER_ERROR into data(LX_DEST).
endtry.
endmethod.
ENDCLASS.
(3) Define services:
@EndUserText.label: 'SVS_EXPOSE_CUSTOM_ENTITY'
define service YSVS_EXPOSE_CUSTOM_ENTITY {
expose YCDS_DEMO11_CUSTOM_ENTITY;
}
(4) How to use the service (not studied yet)
3. CDS VIEW ENTITY creation template
Notes:
Introduced in NW 7.55 and above.
CDS View Entity object can be accessed in ABAP, but cannot be accessed in Hana Sql (no data).
12. Define a simple view entity of a single data source
template:
/*
template 12: Defines a simple CDS view entity with one data source.
*/
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: '${ddl_source_description}'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity ${ddl_source_name_editable} as select from ${data_source_name}
{
${data_source_elements}${
cursor}
}
Example:
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'CDS_DEMO12_VIEW_ENTITY'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity YCDS_DEMO12_VIEW_ENTITY as select from scarr
{
key carrid,
carrname,
url
}
13. Define the root view entity
template:
/*
template 13: Defines a root CDS view entity with a specialized association to a child CDS entity.
Root nodes, compositions and to-parent associations are used to define the structure of a business object which can be used in the ABAP RESTful programming model.
*/
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: '${ddl_source_description}'
define root view entity ${ddl_source_name_editable} as select from ${data_source_name}
composition of ${target_data_source_name} as ${_association_name}
{
${data_source_elements}${
cursor}
${_association_name} // Make association public
}
14. Define the view entity associated with the parent entity
template:
/*
template 14: Defines a CDS view entity with a specialized association to its parent CDS entity.
Compositions and to-parent associations are used to define the structure of a business object which can be used in the ABAP RESTful programming model.
*/
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: '${ddl_source_description}'
define view entity ${ddl_source_name_editable} as select from ${data_source_name}
association to parent ${target_data_source_name} as ${_association_name}
on $$projection.${element_name} = ${_association_name}.${target_element_name}
{
${data_source_elements}${
cursor}
${_association_name} // Make association public
}
15. Inherit projection view entities
template:
/*
template 15: Extends an existing CDS projection view entity by adding the specified elements to its select list.
*/
extend view entity ${view_name} with {
${base_data_source_name}.${element_name}
}
16. Inherit abstract entities
template:
/*
template 16: Extends an abstract CDS entity by adding the specified elements to its select list.
*/
extend abstract entity ${entity_name} with
{
${element_name} : ${element_type};
}
17. Inherit customer entity
template:
/*
template 17: Extends a custom CDS entity by adding the specified elements to its select list.
*/
extend custom entity ${entity_name} with
{
${element_name} : ${element_type};
}
created by xlevon on 20230206.
Original article, please indicate the source for reprinting - X Files
参考文档:
ABAP CDS - Syntax
Working with Hierarchies in ABAP SQL
Custom Entities – Business Technology Platform (SAP Cloud Platform)