SQL Hana
SQL Hana
SAP HANA Service for SAP BTP in AWS and Google Cloud Regions | Cloud
PUBLIC
Warning
This document has been generated from the SAP Help Portal and is an incomplete version of the official SAP product
documentation. The information included in custom documentation may not re ect the arrangement of topics in the SAP Help
Portal, and may be missing important aspects and/or correlations to other topics. For this reason, it is not for productive use.
This is custom documentation. For more information, please visit the SAP Help Portal 1
12/23/2022
SQLScript is a collection of extensions to the Structured Query Language (SQL). The extensions include:
Data extension, which allows the de nition of table types without corresponding tables
Functional extension, which allows the de nition of (side-effect free) functions which can be used to express and
encapsulate complex data ows
Procedural extension, which provides imperative constructs executed in the context of the database process.
Data extension, which allows the de nition of table types without corresponding tables
Functional extension, which allows the de nition of (side-effect free) functions that can be used to express and
encapsulate complex data ows
Procedural extension, which provides imperative constructs executed in the context of the database process.
What is SQLScript?
The motivation behind SQLScript is to embed data-intensive application logic into the database. Currently, applications only
offload very limited functionality into the database using SQL, most of the application logic is normally executed on an
application server. The effect of that is that data to be operated upon needs to be copied from the database onto the
application server and vice versa. When executing data-intensive logic, this copying of data can be very expensive in terms of
processor and data transfer time. Moreover, when using an imperative language like ABAP or JAVA for processing data,
developers tend to write algorithms which follow a one-tuple-at-a-time semantics (for example, looping over rows in a table).
However, these algorithms are hard to optimize and parallelize compared to declarative set-oriented languages like SQL.
The SAP HANA database is optimized for modern technology trends and takes advantage of modern hardware, for example, by
having data residing in the main memory and allowing massive parallelization on multi-core CPUs. The goal of the SAP HANA
database is to support application requirements by making use of such hardware. The SAP HANA database exposes a very
sophisticated interface to the application, consisting of many languages. The expressiveness of these languages far exceeds
that attainable with OpenSQL. The set of SQL extensions for the SAP HANA database, which allows developers to push data-
intensive logic to the database, is called SQLScript. Conceptually SQLScript is related to stored procedures as de ned in the
SQL standard, but SQLScript is designed to provide superior optimization possibilities. SQLScript should be used in cases where
other modeling constructs of SAP HANA, for example analytic views or attribute views are not sufficient. For more information
on how to best exploit the different view types, see "Exploit Underlying Engine".
The set of SQL extensions are the key to avoiding massive data copies to the application server and to leveraging sophisticated
parallel execution strategies of the database. SQLScript addresses the following problems:
Decomposing an SQL query can only be performed by using views. However, when decomposing complex queries by
using views, all intermediate results are visible and must be explicitly typed. Moreover, SQL views cannot be
parameterized, which limits their reuse. In particular they can only be used like tables and embedded into other SQL
statements.
This is custom documentation. For more information, please visit the SAP Help Portal 2
12/23/2022
SQL queries do not have features to express business logic (for example a complex currency conversion). As a
consequence, such business logic cannot be pushed down into the database (even if it is mainly based on standard
aggregations like SUM(Sales), and so on).
An SQL query can only return one result at a time. As a consequence, the computation of related result sets must be
split into separate, usually unrelated, queries.
As SQLScript encourages developers to implement algorithms using a set-oriented paradigm and not using a one-tuple-
at-a-time paradigm, imperative logic is required, for example by iterative approximation algorithms. Thus, it is possible
to mix imperative constructs known from stored procedures with declarative ones.
Related Information
Using SQLScript, you can read and modify information in the database. In some cases, depending on the commands and
parameters you choose, you can create a situation in which data leakage or data tampering can occur. To prevent this, SAP
recommends using the following practices in all procedures.
Mark each parameter using the keywords IN or OUT. Avoid using the INOUT keyword.
Use the INVOKER keyword when you want the user to have the assigned privileges to start a procedure. The default
keyword, DEFINER, allows only the owner of the procedure to start it.
Mark read-only procedures using READS SQL DATA whenever it is possible. This ensures that the data and the
structure of the database are not altered.
Tip
Another advantage to using READS SQL DATA is that it optimizes performance.
Ensure that the types of parameters and variables are as speci c as possible. Avoid using VARCHAR, for example. By
reducing the length of variables you can reduce the risk of injection attacks.
Dynamic SQL
In SQLScript you can create dynamic SQL using one of the following commands: EXEC and EXECUTE IMMEDIATE. Although
these commands allow the use of variables in SQLScript where they might not be supported. In these situations you risk
injection attacks unless you perform input validation within the procedure. In some cases injection attacks can occur by way of
data from another database table.
To avoid potential vulnerability from injection attacks, consider using the following methods instead of dynamic SQL:
Use static SQL statements. For example, use the static statement, SELECT instead of EXECUTE IMMEDIATE and
passing the values in the WHERE clause.
Perform validation on input parameters within the procedure using either SQLScript or server-side JavaScript.
This is custom documentation. For more information, please visit the SAP Help Portal 3
12/23/2022
Escape Code
You might need to use some SQL statements that are not supported in SQLScript, for example, the GRANT statement. In other
cases you might want to use the Data De nition Language (DDL) in which some <name> elements, but not <value> elements,
come from user input or another data source. The CREATE TABLE statement is an example of where this situation can occur.
In these cases you can use dynamic SQL to create an escape from the procedure in the code.
To avoid potential vulnerability from injection attacks, consider using the following methods instead of escape code:
Perform validation on input parameters within the procedure using either SQLScript or server-side JavaScript.
Tip
For more information about security in SAP HANA, see the SAP HANA Security Guide .
Related Information
SQL Injection Prevention Functions
When a user de nes a new procedure, for example using the CREATE PROCEDURE statement, the SAP HANA database query
compiler processes the statement in a similar way it processes an SQL statement. A step-by-step analysis of the process ow
follows below:
Check the statements semantic correctness: derive types for variables and check if their use is consistent.
Optimize the code: optimization distinguishes between declarative logic, displayed in the upper branch, and imperative
logic, displayed in the lower branch. We shall discuss how the SAP HANA database recognizes them below.
When the procedure starts, the invoke activity can be divided into two phases:
1. Compilation
Code generation - for declarative logic the calculation models are created to represent the data ow de ned by
the SQLScript code. It is optimized further by the calculation engine, when it is instantiated. For imperative logic
the code blocks are translated into L-nodes.
The calculation models generated in the previous step are combined into a stacked calculation model.
2. Execution - the execution commences with binding actual parameters to the calculation models. When the calculation
models are instantiated they can be optimized based on concrete input provided. Optimizations include predicate or
projection embedding in the database. Finally, the instantiated calculation model is executed by using any of the
available parts of the SAP HANA database.
With SQLScript you can implement applications by using both imperative orchestration logic and (functional) declarative logic,
and this is also re ected in the way SQLScript processing works for those two coding styles. Imperative logic is executed
sequentially and declarative logic is executed by exploiting the internal architecture of the SAP HANA database and utilizing its
potential for parallelism.
Orchestration Logic
This is custom documentation. For more information, please visit the SAP Help Portal 4
12/23/2022
Orchestration logic is used to implement data- ow and control- ow logic using imperative language constructs such as loops
and conditionals. The orchestration logic can also execute declarative logic, which is de ned in the functional extension by
calling the corresponding procedures. In order to achieve an efficient execution on both levels, the statements are transformed
into a data ow graph to the maximum extent possible. The compilation step extracts data- ow oriented snippets out of the
orchestration logic and maps them to data- ow constructs. The calculation engine serves as execution engine of the resulting
data ow graph. Since the language L is used as intermediate language for translating SQLScript into a calculation model, the
range of mappings may span the full spectrum – from a single internal L-node for a complete SQLScript script in its simplest
form, up to a fully resolved data- ow graph without any imperative code left. Typically, the data ow graph provides more
opportunities for optimization and thus better performance.
To transform the application logic into a complex data- ow graph two prerequisites have to be ful lled:
All data ow operations have to be side-effect free, that is they must not change any global state either in the database
or in the application logic.
In SQLScript the optimizer will transform a sequence of assignments of SQL query result sets to table variables into
parallelizable data ow constructs. The imperative logic is usually represented as a single node in the data ow graph, and thus it
is executed sequentially.
AS
BEGIN
DECLARE v_id BIGINT;
DECLARE v_name VARCHAR(30);
DECLARE v_pmnt BIGINT;
DECLARE v_msg VARCHAR(200);
DECLARE CURSOR c_cursor1 (p_payment BIGINT) FOR
SELECT id, name, payment FROM control_tab
WHERE payment > :p_payment
ORDER BY id ASC;
CALL init_proc();
OPEN c_cursor1(250000);
FETCH c_cursor1 INTO v_id, v_name, v_pmnt;
v_msg = :v_name || ' (id ' || :v_id || ') earns ' || :v_pmnt || ' $.';
CALL ins_msg_proc(:v_msg);
CLOSE c_cursor1;
END
This procedure features a number of imperative constructs including the use of a cursor (with associated state) and local scalar
variables with assignments.
Related Information
ins_msg_proc
This is custom documentation. For more information, please visit the SAP Help Portal 5
12/23/2022
Declarative Logic
Declarative logic is used for efficient execution of data-intensive computations. This logic is represented internally as data ows
which can be executed in a parallel manner. As a consequence, operations in a data- ow graph have to be free of side effects.
This means they must not change any global state neither in the database, nor in the application. The rst condition is ensured
by only allowing changes to the data set that is passed as input to the operator. The second condition is achieved by allowing
only a limited subset of language features to express the logic of the operator. If those prerequisites are ful lled, the following
types of operators are available:
Logically each operator represents a node in the data- ow graph. Custom operators have to be implemented manually by SAP.
Symbol Description
<> Angle brackets are used to surround the name of a syntax element (BNF non-terminal) of the SQL language.
::= The de nition operator is used to provide de nitions of the element appearing on the left side of the operator
in a production rule.
[] Square brackets are used to indicate optional elements in a formula. Optional elements may be speci ed or
omitted.
{} Braces group elements in a formula. Repetitive elements (zero or more elements) can be speci ed within
brace symbols.
| The alternative operator indicates that the portion of the formula following the bar is an alternative to the
portion preceding the bar.
... The ellipsis indicates that the element may be repeated any number of times. If ellipsis appears after
grouped elements, the grouped elements enclosed with braces are repeated. If ellipsis appears after a single
element, only that element is repeated.
!! Introduces normal English text. This is used when the de nition of a syntactic element is not expressed in
BNF.
Throughout the BNF used in this document each syntax term is de ned to one of the lowest term representations shown below.
<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<letter> ::= a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v
| A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V
<comma> ::= ,
<dollar_sign> ::= $
This is custom documentation. For more information, please visit the SAP Help Portal 6
12/23/2022
<double_quotes> ::= "
<hash_symbol> ::= #
<left_bracket> ::= [
<left_curly_bracket> ::= {
<period> ::= .
<pipe_sign> ::= |
<right_bracket> ::= ]
<right_curly_bracket> ::= }
<sign> ::= + | -
<underscore> ::= _
Note
This also holds true for SQL statements, apart from the TEXT and SHORTTEXT types.
Note
SQLScript currently allows a length of 8388607 characters for the NVARCHAR and the VARCHAR data types, unlike SQL
where the length of that data type is limited to 5000.
For more information on scalar types, see SAP HANA SQL and System Views Reference, Data Types.
Table Types
The SQLScript data type extension allows the de nition of table types. These types are used to de ne parameters for
procedures representing tabular results.
CREATE TYPE
Syntax
Syntax Elements
Identi es the table type to be created and, optionally, in which schema it should be created.
This is custom documentation. For more information, please visit the SAP Help Portal 8
12/23/2022
<data_type> ::= DATE | TIME | SECONDDATE | TIMESTAMP | TINYINT | SMALLINT | INTEGER | BIGINT | SMA
| REAL | DOUBLE | VARCHAR | NVARCHAR | ALPHANUM | SHORTTEXT | VARBINARY | BLOB | CLO
Description
The CREATE TYPE statement creates a user-de ned type.
The syntax for de ning table types follows the SQL syntax for de ning new tables. The table type is speci ed by using a list of
attribute names and primitive data types. The attributes of each table type must have unique names.
Example
You create a table type called tt_publishers.
DROP TYPE
This is custom documentation. For more information, please visit the SAP Help Portal 9
12/23/2022
Syntax
Syntax Elements
The identi er of the table type to be dropped, with optional schema name
When the <drop_option> is not speci ed, a non-cascaded drop is performed. This drops only the speci ed type, dependent
objects of the type are invalidated but not dropped.
The invalidated objects can be revalidated when an object with the same schema and object name is created.
Description
The DROP TYPE statement removes a user-de ned table type.
Example
You create a table type called my_type.
This is custom documentation. For more information, please visit the SAP Help Portal 10
12/23/2022
DO BEGIN
DECLARE x, y ROW (a INT, b VARCHAR(16), c TIMESTAMP);
x = ROW(1, 'a', '2000-01-01');
x.a = 2;
y = :x;
SELECT :y.a, :y.b, :y.c FROM DUMMY;
-- Returns [2, 'a', '2000-01-01']
END;
DO BEGIN
DECLARE CURSOR cur FOR SELECT 1 as a, 'a' as b, to_timestamp('2000-01-01') as c FROM DUMMY;
DECLARE x ROW LIKE :cur;
OPEN cur;
FETCH cur INTO x;
SELECT :x.a, :x.b, :x.c FROM DUMMY;
-- Returns [1, 'a', '2000-01-01']
SELECT 2, 'b', '2000-02-02' INTO x FROM DUMMY;
SELECT :x.a, :x.b, :x.c FROM DUMMY;
-- Returns [2, 'b', '2000-02-02']
END;
Limitations
Row type variables are not supported in scalar user-de ned functions.
Logic Container
In SQLScript there are two different logic containers: Procedure and User-De ned Function.
The User-De ned Function container is separated into Scalar User-De ned Function and Table User-De ned Function.
The following sections provide an overview of the syntactical language description for both containers.
Procedures
Procedures allows you to describe a sequence of data transformations on data passed as input and database tables.
Data transformations can be implemented as queries that follow the SAP HANA database SQL syntax by calling other
procedures. Read-only procedures can only call other read-only procedures.
You can parameterize and reuse calculations and transformations described in one procedure in other procedures.
This is custom documentation. For more information, please visit the SAP Help Portal 11
12/23/2022
You can use and express knowledge about relationships in the data; related computations can share common sub-
expressions, and related results can be returned using multiple output parameters.
You can de ne common sub-expressions. The query optimizer decides if a materialization strategy (which avoids
recomputation of expressions) or other optimizing rewrites are best to apply. In any case, it eases the task of detecting
common sub-expressions and improves the readability of the SQLScript code.
CREATE PROCEDURE
You use this SQL statement to create a procedure.
Syntax
CREATE [OR REPLACE] PROCEDURE <proc_name> [(<parameter_clause>)] [LANGUAGE <lang>] [SQL SECURITY <
[READS SQL DATA ] [WITH ENCRYPTION] [AUTOCOMMIT DDL ON|OFF] AS
BEGIN [SEQUENTIAL EXECUTION]
<procedure_body>
END
Syntax Elements
The following syntax elements are available:
Note
The default is IN. Each parameter is marked using the keywords IN/OUT/INOUT. Input and output parameters must
be explicitly assigned a type (that means that tables without a type are note supported)
The input and output parameters of a procedure can have any of the primitive SQL types or a table type. INOUT
parameters can only be of the scalar or the array type.
Array variables or constant arrays can be passed to procedures as input, output, and inout parameters with the following
limitations:
Using an array parameter in the USING clause of Dynamic SQL is not supported.
This is custom documentation. For more information, please visit the SAP Help Portal 12
12/23/2022
<sql_type> ::= DATE | TIME| TIMESTAMP | SECONDDATE | TINYINT | SMALLINT | INTEGER | BIGINT |
| VARCHAR | NVARCHAR | ALPHANUM | VARBINARY | CLOB | NCLOB | BLOB | ST_GEOMETRY
Note
For more information on data types see Data Types in the SAP HANA SQL and System Views Reference on the SAP
Help Portal.
A table type previously de ned with the CREATE TYPE command, see CREATE TYPE.
LANGUAGE <lang>
<lang> ::= SQLSCRIPT | R
Tip
It is a good practice to de ne the language in all procedure de nitions.
Speci cation of the security mode of the procedure. The default is DEFINER.
Indication that that the execution of the procedure is performed with the privileges of the de ner of the procedure
DEFINER
Indication that the execution of the procedure is performed with the privileges of the invoker of the procedure
INVOKER
Speci es the schema for unquali ed objects in the procedure body; if nothing is speci ed, then the current_schema of
the session is used.
Marks the procedure as being read-only and side-effect free - the procedure does not make modi cations to the
database data or its structure. This means that the procedure does not contain DDL or DML statements and that it only
This is custom documentation. For more information, please visit the SAP Help Portal 13
12/23/2022
calls other read-only procedures. The advantage of using this parameter is that certain optimizations are available for
read-only procedures.
By default, every SQLScript procedure or function runs with AUTOCOMMIT mode OFF and AUTOCOMMIT DDL mode OFF.
Now you can explicitly specify whether the procedure should be run with AUTOCOMMIT DDL mode ON or OFF.
Caution
In some cases AUTOCOMMIT DDL mode ON may be required. For example, in administrative operations, like IMPORT,
which cannot run with DDL AUTOCOMMIT mode OFF.
You can nd out the AUTOCOMMIT DDL mode for each procedure by using the column 'AUTO_COMMIT_DDL' in the
monitoring view 'PROCEDURES'.
De nes the main body of the procedure according to the programming language selected
This statement forces sequential execution of the procedure logic. No parallelism takes place.
SEQUENTIAL EXECUTION
This is custom documentation. For more information, please visit the SAP Help Portal 14
12/23/2022
<proc_cursor_param> ::= <param_name> <datatype>
For more information on inserting, updating and deleting data records, see Modifying the Content of Table Variables.
You can modify a data record at a speci c position. There are two equivalent syntax options:
This is custom documentation. For more information, please visit the SAP Help Portal 15
12/23/2022
You can delete data records from a table variable. Wth the following syntax you can delete a single record.
To delete blocks of records from table variables, you can use the following syntax:
Sections of your procedures can be nested using BEGIN and END terminals
Assignment of values to variables - an <expression> can be either a simple expression, such as a character, a date, or a
number, or it can be a scalar function or a scalar user-de ned function.
The ARRAY_AGG function returns the array by aggregating the set of elements in the speci ed column of the table
variable. Elements can optionally be ordered.
The CARDINALITY function returns the number of the elements in the array, <array_variable_name>.
The TRIM_ARRAY function returns the new array by removing the given number of elements,
<numeric_value_expression>, from the end of the array, <array_value_expression>.
The ARRAY function returns an array whose elements are speci ed in the list <array_variable_name>. For more
information see the chapter Array Variables.
Assignment of values to a list of variables with only one function evaluation. For example, <function_expression>
must be a scalar user-de ned function and the number of elements in <var_name_list> must be equal to the number
of output parameters of the scalar user-de ned function.
This is custom documentation. For more information, please visit the SAP Help Portal 16
12/23/2022
| <variable_name> = <unnest_function>
| <variable_name> = <map_merge_op>
The MAP_MERGE operator is used to apply each row of the input table to the mapper function and unite all intermediate
result tables. For more information, see Map Merge Operator.
For more information about the CE operators, see Calculation Engine Plan Operators.
APPLY_FILTER de nes a dynamic WHERE-condition <variable_name> that is applied during runtime. For more
information about that, see the chapter APPLY_FILTER.
The UNNEST function returns a table including a row for each element of the speci ed array.
WITH ORDINALTIY
This is custom documentation. For more information, please visit the SAP Help Portal 17
12/23/2022
You use WHILE to repeatedly call a set of trigger statements while a condition is true.
You use FOR - EACH loops to iterate over all elements in a set of data.
Terminates a loop
Skips a current loop iteration and continues with the next value.
You use the SIGNAL statement to explicitly raise an exception from within your trigger procedures.
You use the RESIGNAL statement to raise an exception on the action statement in an exception handler. If an error code
is not speci ed, RESIGNAL will throw the caught exception.
This is custom documentation. For more information, please visit the SAP Help Portal 18
12/23/2022
You can SIGNAL or RESIGNAL a signal name or an SQL error code.
You use SET MESSAGE_TEXT to deliver an error message to users when speci ed error is thrown during procedure
execution.
For information on <insert_stmt>, see INSERT in the SAP HANA SQL and System Views Reference.
For information on <delete_stmt>, see DELETE in the SAP HANA SQL and System Views Reference.
For information on <update_stmt>, see UPDATE in the SAP HANA SQL and System Views Reference.
For information on <replace_stmt> and <upsert_stmt>, see REPLACE and UPSERT in the SAP HANA SQL and
System Views Reference.
For information on <truncate_stmt>, see TRUNCATE in the SAP HANA SQL and System Views Reference.
<var_name> is a scalar variable. You can assign selected item value to this scalar variable.
Cursor operations
This is custom documentation. For more information, please visit the SAP Help Portal 19
12/23/2022
Procedure call. For more information, see CALL: Internal Procedure Call
Description
The CREATE PROCEDURE statement creates a procedure by using the speci ed programming language <lang>.
Example
Example: Creating a Procedure
The procedure features a number of imperative constructs including the use of a cursor (with associated state) and local scalar
variables with assignments.
DROP PROCEDURE
Syntax
Syntax Elements
This is custom documentation. For more information, please visit the SAP Help Portal 20
12/23/2022
The name of the procedure to be dropped, with optional schema name
If you do not specify the <drop_option>, the system performs a non-cascaded drop. This will only drop the speci ed procedure;
dependent objects of the procedure will be invalidated but not dropped.
The invalidated objects can be revalidated when an object that uses the same schema and object name is created.
CASCADE
RESTRICT
This parameter drops the procedure only when dependent objects do not exist. If this drop option is used and a dependent
object exists an error will be sent.
Description
This statement drops a procedure created using CREATE PROCEDURE from the database catalog.
Examples
You drop a procedure called my_proc from the database using a non-cascaded drop.
ALTER PROCEDURE
You can use ALTER PROCEDURE if you want to change the content and properties of a procedure without dropping the object.
For instance, with ALTER PROCEDURE you can change the content of the body itself. Consider the following GET_PROCEDURES
procedure that returns all procedure names on the database.
AS
BEGIN
procedures = SELECT schema_name AS schema_name, procedure_name AS name FROM PROCEDURES;
END;
This is custom documentation. For more information, please visit the SAP Help Portal 21
12/23/2022
The procedure GET_PROCEDURES should now be changed to return only valid procedures. In order to do so, use ALTER
PROCEDURE:
AS
BEGIN
procedures = SELECT schema_name AS schema_name, procedure_name AS name FROM PROCEDURES WHERE IS_
END;
Besides changing the procedure body, you can also change the language <lang> of the procedure, the default schema
<default_schema_name> as well as change the procedure to read only mode (READS SQL DATA).
Note
If the default schema and read-only mode are not explicitly speci ed, they will be removed. The default language is
SQLScript.
Note
You must have the ALTER privilege for the object you want to change.
Syntax
Syntax Elements
The identi er of the procedure to be altered, with the optional schema name.
Description
The ALTER PROCEDURE RECOMPILE statement manually triggers a recompilation of a procedure by generating an updated
execution plan.
Example
You trigger the recompilation of the my_proc procedure to produce debugging information.
Procedure Calls
A procedure can be called either by a client on the outer-most level, using any of the supported client interfaces, or within the
body of a procedure.
This is custom documentation. For more information, please visit the SAP Help Portal 22
12/23/2022
Recommendation
SAP recommends that you use parameterized CALL statements for better performance. The advantages follow.
The parameterized query compiles only once, thereby reducing the compile time.
A stored query string in the SQL plan cache is more generic and a precompiled query plan can be reused for the same
procedure call with different input parameters.
By not using query parameters for the CALL statement, the system triggers a new query plan generation.
CALL
Syntax
Syntax Elements
Procedure parameters
For more information on these data types, see Backus Naur Form Notation and Scalar Data Types.
Parameters passed to a procedure are scalar constants and can be passed either as IN, OUT or INOUT parameters. Scalar
parameters are assumed to be NOT NULL. Arguments for IN parameters of type table can be either physical tables or views.
The actual value passed for tabular OUT parameters must be`?`.
WITH OVERVIEW
De nes that the result of a procedure call will be stored directly into a physical table.
Calling a procedure WITH OVERVIEW returns one result set that contains information about which table contains the result of
which table output variable. Scalar outputs are returned as regular scalar output parameters. When you pass existing tables to
the output parameters, WITH OVERVIEW inserts the result-set tuples of the procedure into the provided tables. When you
pass '?' to the output parameters, temporary tables holding the result sets are generated. These tables are dropped
automatically once the database session is closed.
Description
This is custom documentation. For more information, please visit the SAP Help Portal 23
12/23/2022
Calls a procedure de ned with CREATE PROCEDURE.
CALL returns a list of result sets with one entry for every tabular result. An iterator can be used to iterate over these results
sets. For each result set you can iterate over the result table in the same manner as you do for query results. SQL statements
that are not assigned to any table variable in the procedure body are added as result sets at the end of the list of result sets.
The type of the result structures will be determined during compilation time but will not be visible in the signature of the
procedure.
CALL when executed by the client the syntax behaves in a way consistent with the SQL standard semantics, for example, Java
clients can call a procedure using a JDBC CallableStatement. Scalar output variables are a scalar value that can be
retrieved from the callable statement directly.
Note
Unquoted identi ers are implicitly treated as upper case. Quoting identi ers will respect capitalization and allow for using
white spaces that are normally not allowed in SQL identi ers.
Examples
In these examples, consider the following procedure signature:
It is also possible to use scalar user de ned function as parameters for procedure call:
CALL proc(udf(),’EUR’,?,?);
CALL proc(udf()* udf()-55,’EUR’, ?, ?);
In this example, udf() is a scalar user-de ned function. For more information about scalar user-de ned functions, see CREATE
FUNCTION
This is custom documentation. For more information, please visit the SAP Help Portal 24
12/23/2022
Syntax Elements:
Note
Use a colon before the identi er name.
Description:
For an internal procedure, in which one procedure calls another procedure, all existing variables of the caller or literals are
passed to the IN parameters of the callee and new variables of the caller are bound to the OUT parameters of the callee. The
result is implicitly bound to the variable given in the function call.
Example:
When the procedure addDiscount is called, the variable <:lt_expensive_books> is assigned to the function and the variable
<lt_on_sales> is bound by this function call.
Related Information
CALL
For example:
When you use named parameters, you can ignore the order of the parameters in the procedure signature. Run the following
commands and you can try some of the examples below.
create procedure myproc (in intab mytab_t,in i int, out outtab mytab_t) as
begin
outtab = select i from :intab where i > :i;
end;
or
Procedure Parameters
Parameter Modes
The following table lists the parameters you can use when de ning your procedures.
Parameter modes
Mode Description
IN An input parameter
This is custom documentation. For more information, please visit the SAP Help Portal 26
12/23/2022
Mode Description
INOUT Speci es a parameter that passes in and returns data to and from the procedure
Note
This is only supported for scalar values. The parameter needs to be parameterized if you call the
procedure, for example CALL PROC ( inout_var=>?). A non-parameterized call of a procedure
with an INOUT parameter is not supported.
Both scalar and table parameter types are supported. For more information on datatypes, see Datatype Extension
Related Information
Data Type Extension
Table Parameters
You can pass tables and views to the parameter of this function.
Note
This is custom documentation. For more information, please visit the SAP Help Portal 27
12/23/2022
Implicit binding of multiple values is currently not supported.
You should always use SQL special identi ers when binding a value to a table variable.
Note
Do not use the following syntax:
The usage of the default value will be illustrated in the next example. Therefore the following tables are needed:
The procedure in the example generates a FULLNAME by the given input table and delimiter. Whereby default values are used
for both input parameters:
END;
For the tabular input parameter INTAB the default table NAMES is de ned and for the scalar input parameter DELIMITER the ʻ,’
is de ned as default. To use the default values in the signature, you need to pass in parameters using Named Parameters. That
means to call the procedure FULLNAME and using the default value would be done as follows:
FULLNAME
--------
DOE,JOHN
This is custom documentation. For more information, please visit the SAP Help Portal 28
12/23/2022
Now we want to pass a different table, i.e. MYNAMES but still want to use the default delimiter value, the call looks then as
follows:
And the result shows that now the table MYNAMES was used:
FULLNAME
--------
DOE,ALICE
Note
Please note that default values are not supported for output parameters.
Related Information
CALL with Named Parameters
Although the general default value handling is supported for input parameters only, the DEFAULT EMPTY is supported for both
tabular IN and OUT parameters.
In the following example use the DEFAULT EMPTY for the tabular output parameter to be able to declare a procedure with an
empty body.
END;
Creating the procedure without DEFAULT EMPTY causes an error indicating that OUTTAB is not assigned. The PROC_EMPTY
procedure can be called as usual and it returns an empty result set:
This is custom documentation. For more information, please visit the SAP Help Portal 29
12/23/2022
An example of calling the procedure without passing an input table follows.
call CHECKINPUT(result=>?)
OUT(1)
-----------------
'Input is empty'
For Functions only tabular input parameter supports the EMPTY keyword :
An example of calling the funtion without passing an input table looks as follows:
Procedure Metadata
When a procedure is created, information about the procedure can be found in the database catalog. You can use this
information for debugging purposes.
The procedures observable in the system views vary according to the privileges that a user has been granted. The following
visibility rules apply:
CATALOG READ or DATA ADMIN – All procedures in the system can be viewed.
SCHEMA OWNER, or EXECUTE – Only speci c procedures where the user is the owner, or they have execute privileges,
will be shown.
Procedures can be exported and imported as are tables, see the SQL Reference documentation for details. For more
information see Data Import Export Statements in the SAP HANA SQL and System Views Referenece.
Related Information
SAP HANA SQL and System Views Reference
SYS.PROCEDURES
Available stored procedures
This is custom documentation. For more information, please visit the SAP Help Portal 30
12/23/2022
Structure
SYS. PROCEDURE_PARAMETERS
Parameters of stored procedures
Structure
This is custom documentation. For more information, please visit the SAP Help Portal 31
12/23/2022
SYS.OBJECT_DEPENDENCIES
Dependencies between objects, for example, views that refer to a speci c table
Structure
This is custom documentation. For more information, please visit the SAP Help Portal 32
12/23/2022
0: NORMAL (default)
1: EXTERNAL_DIRECT (direct
dependency between dependent
object and base object)
2: EXTERNAL_INDIRECT (indirect
dependency between dependent
object und base object)
5: REFERENTIAL_DIRECT (foreign
key dependency between tables)
CREATE PROCEDURE deps.get_tables(OUT outtab1 mytab_t, OUT outtab2 mytab_t) LANGUAGE SQLSCRIPT READS
BEGIN
outtab1 = SELECT * FROM mytab1;
outtab2 = SELECT * FROM mytab2;
END;
CREATE PROCEDURE deps.my_proc (IN val INT, OUT outtab mytab_t) LANGUAGE SQLSCRIPT READS SQL DATA
AS
BEGIN
CALL deps.get_tables(tab1, tab2);
IF :val > 1 THEN
outtab = SELECT * FROM :tab1;
ELSE
outtab = SELECT * FROM :tab2;
END IF;
END;
Find all the (direct and indirect) base objects of the DEPS.GET_TABLES procedure using the following statement.
This is custom documentation. For more information, please visit the SAP Help Portal 33
12/23/2022
SYSTEM MYTAB2 TABLE DEPS GET_TABLES
Look at the DEPENDENCY_TYPE column in more detail. You obtained the results in the table above using a select on all the
base objects of the procedure; the objects shown include both persistent and transient objects. You can distinguish between
these object dependency types using the DEPENDENCY_TYPE column, as follows:
To obtain only the base objects that are used in DEPS.MY_PROC, use the following statement.
Finally, to nd all the dependent objects that are using DEPS.MY_PROC, use the following statement.
PROCEDURE_PARAMETER_COLUMNS
PROCEDURE_PARAMETER_COLUMNS provides information about the columns used in table types which appear as procedure
parameters. The information is provided for all table types in use, in-place types and externally de ned types.
This is custom documentation. For more information, please visit the SAP Help Portal 34
12/23/2022
Functions Calling A table UDF can only be called in the FROM- A scalar UDF can be called in SQL
clause of an SQL statement in the same statements in the same parameter
parameter positions as table names. For positions as table column names. That
example, SELECT * FROM takes place in the SELECT and WHERE
myTableUDF(1) clauses of SQL statements. For example,
SELECT myScalarUDF(1) AS
myColumn FROM DUMMY
Output Must return a table whose type is de ned in Must return scalar values speci ed in
<return_type>. <return_parameter_list>.
Supported functionality The function is tagged as read only by The function is tagged as a read-only
default. DDL and DML are not allowed and function by default.
only other read-only functions can be called.
CREATE FUNCTION
This SQL statement creates read-only user-de ned functions that are free of side effects. This means that neither DDL, nor
DML statements (INSERT, UPDATE, and DELETE) are allowed in the function body. All functions or procedures selected or called
from the body of the function must be read-only.
Syntax
This is custom documentation. For more information, please visit the SAP Help Portal 35
12/23/2022
CREATE [OR REPLACE] FUNCTION <func_name> [(<parameter_clause>)] RETURNS <return_type> [LANGUAGE <la
[WITH ENCRYPTION]
AS
BEGIN
<function_body>
END
Syntax Elements
Scalar user-de ned functions (SUDF) support the following primitive SQL types. Table types (table variables, physical tables, or
views) are also supported as input in SUDFs. Arrays are supported as input and return types.
<sql_type> ::= DATE | TIME | TIMESTAMP | SECONDDATE | TINYINT | SMALLINT | INTEGER | BIGINT | DECIM
<table_type> ::= <identifier>
SUDFs with table parameters can be used like any other SUDF with following exceptions:
Parameterized views, scripted calculation views or TUDFs as input are not supported.
SQLScript internal types, such as cursor variables or ROW types, are not supported.
Note
Take in to consideration the following note on performance. SUDFs operate on table data row by row. In the following
example, the operation would be at least O(record_count(t1) * record_count(t2)).
Table user-de ned functions (TUDF) allow the following range of primitive SQL types. They also support table types and array
types as input.
<sql_type> ::= DATE | TIME | TIMESTAMP | SECONDDATE | TINYINT | SMALLINT | INTEGER | BIGINT | DECIM
<table_type> ::= <identifier>
This is custom documentation. For more information, please visit the SAP Help Portal 36
12/23/2022
To look at a table type previously de ned with the CREATE TYPE command, see CREATE TYPE.
Table UDFs must return a table whose type is de ned by <return_table_type>. And scalar UDF must return scalar values
speci ed in <return_parameter_list>.
The following expression de nes the structure of the returned table data.
LANGUAGE <lang>
<lang> ::= SQLSCRIPT
Default: SQLSCRIPT
Note
Only SQLScript UDFs can be de ned.
DEFINER
Speci es that the execution of the function is performed with the privileges of the de ner of the function.
INVOKER
Speci es that the execution of the function is performed with the privileges of the invoker of the function.
This is custom documentation. For more information, please visit the SAP Help Portal 37
12/23/2022
Speci es the schema for unquali ed objects in the function body. If nothing is speci ed, then the current_schema of the
session is used.
De nes the main body of the table user-de ned functions and scalar user-de ned functions. Since the function is agged as
read-only, neither DDL, nor DML statements (INSERT, UPDATE, and DELETE), are allowed in the function body. A scalar UDF
does not support table operations in the function body and variables of type TABLE as input.
Note
Scalar functions can be marked as DETERMINISTIC, if they always return the same result any time they are called with a
speci c set of input parameters.
De nes one or more local variables with associated scalar type or array type.
An array type has <type> as its element type. An array has a range from 1 to 2,147,483,647, which is the limitation of underlying
structure.
You can assign default values by specifying <expression>s. For more information, see Expressions in the SAP HANA SQL and
System Views Reference on the SAP Help Portal.
This is custom documentation. For more information, please visit the SAP Help Portal 38
12/23/2022
| <proc_fetch>
| <proc_close>
Note
Statements that require DDL AUTOCOMMIT ON, like imports, cannot be used in functions. For more information, see
CREATE PROCEDURE.
Example
How to create a table function is shown in the following example:
How to call the table function scale is shown in the following example:
How to create a scalar function of name func_add_mul that takes two values of type double and returns two values of type
double is shown in the following example:
In a query you can either use the scalar function in the projection list or in the where-clause. In the following example the
func_add_mul is used in the projection list:
A B ADD MUL
-------------------
1 2 3 2
3 4 7 12
Besides using the scalar function in a query you can also use a scalar function in scalar assignment, e.g.:
This is custom documentation. For more information, please visit the SAP Help Portal 39
12/23/2022
RESULT
-----------------
4
ALTER FUNCTION
You can use ALTER FUNCTION if you want to change the content and properties of a function without dropping the object.
For more information about the parameters please refer to CREATE FUNCTION. For instance, with ALTER FUNCTION you can
change the content of the body itself. Consider the following procedure GET_FUNCTIONS that returns all function names on the
database.
AS
BEGIN
return SELECT schema_name AS schema_name,
function_name AS name
FROM FUNCTIONS;
END;
The function GET_FUNCTIONS should now be changed to return only valid functions. In order to do so, we will use ALTER
FUNCTION:
AS
BEGIN
return SELECT schema_name AS schema_name,
function_name AS name
FROM FUNCTIONS
WHERE IS_VALID = 'TRUE';
END;
Besides changing the function body, you can also change the default schema <default_schema_name>.
This is custom documentation. For more information, please visit the SAP Help Portal 40
12/23/2022
Note
If the default schema is not explicitly speci ed, it will be removed.
Note
You need the ALTER privilege for the object you want to change.
DROP FUNCTION
Syntax
Syntax Elements
When <drop_option> is not speci ed a non-cascaded drop will be performed. This will only drop the speci ed function,
dependent objects of the function will be invalidated but not dropped.
The invalidated objects can be revalidated when an object that has same schema and object name is created.
CASCADE
RESTRICT
Drops the function only when dependent objects do not exist. If this drop option is used and a dependent object exists an error
will be thrown.
Description
Drops a function created using CREATE FUNCTION from the database catalog.
Examples
You drop a function called my_func from the database using a non-cascaded drop.
This is custom documentation. For more information, please visit the SAP Help Portal 41
12/23/2022
Function Parameters
The following tables list the parameters you can use when de ning your user-de ned functions.
Function Parameter
Function Metadata
When a function is created, information about the function can be found in the database catalog. You can use this information
for debugging purposes. The functions observable in the system views vary according to the privileges that a user has been
granted. The following visibility rules apply:
This is custom documentation. For more information, please visit the SAP Help Portal 42
12/23/2022
CATALOG READ or DATA ADMIN – All functions in the system can be viewed.
SCHEMA OWNER, or EXECUTE – Only speci c functions where the user is the owner, or they have execute privileges, will
be shown.
SYS.FUNCTIONS
A list of available functions
Structure
SYS.FUNCTION_PARAMETERS
A list of parameters of functions
Structure
This is custom documentation. For more information, please visit the SAP Help Portal 43
12/23/2022
FUNCTION_PARAMETER_COLUMNS
FUNCTION_PARAMETER_COLUMNS provides information about the columns used in table types which appear as function
parameters. The information is provided for all table types in use, in-place types and externally de ned types.
This is custom documentation. For more information, please visit the SAP Help Portal 44
12/23/2022
The usage of the default value will be illustrated in the next example. Therefore the following tables are needed:
The function in the example generates a FULLNAME by the given input table and delimiter. Whereby default values are used for
both input parameters:
END;
For the tabular input parameter INTAB the default table NAMES is de ned and for the scalar input parameter DELIMITER the ʻ,’
is de ned as default.
That means to query the function FULLNAME and using the default value would be done as follows:
FULLNAME
--------
DOE,JOHN
This is custom documentation. For more information, please visit the SAP Help Portal 45
12/23/2022
Now we want to pass a different table, i.e. MYNAMES but still want to use the default delimiter value. To do so you need to use
using Named Parameters to pass in parameters. The query looks then as follows:
And the result shows that now the table MYNAMES was used:
FULLNAME
--------
DOE,ALICE
In a scalar function, default values can also be used, as shown in the next example:
Calling that function by using the default value of the variable delimiter would be the following:
Note
Please note that default values are not supported for output parameters.
Related Information
CALL with Named Parameters
Syntax
Description
This is custom documentation. For more information, please visit the SAP Help Portal 46
12/23/2022
It is possible to create a one-time SQLScript function that can embed imperative SQLScript logic inside an SQL query. Earlier it
was necessary to create an SQLScript function as a metadata object and consume it inside a single query. Similarly to the
anonymous procedure block DO BEGIN…END, the SQL FUNCTION RETURNS… BEGIN… END block supports that kind of one-
time table functions.
Example
Sample Code
select sum(a) from
sql function
returns table (a int, b int)
begin
declare t table(a int, b int);
:t.insert((1, 2));
:t.insert((1, 3));
:t.insert((2, 2));
:t.insert((3, 3));
return :t;
end
Sample Code
-- input parameter
select a from
sql function (in a int => 1)
returns table (a int)
begin
return select :a as a from dummy;
end;
This is custom documentation. For more information, please visit the SAP Help Portal 47
12/23/2022
-- nested SQL FUNCTION clause
select a from
sql function
returns table (a int)
begin
return select * from
sql function
returns table (a int)
begin
return select 1 as a from dummy;
end;
end;
Limitations
If the SQL FUNCTION clause is nested inside another SQLScript object, most of the SQLScript system variables are not
available, if they are not de ned as INPUT parameters.
ROWCOUNT is not shared between the caller object and the SQL FUNCTION but it can still show the selected
ROWCOUNT from the SELECT statement itself.
SQL_ERROR_CODE and SQL_ERROR_MESSAGE are not inherited, although it is possible to de ne them explicitly within
the SQL FUNCTION
When you use such functions, it is not necessary to recalculate the result every time - you can refer to the cached result. If you
want to make a scalar user-de ned function explicitly deterministic, you need to use the optional keyword DETERMINISTIC when
you create your function, as demonstrated in the example below. The lifetime of the cache entry is bound to the query execution
(for example, SELECT/DML). After the execution of the query, the cache is destroyed.
Sample Code
Note
In the system view SYS.FUNCTIONS, the column IS_DETERMINISTIC provides information about whether a function is
deterministic or not.
Non-Deterministic Functions
The following not-deterministic functions cannot be speci ed in deterministic scalar user-de ned functions. They return an error
at function creation time.
nextval/currval of sequence
current_time/current_timestamp/current_date
This is custom documentation. For more information, please visit the SAP Help Portal 48
12/23/2022
current_utctime/current_utctimestamp/current_utcdate
rand/rand_secure
window functions
Note
Currently, PRC is enabled only for deterministic procedures.
Related Information
Deterministic Procedures
Deterministic Procedure Cache
Deterministic Procedures
Syntax
create procedure add (in a int, in b int, out c int) deterministic as begin
c = :a + :b;
end
Description
You can use the keyword DETERMINISTIC when creating a new procedure, if the following conditions are met:
The procedure always returns the same output arguments when it is called with the same input arguments, even if the
session and database state is not the same.
You can also create a procedure with the keyword DETERMINISTIC, even if it does not satisfy the above conditions, by changing
the con guration parameters described in the con guration section. Procedures created with the keyword DETERMINISTIC are
described below as "deterministic procedures", regardless of whether they are logically deterministic or not.
By default, you cannot create a deterministic procedure that contains the following:
Statements with side effects (for example, implicit result sets, DML, DDL, commit/rollback/exec)
You can skip the determinism check when creating deterministic procedures on your responsibility. It is useful when you want to
create logically deterministic procedures that may contain non-deterministic statements. When disabling the check, please be
This is custom documentation. For more information, please visit the SAP Help Portal 49
12/23/2022
aware that the cache can be shared among users, so if the procedure results depend on the current user (for example, the
procedure security is invoker and there are user-speci c functions or use of tables with analytic privileges), it may not behave as
you expect. Disabling the check is not recommended.
If a deterministic procedure has side effects, the side effects may or may not be visible when you call the procedure.
If a deterministic procedure has implicit result sets, they may or may not be returned when you call the procedure.
If a deterministic procedure returns different output arguments for the same input arguments, you may or may not get
the same output arguments when you call the procedure multiple times with the same input arguments.
Con guration
The con guration parameters below refer to Procedure Result Cache (PRC) under the section "sqlscript".
There are also session variables that can be set for each session and which override the settings above.
__SQLSCRIPT_ENABLE_DETERMINISTIC_PROCEDURE_CHECK enable_deterministic_procedure_check
__SQLSCRIPT_ENABLE_DETERMINISTIC_PROCEDURE_RESULT_CACHE enable_deterministic_procedure_cache
Note
Use the session variable "__SQLSCRIPT_ENABLE_DETERMINISTIC_PROCEDURE_CHECK" with caution: although the
procedure can be created successfully in the current session, if the procedure gets invalidated, it might not be revalidated, if
the revalidation occurs in other sessions.
Related Information
Procedure Result Cache
Deterministic Procedure Cache
This is custom documentation. For more information, please visit the SAP Help Portal 50
12/23/2022
Description
By default Procedure Result Cache (PRC) is enabled for deterministic procedures.
The scope of the cache is the current server (for example, indexserver or cacheserver). If you call the same deterministic
procedure in the same server with the same arguments multiple times, the cached results will be used except for the rst call,
unless the cached results are evicted. Since the cache is global in the current server, the results are shared even among
different query plans.
Note
Currently, only scalar parameters are supported for PRC. You can create deterministic procedures having table parameters,
but automatic caching will be disabled for such procedures.
For scalar user-de ned functions, a new cache is created for each statement execution and destroyed after execution. The
cache is local to the current statement which has a xed snapshot of the persistence at a point in time. Due to this behavior,
more things can be considered "deterministic" in deterministic scalar UDFs, such as reading a table.
Related Information
Procedure Result Cache
Deterministic Procedures
Syntax
Code Syntax
CREATE [OR REPLACE] LIBRARY <lib_name>
[LANGUAGE SQLSCRIPT] [DEFAULT SCHEMA <default_schema_name>]
AS BEGIN
[<lib_var_decl_list>]
[<lib_proc_func_list>]
END;
This is custom documentation. For more information, please visit the SAP Help Portal 51
12/23/2022
Description
A library is a set of related variables, procedures and functions. There are two types of libraries: built-in libraries and user-
de ned libraries. A built-in library is a system-provided library with special functions. A user-de ned library is a library written by
a user in SQLScript. Users can make their own libraries and utilize them in other procedures or functions. Libraries are designed
to be used only in SQLScript procedures or functions and are not available in other SQL statements.
A single metadata object is created for multiple procedures and functions. By combining all relevant procedures and
functions into a single metadata object, you reduce metadata management cost. On the other hand, if one function or a
procedure of the library becomes invalid, the whole library becomes invalid.
The atomicity of the relevant objects is guaranteed because they are managed as a single object.
It is easy to handle the visibility of a procedure or a function in a library. When an application gets bigger and complex,
developers might want to use some procedures or functions only in their application and not to open them to application
users. A library can solve this requirement easily by using the access modes PUBLIC and PRIVATE for each library
member.
Constant and non-constant variables are available in a library. You can declare a constant variable for a frequently used
constant value and use the variable name instead of specifying the value each time. A non-constant value is alive during
a session and you can access the value at any time if the session is available.
Note
Any user having the EXECUTE privilege on a library can use that library by means of the USING statement and can
also access its public members.
Limitations
The following limitations apply currently:
The usage of library variables is currently limited. For example, it is not possible to use library variables in the INTO clause
of a SELECT INTO statement and in the INTO clause of dynamic SQL. This limitation can be easily circumvented by using a
normal scalar variable as intermediate value.
This is custom documentation. For more information, please visit the SAP Help Portal 52
12/23/2022
Since session variables are used for library variables, it is possible (provided you the necessary privileges) to read and
modify arbitrary library variables of (other) sessions.
Related Information
Library Members
System Views
Library Members
Syntax
Code Syntax
Using a Library Member
Description
Access Mode
Each library member can have a PUBLIC or a PRIVATE access mode. PRIVATE members are not accessible outside the library,
while PUBLIC members can be used freely in procedures and functions.
The scope of a library member variable is bound to its session. The value of a library variable persists throughout a session. If
the variable is accessed by different statements within the same session, these statements access the same variable. However,
a library member variable can display different values if accessed from different sessions.
Library functions and procedures can be declared as private or public. Private functions and procedures are for internal use
within the library. They cannot be called from outside the library. Public functions and procedures can be used by anyone who
has the EXECUTE privilige for the library. These functions and procedures can be used and declared like non-library functions
and procedures, but they have access to the library private variables, private functions and private procedures. It is also
possible to call procedures and functions from outside the library, as well as other libraries. The use of library functions is limited
to the right-hand side of assignments and cannot be used in queries.
A library member is not a metadata object, so it may have the same name as another procedure or function. When resolving an
unquali ed name in a library de nition, the system rst examines library members de ned before the current library member. If
the name is not found within the library, then the name is searched for in the library schema. To reduce ambiguity and to avoid
duplicate names, it is recommended to use a fully quali ed name for user-de ned functions.
Example
Sample Code
Setup
do begin
declare idx int = 0;
for idx in 1..200 do
insert into data_table values (:idx);
end for;
end;
Sample Code
Library DDL
public procedure get_data(in size int, out result table(col1 int)) as begin
result = select top :size col1 from data_table;
end;
end;
Sample Code
Procedure Using Library
This is custom documentation. For more information, please visit the SAP Help Portal 54
12/23/2022
Sample Code
Result
call myproc(10);
Result:
count(*)
10
call myproc(150);
Result:
count(*)
100
Related Information
User-De ned Libraries
System Views
System Views
System views for user-de ned libraries.
LIBRARIES
LIBRARIES shows available libraries.
IS_VALID Speci es whether the library is valid or not. This becomes false
when its base objects are changed or dropped.
This is custom documentation. For more information, please visit the SAP Help Portal 55
12/23/2022
LIBRARY_MEMBERS
Library members of SQLScript libraries.
Related Information
User-De ned Libraries
Library Members
Description
Until now it was possible to use library members of user-de ned libraries (UDL) only within the scope of other SQLScript
objects like procedures, functions or anonymous blocks. For example, even if you only wanted to run a single library member
procedure, you had to create a procedure or execute the member procedure within an anonymous block. Wrapping the member
access into an anonymous block is simple when there are no parameters, but it can get more complex, if there are input and
output parameters. You can now directly call library member procedures without the use of additional SQLScript objects.
Syntax
Code Syntax
<call_stmt> ::= CALL <proc_name> ( <param_list> ) [WITH OVERVIEW] [IN DEBUG MODE]
| CALL <lib_member_ref> ( <param_list> );
This is custom documentation. For more information, please visit the SAP Help Portal 56
12/23/2022
Behavior
do (in iv int => 1, out otv table(col1 nvarchar(10)) => ?) begin call mylib:memberpro
using mylib as mylib;
call mylib:memberproc(:iv, otv);
end;
Library members can be referenced by library name and library member name. If a library alias is set by a USING statement, the
alias can be used instead of the library name.
If an alias is speci ed, SQLScript rst tries to resolve the unquali ed library name as a library alias. If the name is not found in
the list of library aliases, then SQLScript will resolve the name with a default schema. However, if a schema name is speci ed,
the library is always searched for inside the schema and any existing alias is ignored.
Examples
Sample Code
Example Library
Sample Code
Example 1
This is custom documentation. For more information, please visit the SAP Help Portal 57
12/23/2022
In this example, the library name in the CALL statement is not fully quali ed and there is an alias with the same name. In that
case, mylib is resolved as library mylib and it refers to myschema1.mylib.
Sample Code
Example 2
In this example, the library name in the CALL statement is not fully quali ed and there is no alias with the same name. In that
case, mylib is found only in the default schema and refers to myschema2.mylib.
Sample Code
Exaple 3
In this example, the library name in the CALL statement is mylib and there is an alias with the same name. However, the
library name is fully quali ed with the schema name myschema2 and is resolved as myschema2.mylib.
Limitations
The following limitations apply:
WITH option is not supported for library member CALL statement. For example CALL MYLIB:PROC() WITH HINT (...)
Built-in library member procedures with variable arguments are not supported.
Syntax
The syntax for library table functions, scalar functions and variables accepts a library member reference.
This is custom documentation. For more information, please visit the SAP Help Portal 58
12/23/2022
Code Syntax
Behavior
Sample Code
ERR-00467: cannot use parameter variable: MYLIB:PHI: line 1 col 8 Succeed: [(3.14)]
(at pos 7)
ERR-00007: feature not supported: using library member function Succeed: [(314), (628)]
on the outer boundary of SQLScript: CIRCUMFERENCE: line 1 col 8
(at pos 7)
This is custom documentation. For more information, please visit the SAP Help Portal 59
12/23/2022
ERR-00257: sql syntax error: incorrect syntax near "(": line 1 col 40 Succeed: [(314), (628)]
(at pos 40)
Limitations
EXPLAIN PLAN is not supported.
Built-in library member functions with variable arguments are not supported.
Library member functions and variables are not supported in generated columns and table check conditions.
Related Information
UDL Member Procedure Call Without SQLScript Artifacts
CREATE OR REPLACE
When creating a SQLScript procedure or function, you can use the OR REPLACE option to change the de ned procedure or
function, if it already exists.
Syntax
Behavior
The behavior of this command depends on the existence of the de ned procedure or function. If the procedure or function
already exists, it will be modi ed according to the new de nition. If you do not explicitly specify a property (for example, read
only), this property will be set to the default value. Please refer to the example below. If the procedure or function does not exist
yet, the command works like CREATE PROCEDURE or CREATE FUNCTION.
This is custom documentation. For more information, please visit the SAP Help Portal 60
12/23/2022
Compared to using DROP PROCEDURE followed by CREATE PROCEDURE, CREATE OR REPLACE has the following bene ts:
DROP and CREATE incur object revalidation twice, while CREATE OR REPLACE incurs it only once
If a user drops a procedure, its privileges are lost, while CREATE OR REPLACE preserves them.
Example
Sample Code
create or replace procedure proc(out o table(a int))
default schema system reads sql data deterministic with encryption as
begin
o = select 1 as a from dummy;
end;
call proc(?);
-- Returns 1
create or replace procedure proc(out o table(a int))
language llang as
begin
export Void main(Table<Int32 "A"> "o" & o)
{
Column<Int32> col = o.getColumn<Int32>("A");
col.setElement(0z, 2);
}
end;
call proc(?);
-- Returns 2
-- Note that this procedure is not set to read-only, deterministic, encrypted, or default schema
create or replace procedure proc(out o int) as
begin
o = 3;
end;
-- Returns an error because the signature of the new procedure does not match to that of the pred
Sample Code
CREATE OR REPLACE PROCEDURE test1 as
begin
select * from dummy;
end;
call test1;
-- new parameter
CREATE OR REPLACE PROCEDURE test1 (IN i int) as
begin
select :i from dummy;
select * from dummy;
end;
call test1(?);
-- default value
CREATE OR REPLACE PROCEDURE test1 (IN i int default 1) as
begin
select :i from dummy;
end;
call test1();
-- table type
create column table tab1 (a INT);
create column table tab2 (a INT);
CREATE OR REPLACE PROCEDURE test1(out ot1 table(a INT), out ot2 table(a INT)) as begin
insert into tab1 values (1);
select * from tab1;
insert into tab2 values (2);
select * from tab2;
insert into tab1 values (1);
insert into tab2 values (2);
ot1 = select * from tab1;
ot2 = select * from tab2;
end;
call test1(?, ?);
-- security
CREATE OR REPLACE PROCEDURE test1(out o table(a int))
sql security invoker as
begin
o = select 5 as a from dummy;
end;
call test1(?);
-- change security
ALTER PROCEDURE test1(out o table(a int))
sql security definer as
begin
o = select 8 as a from dummy;
end;
call test1(?);
-- result view
ALTER PROCEDURE test1(out o table(a int))
reads sql data with result view rv1 as
begin
o = select 0 as A from dummy;
end;
call test1(?);
-- table function
CREATE TYPE TAB_T1 AS TABLE(a int);
This is custom documentation. For more information, please visit the SAP Help Portal 62
12/23/2022
-- scalar function
CREATE OR REPLACE FUNCTION sfunc_param returns a int as
begin
A = 0;
end;
select sfunc_param() from dummy;
Anonymous Block
An anonymous block is an executable DML statement which can contain imperative or declarative statements.
All SQLScript statements supported in procedures are also supported in anonymous blocks.
Note
Statements that require DDL AUTOCOMMIT ON, like imports, cannot be used in anonymous blocks. For more information,
see CREATE PROCEDURE.
Compared to procedures, anonymous blocks have no corresponding object created in the metadata catalog - they are cached in
the SQL Plan Cache.
An anonymous block is de ned and executed in a single step by using the following syntax:
DO [(<parameter_clause>)]
BEGIN [SEQUENTIAL EXECUTION]
<body>
END WITH HINT (...)
<body> ::= !! supports the same feature set as the procedure
For more information on <body>, see <procedure_body> in CREATE in the SAP HANA SQL and System Views Reference on
the SAP Help Portal.
With the parameter clause you can de ne a signature, whereby the value of input and output parameters needs to be bound by
using named parameters.
This is custom documentation. For more information, please visit the SAP Help Portal 63
12/23/2022
Note
INOUT parameters and DEFAULT EMPTY are not supported.
The following example illustrates how to call an anonymous block with a parameter clause:
For output parameters only ? is a valid value and cannot be omitted, otherwise the query parameter cannot be bound. Any
scalar expression can be used for the scalar input parameter.
You can also parameterize the scalar parameters, if needed. For example, for the example above, it would look as follows:
Contrary to a procedure, an anonymous block has no container-speci c properties (for example, language, security mode, and
so on). However, the body of an anonymous block is similar to the procedure body.
Note
An anonymous block cannot be used in a procedure or in a function.
It is now possible to use HINTs for anonymous blocks. However, not all hints that are supported for CALL, are also supported for
anonymous blocks (for example, routing hints).
Sample Code
Anonymous Block Hint
DO BEGIN
DECLARE i INT;
FOR i in 1..5 DO
SELECT * FROM dummy;
END FOR;
END WITH HINT(dev_se_use_llvm)
DO
BEGIN
DECLARE I INTEGER;
CREATE TABLE TAB1 (I INTEGER);
FOR I IN 1..10 DO
INSERT INTO TAB1 VALUES (:I);
END FOR;
END;
This example contains an anonymous block that creates a table and inserts values into that table.
Example 2
DO
BEGIN
T1 = SELECT * FROM TAB;
CALL PROC3(:T1, :T2);
SELECT * FROM :T2;
END
Example 3
FOR I in 1..3 DO
INSERT INTO TAB VALUES (:I);
END FOR;
IF :J <> 3 THEN
SIGNAL SQL_ERROR_CODE 10001;
END IF;
END
SQLScript Encryption
Procedure and function de nitions may contain delicate or critical information but a user with system privileges can easily see
all de nitions from the public system views PROCEDURES, FUNCTIONS or from traces, even if the procedure or function owner
has controlled the authorization rights in order to secure their objects. If application developers want to protect their
intellectual property from any other users, even system users, they can use SQLScript encryption.
Note
This is custom documentation. For more information, please visit the SAP Help Portal 65
12/23/2022
Decryption of an encrypted procedure or function is not supported and cannot be performed even by SAP. Users who want to
use encrypted procedures or functions are responsible for saving the original source code and providing supportability
because there is no way to go back and no supportability tools for that purpose are available in SAP HANA.
Syntax
Code Syntax
[CREATE | ALTER] PROCEDURE <proc_name> [(<parameter_clause>)]
[LANGUAGE <lang>] [SQL SECURITY <mode>] [DEFAULT SCHEMA
<default_schema_name>] [READS SQL DATA ]
[<sqlscript_route_option>]
[WITH ENCRYPTION]
AS BEGIN
...
END;
Code Syntax
[CREATE | ALTER] FUNCTION <func_name> [(<parameter_clause>)] RETURNS <return_type>
[LANGUAGE <lang>] [SQL SECURITY <mode>] [DEFAULT SCHEMA <default_schema_name>] [READS SQL DATA]
[<sqlscript_route_option>] [DETERMINISTIC]
[WITH ENCRYPTION]
AS BEGIN
...
END;
Code Syntax
ALTER PROCEDURE <proc_name> ENCRYPTION ON;
ALTER FUNCTION <func_name> ENCRYPTION ON;
Behavior
If a procedure or a function is created by using the WITH ENCRYPTION option, their de nition is saved as an encrypted string
that is not human readable. That de nition is decrypted only when the procedure or the function is compiled. The body in the
CREATE statement is masked in various traces or monitoring views.
Encrypting a procedure or a function with the ALTER PROCEDURE/FUNCTION statement can be achieved in the following ways.
An ALTER PROCEDURE/FUNCTION statement, accompanying a procedure body, can make use of the WITH ENCRYPTION
option, just like the CREATE PROCEDURE/FUNCTION statement.
If you do not want to repeat the procedure or function body in the ALTER PROCEDURE/FUNCTION statement and want to
encrypt the existing procedure or function, you can use ALTER PROCEDURE/FUNCTION <proc_func_name> ENCRYPTION
ON. However, the CREATE statement without the WITH ENCRYPTION property is not secured.
Note
A new encryption key is generated for each procedure or function and is managed internally.
SQLScript Debugger, PlanViz, traces, monitoring views, and others that can reveal procedure de nition are not available for
encrypted procedures or functions.
Additional Considerations
This is custom documentation. For more information, please visit the SAP Help Portal 66
12/23/2022
Not encrypted procedures or functions can be used inside encrypted procedures or functions. However, encryption in the outer
call does not mean that nested calls are also secured. If a nested procedure or a function is not encrypted, then its compilation
and execution details are available in monitoring views or traces.
Object Dependency
The object dependency of encrypted procedures or functions is not secured. The purpose of encryption is to secure the logic of
procedures or functions and object dependency cannot reveal how a procedure or a function works.
There is a large amount of information related to a procedure or a function and hiding all information is hard and makes
problem analysis difficult. Therefore, compilation or execution information, which cannot reveal the logic of a procedure or a
function, can be available to users.
Limitation in Optimization
Some optimizations, which need analysis of the procedure or function de nition, are turned off for encrypted procedures and
functions.
Calculation Views
An encrypted procedure cannot be used as a basis for a calculation view. It is recommended to use table user-de ned functions
instead.
System Views
An additional column IS_ENCRYPTED is added to the views PROCEDURES and FUNCTIONS.
PROCEDURES
FUNCTIONS
For every public interface that shows procedure or function de nitions, such as PROCEDURES or FUNCTIONS, the de nition
column displays only the signature of the procedure, if it is encrypted.
Sample Code
CREATE PROCEDURE TEST_PROC(IN x INT) WITH ENCRYPTION AS BEGIN
SELECT 1 AS I FROM DUMMY;
END;
CREATE FUNCTION TEST_FUNC(IN x INT) RETURNS i INT WITH ENCRYPTION AS BEGIN
This is custom documentation. For more information, please visit the SAP Help Portal 67
12/23/2022
i = 1;
END;
Sample Code
SELECT PROCEDURE_NAME, DEFINITION FROM PROCEDURES WHERE PROCEDURE_NAME = 'TEST_PROC';
Result:
PROCEDURE_NAME DEFINITON
Sample Code
SELECT FUNCTION_NAME, DEFINITION FROM FUNCTIONS WHERE FUNCTION_NAME = 'TEST_FUNC';
Result:
FUNCTION_NAME DEFINITON
Supportability
For every monitoring view showing internal queries, the internal statements will also be hidden, if its parent is an encrypted
procedure call. Debugging tools or plan analysis tools are also blocked.
SQLScript Debugger
PlanViz
Statement-related views
M_ACTIVE_PROCEDURES
In these monitoring views, the SQL statement string is replaced with the string <statement from encrypted procedure
<proc_schema>.<proc_name> (<sqlscript_context_id>)>.
Default Behavior
This is custom documentation. For more information, please visit the SAP Help Portal 68
12/23/2022
Encrypted procedures or functions cannot be exported, if the option ENCRYPTED OBJECT HEADER ONLY is not applied. When
the export target is an encrypted object or if objects, which are referenced by the export object, include an encrypted object,
the export will fail with the error FEATURE_NOT_SUPPORTED. However, when exporting a schema and an encrypted procedure
or function in the schema does not have any dependent objects, the procedure or function will be skipped during the export.
Sample Code
Original Procedure
Sample Code
Export Statement
export all as binary into <path> with encrypted object header only;
Sample Code
Exported create.sql
This approach leads to data ows which are free of side effects. The declarative nature to de ne business logic might require
some deeper thought when specifying an algorithm, but it gives the SAP HANA database freedom to optimize the data ow
which may result in better performance.
The following example shows a simple procedure implemented in SQLScript. To better illustrate the high-level concept, we have
omitted some details.
This is custom documentation. For more information, please visit the SAP Help Portal 69
12/23/2022
big_pub_ids = SELECT publisher AS pid FROM books -- Query Q1 GROUP BY publisher HAVING C
big_pub_books = SELECT title, name, publisher, -- Query Q2 year, price
FROM :big_pub_ids, publishers, books
WHERE pub_id = pid AND pub_id = publisher
AND crcy = :currency;
output_pubs = SELECT publisher, name, -- Query Q3
SUM(price) AS price, COUNT(title) AS cnt FROM :big_pub_books GROUP BY publisher, na
output_year = SELECT year, SUM(price) AS price, -- Query Q4 COUNT(title) AS cnt
FROM :big_pub_books GROUP BY year;
END;
This SQLScript example de nes a read-only procedure that has 2 scalar input parameters and 2 output parameters of type
table. The rst line contains an SQL query Q1, that identi es big publishers based on the number of books they have published
(using the input parameter cnt). Next, detailed information about these publishers along with their corresponding books is
determined in query Q2. Finally, this information is aggregated in 2 different ways in queries Q3 (aggregated per publisher) and
Q4 (aggregated per year) respectively. The resulting tables constitute the output tables of the function.
A procedure in SQLScript that only uses declarative constructs can be completely translated into an acyclic data ow graph
where each node represents a data transformation. The example above could be represented as the data ow graph shown in
the following image. Similar to SQL queries, the graph is analyzed and optimized before execution. It is also possible to call a
procedure from within another procedure. In terms of the data ow graph, this type of nested procedure call can be seen as a
sub-graph that consumes intermediate results and returns its output to the subsequent nodes. For optimization, the sub-graph
of the called procedure is merged with the graph of the calling procedure, and the resulting graph is then optimized. The
optimization applies similar rules as an SQL optimizer uses for its logical optimization (for example lter pushdown). Then the
plan is translated into a physical plan which consists of physical database operations (for example hash joins). The translation
into a physical plan involves further optimizations using a cost model as well as heuristics.
This is custom documentation. For more information, please visit the SAP Help Portal 70
12/23/2022
Table Parameter
Syntax
Description
Table parameters that are de ned in the signature are either input or output parameters. The parameters can be typed either
by using a table type previously de ned with the CREATE TYPE command, or by writing it directly in the signature without any
previously de ned table type.
Example
This is custom documentation. For more information, please visit the SAP Help Portal 71
12/23/2022
The advantage of previously de ned table type is that it can be reused by other procedure and functions. The disadvantage is
that you must take care of its lifecycle.
The advantage of a table variable structure that you directly de ne in the signature is that you do not need to take care of its
lifecycle. In this case, the disadvantage is that it cannot be reused.
Syntax
As a result of the new any table type support, the syntax of table parameters has changed as follows:
Code Syntax
Examples
The following examples illustrate some use cases of the any_table_type parameter for DML and SELECT statements.
Sample Code
This is custom documentation. For more information, please visit the SAP Help Portal 72
12/23/2022
end;
The any_table_type parameter can also be used in other scenarios with different statements.
Sample Code
-- unnest statement
create procedure unst_proc1(in itt table(a int), out ott table(...)) as
begin
tmp = SELECT '1','2','3' as A from :itt;
tmp2 = unnest(ARRAY_AGG(:tmp.a));
ott = select * from :tmp2;
end;
call unst_proc1(ctab1,?);
-- ce functions
create procedure ce_proc1 (out outtab table(...)) as
begin
t = ce_column_table(temptable);
outtab = ce_projection(:t, [b]);
end
call ce_proc1(?);
-- apply filters
CREATE PROCEDURE apply_p1(IN inputtab table(...), IN dynamic_filter_1 VARCHAR(5000)) as
begin
outtab = APPLY_FILTER (:inputtab, :dynamic_filter_1);
select * from :outtab;
end;
This is custom documentation. For more information, please visit the SAP Help Portal 73
12/23/2022
the any_table_type parameter cannot be used within anonymous blocks, other languages or outside the scope of
SQLScript
any_table_type parameters are supported only as input parameter of table UDFs, but not as return parameters
If an output any table type parameter cannot be resolved during procedure creation (for example, out_any_table =
select * from in_any_table), the procedure cannot be called inside SQLScript.
Signature
Local table variables are declared by using the DECLARE keyword. For the referenced type, you can either use a previously
declared table type, or the type de nition TABLE (<column_list_de nition>). The next example illustrates both variants:
You can also directly assign a default value to a table variable by using the DEFAULT keyword or ʻ=’. By default all statements are
allowed all statements that are also supported for the typical table variable assignment.
The table variable can be also agged as read-only by using the CONSTANT keyword. The consequence is that you cannot
override the variable any more. Note that if the CONSTANT keyword is used, the table variable should have a default value, it
cannot be NULL.
An alternative way to declare a table variable is to use the LIKE keyword. You can specify the variable type by using the type of a
persistent table, a view, or another table variable.
This is custom documentation. For more information, please visit the SAP Help Portal 74
12/23/2022
Note
When you declare a table variable using LIKE <table_name>, all the attributes of the columns (like unique, default value,
and so on) in the referenced table are ignored in the declared variable except the not null attribute.
When you use LIKE <table_name> to declare a variable in a procedure, the procedure will be dependent on the
referenced table.
Description
Local table variables are declared by using the DECLARE keyword. A table variable temp can be referenced by using :temp. For
more information, see Referencing Variables. The <sql_identifier> must be unique among all other scalar variables and
table variables in the same code block. However, you can use names that are identical to the name of another variable in a
different code block. Additionally, you can reference those identi ers only in their local scope.
In each block there are table variables declared with identical names. However, since the last assignment to the output
parameter <outTab> can only have the reference of variable <temp> declared in the same block, the result is the following:
N
----
1
In this code example there is no explicit table variable declaration where done, that means the <temp> variable is visible among
all blocks. For this reason, the result is the following:
N
----
2
For every assignment of the explicitly declared table variable, the derived column names and types on the right-hand side are
checked against the explicitly declared type on the left-hand side.
This is custom documentation. For more information, please visit the SAP Help Portal 75
12/23/2022
Another difference, compared to derived types, is that a reference to a table variable without an assignment, returns a warning
during the compilation.
BEGIN
DECLARE a TABLE (i DECIMAL(2,1), j INTEGER);
IF :num = 4
THEN
a = SELECT i, j FROM tab;
END IF;
END;
The example above returns a warning because the table variable <a> is unassigned if <:num> is not 4. This behavior can be
controlled by the con guration parameter UNINITIALIZED_TABLE_VARIABLE_USAGE. Besides issuing a warning, it also offers
the following options:
Create new variable First SQL query assignment Table variable declaration in a block:
tmp = select * from table; DECLARE tmp TABLE(i int);
Variable scope Global scope, regardless of the block where Available in declared block only.
it was rst declared Variable hiding is applied.
Unassigned variable check No warning during the compilation Warning during compilation if it is possible
to refer to the unassigned table variable.
The check is perforrmed only if a table
variable is used.
If both are set, the session variable takes precedence. Setting it to 'ignore_with_warning' has the same effect as
'ignore', except that you additionally get a warning whenever the constraint is ignored. With 'respect', the NOT NULL
constraints (including primary keys) in tables and table types will be taken into consideration but that could invalidate existing
procedures. Consider the following example:
Sample Code
Referencing Variables
Bound variables are referenced by their name (for example, <var>). In the variable reference the variable name is pre xed by
<:> such as <:var>. The procedure or table function describe a data ow graph using their statements and the variables that
connect the statements. The order in which statements are written in a body can be different from the order in which
statements are evaluated. In case a table variable is bound multiple times, the order of these bindings is consistent with the
order they appear in the body. Additionally, statements are only evaluated if the variables that are bound by the statement are
consumed by another subsequent statement. Consequently, statements whose results are not consumed are removed during
optimization.
Example:
In this assignment, the variable <lt_expensive_books> is bound. The <:it_books> variable in the FROM clause refers to an IN
parameter of a table type. It would also be possible to consume variables of type table in the FROM clause which were bound by
an earlier statement. <:minPrice> and <:currency> refer to IN parameters of a scalar type.
Syntax
Syntax Elements
This is custom documentation. For more information, please visit the SAP Help Portal 77
12/23/2022
De nes the parameter used to refer to the given expression.
The parameter name de nition. PLACEHOLDER is used for place holder parameters and HINT for hint parameters.
Description
Using column view parameter binding it is possible to pass parameters from a procedure/scripted calculation view to a
parameterized column view e.g. hierarchy view, graphical calculation view, scripted calculation view.
Examples:
Example 1 - Basic example
In the following example, assume you have the calculation view CALC_VIEW with placeholder parameters "client" and
"currency". You want to use this view in a procedure and bind the values of the parameters during the execution of the
procedure.
CREATE PROCEDURE my_proc_caller (IN in_client INT, IN in_currency INT, OUT outtab mytab_t) LANGUAGE
BEGIN
outtab = SELECT * FROM CALC_VIEW (PLACEHOLDER."$$client$$" => :in_client , PLACEHOLDER."$$curre
END;
The following example assumes that you have a hierarchical column view "H_PROC" and you want to use this view in a
procedure. The procedure should return an extended expression that will be passed via a variable.
CALL "EXTEND_EXPRESSION"('',?);
CALL "EXTEND_EXPRESSION"('subtree("B1")',?);
Description
The MAP_MERGE operator is used to apply each row of the input table to the mapper function and unite all intermediate result
tables. The purpose of the operator is to replace sequential FOR-loops and union patterns, like in the example below, with a
parallel operator.
This is custom documentation. For more information, please visit the SAP Help Portal 78
12/23/2022
Sample Code
DO (OUT ret_tab TABLE(col_a nvarchar(200))=>?)
BEGIN
DECLARE i int;
DECLARE varb nvarchar(200);
t = SELECT * FROM tab;
FOR i IN 1 .. record_count(:t) DO
varb = :t.col_a[:i];
CALL mapper(:varb, out_tab);
ret_tab = SELECT * FROM :out_tab
UNION SELECT * FROM :ret_tab;
END FOR;
END;
Note
The mapper procedure is a read-only procedure with only one output that is a tabular output.
Syntax
The rst input of the MAP_MERGE operator is th mapper table <table_or_table_variable> . The mapper table is a table
or a table variable on which you want to iterate by rows. In the above example it would be table variable t.
The second input is the mapper function <mapper_identifier> itself. The mapper function is a function you want to have
evaluated on each row of the mapper table <table_or_table_variable>. Currently, the MAP_MERGE operator supports
only table functions as <mapper_identifier>. This means that in the above example you need to convert the mapper
procedure into a table function.
You also have to pass the mapping argument <table_or_table_variable>.<column_Name> as an input of the mapper
function. Going back to the example above, this would be the value of the variable varb.
Example
As an example, let us rewrite the above example to leverage the parallel execution of the MAP_MERGE operator. We need to
transform the procedure into a table function, because MAP_MERGE only supports table functions as <mapper_identifier>.
Sample Code
CREATE FUNCTION mapper (IN a nvarchar(200))
RETURNS TABLE (col_a nvarchar(200))
AS
BEGIN
ot = SELECT :a AS COL_A from dummy;
RETURN :ot;
END;
After transforming the mapper procedure into a function, we can now replace the whole FOR loop by the MAP_MERGE operator.
This is custom documentation. For more information, please visit the SAP Help Portal 79
12/23/2022
Syntax
Code Syntax
MAP_REDUCE(<input table/table variable name>, <mapper specification>, <reducer specification>)
<mapper spec> ::= <mapper TUDF>(<list of mapper parameters>) group by <list of columns in the TUD
<reducer spec> ::= <reduce TUDF>(<list of reducer TUDF parameters>)
| <reduce procedure>(<list of reducer procedure parameters>)
<mapper parameter> ::= <table/table variable name>.<column name> | <other scalar parameter>
<reducer TUDF parameter> ::= <ID> | <ID>.<key column name> | <other scalar parameter>
<reducer procedure parameter> ::= <reducer TUDF parameter> | <output table parameter>
Example
We take as an example a table containing sentences with their IDs. If you want to count the number of sentences that contain a
certain character and the number of occurrences of each character in the table, you can use the MAP_REDUCE operator in the
following way:
Mapper Function
Sample Code
Mapper Function
This is custom documentation. For more information, please visit the SAP Help Portal 80
12/23/2022
Reducer Function
Sample Code
Reducer Function
Sample Code
do begin
declare result table(c varchar, stmt_freq int, total_freq int);
result = MAP_REDUCE(tab, mapper(tab.id, tab.sentence) group by c as X,
reducer(X.c, X));
select * from :result order by c;
end;
1. The mapper TUDF processes each row of the input table and returns a table.
2. When all rows are processed by the mapper, the output tables of the mapper are aggregated into a single big table (like
MAP_MERGE).
This is custom documentation. For more information, please visit the SAP Help Portal 81
12/23/2022
4. For each group, the key values are separated from the table. The grouped table without key columns is called 'value
table'. The order of the rest of columns is preserved. It is possible to have multiple key columns. If the layout of the
output table is table(a int, b varchar, c timestamp, d int) and the key column is b and c, the layout of
the value table is table(a int, d int).
This is custom documentation. For more information, please visit the SAP Help Portal 82
12/23/2022
5. The reducer TUDF (or procedure) processes each group and returns a table (or multiple tables).
6. When all groups are processed, the output tables of the reducer are aggregated into a single big table (or multiple
tables, if the reducer is a procedure).
This is custom documentation. For more information, please visit the SAP Help Portal 83
12/23/2022
create procedure reducer_procedure(in c varchar, in values table(id int, freq int), out otab table
reads sql data as begin
otab = select :c as c, count(distinct(id)) as stmt_freq, sum(freq) as total_freq from :values;
end;
do begin
declare result table(c varchar, stmt_freq int, total_freq int);
MAP_REDUCE(tab, mapper(tab.id, tab.sentence) group by c as X,
reducer_procedure(X.c, X, result));
select * from :result order by c;
end;
Sample Code
create function reducer(in c varchar, in values table(id int, freq int), in some_extra_arg1 int,
returns table (c varchar, stmt_freq int, total_freq int) as begin
...
end;
do begin
declare result table(c varchar, stmt_freq int, total_freq int);
declare extra_arg1, extra_arg2 int;
This is custom documentation. For more information, please visit the SAP Help Portal 84
12/23/2022
declare extra_arg3, extra_arg4 table(...);
... more extra args ...
result = MAP_REDUCE(tab, mapper(tab.id, tab.sentence, :extra_arg1, :extra_arg3, ...) group by
reducer(X.c, X, :extra_arg2, :extra_arg4, 1+1, ...));
select * from :result order by c;
end;
Note
There is no restriction about the order of input table parameters, input column parameters, extra parameters and so on. It is
also possible to use default parameter values in mapper/reducer TUDFs or procedures.
Restrictions
The following restrictions apply:
Only Mapper and Reducer are supported (no other Hadoop functionalities like group comparator, key comparator and so
on).
The alias ID in the mapper output and the ID in the Reducer TUDF (or procedure) parameter must be the same.
The Reducer procedure should be a read-only procedure and cannot have scalar output parameters.
Related Information
Map Merge Operator
Hints
The SQLScript compiler combines statements to optimize code. Hints enable you to block or enforce the inlining of table
variables.
Note
Using a HINT needs to be considered carefully. In some cases, using a HINT could end up being more expensive.
Block Statement-Inlining
The overall optimization guideline in SQLScript states that dependent statements are combined if possible. For example, you
have two table variable assignments as follows:
There can be situations, however, when the combined statements lead to a non-optimal plan and as a result, to less-than-
optimal performance of the executed statement. In these situations it can help to block the combination of speci c statements.
Therefore SAP has introduced a HINT called NO_INLINE. By placing that HINT at the end of select statement, it blocks the
combination (or inlining) of that statement into other statements. An example of using this follows:
By adding WITH HINT (NO_INLINE) to the table variable tab, you can block the combination of that statement and ensure
that the two statements are executed separately.
Enforce Statement-Inlining
Using the hint called INLINE helps in situations when you want to combine the statement of a nested procedure into the outer
procedure.
Currently statements that belong to nested procedure are not combined into the statements of the calling procedures. In the
following example, you have two procedures de ned.
By executing the procedure, ProcCaller, the two table assignments are executed separately. If you want to have both
statements combined, you can do so by using WITH HINT (INLINE) at the statement of the output table variable. Using this
example, it would be written as follows:
Now, if the procedure, ProcCaller, is executed, then the statement of table variable tab2 in ProcInner is combined into
the statement of the variable, tab, in the procedure, ProcCaller:
SELECT I FROM (SELECT I FROM T WITH HINT (INLINE)) where I > 10;
ROUTE_TO Hint
This is custom documentation. For more information, please visit the SAP Help Portal 86
12/23/2022
The ROUTE_TO hint routes the query to the speci ed volume ID or service type.
Syntax
Code Syntax
<servicetype> ::= 'indexserver' | 'xsengine' | 'scriptserver' | 'dpserver' | 'computeserver'
Description
The ROUTE_TO hint can be used with either "volume ID", or "service type". If the "volume id" is provided, the statement is
intended to be routed to the speci ed volume. But if the "service type" (a string argument that can have values like
"indexserver", "computeserver" and so on) is provided within the hint, the statement can be routed to all nodes related to this
service.
Example
Sample Code
create table mytab(a int);
insert into mytab values(1);
For more information, see Orchestration Logic and Declarative SQLScript Logic.
Scalar Variables
Syntax
This is custom documentation. For more information, please visit the SAP Help Portal 87
12/23/2022
DECLARE <sql_identifier> [{,<sql_identifier> }...] [CONSTANT] <type> | AUTO [NOT NULL] <proc_defaul
Syntax Elements
Description
Local variables are declared by using the DECLARE keyword and they can optionally be initialized with their declaration. By
default scalar variables are initialized with NULL. A scalar variable var can be referenced as described above by using :var.
Tip
If you want to access the value of the variable, use :var in your code. If you want to assign a value to the variable, use var in
your code.
Assignment is possible multiple times, overwriting the previous value stored in the scalar variable. Assignment is performed
using the = operator.
Recommendation
Even though the := operator is still available, SAP recommends that you use only the = operator in de ning scalar variables.
Example
CREATE PROCEDURE proc (OUT z INT) LANGUAGE SQLSCRIPT READS SQL DATA
AS
BEGIN
DECLARE a int;
DECLARE b int = 0;
DECLARE c int DEFAULT 0;
This examples shows various ways for making declarations and assignments.
Note
You can assign a scalar UDF to a scalar variable with 1 output or more than 1 output, as depicted in the following code
examples.
This is custom documentation. For more information, please visit the SAP Help Portal 88
12/23/2022
Assign a scalar UDF to a scalar variable:
Syntax
Code Syntax
SELECT <select_list> INTO <var_name_list> [DEFAULT <scalar_expr_list>] <from_clause>
[<where_clause>]
[<group_by_clause>]
[<having_clause>]
[{<set_operator> <subquery>, ... }]
[<order_by_clause>]
[<limit>] ;
Description
It is also possible to use a single array element as the result of SELECT INTO and EXEC INTO. The syntax of the INTO clause was
extended as follows:
Sample Code
DROP TABLE T1;
CREATE TABLE T1 (A INT NOT NULL, B VARCHAR(10));
DO BEGIN
DECLARE A_COPY INT ARRAY;
DECLARE B_COPY VARCHAR(10) ARRAY;
SELECT A, B INTO A_COPY[1], B_COPY[1] DEFAULT -2+1, NULL FROM T1;
SELECT :A_COPY[1], :B_COPY[1] from dummy;
This is custom documentation. For more information, please visit the SAP Help Portal 89
12/23/2022
--(A_COPY[1],B_COPY[1]) = (-1,?), use default value
EXEC 'SELECT A FROM T1' INTO A_COPY[1] DEFAULT 2;
SELECT :A_COPY[1], :B_COPY[1] from dummy;
--(A_COPY[1]) = (2), exec into statement with default value
INSERT INTO T1 VALUES (0, 'sample0');
SELECT A, B INTO A_COPY[1], B_COPY[1] DEFAULT 5, NULL FROM T1;
SELECT :A_COPY[1], :B_COPY[1] from dummy;
--(A_COPY[1],B_COPY[1]) = (0,'sample0'), executed as-is
END;
Example
DO BEGIN
DECLARE A_COPY INT;
DECLARE B_COPY VARCHAR(10);
CREATE ROW TABLE T1 (A INT NOT NULL, B VARCHAR(10));
SELECT A, B INTO A_COPY, B_COPY DEFAULT -2+1, NULL FROM T1;
--(A_COPY,B_COPY) = (-1,?), use default value
EXEC 'SELECT A FROM T1' INTO A_COPY DEFAULT 2;
--(A_COPY) = (2), exec into statement with default value
INSERT INTO T1 VALUES (0, 'sample0');
SELECT A, B INTO A_COPY, B_COPY DEFAULT 5, NULL FROM T1;
--(A_COPY,B_COPY) = (0,'sample0'), executed as-is
END;
Related Information
EXEC
EXECUTE IMMEDIATE
CREATE PROCEDURE
Description
SQLScript now supports SELECT as an SQL query within scalar expressions.
If the SELECT statement returns a 1*1 result set (1 row and 1 column), that result set can be used directly as an expression.
Examples
Sample Code
x = (SELECT TOP 1 val from mytab) * 10; ...
This is custom documentation. For more information, please visit the SAP Help Portal 90
12/23/2022
The result set of the sub-query is expected to have a 1*1 size but if the result set has 0 records, a null value will be returned. In
any other case, you will get an error message.
If the right-hand side of an assignment contains only a SELECT statement (even with parenthesizes, for example: x =
(SELECT * FROM tab)), it will be always be treated as a table variable assignment. The workaround is to use SELECT INTO.
do begin
declare n int;
n = (select i from mytab); -- ERR-01310: scalar type is not allowed: N
end;
do begin
declare n int;
select i into n from mytab; -- workaround
end;
Limitations
Auto type is not supported.
do begin
declare n auto = (select 10 from dummy) + 1; -- ERR-00007: feature not supported: subquery in aut
end;
Table Variables
Table variables are, as the name suggests, variables with a reference to tabular data structure. The same applies to tabular
parameters, unless speci ed otherwise.
Related Information
This is custom documentation. For more information, please visit the SAP Help Portal 91
12/23/2022
Table Variable Type De nition
<table_variable>.<column_name>[<index>]
For example, writing to certain cell of a table variable is illustrated in the following example. Here we simply change the value in
the second row of column A.
Reading from a certain cell of a table variable is done in similar way. Note that for the read access, the ʻ:’ is needed in front of
the table variable.
The same rules apply for <index> as for the array index. That means that the <index> can have any value from 1 to 2^31 and
that SQL Expression and Scalar User De ned Functions (Scalar UDF) that return a number also can be used as an index.
Instead of using a constant scalar values, it is also possible to use a scalar variable of type INTEGER as <index>.
Restrictions:
Not applicable in SQL queries like SELECT :MY_TABLE_VAR.COL[55] AS A FROM DUMMY . You need to assign the value
to be used to a scalar variable rst.
Note
This is custom documentation. For more information, please visit the SAP Help Portal 92
12/23/2022
For all position expressions the valid values are in the interval from 1 to 2^31-1.
All existing data records at positions starting from the given index onwards, are moved to the next position. If the index is
greater than the original table size, the records between the inserted record and the original last record are initialized with
NULL values.
Sample Code
CREATE TABLE TAB(K VARCHAR(20), V INT);
IF IS_EMPTY(:IT) THEN
RETURN;
END IF;
CALL ADD_SUM(TAB, ?)
K V
------------------
Section A 0
A 7.582
A 8.650
Sum A 16.232
Section B 0
B 4.730
B 8.602
Sum B 13.332
Section C 0
C 1.960
This is custom documentation. For more information, please visit the SAP Help Portal 93
12/23/2022
C 3.836
C 3.257
Sum C 9.053
Section D 0
D 1.318
Sum D 1.318
If you do not specify an index (position), the data record will be appended at the end.
Sample Code
CREATE TABLE SOURCE(K VARCHAR(20), PCT DECIMAL(5, 2), V DECIMAL(10, 2));
CREATE TABLE TARGET(K VARCHAR(20), V DECIMAL(10, 2));
CREATE PROCEDURE SPLIT(IN IT SOURCE, OUT OT1 TARGET, OUT OT2 TARGET) AS
BEGIN
DECLARE IDX INT;
DECLARE MAXIDX INT = RECORD_COUNT(:IT);
OT1 OT2
K V K V
------------------------
A 43,99 A 690,43
A 214,63 A 207,64
B 272,15 B 90,38
C 117,32 C 17,21
C 2.197,59 C 524,9
Note
The values for the omitted columns are initialized with NULL values.
Code Syntax
:<target_table_var>[.(<column_list>)].INSERT(:<source_table_var>[, <position>])
This is custom documentation. For more information, please visit the SAP Help Portal 94
12/23/2022
If no position is speci ed, the values will be appended to the end. The positions starts from 1 - NULL and all values smaller than 1
are invalid. If no column list is speci ed, all columns of the table are insertion targets.
Sample Code
Usage Example
:tab_a.insert(:tab_b);
:tab_a.(col1, COL2).insert(:tab_b);
:tab_a.INSERT(:tab_b, 5);
:tab_a.("a","b").insert(:tab_b, :index_to_insert);
The mapping which column of the source table is inserted into which column of the target table is done according to the column
position. The source table has to have the same number of columns as the target table or as the number of columns in the
column list.
If SOURCE_TAB has columns (X, A, B, C) and TARGET_TAB has columns (A, B, C, D), then
:target_tab.insert(:source_tab) will insert X into A, A into B, B into C and C into D.
If another order is desired, the column sequence has to speci ed in the column list for the TARGET_TAB. for example
:TARGET_TAB.(D, A, B, C).insert(:SOURCE_TAB) will insert X into D, A into A, B into B and C into C.
The types of the columns have to match, otherwise it is not possible to insert data into the column. For example, a column of
type DECIMAL cannot be inserted in an INTEGER column and vice versa.
Sample Code
Iterative Result Build
CALL P(?)
K V
--------
C 3.890
B 2.045
B 2.067
A 1.123
This is custom documentation. For more information, please visit the SAP Help Portal 95
12/23/2022
Note
The index must be speci ed.
Note
The values for the omitted columns remain unchanged.
Sample Code
CREATE TABLE TAB (V1 INT, V2 INT);
INSERT INTO TAB VALUES(599, 7442);
INSERT INTO TAB VALUES(5083, 4226);
INSERT INTO TAB VALUES(7507, 3253);
INSERT INTO TAB VALUES(8721, 1453);
INSERT INTO TAB VALUES(8072, 2749);
V1 V2
------------
2.749 8.072
1.453 8.721
3.253 7.507
4.226 5.083
7.442 599
Note
You can also set values at a position outside the original table size. Just like with INSERT, the records between the original
last record and the newly inserted records are initialized with NULL values.
:<table_variable>.DELETE([ <index> ])
This is custom documentation. For more information, please visit the SAP Help Portal 96
12/23/2022
If the index is outside the table size, no operation is performed.
Sample Code
CREATE TABLE HIER(PARENT VARCHAR(30), CHILD VARCHAR(30));
INSERT INTO HIER VALUES ('root', 'A');
INSERT INTO HIER VALUES ('root', 'B');
INSERT INTO HIER VALUES ('A', 'C');
INSERT INTO HIER VALUES ('C', 'D');
INSERT INTO HIER VALUES ('A', 'E');
INSERT INTO HIER VALUES ('E', 'F');
INSERT INTO HIER VALUES ('E', 'G');
CREATE PROCEDURE CALC_LEVEL (IN IT HIER, IN ROOT VARCHAR(30), OUT OT_LEVEL TABLE(NODE VARCHAR(30
BEGIN
DECLARE STACK TABLE(NODE VARCHAR(30), L INT);
NODE L
-------
root 1
A 2
B 2
C 3
E 3
D 4
F 4
G 4
To delete blocks of records from table variables, you can use the following syntax:
If the starting index is greater than the table size, no operation is performed. If the end index is smaller than the starting index,
an error occurs. If the end index is greater than the table size, all records from the starting index to the end of the table are
deleted.
Sample Code
CREATE TABLE PROD_PER_DATE (PROD_NAME VARCHAR(20), PROD_DATE DATE, NUM_DELTA INT);
INSERT INTO PROD_PER_DATE VALUES ('PC', '20170105', 100);
INSERT INTO PROD_PER_DATE VALUES ('PC', '20170106', 50);
INSERT INTO PROD_PER_DATE VALUES ('PC', '20170117', 200);
INSERT INTO PROD_PER_DATE VALUES ('Notebook', '20170320', 30);
INSERT INTO PROD_PER_DATE VALUES ('Notebook', '20170322', 310);
INSERT INTO PROD_PER_DATE VALUES ('Phone', '20170121', 20);
INSERT INTO PROD_PER_DATE VALUES ('Phone', '20170205', 50);
This is custom documentation. For more information, please visit the SAP Help Portal 97
12/23/2022
IF TO_IDX = 0 THEN
TO_IDX = IDX;
END IF;
:INTERVALS.INSERT((FROM_IDX, TO_IDX));
IDX = RECORD_COUNT(:INTERVALS);
WHILE IDX > 0 DO
:OT_RESULT.DELETE(:INTERVALS.FROM_IDX[IDX] .. :INTERVALS.TO_IDX[IDX]);
IDX = IDX - 1;
END WHILE;
END;
Note
The algorithm works with positive delta values only.
:<table_variable>.DELETE(<array_of_integers>)
The provided array expression contains indexes pointing to records which shall be deleted from the table variable. If the array
contains an invalid index (for example, zero), an error occurs.
This is custom documentation. For more information, please visit the SAP Help Portal 98
12/23/2022
Sample Code
CREATE TABLE PROD_PER_DATE (PROD_NAME VARCHAR(20), PROD_DATE DATE, NUM_DELTA INT);
INSERT INTO DATE_VALUES VALUES ('PC', '20170105', 100);
INSERT INTO DATE_VALUES VALUES ('PC', '20170106', -50);
INSERT INTO DATE_VALUES VALUES ('PC', '20170117', 200);
INSERT INTO DATE_VALUES VALUES ('Notebook', '20170320', 300);
INSERT INTO DATE_VALUES VALUES ('Notebook', '20170322', -10);
INSERT INTO DATE_VALUES VALUES ('Phone', '20170121', 20);
INSERT INTO DATE_VALUES VALUES ('Phone', '20170205', 50);
:OT_RESULT.DELETE(:DEL_IDX);
END;
Note
This algorithm works also with negative delta values.
UNNEST Function
The UNNEST function combines one or many arrays and/or table variables. The result table includes a row for each element of
the speci ed array. The result of the UNNEST function needs to be assigned to a table variable. The syntax is:
This is custom documentation. For more information, please visit the SAP Help Portal 99
12/23/2022
<unnest_param> ::= :table_variable
| :array_variable
| :array_function
For example, the following statements convert the array arr_id of type INTEGER and the array arr_name of type
VARCHAR(10) into a table and assign it to the tabular output parameter rst:
For multiple arrays, the number of rows will be equal to the largest cardinality among the cardinalities of the arrays. In the
returned table, the cells that are not corresponding to any elements of the arrays are lled with NULL values. The example
above would result in the following tabular output of rst:
:ARR_ID :ARR_NAME
-------------------
1 name1
2 name2
? name3
The returned columns of the table can also be explicitly named be using the AS clause. In the following example, the column
names for :ARR_ID and :ARR_NAME are changed to ID and NAME.
ID NAME
-------------------
1 name1
2 name2
? name3
As an additional option, an ordinal column can be speci ed by using the WITH ORDINALITY clause.
The ordinal column will then be appended to the returned table. An alias for the ordinal column needs to be explicitly speci ed.
The next example illustrates the usage. SEQ is used as an alias for the ordinal column:
This is custom documentation. For more information, please visit the SAP Help Portal 100
12/23/2022
The result of calling this procedure is, as follows:
AMOUNT SEQ
----------------
10 1
20 2
Note
The UNNEST function cannot be referenced directly in a FROM clause of a SELECT statement.
It is also possible to use table variables in the UNNEST function. While for arrays the associated column-speci er list entry
needs to contain a single column name, the associated entry for a table variable must be either '*' or a projection aliasing list. '*'
means that all columns of the input table should be included in the result. With the projection aliasing list, it is possible to
specify a subset of the columns of the input table and to rename them in order to avoid name con icts (a result must not
contain multiple columns with the same name).
Sample Code
create column table tab0(a int);
insert into tab0 values(1);
insert into tab0 values(2);
insert into tab0 values(3);
do begin
t0 = select * from tab0 order by a asc;
t1 = select * from tab0 order by a desc;
lt = unnest(:t0, :t1) as (*, (a as b));
select * from :lt;
end;
do begin
t0 = select * from tab0 order by a asc;
t1 = select * from tab0 order by a desc;
lt = unnest(:t0, :t1) as (*, (a as b, a as c));
select * from :lt;
end;
If the result table variable is declared explicitly, it may contain columns with NOT NULL types. Due to the fact that the columns
are adjusted to the longest column, this scenario may lead to a run-time error. The following table shows the NOT NULL
behavior:
Note
Array types are always nullable.
Note
This is custom documentation. For more information, please visit the SAP Help Portal 101
12/23/2022
Default Column Names
If there is no column speci er list, the column names for arrays and the ordinality column in the result table will be
generated. A generated name always begins with "COL" and is followed by a number, which refers to the column index in the
result table. For example, if the third column in the result table has a generated name, it is "COL3". However, if this name is
already occupied because the input table variable contains a column with this name, the index number will be increased to
generate an unoccupied column name (if "COL3" is used, "COL4" is the next candidate). This behavior is similar for the
ordinality column. This column is named "ORDINALITY" (without index), if this name is available and "ORDINALITY" + INDEX
(starting from 1), if "ORDINALITY" is already occupied.
IS_EMPTY takes as an argument a <table_name> or a <table_variable>. It returns true if the table or table variable is empty
and false otherwise.
You can use IS_EMPTY in conditions like in IF-statements or WHILE-loops. For instance, in the next example IS_EMPTY is used in
an IF-statement:
Note
Note that the IS_EMPTY cannot be used in SQL queries or expressions.
RECORD_COUNT takes as the argument <table_name> or <table_variable> and returns the number of records of type BIGINT.
You can use RECORD_COUNT in all places where expressions are supported such as IF-statements, loops or scalar assignments.
In the following example it is used in a loop:
This is custom documentation. For more information, please visit the SAP Help Portal 102
12/23/2022
END FOR;
END
Note
RECORD_COUNT cannot be used in queries.
Syntax
Description
The size of the column list and the value list must be the same, columns and values are matched by their position in the list. The
<start_position> is optional, the default is 1 ( rst position), which is equal to scanning all data.
The search function itself can be used in further expressions, but not directly in SQL statements.
The position of the rst matching record is returned (or NULL, if no record matches). This result can be used in conjunction with
other table variable operators (DELETE, UPDATE).
Example
Sample Code
DECLARE LT1 TABLE ("Key1"…, "Key2"…, "Val1"…);
LT1 = … – see Table LT1 Initial State
pos = :LT1.SEARCH (("Key1", "Key2"), ('I', 3)); – pos = NULL (not found)
:LT1.INSERT(('I', 3, 'X')); –- see Table LT1 after a Single Insert
pos = :LT1.SEARCH(("Key1", "Key2"), ('M', 3)); – pos = 5
:LT1.DELETE(pos);
val = LT1."Val1"[:LT1.SEARCH(("Key1", "Key2"), ('E', 5))]; – val = 'V12'
A 1 V11
E 5 V12
B 6 V13
E 7 V14
This is custom documentation. For more information, please visit the SAP Help Portal 103
12/23/2022
M 3 V15
A 1 V11
E 5 V12
B 6 V13
E 7 V14
M 3 V15
I 3 X
A 1 V11
E 5 V12
B 6 V13
E 7 V14
I 3 X
INSERT
UPDATE
DELETE
The syntax of the statements is identical with that for manipulating persistent tables. The only difference is that you need to
mark the variables by using a colon.
Constraints
The DML statements for table variables support the following constraint checks:
Primary key
NOT NULL
This is custom documentation. For more information, please visit the SAP Help Portal 104
12/23/2022
The constraints can be de ned in both the user-de ned table type and in the declaration, similarly to the persistent table
de nition.
Conversion
If you need to combine DML statements with other types of statements for one data set, you need to use multiple table
variables. It is possible to convert data between a variable used in a DML statement and a variable not used in a DML
statement in both directions.
Note
Both variables are declared the same way, that is at declaration time there is no difference between variables used in a DML
statement and variables not used in a DML statement. In both directions, the conversion implies a data copy.
Use Cases
This is custom documentation. For more information, please visit the SAP Help Portal 105
12/23/2022
You can use DML statements if your scenario relies mainly on SQL statements, especially if you need to utilize a complex SQL
logic for manipulation of your data, like:
constraint checks
In other cases, it is recommended to use the SQLScript table variable operators for manipulation of table variable data because
they offer a better performance, can be combined with other table variable relevant statements and do not imply any
restriction with regards to procedure or function parameter handling.
Note
The primary key check can also be accomplished by using sorted table variables.
Limitations
DML statements on table variables cannot be used in autonomous transactions and parallel execution blocks.
Neither input, nor output procedure or function parameters can be manipulated with DML statements.
Introduction
Sorted table variables are a special kind of table variables designed to provide efficient access to their data records by means of
a de ned key. They are suitable for usage in imperative algorithms operating on mass data. The data records of sorted table
variables are always sorted by a search key which is speci ed in the data type of the variable. When accessing the data via the
SQLScript search operator, the efficient binary search is utilized, if possible.
Search Key
The search key can be any subset of the table variable columns. The order of the columns in the search key de nition is
important: the data records are rst sorted by the rst search key column, then by the second search key column and so on.
Note
The table LT is sorted by columns B, A, C:
Position A B C D
1 0 1 10 100
2 2 1 15 200
3 1 2 3 150
4 1 2 5 30
To see how the search key is utilized, check the explanation below about the table variable search operator.
Primary Key
Sorted table variables also allow primary key speci cation. The primary key must consist exactly of the search key columns. The
uniqueness of the primary key is checked in every operation on the table variable (table assignment, insert operator, and so on).
If the uniqueness is violated, the corresponding error is thrown.
CREATE TYPE <name> AS TABLE (<column list>) SQLSCRIPT SEARCH KEY(<key list>)
Variable Declaration
The search key can also be speci ed as part of a variable declaration:
In the second case, the table type must not include any search key de nition.
CREATE PROCEDURE <proc> (IN <param> TABLE(<column list>) SEARCH KEY(<key list>))
CREATE PROCEDURE <proc> (IN <param> <table type> SEARCH KEY(<key list>))
In the second case, the table type must not include any search key de nition.
The input sorted table variables are re-sorted on call, unless a sorted table variable with a compatible key was provided (in this
case, no re-sorting is necessary).
Input sorted table variables cannot be modi ed within the procedure or the function.
For outermost calls, the result sets corresponding to output sorted table variables are sorted according to the search key, using
the ORDER BY clause. Thus you can ensure that the output table parameters have a de ned sequence of the data records.
For sub-calls, the sorted outputs can be assigned to any kind of table variable - unsorted, or sorted with another search key (this
requires a copy and/or a resorting). The usual use case should be indeed an assignment to a sorted table variable with the
same search key (this requires neither a copy nor a resorting).
:LT.SEARCH(B, 1) You search by column B. Binary search can be applied and the 1st
data record is found.
:LT.SEARCH((B, A), (1, 2)) You search by columns B, A. Binary search can be applied and the
2nd data record is found.
:LT.SEARCH((B, C), (1, 15)) You search by columns B, C. Binary search can be applied only for
column B (B = 1), because the column A, which would be the next
search key column, is not provided. The binary search narrows
down the search interval to 1..2 and this interval is searched
sequentially for C = 200 and the 2nd data record is found.
However, if you search by the complete search key (all search key columns are speci ed) and there is no matching record, a
negative value is returned instead of NULL. The absolute value of the return value indicates the position where a data record
with the speci ed key values would be inserted in to keep the sorting.
:LT.SEARCH(B, 3) The full search key was not speci ed and there is no matching data
record. The result is NULL.
:LT.SEARCH((B, A, C), (1, 2, 20)) The full search key was speci ed and there is no matching data
record. The result is -3, because a data record having B = 1, A = 2,
C = 20 would have to be inserted at position 3.
This allows you to insert a missing data record directly at the correct position. Otherwise the insert operator would have to
search for this position once more.
Example:
Sample Code
This is custom documentation. For more information, please visit the SAP Help Portal 108
12/23/2022
Sample Code
A table variable has 3 search key columns and you iterate over data records having a speci c key value combination for the
rst two search key columns.
Insert operator
The insert operator without explicit position speci cation inserts the data record(s) at the correct positions
taking the sorting de nition into account.
The insert operator with explicit position speci cation checks if the sorting would be violated. If so, an error is
raised and no data is inserted.
When inserting a table variable into a sorted table variable with explicit position speci cation, the input table
variable is not re-sorted, it must comply with the sorting de nition.
The highest explicitly speci ed position for insertion is the current table variable size increased by one (otherwise,
empty data records would be created, which may violate the sorting).
It is not allowed to modify not existing data records (this would lead to creation of new data records and possibly
sorting violation).
As mentioned above, if a primary key is de ned, then its uniqueness is checked as well.
Limitations
This is custom documentation. For more information, please visit the SAP Help Portal 109
12/23/2022
The following data types are not supported for the search key:
LOB types
Description
It is possible to declare a variable without specifying its type explicitly and let SQLScript determine the type automatically. This
auto type derivation can be used for scalar variables, tables and arrays.
Syntax
Code Syntax
DECLARE <var> AUTO = <value>
Note
The default value is mandatory and cannot be omitted.
Note
The existing syntax for de nition of scalar and table variables is expanded as follows:
Code Syntax
Local Auto Scalar Variables
Code Syntax
Local Auto Table Variables
Caution
Potential incompatibility
The new feature may introduce some problems with existing procedures or functions, since AUTO is now interpreted as a
keyword with higher precedence than a table or a table type named AUTO. The workaround for this incompatibility is to use
SCHEMA.AUTO or quoted "AUTO" to interpret it as table type.
Sample Code
Example of incompatibility
This is custom documentation. For more information, please visit the SAP Help Portal 110
12/23/2022
Sample Code
Workaround
Examples
Sample Code
declare var1 auto = 1.0;
declare arr1 auto = array(1, 2);
declare tab1 auto = select 1 as x from dummy;
VARCHAR(n) VARCHAR(MAX_LENGTH)
NVARCHAR(n) NVARCHAR(MAX_LENGTH)
ALHPANUM(n) ALPHANUM(MAX_LENGTH)
VARBINARY(n) VARBINARY(MAX_LENGTH)
DECIMAL(p, s) DECIMAL
SMALLDECIMAL DECIMAL
Auto type cannot be used, if the default value contains one of the following:
System variables
This is custom documentation. For more information, please visit the SAP Help Portal 111
12/23/2022
To set the value of a global session variable you use the following syntax:
While <key> can only be a constant string or a scalar variable, <values> can be any expression, scalar variable or function
which returns a value that is convertible to string. Both have maximum length of 5000 characters. The session variable cannot
be explicitly typed and is of type string. If <value> is not of type string the value will be implicitly converted to string.
The next examples illustrate how you can set the value of a session variable in a procedure:
To retrieve the session variable, the function SESSION_CONTEXT (<key>) can be used.
For more information on SESSION_CONTEXT, see SESSION_CONTEXT in the SAP HANA SQL and System Views Reference on
the SAP Help Portal.
For example, the following function retrieves the value of session variable 'MY_VAR'
Note
SET <key> = <value> cannot not be used in functions and procedure agged as READ ONLY (scalar and table functions
are implicitly READ ONLY).
Note
The maximum number of session variables can be con gured with the con guration parameter max_session_variables under
the section session (min=1, max=5000). The default is 1024.
Note
Session variables are null by default and can be reset to null using UNSET <key>. For more information on UNSET, see
UNSET in the SAP HANA SQL and System Views Reference.
This is custom documentation. For more information, please visit the SAP Help Portal 112
12/23/2022
call nested_block(?)
--> OUT:[2]
From this result you can see that the inner most nested block value of 3 has not been passed to the val variable. Now let's
rede ne the procedure without the inner most DECLARE statement:
Now when you call this modi ed procedure the result is:
call nested_block(?)
--> OUT:[3]
From this result you can see that the innermost nested block has used the variable declared in the second level nested block.
This is custom documentation. For more information, please visit the SAP Help Portal 113
12/23/2022
Conditionals
CREATE PROCEDURE nested_block_if(IN inval INT, OUT val INT) LANGUAGE SQLSCRIPT READS SQL DATA AS
BEGIN
DECLARE a INT = 1;
DECLARE v INT = 0;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
val = :a;
END;
v = 1 /(1-:inval);
IF :a = 1 THEN
DECLARE a INT = 2;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
val = :a;
END;
v = 1 /(2-:inval);
IF :a = 2 THEN
DECLARE a INT = 3;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
val = :a;
END;
v = 1 / (3-:inval);
END IF;
v = 1 / (4-:inval);
END IF;
v = 1 / (5-:inval);
END;
call nested_block_if(1, ?)
-->OUT:[1]
call nested_block_if(2, ?)
-->OUT:[2]
call nested_block_if(3, ?)
-->OUT:[3]
call nested_block_if(4, ?)
--> OUT:[2]
call nested_block_if(5, ?)
--> OUT:[1]
While Loop
CREATE PROCEDURE nested_block_while(OUT val INT) LANGUAGE SQLSCRIPT READS SQL DATA AS
BEGIN
DECLARE v int = 2;
val = 0;
WHILE v > 0
DO
DECLARE a INT = 0;
a = :a + 1;
val = :val + :a;
v = :v - 1;
END WHILE;
END;
call nested_block_while(?)
--> OUT:[2]
For Loop
This is custom documentation. For more information, please visit the SAP Help Portal 114
12/23/2022
FOR R as C DO
DECLARE CURSOR C FOR SELECT * FROM mytab2;
a1 = :a1 + R.a;
FOR R as C DO
DECLARE CURSOR C FOR SELECT * FROM mytab3;
a2 = :a2 + R.a;
FOR R as C DO
a3 = :a3 + R.a;
END FOR;
END FOR;
END FOR;
IF inval = 1 THEN
val = :a1;
ELSEIF inval = 2 THEN
val = :a2;
ELSEIF inval = 3 THEN
val = :a3;
END IF;
END;
call nested_block_for(1, ?)
--> OUT:[1]
call nested_block_for(2, ?)
--> OUT:[2]
call nested_block_for(3, ?)
--> OUT:[3]
Loop
Note
The example below uses tables and values created in the For Loop example above.
CREATE PROCEDURE nested_block_loop(IN inval INT, OUT val INT) LANGUAGE SQLSCRIPT READS SQL DATA AS
BEGIN
DECLARE a1 int;
DECLARE a2 int;
DECLARE a3 int;
DECLARE v1 int default 1;
DECLARE v2 int default 1;
DECLARE v3 int default 1;
DECLARE CURSOR C FOR SELECT * FROM mytab1;
OPEN C;
FETCH C into a1;
CLOSE C;
LOOP
DECLARE CURSOR C FOR SELECT * FROM mytab2;
This is custom documentation. For more information, please visit the SAP Help Portal 115
12/23/2022
OPEN C;
FETCH C into a2;
CLOSE C;
LOOP
DECLARE CURSOR C FOR SELECT * FROM mytab3;
OPEN C;
FETCH C INTO a3;
CLOSE C;
IF :v2 = 1 THEN
BREAK;
END IF;
END LOOP;
IF :v1 = 1 THEN
BREAK;
END IF;
END LOOP;
IF :inval = 1 THEN
val = :a1;
ELSEIF :inval = 2 THEN
val = :a2;
ELSEIF :inval = 3 THEN
val = :a3;
END IF;
END;
call nested_block_loop(1, ?)
--> OUT:[1]
call nested_block_loop(2, ?)
--> OUT:[2]
call nested_block_loop(3, ?)
--> OUT:[3]
Control Structures
Conditionals
Syntax
IF <bool_expr1>
THEN
<then_stmts1>
[{ELSEIF <bool_expr2>
THEN
<then_stmts2>}...]
[ELSE
<else_stmts3>]
END IF
Syntax Elements
This is custom documentation. For more information, please visit the SAP Help Portal 116
12/23/2022
Note
NULL is the default value for all local variables.
Speci es the comparison value. This can be based on either scalar literals or scalar variables.
Description
The IF statement consists of a Boolean expression <bool_expr1>. If this expression evaluates to true, the statements
<then_stmts1> in the mandatory THEN block are executed. The IF statement ends with END IF. The remaining parts are
optional.
If the Boolean expression <bool_expr1> does not evaluate to true, the ELSE-branch is evaluated. The statements
<else_stmts3> are executed without further checks. No ELSE-branches or ELSEIF-branches are allowed after an else
branch.
Alternatively, when ELSEIF is used instead of ELSE a further Boolean expression <bool_expr2> is evaluated. If it evaluates
to true, the statements <then_stmts2> are executed. In this manner an arbitrary number of ELSEIF clauses can be added.
This statement can be used to simulate the switch-case statement known from many programming languages.
The predicate x [NOT] BETWEEN lower AND upper can also be used within the expression <bool_expr1>. It works just like
[ NOT ] ( x >= lower AND x <= upper). For more information, see Example 4.
Examples
Example 1
You use the IF statement to implement the functionality of the UPSERT statement in SAP HANA database.
This is custom documentation. For more information, please visit the SAP Help Portal 117
12/23/2022
END IF;
END;
Example 2
Example 3
It is also possible to use a scalar UDF in the condition, as shown in the following example.
Example 4
Related Information
ins_msg_proc
While Loop
Syntax
WHILE <condition> DO
<proc_stmts>
END WHILE
This is custom documentation. For more information, please visit the SAP Help Portal 118
12/23/2022
Syntax Elements
Description
The WHILE loop executes the statements <proc_stmts> in the body of the loop as long as the Boolean expression at the
beginning <condition> of the loop evaluates to true.
The predicate x [NOT] BETWEEN lower AND upper can also be used within the expression of the <condition>. It works
just like [ NOT ] ( x >= lower AND x <= upper). For more information, see Example 3.
Example 1
You use WHILE to increment the :v_index1 and :v_index2 variables using nested loops.
Example 2
You can also use scalar UDF for the while condition as follows.
Example 3
Caution
No speci c checks are performed to avoid in nite loops.
For Loop
Syntax:
Syntax elements:
REVERSE
Description:
The for loop iterates a range of numeric values and binds the current value to a variable <loop-var> in ascending order.
Iteration starts with the value of <start_value> and is incremented by one until the <loop-var> is greater than
<end_value> .
If <start_value> is larger than <end_value>, <proc_stmts> in the loop will not be evaluated.
Example 1
You use nested FOR loops to call a procedure that traces the current values of the loop variables appending them to a table.
This is custom documentation. For more information, please visit the SAP Help Portal 120
12/23/2022
Example 2
You can also use scalar UDF in the FOR loop, as shown in the following example.
BREAK
CONTINUE
Syntax elements:
BREAK
CONTINUE
Speci es that a loop should stop processing the current iteration, and should immediately start processing the next.
Description:
Example:
You de ned the following loop sequence. If the loop value :x is less than 3 the iterations will be skipped. If :x is 5 then the loop
will terminate.
This is custom documentation. For more information, please visit the SAP Help Portal 121
12/23/2022
Related Information
ins_msg_proc
Operators
IN Operator
Description
SQLScript supports the use of IN clauses as conditions in IF or WHILE statements. Just like in standard SQL, the condition can
take one of the following forms:
a list of expressions on the left-hand side and a list of lists of expressions on the right-hand side
a list of expressions on the left-hand side and a subquery on the right-hand side
In both cases, the numbers and types of entries in each list of the respective row of the result set on the right-hand side must
match the numbers and types of entries on the left-hand side.
Examples
Sample Code
Pseudo Code Examples
This is custom documentation. For more information, please visit the SAP Help Portal 122
12/23/2022
IF :i NOT IN (SELECT a FROM mytable) THEN
[...]
END IF;
Limitations
Floating-point numbers, variables, and expressions can be used but due to the implementation of these data types, the results
of the calculations may be inaccurate. For more information, see the chapter Numeric Data Types in the SAP HANA SQL and
System Views Reference.
EXISTS Operator
SQLScript supports the use of EXISTS clauses as conditions in IF and WHILE statements. Just like in standard SQL, it evaluates
to true if the sub-query returns a non-empty result set, and to false in any other case.
--
IF NOT EXISTS (SELECT * FROM SYS.TABLES WHERE schema_name = :schema AND table_name = :table) THEN
...
END IF
--
WHILE :i < 100 AND EXISTS (SELECT * FROM mytab WHERE a = :i) DO
i = :i + 1;
...
END WHILE
--
WHILE NOT EXISTS (SELECT * FROM mytab WHERE a > sfunc(:z).r2) DO
...
END WHILE
This is custom documentation. For more information, please visit the SAP Help Portal 123
12/23/2022
BETWEEN Operator
The predicate x [NOT] BETWEEN lower AND upper can be used within the expression of the <condition> of a WHILE
loop. It works just like [ NOT ] ( x >= lower AND x <= upper).
Example
Sample Code
Related Information
While Loop
Cursors
Cursors are used to fetch single rows from the result set returned by a query. When a cursor is declared, it is bound to the query.
It is possible to parameterize the cursor query.
De ne Cursor
Syntax:
Syntax elements:
This is custom documentation. For more information, please visit the SAP Help Portal 124
12/23/2022
Description:
Cursors can be de ned either after the signature of the procedure and before the procedure’s body or at the beginning of a
block with the DECLARE token. The cursor is de ned with a name, optionally a list of parameters, and an SQL SELECT
statement. The cursor provides the functionality to iterate through a query result row-by-row. Updating cursors is not
supported.
Note
Avoid using cursors when it is possible to express the same logic with SQL. You should do this as cursors cannot be optimized
the same way SQL can.
Example:
You create a cursor c_cursor1 to iterate over results from a SELECT on the books table. The cursor passes one parameter
v_isbn to the SELECT statement.
Sample Code
Example for Cursor Holdability
Related Information
This is custom documentation. For more information, please visit the SAP Help Portal 125
12/23/2022
SELECT Statement (Data Manipulation)
Open Cursor
Syntax:
OPEN <cursor_name>[(<argument_list>)]
Syntax elements:
Speci es one or more arguments to be passed to the select statement of the cursor.
Description:
Evaluates the query bound to a cursor and opens the cursor, so that the result can be retrieved. If the cursor de nition contains
parameters, the actual values for each of these parameters should be provided when the cursor is opened.
This statement prepares the cursor, so that the results for the rows of a query can be fetched.
Example:
You open the cursor c_cursor1 and pass a string '978-3-86894-012-1' as a parameter.
OPEN c_cursor1('978-3-86894-012-1');
Close Cursor
Syntax:
CLOSE <cursor_name>
Syntax elements:
Description:
This is custom documentation. For more information, please visit the SAP Help Portal 126
12/23/2022
Closes a previously opened cursor and releases all associated state and resources. It is important to close all cursors that were
previously opened.
Example:
CLOSE c_cursor1;
Syntax elements:
Speci es the name of the cursor where the result will be obtained.
Speci es the variables where the row result from the cursor will be stored.
Description:
Fetches a single row in the result set of a query and moves the cursor to the next row. It is assumed that the cursor was
declared and opened before. You can use the cursor attributes to check if the cursor points to a valid row.
Example:
You fetch a row from the cursor c_cursor1 and store the results in the variables shown.
Related Information
Attributes of a Cursor
Attributes of a Cursor
A cursor provides a number of methods to examine its current state. For a cursor bound to variable c_cursor1, the attributes
summarized in the table below are available.
This is custom documentation. For more information, please visit the SAP Help Portal 127
12/23/2022
Cursor Attributes
Attribute Description
c_cursor1::NOTFOUND Is true if the previous fetch operation returned no valid row, false
otherwise. Before calling OPEN or after calling CLOSE on a cursor
this will always return true.
c_cursor1::ROWCOUNT Returns the number of rows that the cursor fetched so far. This
value is available after the rst FETCH operation. Before the rst
fetch operation the number is 0.
Example:
The example below shows a complete procedure using the attributes of the cursor c_cursor1 to check if fetching a set of
results is possible.
OPEN c_cursor1('978-3-86894-012-1');
IF c_cursor1::ISCLOSED THEN
CALL ins_msg_proc('WRONG: cursor not open');
ELSE
CALL ins_msg_proc('OK: cursor open');
END IF;
FETCH c_cursor1 INTO v_isbn, v_title, v_price, v_crcy;
IF c_cursor1::NOTFOUND THEN
CALL ins_msg_proc('WRONG: cursor contains no valid data');
ELSE
CALL ins_msg_proc('OK: cursor contains valid data');
END IF;
CLOSE c_cursor1;
END
Related Information
ins_msg_proc
Syntax elements:
This is custom documentation. For more information, please visit the SAP Help Portal 128
12/23/2022
De nes an identi er to contain the row result.
Speci es one or more arguments to be passed to the select statement of the cursor.
To access the row result attributes in the body of the loop, you use the displayed syntax.
Description:
Opens a previously declared cursor and iterates over each row in the result set of the query bound to the cursor. The
statements in the body of the procedure are executed for each row in the result set. After the last row from the cursor has been
processed, the loop is exited and the cursor is closed.
Tip
As this loop method takes care of opening and closing cursors, resource leaks can be avoided. Consequently, this loop is
preferred to opening and closing a cursor explicitly and using other loop-variants.
Within the loop body, the attributes of the row that the cursor currently iterates over can be accessed like an attribute of the
cursor. Assuming that <row_var> is a_row and the iterated data contains a column test, then the value of this column can
be accessed using a_row.test.
Example:
The example below demonstrates how to use a FOR-loop to loop over the results from c_cursor1.
This is custom documentation. For more information, please visit the SAP Help Portal 129
12/23/2022
END;
Related Information
ins_msg_proc
Updatable Cursor
Syntax
Description
When you iterate over each row of a result set, you can use the updatable cursor to change a record directly on the row, to
which the cursor is currently pointing. The updatable cursor is a standard SQL feature (ISO/IEC 9075-2:2011).
For more information, see sections 14.8 & 14.13 in the SQL standard documentation (ISO/IEC 9075-2:2011).
Restrictions
The following restrictions apply:
The cursor has to be declared with a SELECT statement having the FOR UPDATE clause in order to prevent concurrent
WRITE on tables (without FOR UPDATE, the cursor is not updatable)
The updatable cursor may be used only for UPDATE and DELETE operations.
Only persistent tables (both ROW and COLUMN tables) can be updated with an updatable cursor.
UPDATE or DELETE operations performed on a table by means of an updatable cursor are allowed only one time per row.
Note
Updating the same row multiple times is possible, if several cursors selecting the same table are declared within a single
transaction.
Examples
Example for updating a single table by using an updatable cursor:
Sample Code
This is custom documentation. For more information, please visit the SAP Help Portal 130
12/23/2022
INSERT INTO employees VALUES (20010, 'Sam');
INSERT INTO employees VALUES (21, 'Julie');
INSERT INTO employees VALUES (10005, 'Kate');
DO BEGIN
DECLARE CURSOR cur FOR SELECT * FROM employees FOR UPDATE;
FOR r AS cur DO
IF r.employee_id < 10000 THEN
UPDATE employees SET employee_id = employee_id + 10000
WHERE CURRENT OF cur;
ELSE
DELETE FROM employees WHERE CURRENT OF cur;
END IF;
END FOR;
END;
Example for updating or deleting multiple tables (currently COLUMN tables only supported) by means of an updatable cursor.
Note
In this case, you have to specify columns of tables to be locked by using the FOR UPDATE OF clause within the SELECT
statement of the cursor. Keep in mind that DML execution by means of an updatable cursor is allowed only one time per row.
Sample Code
CREATE COLUMN TABLE employees (employee_id INTEGER, employee_name VARCHAR(30), department_id INTE
INSERT INTO employees VALUES (1, 'John', 1);
INSERT INTO employees VALUES (2, 'Sam', 2);
INSERT INTO employees VALUES (3, 'Julie', 3);
INSERT INTO employees VALUES (4, 'Kate', 4);
DO BEGIN
DECLARE CURSOR cur FOR SELECT employees.employee_name, departments.department_name
FROM employees, departments WHERE employees.department_id = departments.department_id
FOR UPDATE OF employees.employee_id, departments.department_id;
FOR r AS cur DO
IF r.department_name = 'Development' THEN
UPDATE employees SET employee_id = employee_id + 10000, department_id = department_id
WHERE CURRENT OF cur;
UPDATE departments SET department_id = department_id + 100
WHERE CURRENT OF cur;
ELSEIF r.department_name = 'HR' THEN
DELETE FROM employees WHERE CURRENT OF cur;
DELETE FROM departments WHERE CURRENT OF cur;
END IF;
END FOR;
END;
Cursor Holdability
Syntax
This is custom documentation. For more information, please visit the SAP Help Portal 131
12/23/2022
Description
It is now possible to use control features directly within SQLScript in order to control cursor holdability for speci c objects
instead of using a system con guration, as it was necessary before.
Expression Description
DECLARE CURSOR cursor_name WITH HOLD FOR … Declares a cursor with holdability for both commit and rollback
DECLARE CURSOR cursor_name WITHOUT HOLD FOR … Declares a cursor without holdability for both commit and rollback
DECLARE CURSOR cursor_name FOR … Declares a cursor with holdability for commit and without
holdability for rollback
Controlling the cursor holdability by cursor declaration gets higher priority than system con guration:
If a cursor is holdable for commit and not holdable for rollback, it will have holdability for rollback after commit. A not holdable
cursor will be invalidated by transactional operations (commit or rollback), but not closed. It will return a null value for fetch
operations rather than throwing an exception and an exception will be thrown by using an updatable cursor.
Example
Sample Code
CREATE TABLE mytab (col INT);
INSERT INTO mytab VALUES (10);
CREATE PROCEDURE testproc AS BEGIN
DECLARE i INT;
DECLARE CURSOR mycur WITH HOLD FOR SELECT * FROM mytab;
OPEN mycur;
ROLLBACK;
FETCH mycur INTO i;
CLOSE mycur;
SELECT :i as i FROM DUMMY;
END;
Restrictions
It is currently not possible to use an updatable cursor while the cursor is holdable on rollback, since DML operations using an
updatable cursor after rollback may cause unexpected results.
This is custom documentation. For more information, please visit the SAP Help Portal 132
12/23/2022
Autonomous Transaction
Syntax:
Description:
The autonomous transaction is independent from the main procedure. Changes made and committed by an autonomous
transaction can be stored in persistency regardless of commit/rollback of the main procedure transaction. The end of the
autonomous transaction block has an implicit commit.
The examples show how commit and rollback work inside the autonomous transaction block. The rst updates (1) are
committed, whereby the updates made in step (2) are completely rolled back. And the last updates (3) are committed by the
implicit commit at the end of the autonomous block.
CREATE PROCEDURE PROC1( IN p INT , OUT outtab TABLE (A INT)) LANGUAGE SQLSCRIPT AS
BEGIN
DECLARE errCode INT;
DECLARE errMsg VARCHAR(5000);
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN AUTONOMOUS TRANSACTION
errCode= ::SQL_ERROR_CODE;
errMsg= ::SQL_ERROR_MESSAGE ;
INSERT INTO ERR_TABLE (PARAMETER,SQL_ERROR_CODE, SQL_ERROR_MESSAGE)
VALUES ( :p, :errCode, :errMsg);
END;
outtab = SELECT 1/:p as A FROM DUMMY; -- DIVIDE BY ZERO Error if p=0
END
In the example above, an autonomous transaction is used to keep the error code in the ERR_TABLE stored in persistency.
If the exception handler block were not an autonomous transaction, then every insert would be rolled back because they were
all made in the main transaction. In this case the result of the ERR_TABLE is as shown in the following example.
P |SQL_ERROR_CODE| SQL_ERROR_MESSAGE
--------------------------------------------
0 | 304 | division by zero undefined: at function /()
This is custom documentation. For more information, please visit the SAP Help Portal 133
12/23/2022
END;
END;
The LOG_TABLE table contains 'MESSAGE', even though the inner autonomous transaction rolled back.
DDL
Cursor
Table assignments
Note
You have to be cautious if you access a table both before and inside an autonomous transaction started in a nested
procedure (e.g. TRUNCATE, update the same row), because this can lead to a deadlock situation. One solution to avoid this is
to commit the changes before entering the autonomous transaction in the nested procedure.
Transactional Statements
The COMMIT command commits the current transaction and all changes before the COMMIT command is written to persistence.
The ROLLBACK command rolls back the current transaction and undoes all changes since the last COMMIT.
Example 1:
In this example, the B_TAB table has one row before the PROC1 procedure is executed:
V ID
0 1
After you execute the PROC1 procedure, the B_TAB table is updated as follows:
This is custom documentation. For more information, please visit the SAP Help Portal 134
12/23/2022
V ID
3 1
This means only the rst update in the procedure affected the B_TAB table. The second update does not affect the B_TAB table
because it was rolled back.
The following graphic provides more detail about the transactional behavior. With the rst COMMIT command, transaction tx1
is committed and the update on the B_TAB table is written to persistence. As a result of the COMMIT, a new transaction starts,
tx2.
By triggering ROLLBACK, all changes done in transaction tx2 are reverted. In Example 1, the second update is reverted.
Additionally after the rollback is performed, a new transaction starts, tx3.
The transaction boundary is not tied to the procedure block. This means that if a nested procedure contains a
COMMIT/ROLLBACK, then all statements of the top-level procedure are affected.
Example 2:
In Example 2, the PROC1 procedure calls the PROC2procedure. The COMMIT in PROC2 commits all changes done in the tx1
transaction (see the following graphic). This includes the rst update statement in the PROC1 procedure as well as the update
statement in the PROC2 procedure. With COMMIT a new transaction starts implicitly, tx2.
This is custom documentation. For more information, please visit the SAP Help Portal 135
12/23/2022
Therefore the ROLLBACK command in PROC1 only affects the previous update statement; all other updates were committed
with the tx1 transaction.
Note
If you used DSQL in the past to execute these commands (for example, EXEC ‘COMMIT’, EXEC ’ROLLBACK’), SAP
recommends that you replace all occurrences with the native commands COMMIT/ROLLBACK because they are more
secure.
The COMMIT/ROLLBACK commands are not supported in Scalar UDF or in Table UDF.
SAVEPOINT
SQLScript now supports transactional savepoints that allow the rollback of a transaction to a de ned point. This includes:
Limitation
SAVEPOINT is a transactional statement, such as COMMIT or ROLLBACK. Therefore, the limitations of transactional
statements apply to SAVEPOINT as well.
Example
This is custom documentation. For more information, please visit the SAP Help Portal 136
12/23/2022
SAVEPOINT save1;
insert into t1 values(2);
ROLLBACK TO SAVEPOINT save1;
select * from t1;
RELEASE SAVEPOINT save1;
end;
call test; -- result: {1}
select * from t1; -- result: {1}
Dynamic SQL
Dynamic SQL allows you to construct an SQL statement during the execution time of a procedure. While dynamic SQL allows
you to use variables where they may not be supported in SQLScript and provides more exibility when creating SQL
statements, it does have some disadvantages at run time:
You cannot bind the result of a dynamic SQL statement to an SQLScript variable.
You must be very careful to avoid SQL injection bugs that might harm the integrity or security of the database.
Note
You should avoid dynamic SQL wherever possible as it may have a negative impact on security or performance.
EXEC
Syntax:
Description:
EXEC executes the SQL statement <sql-statement> passed in a string argument. EXEC does not return any result set, if
<sql_statement> is a SELECT statement. You have to use EXECUTE IMMEDIATE for that purpose.
If the query returns a single row, you can assign the value of each column to a scalar variable by using the INTO clause.
INTO <var_name_list>
<var_name_list> ::= <var_name>[{, <var_name>}...]
<var_name> ::= <identifier> | <identifier> '[' <index> ']'
Sample Code
DO (IN TNAME NVARCHAR(10) =>'mytable',
IN CNAME1 NVARCHAR(10) => 'I',
IN CNAME2 NVARCHAR(10) => 'A',
OUT K INT =>?, OUT J INT => ?)
BEGIN
This is custom documentation. For more information, please visit the SAP Help Portal 137
12/23/2022
EXEC 'select max(' || :cname1 || ') as a, min(' ||:cname2 ||') as b from '|| :TNAME INTO K,
END;
The EXEC INTO statement does not accept empty result sets, so you need to de ne exit handlers in case of an empty result set
or use DEFAULT values. The following example illustrates how to use default values with an EXEC statement:
Sample Code
DO BEGIN
DECLARE A_COPY INT;
DECLARE B_COPY VARCHAR(10);
CREATE ROW TABLE T1 (A INT NOT NULL, B VARCHAR(10));
SELECT A, B INTO A_COPY, B_COPY DEFAULT -2+1, NULL FROM T1;
--(A_COPY,B_COPY) = (-1,?), use default value
EXEC 'SELECT A FROM T1' INTO A_COPY DEFAULT 2;
--(A_COPY) = (2), exec into statement with default value
INSERT INTO T1 VALUES (0, 'sample0');
SELECT A, B INTO A_COPY, B_COPY DEFAULT 5, NULL FROM T1;
--(A_COPY,B_COPY) = (0,'sample0'), executed as-is
END;
It is also possible to use a single array element as the result of EXEC INTO. The following example illustrates the case.
Sample Code
DROP TABLE T1;
CREATE TABLE T1 (A INT NOT NULL, B VARCHAR(10));
DO BEGIN
DECLARE A_COPY INT ARRAY;
DECLARE B_COPY VARCHAR(10) ARRAY;
SELECT A, B INTO A_COPY[1], B_COPY[1] DEFAULT -2+1, NULL FROM T1;
SELECT :A_COPY[1], :B_COPY[1] from dummy;
--(A_COPY[1],B_COPY[1]) = (-1,?), use default value
EXEC 'SELECT A FROM T1' INTO A_COPY[1] DEFAULT 2;
SELECT :A_COPY[1], :B_COPY[1] from dummy;
--(A_COPY[1]) = (2), exec into statement with default value
INSERT INTO T1 VALUES (0, 'sample0');
SELECT A, B INTO A_COPY[1], B_COPY[1] DEFAULT 5, NULL FROM T1;
SELECT :A_COPY[1], :B_COPY[1] from dummy;
--(A_COPY[1],B_COPY[1]) = (0,'sample0'), executed as-is
END;
USING <expression_list>
<expression_list>::= <expression> [{ , <expression>} …]
<expression> can be either a simple expression, such as a character, a date, a number, or a scalar variable.
Sample Code
DO (IN TNAME NVARCHAR(10) =>'mytable',
IN CNAME1 NVARCHAR(10) => 'I',
IN CNAME2 NVARCHAR(10) => 'A',
OUT K INT =>?, OUT J INT => ?)
BEGIN
This is custom documentation. For more information, please visit the SAP Help Portal 138
12/23/2022
DECLARE a , b INT = 2;
EXEC 'select max(' || :cname1 || ') + ?*? as a, min(' ||:cname2 ||') as b from '|| :TNAME IN
END;
When the suffix READS SQL DATA is attached, the statement is considered read-only. Since it is not possible to check at
compile time whether the statement that is about to be executed is read-only, the operation returns a run-time error, if the
executed statement is not read-only. The read-only declaration has the following advantages:
DSQL can be used in a read-only context, for example read-only procedures and table user-de ned functions
read-only DSQL can be parallelized with other read-only operations thus improving the overall execution time.
To avoid the repetition of the suffix READS SQL DATA, every DSQL inside a read-only procedure or function will automatically by
considered read-only, regardless of the suffix. However, it is still possible to add the suffix.
EXECUTE IMMEDIATE
Syntax:
Description:
EXECUTE IMMEDIATE executes the SQL statement passed in a string argument. The results of queries executed with
EXECUTE IMMEDIATE are appended to the procedures result iterator.
You can also use the INTO und USING clauses to pass in or out scalar values. With the INTO clause the result set is not
appended to the procedure result iterator. For more information, see the EXEC statement documentation.
When the suffix READS SQL DATA is attached, the statement is considered read-only. Since it is not possible to check at
compile time whether the statement that is about to be executed is read-only, the operation returns a run-time error, if the
executed statement is not read-only. The read-only declaration has the following advantages:
DSQL can be used in a read-only context, for example read-only procedures and table user-de ned functions
read-only DSQL can be parallelized with other read-only operations thus improving the overall execution time.
To avoid the repetition of the suffix READS SQL DATA for every DSQL statement in a read-only procedure or a function, the
DSQL will automatically be considered read-only, regardless of the suffix. However, it is still possible to add the suffix.
Example:
This is custom documentation. For more information, please visit the SAP Help Portal 139
12/23/2022
You use dynamic SQL to delete the contents of the table tab, insert a value and, nally, to retrieve all results in the table.
Related Information
EXEC
Syntax
Description
EXEC executes the SQL statement <sql-statement> passed as a string argument. EXEC does not return a result set, if
<sql_statement> is a SELECT-statement. You have to use EXECUTE IMMEDIATE for that purpose.
If the query returns result sets or output parameters, you can assign the values to scalar or table variables with the INTO
clause.
When the SQL statement is a SELECT statement and there are table variables listed in the INTO clause, the result sets are
assigned to the table variables sequentially. If scalar variables are listed in the INTO clause for a SELECT statement, it works like
<select_into_stmt> and assigns the value of each column of the rst row to a scalar variable when a single row is returned
from a single result set. When the SQL statement is a CALL statement, output parameters represented as':<var_name>' in
the SQL statement are assigned to the variables in the INTO clause that have the same names.
Examples
Sample Code
INTO Example 1
Sample Code
INTO Example 2
Sample Code
INTO Example 3
Note
You can also bind scalar or table values with the USING clause.
When <sql-statement> uses ':<var_name>' as a parameter, only variable references are allowed in the USING clause and
variables with the same name are bound to the parameter ':<var_name>'. However, when <sql-statement> uses '?' as
a parameter (unnamed parameter bound), any expression is allowed in the USING clause and values are mapped to
parameters sequentially. The unnamed parameter bound is supported when there are only input parameters.
Sample Code
USING Example 1
DO BEGIN
DECLARE tv TABLE (col1 INT) = SELECT * FROM mytab;
DECLARE a INT = 123;
DECLARE tv2 TABLE (col1 INT);
EXEC 'select col1 + :a as col1 from :tv' INTO tv2 USING :a, :tv;
SELECT * FROM :tv2;
END;
Sample Code
USING Example 2
Sample Code
USING Example 3
DO BEGIN
DECLARE tv TABLE (col1 INT) = SELECT * FROM mytab;
DECLARE a INT = 123;
EXEC 'call myproc(:a, :tv)' USING :a, :tv;
END;
Limitations
A table variable cannot be used in both an INTO-clause and a USING-clause.
The parameter '?' and the variable reference ':<var_name>' cannot be used at the same time in an SQL statement.
APPLY_FILTER
Syntax
Syntax Elements
The variable where the result of the APPLY_FILTER function will be stored.
You can use APPLY_FILTER with persistent tables and table variables.
<table_name> :: = <identifier>
This is custom documentation. For more information, please visit the SAP Help Portal 142
12/23/2022
Note
The following constructs are not supported in the lter string <filter_variable_name>:
Description
The APPLY_FILTER function applies a dynamic lter to a table or a table variable. In terms of logic, it can be considered a
partially dynamic SQL statement. The advantage of the function is that you can assign it to a table variable and that will not
block SQL inlining.
Caution
The disadvantage of APPLY_FILTER is the missing parametrization capability. Using constant values always leads to
preparing a new query plan and, therefore, to different query Plan Cache entries for the different parameter values. This
comes along with additional time spent for query preparation and potential cache ooding effects in fast-changing
parameter value scenarios. To avoid this, we recommend to use EXEC with USING clause to make use of a parametrized
WHERE-clause.
Sample Code
Before:
Sample Code
After:
EXEC 'SELECT * FROM :lt0 WHERE (' || :column || ' = :value' INTO lt USING :lt0, :value READS SQL
Examples
Example 1 - Applying a lter to a persistent table
This is custom documentation. For more information, please visit the SAP Help Portal 143
12/23/2022
procedures = SELECT SCHEMA_NAME, PROCEDURE_NAME FROM :temp_procedures;
END;
END;
Exception Handling
Exception handling is a method for handling exception and completion conditions in an SQLScript procedure.
For example, the following exit handler catches all SQLEXCEPTION and returns the information that an exception was thrown:
DECLARE EXIT HANDLER FOR SQLEXCEPTION SELECT 'EXCEPTION was thrown' AS ERROR FROM dummy;
There are two system variables ::SQL_ERROR_CODE and ::SQL_ERROR_MESSAGE that can be used to get the error code and
the error message, as shown in the next example:
CREATE PROCEDURE MYPROC (IN in_var INTEGER, OUT outtab TABLE(I INTEGER) ) AS
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
SELECT ::SQL_ERROR_CODE, ::SQL_ERROR_MESSAGE FROM DUMMY;
outtab = SELECT 1/:in_var as I FROM dummy;
END;
::SQL_ERROR_CODE ::SQL_ERROR_MESSAGE
This is custom documentation. For more information, please visit the SAP Help Portal 144
12/23/2022
::SQL_ERROR_CODE ::SQL_ERROR_MESSAGE
304 Division by zero unde ned: the right-hand value of the division cannot be zero at function /() (please check lines:
6)
Besides de ning an exit handler for an arbitrary SQLEXCEPTION, you can also de ne it for a speci c error code number by using
the keyword SQL_ERROR_CODE followed by an SQL error code number.
For example, if only the “division-by-zero” error should be handled the exception handler, the code looks as follows:
The following error codes are supported in the exit handler. You can use the system view M_ERROR_CODES to get more
information about the error codes.
Type Description
ERR_TX_ROLLBACK_DEADLOCK
ERR_TX_SERIALIZATION
ERR_TX_LOCK_ACQUISITION_FAIL
When catching transactional errors, the transaction still lives inside the EXIT HANDLER. That allows the explicit use of COMMIT
or ROLLBACK.
Note
It is now possible to de ne an exit handler for the statement FOR UPDATE NOWAIT with the error code 146. For more
information, see Supported Error Codes.
Instead of using an error code the exit handler can be also de ned for a condition.
If you want to do more in the exit handler, you have to use a block by using BEGIN…END . For instance preparing some additional
information and inserting the error into a table:
This is custom documentation. For more information, please visit the SAP Help Portal 145
12/23/2022
INSERT INTO LOG_TABLE VALUES ( ::SQL_ERROR_CODE,
::SQL_ERROR_MESSAGE,
:procedure_name,
:parameters );
END;
tab = SELECT 1/:in_var as I FROM dummy;
Note
In the example above, in case of an unhandled exception the transaction will be rolled back. Thus the new row in the table
LOG_TABLE will be gone as well. To avoid this, you can use an autonomous transaction. For more information, see
Autonomous Transaction.
Description
The EXIT handler in SQLScript already offers a way to process exception conditions in a procedure or a function during
execution. The CONTINUE handler not only allows you to handle the error but also to continue with the execution after an
exception has been thrown.
Caution
Triggers are not supported inside CONTINUE HANDLER.
Syntax
Code Syntax
Behavior
The behavior of the CONTINUE handler for catching and handling exceptions is the same as that of the EXIT handler with the
following exceptions and extensions.
SQLScript execution continues with the statement following the exception-throwing statement right after catching and
handling the exception.
Sample Code
DO BEGIN
DECLARE A INT = 10;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN -- Catch the exception
SELECT ::SQL_ERROR_CODE, ::SQL_ERROR_MESSAGE FROM DUMMY;
This is custom documentation. For more information, please visit the SAP Help Portal 146
12/23/2022
END;
A = 1 / 0; -- An exception will be thrown
SELECT :A FROM DUMMY; -- Continue from this statement after handling the exception
END;
In multilayer blocks, SQLScript execution continues with the next statement in the inner-most block after the exception-
throwing statement.
Sample Code
DO BEGIN
DECLARE A INT = 10;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SELECT ::SQL_ERROR_CODE, ::SQL_ERROR_MESSAGE FROM D
SELECT :A FROM DUMMY;
BEGIN
A = 1 / 0; -- An exception throwing
A = :A + 1; -- Continue from this statement after handling the exception
END;
SELECT :A FROM DUMMY; -- Result: 11
END;
It is difficult to determine which statement is the statement following an error-throwing statement in parallel execution blocks.
Some of the statements may have already been executed before the exception occurs.
For this reason, implicit or explicit parallel execution is not supported within the scope of a continue handler.
Sample Code
DO BEGIN
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SELECT ::SQL_ERROR_CODE, ::SQL_ERROR_MESSAGE FROM D
BEGIN PARALLEL EXECUTION -- not supported
CALL PROC;
CALL PROC;
CALL PROC;
END;
END;
If there is an error in a conditional statement for an IF, a WHILE, or a FOR block, the whole block will be skipped after handling
the error because the condition is no longer valid.
Sample Code
This is custom documentation. For more information, please visit the SAP Help Portal 147
12/23/2022
DO BEGIN
DECLARE A INT = 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SELECT ::SQL_ERROR_CODE, ::SQL_ERROR_MESSAGE FROM D
IF A = 1 / 0 THEN -- An error occurs
A = 1;
ELSE
A = 2;
END IF;
SELECT :A FROM DUMMY; -- Continue from here, Result: 0
END;
EXIT handlers cannot be declared within the same scope or within a nested scope of a CONTINUE handler, but CONTINUE
handlers can be declared in the nested scope of an EXIT handler.
Sample Code
DO BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION SELECT ::SQL_ERROR_CODE, ::SQL_ERROR_MESSAGE FROM DUMMY
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION SELECT ::SQL_ERROR_CODE, ::SQL_ERROR_MESSAGE FROM D
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SELECT ::SQL_ERROR_CODE, ::SQL_ERROR_MESSAGE FR
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION SELECT ::SQL_ERROR_CODE, ::SQL_ERROR_MESSAGE FR
SELECT 1 / 0 FROM DUMMY;
END;
END;
END;
Variable Values
The value of the variable remains as it was before the execution of the statement that returns an exception.
Sample Code
DO BEGIN
DECLARE CONTINUE HANDLER FOR SQL_ERROR_CODE 12346 BEGIN END;
BEGIN
DECLARE CONTINUE HANDLER FOR SQL_ERROR_CODE 12345 BEGIN
SIGNAL SQL_ERROR_CODE 12346;
SELECT ::SQL_ERROR_CODE FROM DUMMY; -- 12346, not 12345
END;
This is custom documentation. For more information, please visit the SAP Help Portal 148
12/23/2022
SIGNAL SQL_ERROR_CODE 12345;
END;
END;
DO BEGIN
DECLARE A INT = 10;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN
SELECT :A FROM DUMMY; -- Result: 10
END;
A = 1 / 0;
SELECT :A FROM DUMMY; -- Result: 10
END;
DECLARE CONDITION
Declaring a CONDITION variable allows you to name SQL error codes or even to de ne a user-de ned condition.
These variables can be used in EXIT HANDLER declaration as well as in SIGNAL and RESIGNAL statements. Whereby in SIGNAL
and RESIGNAL only user-de ned conditions are allowed.
Using condition variables for SQL error codes makes the procedure/function code more readable. For example instead of using
the SQL error code 304, which signals a division by zero error, you can declare a meaningful condition for it:
Besides declaring a condition for an already existing SQL error code, you can also declare a user-de ned condition. Either de ne
it with or without a user-de ned error code.
Considering you would need a user-de ned condition for an invalid procedure input you have to declare it as in the following
example:
Optional you can also associate a user-de ned error code, e.g. 10000:
Note
Please note the user-de ned error codes must be within the range of 10000 to 19999.
How to signal and/or resignal a user-de ned condition will be handled in the section SIGNAL and RESIGNAL.
This is custom documentation. For more information, please visit the SAP Help Portal 149
12/23/2022
The error value returned by the SIGNAL statement is either an SQL_ERROR_CODE, or a user_de ned_condition that was
previously de ned with DECLARE CONDITION. The used error code must be within the user-de ned range of 10000 to 19999.
To raise a user-de ned condition, for example invalid_input, as declared in the previous section (see DECLARE CONDITION), use
the following command:
SIGNAL invalid_input;
But none of these user-de ned exceptions have an error message text. That means that the value of the system variable
::SQL_ERROR_MESSAGE is empty. Whereas the value of ::SQL_ERROR_CODE is 10000.
In both cases you get the following information in case the user-de ned exception is thrown:
[10000]: user-defined error: "SYSTEM"."MY": line 4 col 2 (at pos 96): [10000] (range 3) user-define
In the following example, the procedure signals an error in case the input argument of start_date is greater than the input
argument of end_date:
END;
This is custom documentation. For more information, please visit the SAP Help Portal 150
12/23/2022
If the procedures are called with invalid input arguments, you receive the following error message:
user-defined error: [10000] "MYSCHEMA"."GET_CUSTOMERS": line 9 col 3 (at pos 373): [10000] (range
For more information on how to handle the exception and continue with procedure execution, see Nested Block Exceptions in
Exception Handling Examples.
The RESIGNAL statement is used to pass on the exception that is handled in the exit handler.
Besides pass on the original exception by simple using RESIGNAL you can also change some information before pass it on.
Please note that the RESIGNAL statement can only be used in the exit handler.
Using RESIGNAL statement without changing the related information of an exception is done as follows:
CREATE PROCEDURE MYPROC (IN in_var INTEGER, OUT outtab TABLE(I INTEGER) ) AS
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
RESIGNAL;
In case of <in_var> = 0 the raised error would be the original SQL error code and message text.
You can change the error message of an SQL error by using SET MESSAGE _TEXT:
The original SQL error message will be now replaced by the new one:
[304]: division by zero undefined: [304] "SYSTEM"."MY": line 4 col 10 (at pos 131): [304] (range 3
You can get the original message via the system variable ::SQL_ERROR_MESSAGE. This is useful, if you still want to keep the
original message, but would like to add additional information:
CALL MYPROC;
CALL MYPROC;
CALL MYPROC;
This is custom documentation. For more information, please visit the SAP Help Portal 152
12/23/2022
CALL MYPROC;
Signal an Exception
The SIGNAL statement can be used to explicitly raise an exception from within your procedures.
Note
The error code used must be within the user-de ned range of 10000 to 19999.
CALL MYPROC;
Resignal an Exception
The RESIGNAL statement raises an exception on the action statement in exception handler. If error code is not speci ed,
RESIGNAL will throw the caught exception.
CALL MYPROC;
This is custom documentation. For more information, please visit the SAP Help Portal 153
12/23/2022
CALL MYPROC;
This is custom documentation. For more information, please visit the SAP Help Portal 154
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 155
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 156
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 157
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 158
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 159
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 160
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 161
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 162
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 163
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 164
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 165
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 166
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 167
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 168
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 169
12/23/2022
Array Variables
This is custom documentation. For more information, please visit the SAP Help Portal 170
12/23/2022
An array is an indexed collection of elements of a single data type. In the following section we explore the varying ways to de ne
and use arrays in SQLScript.
You can declare an array <variable_name> with the element type <sql_type>. The following SQL types are supported:
<sql_type> ::=
DATE | TIME| TIMESTAMP | SECONDDATE | TINYINT | SMALLINT | INTEGER | BIGINT | DECIMAL | SMALLDECIMA
Only unbounded arrays with a maximum cardinality of 2^31 are supported. You cannot de ne a static size for an array.
You can use the array constructor to directly assign a set of values to the array.
The array constructor returns an array containing elements speci ed in the list of value expressions. The following example
illustrates an array constructor that contains the numbers 1, 2 and 3:
Besides using scalar constants you can also use scalar variables or parameters instead, as shown in the next example.
Note
Note you cannot use TEXT or SHORTTEXT as the array type.
This is custom documentation. For more information, please visit the SAP Help Portal 171
12/23/2022
The <array_index> indicates the index of the element in the array to be modi ed whereby <array_index> can have any value
from 1 to 2^31. For example the following statement stores the value 10 in the second element of the array id:
id[2] = 10;
Please note that all unset elements of the array are NULL. In the given example id[1] is then NULL.
Instead of using a constant scalar value it is also possible to use a scalar variable of type INTEGER as <array_index>. In the next
example, variable I of type INTEGER is used as an index.
DECLARE i INT ;
DECLARE arr NVARCHAR(15) ARRAY ;
for i in 1 ..10 do
arr [:i] = 'ARRAY_INDEX '|| :i;
end for;
SQL Expressions and Scalar User De ned Functions (Scalar UDF) that return a number also can be used as an index. For
example, a Scalar UDF that adds two values and returns the result of it
Note
The array starts with the index 1.
For example, the following copies the value of the second element of array arr to variable var. Since the array elements are of
type NVARCHAR(15) the variable var has to have the same type:
Please note that you have to use ʻ:’ before the array variable if you read from the variable.
This is custom documentation. For more information, please visit the SAP Help Portal 172
12/23/2022
Instead of assigning the array element to a scalar variable it is possible to directly use the array element in the SQL expression
as well. For example, using the value of an array element as an index for another array.
DO
BEGIN
DECLARE arr TINYINT ARRAY = ARRAY(1,2,3);
DECLARE index_array INTEGER ARRAY = ARRAY(1,2);
DECLARE value TINYINT;
arr[:index_array[1]] = :arr[:index_array[2]];
value = :arr[:index_array[1]];
select :value from dummy;
END;
ARRAY_AGG Function
The ARRAY_AGG function converts a column of a table variable into an array.
In the following example the column A of table variable tab is aggregated into array id:
The type of the array needs to have the same type as the column.
Optionally the ORDER BY clause can be used to determine the order of the elements in the array. If it is not speci ed, the array
elements are ordered non-deterministic. In the following example all elements of array id are sorted descending by column B.
Additionally it is also possible to de ne where NULL values should appear in the result set. By default NULL values are returned
rst for ascending ordering, and last for descending ordering. You can override this behavior using NULLS FIRST or NULLS LAST
to explicitly specify NULL value ordering. The next example shows how the default behavior for the descending ordering can be
overwritten by using NULLS FIRST:
DO
BEGIN
DECLARE id NVARCHAR(10) ARRAY;
tab = SELECT A FROM ctab;
id = ARRAY_AGG(:tab.A ORDER BY A DESC NULLS FIRST);
Note
ARRAY_AGG function does not support using value expressions instead of table variables.
This is custom documentation. For more information, please visit the SAP Help Portal 173
12/23/2022
TRIM_ARRAY Function
The TRIM_ARRAY function removes elements from the end of an array. TRIM_ARRAY returns a new array with a
<trim_quantity> number of elements removed from the end of the array <array_variable>.
TRIM_ARRAY”(“:<array_variable>, <trim_quantity>”)”
<array_variable> ::= <identifier>
<trim_quantity> ::= <unsigned_integer>
ID
---
1
2
CARDINALITY Function
The CARDINALITY function returns the highest index of a set element in the array <array_variable>. It returns N (>= 0), if the
index of the N-th element is the largest among the indices.
CARDINALITY(:<array_variable>)
The result is n=0 because there is no element in the array. In the next example, the cardinality is 20, as the 20th element is set.
This implicitly sets the elements 1-19 to NULL:
END;
The CARDINALITY function can also directly be used everywhere where expressions are supported, for example in a condition:
Restriction
This feature supports array parameters only for server-side query parameters. It is not possible to use client-side
array interfaces. Array parameters cannot be used in the outermost queries or calls. It is allowed to use array
parameters only in nested queries or nested calls.
Syntax
This is custom documentation. For more information, please visit the SAP Help Portal 175
12/23/2022
Code Syntax
CREATE [OR REPLACE] PROCEDURE <proc_name> [(<parameter_clause>)] [LANGUAGE <lang>] [SQL SECURITY
<procedure_body>
END
Code Syntax
CREATE FUNCTION <func_name> [(<parameter_clause>)] RETURNS <return_type> [LANGUAGE <lang>] [SQL S
AS BEGIN
<function_body>
END
Examples
Sample Code
create procedure my_l_proc_out(out c int array, in b int array) as
begin
c = array(123456, 7890);
c[3] = :b[1];
c[4] = :b[2];
end;
do begin
declare a int array;
declare b int array = array(3, 4);
call my_l_proc_out(:a, :b);
select :a from dummy;
END;
Sample Code
create function my_sudf_arr (in a int array) returns b int array as
begin
b = subarray(:a, 1, 2);
end;
This is custom documentation. For more information, please visit the SAP Help Portal 176
12/23/2022
do begin
declare arr_var int array = array(1, 2, 3, 4);
select my_sudf_arr(:arr_var) x from dummy;
end;
Sample Code
create function my_tudf_arr (in A int array) returns table(I int) as
begin
B = unnest(:A);
return select ":A" as I from :B;
end;
do begin
declare arr_var int array = array(1, 2, 3, 4);
select * from my_tudf_arr(:arr_var);
end;
Note
For improving SQLScript usability, not only constant arrays but also array variables can be used in DML and queries. In
addition, it is also possible to use array variables in the SELECT INTO clause.
Sample Code
create table tab1 (i int, a int array);
do begin
declare a int array = array(1, 2, 3);
declare b int array;
insert into tab1 values (1, :a);
select tab1.A into b from tab1;
select array(1,2,3) into b from dummy;
insert into tab1 values (1, array(1, 2, 3));
select :a from dummy;
end;
Note
The system view ELEMENT_TYPES now shows the element data type of the parameter, if it is an array type. The
ELEMENT_TYPES view has the columns SCHEMA_NAME, OBJECT_NAME, ELEMENT_NAME, and DATA_TYPE_NAME.
Limitations
The following limitations apply:
Using an array parameter in the USING clause of Dynamic SQL is not supported.
Syntax IS_SQL_INJECTION_SAFE
This is custom documentation. For more information, please visit the SAP Help Portal 177
12/23/2022
If your SQLScript procedure needs execution of dynamic SQL statements where the parts of it are derived from untrusted input
(e.g. user interface), there is a danger of an SQL injection attack. The following functions can be utilized in order to prevent it:
IS_SQL_INJECTION_SAFE(string_var[, num_tokens]) to be used to check that a variable contains safe simple SQL
identi ers (up to num_tokens, default is 1)
Example:
The following values of input parameters can manipulate the dynamic SQL statement in an unintended way:
new_val: ' --
old_val: ' or 1 = 1 --
This cannot happen if you validate and/or process the input values:
IS_SQL_INJECTION_SAFE(<value>[, <max_tokens>])
Syntax Elements
This is custom documentation. For more information, please visit the SAP Help Portal 178
12/23/2022
String to be checked.
Description
Checks for possible SQL injection in a parameter which is to be used as a SQL identi er. Returns 1 if no possible SQL injection is
found, otherwise 0.
Example
The following code example shows that the function returns 0 if the number of tokens in the argument is different from the
expected number of a single token (default value).
safe
-------
0
The following code example shows that the function returns 1 if the number of tokens in the argument matches the expected
number of 3 tokens.
safe
-------
1
Syntax ESCAPE_SINGLE_QUOTES
ESCAPE_SINGLE_QUOTES(<value>)
Description
Escapes single quotes (apostrophes) in the given string <value>, ensuring a valid SQL string literal is used in dynamic SQL
statements to prevent SQL injections. Returns the input string with escaped single quotes.
Example
The following code example shows how the function escapes a single quote. The one single quote is escaped with another single
quote when passed to the function. The function then escapes the parameter content Str'ing to Str''ing, which is
returned from the SELECT.
This is custom documentation. For more information, please visit the SAP Help Portal 179
12/23/2022
string_literal
---------------
Str''ing
Syntax ESCAPE_DOUBLE_QUOTES
ESCAPE_DOUBLE_QUOTES(<value>)
Description
Escapes double quotes in the given string <value>, ensuring a valid SQL identi er is used in dynamic SQL statements to prevent
SQL injections. Returns the input string with escaped double quotes.
Example
The following code example shows that the function escapes the double quotes.
table_name
--------------
TAB""LE
For example, in the following procedure several UPDATE statements on different tables are parallelized:
Note
This is custom documentation. For more information, please visit the SAP Help Portal 180
12/23/2022
Only DML statements on column store tables are supported within the parallel execution block.
In the next example several records from a table variable are inserted into different tables in parallel.
Sample Code
You can also parallelize several calls to read-write procedures. In the following example, several procedures performing
independent INSERT operations are executed in parallel.
Sample Code
This is custom documentation. For more information, please visit the SAP Help Portal 181
12/23/2022
call cproc;
Note
Only the following statements are allowed in read-write procedures, which can be called within a parallel block:
DML
Imperative logic
Autonomous transaction
Only concurrent reads on one table are allowed. Implicit SELECT and SELCT INTO scalar variable statements are
supported.
Calling procedures containing dynamic SQL (for example, EXEC, EXECUTE IMMEDIATE) is not supported in parallel blocks
Mixing read-only procedure calls and read-write procedure calls in a parallel block is not allowed.
Description
Before the introduction of SQLScript recursive logic, it was necessary to rewrite any recursive operation into an operation using
iterative logic, if it was supposed to be used within an SQLScript procedure or a function. SQLScript now supports recursive
logic that allows you to write a procedure or a function that calls itself within its body until the abort condition is met.
Example
Sample Code
This is custom documentation. For more information, please visit the SAP Help Portal 182
12/23/2022
call factorial_proc(10, ?);
Limitations
The following limitations apply:
User-de ned functions do not have an explicit call-depth check, but the system will return a run-time error when no
further evaluation is available.
The execution of Calculation Engine Plan Operators currently is bound to processing within the calculation engine and does
not allow a possibility to use alternative execution engines, such as L native execution. As most Calculation Engine Plan
Operators are converted internally and treated as SQL operations, the conversion requires multiple layers of optimizations.
This can be avoided by direct SQL use. Depending on your system con guration and the version you use, mixing Calculation
Engine Plan Operators and SQL can lead to signi cant performance penalties when compared to to plain SQL
implementation.
This is custom documentation. For more information, please visit the SAP Help Portal 183
12/23/2022
Overview: Mapping between CE_* Operators and SQL
This is custom documentation. For more information, please visit the SAP Help Portal 184
12/23/2022
Calculation engine plan operators encapsulate data-transformation functions and can be used in the de nition of a procedure
or a table user-de ned function. They constitute a no longer recommended alternative to using SQL statements. Their logic is
directly implemented in the calculation engine, which is the execution environments of SQLScript.
Data Source Access operators that bind a column table or a column view to a table variable.
Relational operators that allow a user to bypass the SQL processor during evaluation and to directly interact with the
calculation engine.
CE_COLUMN_TABLE
Syntax:
CE_COLUMN_TABLE(<table_name> [<attributes>])
Syntax Elements:
This is custom documentation. For more information, please visit the SAP Help Portal 185
12/23/2022
Identi es the table name of the column table, with optional schema name.
Description:
The CE_COLUMN_TABLE operator provides access to an existing column table. It takes the name of the table and returns its
content bound to a variable. Optionally a list of attribute names can be provided to restrict the output to the given attributes.
Note that many of the calculation engine operators provide a projection list for restricting the attributes returned in the output.
In the case of relational operators, the attributes may be renamed in the projection list. The functions that provide data source
access provide no renaming of attributes but just a simple projection.
Note
Calculation engine plan operators that reference identi ers must be enclosed with double-quotes and capitalized, ensuring
that the identi er's name is consistent with its internal representation.
If the identi ers have been declared without double-quotes in the CREATE TABLE statement (which is the normal method),
they are internally converted to upper-case letters. Identi ers in calculation engine plan operators must match the internal
representation, that is they must be upper case as well.
In contrast, if identi ers have been declared with double-quotes in the CREATE TABLE statement, they are stored in a case-
sensitive manner. Again, the identi ers in operators must match the internal representation.
CE_JOIN_VIEW
Syntax:
CE_JOIN_VIEW(<column_view_name>[{,<attributes>,}...])
Syntax elements:
Speci es the name of the required columns from the column view.
Description:
This is custom documentation. For more information, please visit the SAP Help Portal 186
12/23/2022
The CE_JOIN_VIEW operator returns results for an existing join view (also known as Attribute View). It takes the name of the
join view and an optional list of attributes as parameters of such views/models.
CE_OLAP_VIEW
Syntax:
CE_OLAP_VIEW(<olap_view_name>, '['<attributes>']')
Syntax elements:
Note
Note you must have at least one <aggregation_exp> in the attributes.
count("column")
sum("column")
min("column")
max("column")
This is custom documentation. For more information, please visit the SAP Help Portal 187
12/23/2022
Description:
The CE_OLAP_VIEW operator returns results for an existing OLAP view (also known as an Analytical View). It takes the name of
the OLAP view and an optional list of key gures and dimensions as parameters. The OLAP cube that is described by the OLAP
view is grouped by the given dimensions and the key gures are aggregated using the default aggregation of the OLAP view.
CE_CALC_VIEW
Syntax:
CE_CALC_VIEW(<calc_view_name>, [<attributes>])
Syntax elements:
Speci es the name of the required attributes from the calculation view.
Description:
The CE_CALC_VIEW operator returns results for an existing calculation view. It takes the name of the calculation view and
optionally a projection list of attribute names to restrict the output to the given attributes.
Relational Operators
The calculation engine plan operators presented in this section provide the functionality of relational operators that are directly
executed in the calculation engine. This allows exploitation of the speci c semantics of the calculation engine and to tune the
code of a procedure if required.
CE_JOIN
Syntax:
Syntax elements:
This is custom documentation. For more information, please visit the SAP Help Portal 188
12/23/2022
Speci es a list of join attributes. Since CE_JOIN requires equal attribute names, one attribute name per pair of join attributes
is sufficient. The list must at least have one element.
Speci es a projection list for the attributes that should be in the resulting table.
Note
If the optional projection list is present, it must at least contain the join attributes.
Description:
The CE_JOIN operator calculates a natural (inner) join of the given pair of tables on a list of join attributes. For each pair of join
attributes, only one attribute will be in the result. Optionally, a projection list of attribute names can be given to restrict the
output to the given attributes. Finally, the plan operator requires each pair of join attributes to have identical attribute names.
In case of join attributes having different names, one of them must be renamed prior to the join.
CE_LEFT_OUTER_JOIN
Calculate the left outer join. Besides the function name, the syntax is the same as for CE_JOIN.
CE_RIGHT_OUTER_JOIN
Calculate the right outer join. Besides the function name, the syntax is the same as for CE_JOIN.
Note
CE_FULL_OUTER_JOIN is not supported.
CE_PROJECTION
Syntax:
Syntax elements:
This is custom documentation. For more information, please visit the SAP Help Portal 189
12/23/2022
Speci es a list of attributes that should be in the resulting table. The list must at least have one element. The attributes can be
renamed using the SQL keyword AS, and expressions can be evaluated using the CE_CALC function.
Speci es an optional lter where Boolean expressions are allowed. See CE_CALC for the lter expression syntax.
Description:
Restricts the columns of the table variable <var_table> to those mentioned in the projection list. Optionally, you can also
rename columns, compute expressions, or apply a lter.
With this operator, the <projection_list> is applied rst, including column renaming and computation of expressions. As
last step, the lter is applied.
Caution
Be aware that < lter> in CE_PROJECTION can be vulnerable to SQL injection because it behaves like dynamic SQL. Avoid
use cases where the value of < lter> is passed as an argument from outside of the procedure by the user himself or herself,
for example:
create procedure proc (in filter nvarchar (20), out output ttype)
begin
tablevar = CE_COLUMN_TABLE(TABLE);
output = CE_PROJECTION(:tablevar,
["A", "B"], '"B" = :filter );
end;
It enables the user to pass any expression and to query more than was intended, for example: '02 OR B = 01'.
CE_CALC
Syntax:
Syntax elements:
Speci es the expression to be evaluated. Expressions are analyzed using the following grammar:
This is custom documentation. For more information, please visit the SAP Help Portal 190
12/23/2022
Where terminals in the grammar are enclosed, for example 'token' (denoted with id in the grammar), they are like SQL
identi ers. An exception to this is that unquoted identi ers are converted into lower-case. Numeric constants are basically
written in the same way as in the C programming language, and string constants are enclosed in single quotes, for example, 'a
string'. Inside string, single quotes are escaped by another single quote.
An example expression valid in this grammar is: "col1" < ("col2" + "col3"). For a full list of expression functions, see
the following table.
Description:
CE_CALC is used inside other relational operators. It evaluates an expression and is usually then bound to a new column. An
important use case is evaluating expressions in the CE_PROJECTION operator. The CE_CALC function takes two arguments:
Expression Functions
dec oat convert arg to dec oat type dec oat dec oat(arg)
midstr returns a part of the string starting at arg2, string midstr(string, int, int)
arg3 bytes long. arg2 is counted from 1 (not
0) 2
This is custom documentation. For more information, please visit the SAP Help Portal 191
12/23/2022
leftstr returns arg2 bytes from the left of the arg1. string leftstr(string, int)
If arg1 is shorter than the value of arg2, the
complete string will be returned. 1
rightstr returns arg2 bytes from the right of the string rightstr(string, int)
arg1. If arg1 is shorter than the value of
arg2, the complete string will be returned. 1
instr returns the position of the rst occurrence int instr(string, string)
of the second string within the rst string
(>= 1) or 0, if the second string is not
contained in the rst. 1
This is custom documentation. For more information, please visit the SAP Help Portal 192
12/23/2022
Mathematical Functions The math functions described here generally operate on oating point values; their inputs
will automatically convert to double, the output will also be a double.
double log(double) These functions have the same functionality as in the Cprogramming language.
double exp(double)
double log10(double)
double sin(double)
double cos(double)
double tan(double)
double asin(double)
double acos(double)
double atan(double)
double sinh(double)
double cosh(double)
double oor(double)
double ceil(double)
sign sign returns -1, 0 or 1 depending on the sign int sign(double), etc.
of its argument. Sign is implemented for all
int sign(date)
numeric types, date, and time.
int sign(time)
time abs(time)
This is custom documentation. For more information, please visit the SAP Help Portal 193
12/23/2022
Further Functions
1
Due to calendar variations with dates earlier that 1582, the use of the date data type is deprecated; you should use the
daydate data type instead.
Note
date is based on the proleptic Gregorian calendar. daydate is based on the Gregorian calendar which is also the calendar
used by SAP HANA SQL.
2 These Calculation Engine string functions operate using single byte characters. To use these functions with multi-byte
character strings please see section: Using String Functions with Multi-byte Character Encoding below. Note, this limitation
does not exist for the SQL functions of the SAP HANA database which support Unicode encoded strings natively.
Related Information
CE_CALC
CE_AGGREGATION
Syntax:
This is custom documentation. For more information, please visit the SAP Help Portal 194
12/23/2022
Syntax elements:
Note
CE_AGGREGATION cannot handle tables directly as input.
Speci es a list of aggregates. For example, [SUM ("A"), MAX("B")] speci es that in the result, column "A" has to be
aggregated using the SQL aggregate SUM and for column B, the maximum value should be given.
count("column")
sum("column")
min("column")
max("column")
Speci es an optional list of group-by attributes. For instance, ["C"] speci es that the output should be grouped by column C.
Note that the resulting schema has a column named C in which every attribute value from the input table appears exactly once.
If this list is absent the entire input table will be treated as a single group, and the aggregate function is applied to all tuples of
the table.
Speci es the name of the column attribute for the results to be grouped by.
This is custom documentation. For more information, please visit the SAP Help Portal 195
12/23/2022
Note
CE_AGGREGATION implicitly de nes a projection: All columns that are not in the list of aggregates, or in the group-by list,
are not part of the result.
Description:
The result schema is derived from the list of aggregates, followed by the group-by attributes. The order of the returned columns
is de ned by the order of columns de ned in these lists. The attribute names are:
For the aggregates, the default is the name of the attribute that is aggregated.
For instance, in the example above ([SUM("A"),MAX("B")]), the rst column is called A and the second is B.
For the group-by attributes, the attribute names are unchanged. They cannot be renamed using CE_AGGREGATION.
Note
Note that count(*) can be achieved by doing an aggregation on any integer column; if no group-by attributes are provided,
this counts all non-null values.
CE_UNION_ALL
Syntax:
Syntax elements:
Description:
The CE_UNION_ALL function is semantically equivalent to SQL UNION ALL statement. It computes the union of two tables
which need to have identical schemas. The CE_UNION_ALL function preserves duplicates, so the result is a table which
contains all the rows from both input tables.
Special Operators
In this section we discuss operators that have no immediate counterpart in SQL.
CE_VERTICAL_UNION
Syntax
This is custom documentation. For more information, please visit the SAP Help Portal 196
12/23/2022
Syntax Elements
Speci es a list of attributes that should be in the resulting table. The list must at least have one element. The attributes can be
renamed using the SQL keyword AS.
Description
For each input table variable the speci ed columns are concatenated. Optionally columns can be renamed. All input tables must
have the same cardinality.
Caution
The vertical union is sensitive to the order of its input. SQL statements and many calculation engine plan operators may
reorder their input or return their result in different orders across starts. This can lead to unexpected results.
CE_CONVERSION
Syntax:
Syntax elements:
Speci es the parameters for the conversion. The CE_CONVERSIONoperator is highly con gurable via a list of key-value pairs.
For the exact conversion parameters permissible, see the Conversion parameters table.
Specify the key and value pair for the parameter setting.
This is custom documentation. For more information, please visit the SAP Help Portal 197
12/23/2022
Speci es the parameter key name.
Description:
Applies a unit conversion to input table <var_table> and returns the converted values. Result columns can optionally be
renamed. The following syntax depicts valid combinations. Supported keys with their allowed domain of values are:
Conversion parameters
This is custom documentation. For more information, please visit the SAP Help Portal 198
12/23/2022
TRACE
Syntax:
TRACE(<var_input>)
Syntax elements:
Description:
The TRACE operator is used to debug SQLScript procedures. It traces the tabular data passed as its argument into a local
temporary table and returns its input unmodi ed. The names of the temporary tables can be retrieved from the
SYS.SQLSCRIPT_TRACE monitoring view.
This is custom documentation. For more information, please visit the SAP Help Portal 199
12/23/2022
Example:
out = TRACE(:input);
Caution
This operator should not be used in production code as it will cause signi cant run-time overhead. Additionally, the naming
conventions used to store the tracing information may change. This operator should only be used during development for
debugging purposes.
When creating a procedure, all nested procedures that belong to that procedure must exist beforehand. If procedure P1 calls
P2 internally, then P2 must have been created earlier than P1. Otherwise, P1 creation fails with the error message,“P2 does
not exist”. With large application logic and no export or delivery unit available, it can be difficult to determine the order in which
the objects need to be created.
To avoid this kind of dependency problem, SAP introduces HEADERS. HEADERS allow you to create a minimum set of metadata
information that contains only the interface of the procedure or function.
AS HEADER ONLY
You create a header for a procedure by using the HEADER ONLY keyword, as in the following example:
With this statement you create a procedure <proc_name> with the given signature <parameter_clause>. The procedure
<proc_name> has no body de nition and thus has no dependent base objects. Container properties (for example, security
mode, default_schema, and so on) cannot be de ned with the header de nition. These are included in the body de nition.
The following statement creates the procedure TEST_PROC with a scalar input INVAR and a tabular output OUTTAB:
CREATE PROCEDURE TEST_PROC (IN INVAR NVARCHAR(10), OUT OUTTAB TABLE(no INT)) AS HEADER ONLY
By checking the is_header_only eld in the system view PROCEDURE, you can verify that a procedure only header is de ned.
If you want to check for functions, then you need to look into the system view FUNCTIONS.
Once a header of a procedure or function is de ned, other procedures or functions can refer to it in their procedure body.
Procedures containing these headers can be compiled as shown in the following example:
This is custom documentation. For more information, please visit the SAP Help Portal 200
12/23/2022
CREATE PROCEDURE OUTERPROC (OUT OUTTAB TABLE (NO INT)) LANGUAGE SQLSCRIPT
AS
BEGIN
DECLARE s INT;
s = 1;
CALL TEST_PROC (:s, outtab);
END;
As long as the procedure and/or the function contain only a header de nition, they cannot be executed. Furthermore, all
procedures and functions that use this procedure or function containing headers cannot be executed because they are all
invalid.
To change this and to make a valid procedure or function from the header de nition, you must replace the header by the full
container de nition. Use the ALTER statement to replace the header de nition of a procedure, as follows:
ALTER PROCEDURE <proc_name> [(<parameter_clause>)] [LANGUAGE <lang>] [SQL SECURITY <mode>] [DEFAULT
BEGIN [SEQUENTIAL EXECUTION]
<procedure_body>
END
For a function header, the task is similar, as shown in the following example:
ALTER FUNCTION <func_name> RETURNS <return_type> [LANGUAGE <lang>] [SQL SECURITY <mode>][DEFAULT SC
AS
BEGIN
<function_body>
END
For example, if you want to replace the header de nition of TEST_PROC that was de ned already, then the ALTER statement
might look as follows:
ALTER PROCEDURE TEST_PROC (IN INVAR NVARCHAR(10), OUT OUTTAB TABLE(no INT))
LANGUAGE SQLSCRIPT SQL SECURITY INVOKER READS SQL DATA
AS
BEGIN
DECLARE tvar TABLE (no INT, name nvarchar(10));
tvar = SELECT * FROM TAB WHERE name = :invar;
outtab = SELECT no FROM :tvar;
END
You cannot change the signature with the ALTER statement. If the name of the procedure or the function or the input and
output variables do not match, you will receive an error.
Note
The ALTER PROCEDURE and the ALTER FUNCTION statements are supported only for a procedure or a function containing
a header de nition.
The following example illustrates a small scenario for using spatial data type and function in SQLScript.
The function get_distance calculates the distance between the two given parameters < rst> and <second> of type
ST_GEOMETRY by using the spatial function ST_DISTANCE.
This is custom documentation. For more information, please visit the SAP Help Portal 201
12/23/2022
The ʻ:’ in front of the variable < rst> is needed because you are reading from the variable.
The function get_distance itself is called by the procedure nested_call. The procedure returns the distance and the text
representation of the ST_GEOMETRY variable < rst>.
END;
END;
Out(1) Out(2)
----------------------------------------------------------------------
8,602325267042627 POINT(7 48)
Note that the optional SRID (Spatial Reference Identi er) parameter in SQL spatial functions is mandatory if the function is
used within SQLScript. If you do not specify the SRID, you receive an error as demonstrated with the function
ST_GEOMFROMTEXT in the following example. Here SRID 0 is used to specify the default spatial reference system.
DO
BEGIN
DECLARE arr ST_GEOMETRY ARRAY;
DECLARE line1 ST_GEOMETRY = ST_GEOMFROMTEXT('LINESTRING(1 1, 2 2, 5 5)', 0);
DECLARE line2 ST_GEOMETRY = ST_GEOMFROMTEXT('LINESTRING(1 1, 3 3, 5 5)', 0);
arr[1] = :line1;
arr[2] = :line2;
tmp2 = UNNEST(:arr) AS (A);
select A from :tmp2;
END;
If you do not use the same SRID for the ST_GEOMETRY variables <line1> and <line2> latest the UNNEST will return an error
because it is not allowed for the values in one column to have different SRID.
In addition, there is a consistency check for output table variables to ensure that all elements of a spatial column have the same
SRID.
Note
This is custom documentation. For more information, please visit the SAP Help Portal 202
12/23/2022
The following functions are currently not supported in SQLScript:
ST_CLUSTERID
ST_CLUSTERCENTEROID
ST_CLUSTERENVELOPE
ST_CLUSTERCONVEXHULL
ST_AsSVG
The construction of objects with the NEW keyword is also not supported in SQLScript. Instead you can use
ST_GEOMFROMTEXT(ʻPOINT(1 1)’, srid).
For more information on SQL spatial functions and their usage, see SAP HANA Spatial Reference available on the SAP HANA
Platform.
System Variables
System variables are built-in variables in SQLScript that provide you with information about the current context.
the result of that function is then the name and the schema_name of the function:
SCHEMA_NAME NAME
----------------------------------------
MY_SCHEMA RETURN_NAME
The next example shows that you can also pass the two system variables as arguments to procedure or function call.
This is custom documentation. For more information, please visit the SAP Help Portal 203
12/23/2022
END;
Note
Note that in anonymous blocks the value of both system variables is NULL.
The two system variable will always return the schema name and the name of the procedure or function. Creating a synonym on
top of the procedure or function and calling it with the synonym will still return the original name as shown in the next example.
We create a synonym on the RETURN_NAME function from above and will query it with the synonym:
SCHEMA_NAME NAME
------------------------------------------------------
MY_SCHEMA RETURN_NAME
::ROWCOUNT
The system variable ::ROWCOUNT stores either the number of updated rows of the previously executed DML, CALL and CREATE
TABLE statement, or the number of rows returned from a SELECT statement. There is no accumulation of ::ROWCOUNT values
from all previously executed statements. When the previous statement does not return a value, the previous value of
::ROWCOUNT is retained. When ::ROWCOUNT is used right after a PARALLEL EXECUTION block, the system variable stores only
the value of the last statement in the procedure de nition.
Caution
Until SAP HANA 2.0 SPS03, the system variable ::ROWCOUNT was updated only after DML statements. Starting with SAP
HANA 2.0 SPS04, the behavior of ::ROWCOUNT changes, it is now also updated for SELECT, CALL and CREATE TABLE
statements.
This is custom documentation. For more information, please visit the SAP Help Portal 204
12/23/2022
::ROWCOUNT for a nested CALL statement is an aggregation of the number of updated rows and does not include the
number of rows returned from SELECT statements.
::ROWCOUNT for a SELECT statement is supported for normal SELECT statements, SELECT INTO statements and table
variable assignments that contain a SELECT statement. It does not include SELECT sub-queries as a part of DML or DDL.
::ROWCOUNT for SELECT statements with multiple result sets is not supported.
Note
When ::ROWCOUNT is used after a SELECT statement, it requires to fetch entire rows from the result set to get the total
number of selected rows. When the result from the SELECT statement is assigned to a table variable or scalar variable it has
barely any effect on the performance. However, a SELECT statement that is returning a result set cannot avoid fetching all
rows implicitly regardless of how many rows will be explicitly fetched from the result set.
The following examples demonstrate how you can use ::ROWCOUNT in a procedure. Consider we have the following table T:
Now we want to update table T and want to return the number of updated rows:
UPDATED_ROWS
-------------------------
2
In the next example we change the procedure by having two update statements and in the end we again get the row count:
By calling the procedure you will see that the number of updated rows is now 1. That is because the las update statements only
updated one row.
UPDATED_ROWS
-------------------------
1
This is custom documentation. For more information, please visit the SAP Help Portal 205
12/23/2022
If you now want to have the number of all updated rows you have to retrieve the row count information after each update
statement and accumulate them:
By now calling this procedure again the number of updated row is now 3:
UPDATED_ROWS
-------------------------
3
Caution
The update of ::ROWCOUNT in SAP HANA 2.0 SPS04 introduces an incompatible behavior change. Please refer to the
following description for the details, workaround and supporting tools.
Since ::ROWCOUNT is now updated after SELECT, CALL and CREATE TABLE statements, the behavior of existing procedures
may change, if the system variable ::ROWCOUNT is not used directly after a DML statement. Using ::ROWCOUNT directly after
the target statement is recommended and can guarantee the same behavior between different versions.
To detect such cases, new rules were introduced in SQLScript Code Analyzer:
Based on the result from the SQLScript Code Analyzer rule, you can update your procedures according to the new standard
behavior.
The following scenario shows a simple example of the impact of the behavior changes.
Sample Code
Behavior Change Example
do begin
insert into mytab select * from mytab2; -- ::ROWCOUNT = 1
x = select * from mytab; -- ::ROWCOUNT = 1 (retained, SPS03), ::RWCOUNT = 2 (SPS
select ::rowcount from dummy; -- 1 in SPS03, 2 in SPS04
end;
This is custom documentation. For more information, please visit the SAP Help Portal 206
12/23/2022
SELECT statement N/A (retain previous value) The number of rows returned from
the SELECT statement
select * from mytab;
Table variable statement with SELECT statement N/A (retain previous value) The number of rows returned from
the SELECT statement
tv = select * from mytab;
SELECT INTO statement N/A (retain previous value) 1 if the statement is executed
successfully, retains the previous
select i into a from mytab; value otherwise.
SELECT INTO statement with default value N/A (retain previous value) 0 if the default values are assigned,
1 if the values are assigned from
select i into a default 2 from mytab; the SELECT statement, retains the
previous value otherwise.
EXEC INTO with SELECT statement 0 EXEC INTO with scalar variables
works similar to SELECT INTO
exec 'select i, j from mytab' into s1, s2; case.
exec 'select * from mytab' into tv;
EXEC INTO with a table variable
works similar to a table variable
assign statement case.
Nested CALL statement N/A (retain previous value) The number of updated rows.
call proc_nested;
CREATE TABLE statement N/A (retains previous value) The number of updated rows
::CURRENT_LINE_NUMBER
SQLScript procedures, functions and triggers can return the line number of the current statement via
::CURRENT_LINE_NUMBER.
Syntax
::CURRENT_LINE_NUMBER
Example
This is custom documentation. For more information, please visit the SAP Help Portal 207
12/23/2022
Sample Code
1 create procedure proc_inner(out o int) as
2 begin
3 o = ::CURRENT_LINE_NUMBER;
4 end;
Sample Code
1 create procedure proc_outer as
2 begin
3 declare a int;
4 call proc_inner(a);
5 select :a, ::CURRENT_LINE_NUMBER from dummy;
6 end;
7 call proc_outer;
8 -- Returns [3, 5]
Sample Code
1 do begin
2 declare a int = ::CURRENT_LINE_NUMBER;
3 select :a, ::CURRENT_LINE_NUMBER + 1 from dummy;
4 end;
5 -- Returns [2, 3 + 1]
Built-In Libraries
This section provides information about built-in libraries in SQLScript.
Procedure SLEEP_SECONDS
This procedure puts the current process on hold. It has one input parameter of type DOUBLE which speci es the waiting time in
seconds. The maximum precision is one millisecond (0.001), but the real waiting time may be slightly longer (about 1-2 ms) than
the given time.
Note
If you pass 0 or NULL to SLEEP_SECONDS, SQLScript executor will do nothing (also no log will be written).
Procedure WAKEUP_CONNECTION
This procedure resumes a waiting process. It has one input parameter of type INTEGER which speci es the ID of a waiting
connection. If this connection is waiting because the procedure SLEEP_SECONDS has been called, the sleep is terminated and
This is custom documentation. For more information, please visit the SAP Help Portal 208
12/23/2022
the process continues. If the given connection does not exist or is not waiting because of SLEEP_SECONDS, an error is raised.
If the user calling WAKEUP_CONNECTION is not a session admin and is different from the user of the waiting connection, an
error is raised as well.
Note
The waiting process is also terminated, if the session is canceled (with ALTER SYSTEM CANCEL SESSION or ALTER
SYSTEM DISCONNECT SESSION).
The sleeping process is listed in the monitoring view M_SERVICE_THREADS. Its LOCK_WAIT_NAME starts with
'SQLScript/SQLScript_Sync/Sleep/'.
Limitations
The library cannot be used in functions (neither in scalar, nor in tabular ones) and in calculation views.
Examples
Sample Code
Monitor
Sample Code
Resume all sleeping processes
This is custom documentation. For more information, please visit the SAP Help Portal 209
12/23/2022
The SQLSCRIPT_STRING library offers a handy and simple way for manipulating strings. You can split libraries with given
delimiters or regular expressions, format or rearrange strings, and convert table variables into the already available strings.
Syntax
Code Syntax
CREATE LIBRARY SYS.SQLSCRIPT_STRING LANGUAGE SQLSCRIPT AS BUILTIN
BEGIN
FUNCTION SPLIT(IN VALUE NVARCHAR(5000), IN SEPARATOR NVARCHAR(5000), IN MAXSPLIT INT DEFAULT
FUNCTION SPLIT_TO_TABLE(IN VALUE NVARCHAR(5000), IN SEPARATOR NVARCHAR(5000), IN MAXSPLIT INT
FUNCTION SPLIT_TO_ARRAY(IN VALUE NVARCHAR(5000), IN SEPARATOR NVARCHAR(5000), IN MAXSPLIT INT
FUNCTION TABLE_SUMMARY(IN TABLE TABLE(...), IN ROWS INT DEFAULT 100) RETURNS RESULT NVARCHAR
END;
SPLIT / SPLIT_REGEXPR
The SPLIT(_REGEXPR) function returns multiple variables depending on the given parameters.
String without separators as input returns an array with the whole given string in the rst element.
SPLIT_TO_TABLE / SPLIT_REGEXPR_TO_TABLE
The SPLIT_TO_TABLE(_REGEXPR) returns a single-column table with table type (WORD NVARCHAR(5000))
A string without separators as input returns a single-column table with a whole given string in the rst row
A string with N-1 separator as input returns a single-column table with N separated strings in N rows.
Sample Code
This is custom documentation. For more information, please visit the SAP Help Portal 210
12/23/2022
DO BEGIN
USING SQLSCRIPT_STRING AS LIB;
DECLARE a1, a2, a3 INT;
(a1, a2, a3) = LIB:SPLIT('10, 20, 30', ', '); --(10, 20, 30)
END;
Sample Code
DO BEGIN
USING SQLSCRIPT_STRING AS LIB;
DECLARE first_name, last_name STRING;
DECLARE area_code, first_num, last_num INT;
DO BEGIN
USING SQLSCRIPT_STRING AS LIB;
DECLARE first_name, last_name STRING;
DO BEGIN
USING SQLSCRIPT_STRING AS LIB;
DECLARE first_name, last_name STRING;
(first_name, last_name) = LIB:SPLIT('Michael Forsyth Jr', ' '); -- too many values
END;
Sample Code
DO BEGIN
USING SQLSCRIPT_STRING AS LIB;
DECLARE arr INT ARRAY;
DECLARE arr2 NVARCHAR(100) ARRAY;
DECLARE tv, tv2 TABLE(RESULT NVARCHAR(5000));
Note
The SPLIT_TO_TABLE function currently does not support implicit table variable declaration.
This is custom documentation. For more information, please visit the SAP Help Portal 211
12/23/2022
FORMAT String
Code Syntax
Type Meaning
Type Meaning
'c' Character
Type Meaning
This is custom documentation. For more information, please visit the SAP Help Portal 212
12/23/2022
'F' Fixed point. Use NAN for nan and INF for inf in the result.
Type 'e' with precision p-1, the number has exponent exp
If -4 <= exp < p, the same as 'f' and the precision is p-1-exp
Example
Type Example
FORMAT
Returns a single formatted string using a given format string and additional arguments. Two type of additional arguments are
supported: scalar variables and a single array. The rst argument type accepts only scalar variables and should have a proper
This is custom documentation. For more information, please visit the SAP Help Portal 213
12/23/2022
number and type of arguments. With the second argument type is allowed only one array that should have a proper size and
type.
FORMAT_TO_TABLE/FORMAT_TO_ARRAY
Returns a table or an array with N formatted strings using a given table variable. FORMAT STRING is applied row by row.
Sample Code
DO BEGIN
USING SQLSCRIPT_STRING AS LIB;
DECLARE your_name STRING = LIB:FORMAT('{} {}', 'John', 'Sutherland'); --'John Sutherland'
DECLARE name_age STRING = LIB:FORMAT('{1} {0}', 30, 'Sutherland'); --'Sutherland 30'
DECLARE pi_str STRING = LIB:FORMAT('PI: {:06.2f}', 3.141592653589793); --'PI: 003.14'
DECLARE ts STRING = LIB:FORMAT('Today is {}', TO_VARCHAR (current_timestamp, 'YYYY/MM/DD')); --'T
DECLARE scores double ARRAY = ARRAY(1.4, 2.1, 40.3);
DECLARE score_str STRING = LIB:FORMAT('{}-{}-{}', :scores); --'1.4-2.1-40.3'
END;
DO BEGIN
USING SQLSCRIPT_STRING AS LIB;
DECLARE arr NVARCHAR(5000) ARRAY;
declare tv table(result NVARCHAR(5000));
--tt: [('John', 'Sutherland', 1988), ('Edward','Stark',1960)]
DECLARE tt TABLE (first_name NVARCHAR(100), last_name NVARCHAR(100), birth_year INT);
tt.first_name[1] = 'John';
tt.last_name[1] = 'Sutherland';
tt.birth_year[1] = 1988;
tt.first_name[2] = 'Edward';
tt.last_name[2] = 'Stark';
tt.birth_year[2] = 1960;
TABLE_SUMMARY
TABLE_SUMMARY converts a table variable into a single formatted string. It serializes the table into a human-friendly format,
similar to the current result sets in the client. Since the table is serialized as a single string, the result is fetched during the
PROCEDURE execution, not at the client-side fetch time. The parameter MAX_RECORDS limits the number of rows to be
serialized. If the size of the formatted string is larger than NVARCHAR(8388607), only the limited size of the string is returned.
By means of SQLScript FORMAT functions, the values in the table are formatted as follows:
LOB types: formatted with SQLScript FORMAT string ".32s" (maximum 32 characters)
Float types: formatted with SQLScript FORMAT string “.2f” (2 digit oating point value)
Fixed types: formatted with SQLScript FORMAT string "" (default: preserve original precision + scale)
Sample Code
This is custom documentation. For more information, please visit the SAP Help Portal 214
12/23/2022
INSERT INTO SAMPLE1 VALUES ('Kevin Lawrence', 56);
INSERT INTO SAMPLE1 VALUES ('Leonard Poole', 31);
INSERT INTO SAMPLE1 VALUES ('Vanessa Avery', 16);
DO
BEGIN
USING SQLSCRIPT_STRING AS STRING;
USING SQLSCRIPT_PRINT AS PRINT;
T1 = SELECT * FROM SAMPLE1;
Print:PRINT_LINE(STRING:TABLE_SUMMARY(:T1, 3));
END;
------------------------
NAME,AGE
John Bailey,28
Kevin Lawrence,56
Leonard Poole,31
Syntax
Code Syntax
CREATE LIBRARY SYS.SQLSCRIPT_PRINT LANGUAGE SQLSCRIPT AS BUILTIN
BEGIN
PROCEDURE PRINT_LINE(IN VALUE NVARCHAR(8388607));
PROCEDURE PRINT_TABLE(IN TAB TABLE(...), IN MAX_RECORDS INT DEFAULT 100);
END;
Description
The PRINT library makes it possible to print strings or even whole tables. It is especially useful when used together with the
STRING library. The PRINT library procedures produce a server-side result from the parameters and stores it in an internal
buffer. All stored strings will be printed in the client only after the end of the PROCEDURE execution. In case of nested
execution, the PRINT results are delivered to the client after the end of the outermost CALL execution. The traditional result-
set based results are not mixed up with PRINT results.
The PRINT library procedures can be executed in parallel. The overall PRINT result is ushed at once, without writing it on a
certain stream for each request. SQLScript ensures the order of PRINT results, based on the description order in the
PROCEDURE body, not on the order of execution.
Note
The built-in library SQLSCRIPT_PRINT is only supported in SAP HANA HDBSQL.
PRINT_LINE
This library procedure returns a string as a PRINT result. The procedure accepts NVARCHAR values as input, but also most
other values are possible, as long as implicit conversion is possible (for example, INTEGER to NVARCHAR). Hence, most of the
non-NVACHAR values can be used as parameters, since they are supported with SQLScript implicit conversion. Users can freely
This is custom documentation. For more information, please visit the SAP Help Portal 215
12/23/2022
introduce string manipulation by using either a concatenation operator (||), a TO_NVARCHAR() value formatting, or the newly
introduced SQLSCRIPT_STRING built-in library.
PRINT_TABLE
This library procedure takes a table variable and returns a PRINT result. PRINT_TABLE() parses a table variable into a single
string and sends the string to the client. The parameter MAX_RECORDS limits the number of rows to be printed.
PRINT_TABLE() is primarily used together with TABLE_SUMMARY of the STRING library.
Example
Sample Code
DO
BEGIN
USING SQLSCRIPT_PRINT as LIB;
LIB:PRINT_LINE('HELLO WORLD');
LIB:PRINT_LINE('LINE2');
LIB:PRINT_LINE('LINE3');
END;
DO
BEGIN
USING SQLSCRIPT_PRINT as LIB1;
USING SQLSCRIPT_STRING as LIB2;
LIB1:PRINT_LINE('HELLO WORLD');
LIB1:PRINT_LINE('Here is SAMPLE1');
T1 = SELECT * FROM SAMPLE1;
LIB1:PRINT_LINE(LIB2:TABLE_SUMMARY(:T1));
LIB1:PRINT_LINE('Here is SAMPLE2');
T2 = SELECT * FROM SAMPLE2;
LIB1:PRINT_TABLE(:T2);
LIB1:PRINT_LINE('End of PRINT');
END;
Interface
Code Syntax
This is custom documentation. For more information, please visit the SAP Help Portal 216
12/23/2022
PUBLIC PROCEDURE START_LOGGING(CONFIGURATION_NAME VARCHAR(32));
PUBLIC PROCEDURE STOP_LOGGING(CONFIGURATION_NAME VARCHAR(32));
Description
Logging
An SQLScript object with LOG() is called a logging object. A log message can be categorized by its topic.
Procedure Description
LOG (LEVEL, TOPIC, MESSAGE, ...) A formatted log message is inserted in the output table if there is a
con guration that enables the log. The invoking user should have
the SQLSCRIPT LOGGING privilege for the current object. Saving
log messages requires a con guration, otherwise the logging will be
ignored.
Restriction
Not available inside scalar user-de ned functions and
autonomous transaction blocks.
Con guration
A con guration is an imaginary object designed for logging settings. It is not a persistence object and lasts only until the end of
the execution of the outermost statement. All settings for logging can be controlled by con gurations. At least 1 con guration is
required to save the log messages and up to 10 con gurations can exist at a time.
Procedure Description
CREATE_CONFIGURATION (CONFIGURATION_NAME) A constructor to create a con guration with the given name. The
CONFIGURATION_NAME should be unique during the whole
execution.
DROP_CONFIGURATION (CONFIGURATION_NAME) A destructor to remove the con guration with the given name. All
con gurations are destructed automatically when the outermost
statement nishes its execution.
SET_LEVEL (CONFIGURATION_NAME, LEVEL) This is a mandatory con guration setting. The Logging Library
writes logs with higher (less verbose level) or equal level. The
levels (from less verbose to more verbose) are: fatal, error, warning,
info, debug
SQLScript Objects
This is custom documentation. For more information, please visit the SAP Help Portal 217
12/23/2022
SQLSCRIPT_LOGGING supports procedures, table functions and SQLScript libraries. SQLScript objects need to be registered to
a con guration in order to collect logs from the objects. Only object-wise con gurations are supported, a member-wise setting
for libraries is not available.
Procedure Description
ADD_SQLSCRIPT_OBJECT (CONFIGURATION_NAME, Opt-in for collecting logs from the object. It requires SQLSCRIPT
SCHEMA_NAME, OBJECT_NAME) LOGGING privilege for the object. Up to 10 objects can be added to
a single con guration.
Output Table
Log messages from logging objects are inserted into an output table.
Procedure Description
SET_OUTPUT_TABLE (CONFIGURATION_NAME, SCHEMA_NAME, Sets which table should be used as an output table. Only a single
TABLE_NAME) output table is supported. The table type must match
SQLSCRIPT_LOGGING_TABLE_TYPE. This is a mandatory
con guration setting
Filters
You can focus on speci c messages by using lters. The OR operator is applied in case of multiple lter values:
will be evaluated as
Note
Currently only the type 'topic' is supported.
Procedure Description
SET_FILTER (CONFIGURATION_NAME, TYPE, ...) Sets a lter for logging. Supports open-ended parameter for
multiple lter values.
ADD_FILTER (CONFIGURATION_NAME, TYPE, ...) Adds lter values to the lter type
REMOVE_FILTER (CONFIGURATION_NAME, TYPE, ...) Remove lter values from the lter type
SQLSCRIPT_LOGGING requires to explicitly start the logging before calling an object. The logging is stopped implicitly when the
outermost statement execution is nished but can also be stopped explicitly.
This is custom documentation. For more information, please visit the SAP Help Portal 218
12/23/2022
Procedure Description
START_LOGGING (CONFIGURATION_NAME) Start to collect logs for the given con guration. Throws an error if
the output table or level are not set.
STOP_LOGGING (CONFIGURATION_NAME) Stop collecting logs for the given con guration.
b. Set up the logging level and the output table created in step 1.
c. Add one ore more SQLScript objects (a procedure, a function, a library) to the con guration.
e. Start logging.
Example
Sample Code
create function tudf1() returns table(a int) as begin
using SQLSCRIPT_LOGGING as LIB;
call LIB:LOG('debug', 'all', 'start tudf1');
s = select 1 as a from dummy;
call LIB:LOG('debug', 'all', 'this is tudf1');
call LIB:LOG('debug', 'all', 'end tudf1');
return :s;
end;
DO BEGIN
using SQLSCRIPT_LOGGING as LIB;
-- conf1
call LIB:CREATE_CONFIGURATION('conf1');
call LIB:ADD_SQLSCRIPT_OBJECT('conf1', current_schema, 'TUDF1');
call LIB:SET_OUTPUT_TABLE('conf1', current_schema, 'T1');
call LIB:SET_LEVEL('conf1', 'debug');
call LIB:START_LOGGING('conf1');
-- conf2
call LIB:CREATE_CONFIGURATION('conf2');
call LIB:ADD_SQLSCRIPT_OBJECT('conf2', current_schema, 'TUDF2');
call LIB:SET_OUTPUT_TABLE('conf2', current_schema, 'T2');
This is custom documentation. For more information, please visit the SAP Help Portal 219
12/23/2022
call LIB:SET_LEVEL('conf2', 'debug');
call LIB:START_LOGGING('conf2');
-- all
call LIB:CREATE_CONFIGURATION('conf_all');
call LIB:ADD_SQLSCRIPT_OBJECT('conf_all', current_schema, 'TUDF1');
call LIB:ADD_SQLSCRIPT_OBJECT('conf_all', current_schema, 'TUDF2');
call LIB:SET_OUTPUT_TABLE('conf_all', current_schema, 'T_ALL');
call LIB:SET_LEVEL('conf_all', 'debug');
call LIB:START_LOGGING('conf_all');
DO BEGIN
using SQLSCRIPT_LOGGING as LIB;
call LIB:CREATE_CONFIGURATION('conf1');
call LIB:SET_OUTPUT_TABLE('conf1', current_schema, 'T1');
call LIB:SET_LEVEL('conf1', 'debug');
call LIB:ADD_SQLSCRIPT_OBJECT('conf1', 'SQLSCRIPT_LOGGING_USER_A', 'P1');
call LIB:START_LOGGING('conf1');
call SQLSCRIPT_LOGGING_USER_A.p1;
call LIB:STOP_LOGGING('conf1');
END;
Related Information
SQLSCRIPT_LOGGING Privilege
SQLSCRIPT_LOGGING_TABLE_TYPE
SQLSCRIPT_LOGGING Privilege
SQLSCRIPT LOGGING privilege is required to collect logs for a SQLScript object. A logging user can be different from the
procedure owner and the owner can expose log messages to other users selectively by using this privilege.
Syntax
Code Syntax
<schema_privilege> ::= ALL PRIVILEGES |...| SQLSCRIPT LOGGING
<object_privilege> ::= ALL PRIVILEGES |...| SQLSCRIPT LOGGING
Example
Sample Code
connect sqlscript_logging_user_a password Dummy1234;
create procedure p1 sql security invoker as begin
using SQLSCRIPT_LOGGING as LIB;
This is custom documentation. For more information, please visit the SAP Help Portal 220
12/23/2022
call LIB:LOG('error', 'sqlscript', 'hello world');
end;
Related Information
Built-In Library SQLSCRIPT_LOGGING
SQLSCRIPT_LOGGING_TABLE_TYPE
SQLSCRIPT_LOGGING:LOG can only write logs to a table with a prede ned table type. You can create an output table using the
type SYS.SQLSCRIPT_LOGGING_TABLE_TYPE or the public synonym SQLSCRIPT_LOGGING_TABLE_TYPE.
De nition
CREATE TYPE SYS.SQLSCRIPT_LOGGING_TABLE_TYPE AS TABLE ( HOST VARCHAR(64) NOT NULL, PORT INTEGER NOT
CONNECTION_ID INTEGER NOT NULL, TRANSACTION_ID INTEGER NOT NULL, TIMESTAMP TIMESTAMP NOT NULL,
DATABASE_NAME NVARCHAR(256), SCHEMA_NAME NVARCHAR(256), OBJECT_NAME NVARCHAR(256), MEMBER_NAME
SOURCE_LINE INTEGER NOT NULL, MESSAGE NVARCHAR(5000));
Example
Sample Code
create table mytab like sys.sqlscript_logging_table_type;
Related Information
Built-In Library SQLSCRIPT_LOGGING
Example
The following procedure uses two scalar variables (var1 and var2) in the WHERE-clause of a nested query.
Sample Code
CREATE PROCEDURE PROC (IN var1 INT, IN var2 INT, OUT tab mytab)
AS
BEGIN
tab = SELECT * FROM MYTAB WHERE MYCOL >:var1
This is custom documentation. For more information, please visit the SAP Help Portal 221
12/23/2022
OR MYCOL =:var2;
END;
Sample Code
will prepare the nested query of the table variable tab by using query parameters for the scalar parameters:
Sample Code
Before the query is executed, the parameter values will be bound to the query parameters.
Calling the procedure without query parameters and using constant values directly
Sample Code
CALL PROC (var1=>1, var2=>2, mytab=>?)
will lead to the following query string that uses the parameter values directly:
Sample Code
SELECT * FROM MYTAB WHERE MYCOL >1 OR MYCOL =2;
The advantage of using query parameters is that the generated query plan cache entry can be used even if the values of the
variables var1 and var2 change.
A potential disadvantage is that there is a chance of not getting the most optimal query plan because optimizations using
parameter values cannot be performed directly during compilation time. Using constant values will always lead to preparing a
new query plan and therefore to different query plan cache entries for the different parameter values. This comes along with
additional time spend for query preparation and potential cache ooding effects in fast-changing parameter value scenarios.
In order to control the parameterization behavior of scalar parameters explicitly, you can use the function
BIND_AS_PARAMETER and BIND_AS_VALUE. The decision of the optimizer and the general con guration are overridden when
you use these functions.
Syntax
Using BIND_AS_PARAMETER will always use a query parameter to represent a <scalar_variable> during query preparation.
Using BIND_AS_VALUE will always use a value to represent a <scalar_variable> during query preparation.
This is custom documentation. For more information, please visit the SAP Help Portal 222
12/23/2022
The following example represents the same procedure from above but now using the functions BIND_AS_PARAMETER and
BIND_AS_VALUE instead of referring to the scalar parameters directly:
Sample Code
CREATE PROCEDURE PROC (IN var1 INT, IN var2 INT, OUT tab mytab)
AS
BEGIN
tab = SELECT * FROM MYTAB WHERE MYCOL > BIND_AS_PARAMETER(:var1)
OR MYCOL = BIND_AS_VALUE(:var2);
END;
Sample Code
CALL PROC (var1=>?, var2=>?, mytab=>?)
and bind the values (1 for var1 and 2 for var2), the following query string will be prepared
Sample Code
SELECT * FROM MYTAB WHERE MYCOL >? OR MYCOL = 2;
The same query string will be prepared even if you call this procedure with constant values because the functions override the
decisions of the optimizer.
Sample Code
CALL PROC (var1=>1, var2=>2, mytab=>?)
Supportability
M_ACTIVE_PROCEDURES
The view M_ACTIVE_PROCEDURES monitors all internally executed statements starting from a procedure call. That also
includes remotely executed statements.
M_ACTIVE_PROCEDURES is similar to M_ACTIVE_STATEMENTS but keeps the records of completed internal statements until
the parent procedure nishes, and shows them in hierarchical order of nested level. The structure of M_ACTIVE_PROCEDURES
looks as follows:
This is custom documentation. For more information, please visit the SAP Help Portal 223
12/23/2022
Note
By default this column shows '-1'. You
need to perform the following
con gurations to enable the statistics.
global.ini:
('resource_tracking',
'enable_tracking') = 'true’
global.ini:
('resource_tracking',
'memory_tracking') = 'true'
This is custom documentation. For more information, please visit the SAP Help Portal 224
12/23/2022
M_ACTIVE_PROCEDURES is also helpful for analyzing long-running procedures and for determining their current status. You can
run the following query from another session to nd out more about the status of a procedure, like MY_SCHEMA.MY_PROC in
the example:
There is also an INI-con guration monitoring_level to control the granularity of monitoring level:
Level Description
1 Default mode. Enables pro ling information, but still disables the
collection of STATEMENT_PARAMTER values.
To prevent ooding of the memory with irrelevant data, the number of records is limited. If the record count exceeds the given
threshold, the rst record is deleted irrespective of its status. The limit can be adjusted the INI-parameter
execution_monitoring_limit , for example execution_monitoring_limit = 100 000.
Limitations:
Information other than EAPI layer is not monitored (but might be included in the total compilation time or execution
time).
The default behavior of M_ACTIVE_PROCEDURES is to keep the records of completed internal statements until the parent
procedure is complete. This behavior can be changed with the following two con guration parameters:
NUMBER_OF_CALLS_TO_RETAIN_AFTER_EXECUTION and RETENTION_PERIOD_FOR_SQLSCRIPT_CONTEXT.
With NUMBER_OF_CALLS_TO_RETAIN_AFTER_EXECUTION, you can specify how many calls are retained after execution and
RETENTION_PERIOD_FOR_SQLSCRIPT_CONTEXT de nes how long the result should be kept in M_ACTIVE_PROCEDURES. The
following options are possible:
Both parameters are set: M_ACTIVE_PROCEDURES keeps the speci ed numbers of records for the speci ed amount of
time
Note
All con guration parameters need to be de ned in the section sqlscript .
Query Export
This is custom documentation. For more information, please visit the SAP Help Portal 225
12/23/2022
The Query Export is an enhancement of the EXPORT statement. It allows exporting queries, that is database objects used in a
query together with the query string and parameters. This query can be either standalone, or executed as a part of a SQLScript
procedure.
Prerequisites
In order to execute the query export as a developer you need an EXPORT system privilege.
Procedure
To export one or multiple queries of a procedure, use the following syntax:
With <export_format> you de ne whether the export should use a BINARY format or a CSV format.
Note
Currently the only format supported for SQLScript query export is CSV . If you choose BINARY, you get a warning message
and the export is performed in CSV.
The server path where the export les are be stored is speci ed as <path>.
For more information about <export_option_list>, see EXPORT in the SAP HANA SQL and System Views Reference on the SAP
Help Portal.
Apart from SELECT statements, you can export the following statement types as well:
With the <sqlscript_location_list> you can de ne in a comma-separated list several queries that you want to export. For each
query you have to specify the name of the procedure with <procedure_name> to indicate where the query is located.
<procedure_name> can be omitted if it is the same procedure as the procedure in <procedure_call_statement>.
This is custom documentation. For more information, please visit the SAP Help Portal 226
12/23/2022
You also need to specify the line information, <line_number>, and the column information, <column_number>. The line number
must correspond to the rst line of the statement. If the column number is omitted, all statements (usually there is just one) on
this line are exported. Otherwise the column must match the rst character of the statement.
The line and column information is usually contained in the comments of the queries generated by SQLScript and can be taken
over from there. For example, the monitoring view M_ACTIVE_PROCEDURES or the statement statistic in PlanViz shows the
executed queries together with the comment.
If you want to export both queries of table variables tabtemp, then the <sqlscript_location> looks as follows: and
For the query of table variable temp we also speci ed the column number because there are two table variable assignments on
one line and we only wanted to have the rst query.
To export these queries, the export needs to execute the procedure call that triggers the execution of the procedure containing
the queries. Therefore the procedure call has to be speci ed as well by using <procedure_call_statement>:
EXPORT ALL AS CSV INTO '/tmp' ON (proc_one LINE 15), ( proc_two LINE 27 COLUMN 4) FOR CALL PROC_ON
If you want to export a query that is executed multiple times, you can use <pass_number> to specify which execution should be
exported. If <pass_number> is omitted, only the rst execution of the query is exported. If you need to export multiple passes,
but not all of them, you need to specify the same location multiple times with the corresponding pass numbers.
This is custom documentation. For more information, please visit the SAP Help Portal 227
12/23/2022
...
40 END;
Given the above example, we want to export the query on line 34 but only the snapshot of the 2nd and 30th loop iteration. The
export statement is then the following, considering that PROC_LOOP is a procedure call:
EXPORT ALL AS CSV INTO '/tmp' ON (myschema.proc_loop LINE 34 PASS 2), (myschema.proc_loop LINE 34 P
If you want to export the snapshots of all iterations you need to use PASS ALL:
EXPORT ALL AS CSV INTO '/tmp' ON (myschema.proc_loop LINE 34 PASS ALL) FOR CALL PROC_LOOP(...);
Overall the SQLScript Query Export creates one subdirectory for each exported query under the given path <path> with the
following name pattern <schema_name>-<procedure_name>-<line_number>-<column_number>-<pass_number >. For
example the directories of the rst above mentioned export statement would be the following:
|_ /tmp
|_ MYSCHEMA-PROC_LOOP-34-10-2
|_Query.sql
|_index
|_export
|_ MYSCHEMA-PROC_LOOP-34-10-30
|_Query.sql
|_index
|_export
The exported SQLScript query is stored in a le named Query.sql and all related base objects of that query are stored in the
directories index and export, as it is done for a typical catalog export.
You can import the exported objects, including temporary tables and their data, with the IMPORT statement.
For more information about IMPORT, see IMPORT in the SAP HANA SQL and System Views Reference on the SAP Help Portal.
Note
Queries within a function are not supported and cannot be exported.
Note
Query export is not supported on distributed systems. Only single-node systems are supported.
If the derived type is larger (for example, BIGINT) than the expected type (for example, INTEGER) this can lead to errors, as
illustrated in the following example.
The procedure PROC_TYPE_MISMATCH has a de ned tabular output variable RESULT with a single column of type VARCHAR
with a length of 2. The derived type from the table variable assignment has a single column of type VARCHAR with a length of
10.
This is custom documentation. For more information, please visit the SAP Help Portal 228
12/23/2022
Calling this procedure will work ne as long as the difference in length does not matter, for example calling this procedure from
any SQL client will not cause an issues. However, using the result for further processing can lead to an error as illustrated in the
following example:
To avoid such errors, the con guration parameters Typecheck_Procedure_Output_Var and Typecheck_Procedure_Input_Var
were introduced. These parameters are intended to expose differences between expected and derived type information. The
default behavior of the parameters is to return a warning in case of type mismatch. For example, during the creation or call of
procedure PROC_WITH_TYPE_MISMATCH, the following warning will be thrown:
Declared type "VARCHAR(2)" of attribute "A" not same as assigned type "VARCHAR(10)"
The con guration parameters have three different levels to reveal differences between expected and derived types if the
derived type is larger than the expected type:
strict return type mismatch: Declared type Error in case of potential type error
"VARCHAR(2)" of attribute "A" not same as
assigned type "VARCHAR(10)"
Note
Both con guration parameters need to be de ned in the sqlscript section.
SQLScript Debugger
With the SQLScript debugger you can investigate functional issues. The debugger is available in the SAP WebIDE for SAP HANA
(WebIDE) and in ABAP in Eclipse (ADT Debugger). In the following we want to give you an overview of the available functionality
and also in which IDE it is supported. For a detailed description of how to use the SQLScript debugger, see the documentation of
SAP WebIDE for SAP HANA and ABAP in Eclipse available at the SAP HANA Help Portal.
This is custom documentation. For more information, please visit the SAP Help Portal 229
12/23/2022
Conditional Breakpoints
A conditional breakpoint can be used to break the debugger in the breakpoint-line only when certain conditions are met. This is
especially useful when a Breakpoint is set within a loop.
Each breakpoint can have only one condition. The condition expressions can contain any SQL function. A condition must either
contain an expression that results in true or false, or can contain a single variable or a complex expression without restrictions
in the return type.
When setting a conditional breakpoint, the debugger will check all conditions for potential syntax errors. It checks for:
unknown variables
At execution time the debugger will check and evaluate the conditions of the conditional breakpoints, but with the given
variables and its values. If the value of a variable in a condition is not accessible and therefor the condition cannot be evaluated,
the debugger will send a warning and will break for the breakpoint anyway.
Note
The debugger will also break and send a warning, if there are expressions set, that access a variable that is not yet
accessible at this point (NULL value).
Note
Conditional breakpoints are only supported for scalar variables.
For more information on SQL functions, see FUNCTION in the SAP HANA SQL and System Views Reference on the SAP Help
Portal.
This is custom documentation. For more information, please visit the SAP Help Portal 230
12/23/2022
Watchpoints
Watchpoints give you the possibility to watch the values of variables or complex expressions and break the debugger, if certain
conditions are met.
For each watchpoint you can de ne an arbitrary number of conditions. The conditions can either contain an expression that
results in true or false or contain a single variable or complex expression without restrictions in the return type.
When setting a watchpoint, the debugger will check all conditions for potential syntax errors. It checks for:
At execution time the debugger will check and evaluate the conditions of the watchpoints, but with the given variables and its
values. A watchpoint will be skipped, if the value of a variable in a condition is not accessible. But in case the return type of the
condition is wrong , the debugger will send a warning to the user and will break for the watchpoint anyway.
Note
If a variable value changes to NULL, the debugger will not break since it cannot evaluate the expression anymore.
Break on Error
You can activate the Exception Mode to allow the Debugger to break, if an error in the execution of a procedure or a function
occurs. User-de ned exceptions are also handled.
The debugger stops on the line, where the exception is thrown, and allows access to the current value of all local variables, the
call stack and a short information about the error. After that, the execution can continue and you can step into the exception
handler or into further exceptions (fore example, on a CALL statement).
Save Table
Save Table allows you to store the result set of a table variable into a persistent table in a prede ned schema in a debugging
session.
Syntax
EXPLAIN PLAN [SET STATEMENT_NAME = <statement_name>] FOR <explain_plan_entry>
Syntax Elements
<statement_name> ::= <string_literal> Speci es the name of a speci c execution plan in the output table
for a given SQL statement
This is custom documentation. For more information, please visit the SAP Help Portal 231
12/23/2022
<explain_plan_entry> ::= <call_statement> | SQL <plan_id> speci es the identi er of the entry in the SQL plan
PLAN CACHE ENTRY <plan_id> cache to be explained. Refer to the M_SQL_PLAN_CACHE
monitoring view to nd the <plan_id> for the desired cache entry.
<plan_id> ::= <integer_literal>
<call_statement> speci es the procedure call to explain the
plan for. For more information about subqueries, see the CALL
statement.
Note
The EXPLAIN PLAN [SET STATEMENT_NAME = <statement_name>] FOR SQL PLAN CACHE ENTRY <plan_id>
command can only be run by users with the OPTIMIZER_ADMIN privilege.
Description
EXPLAIN PLAN provides information about the compiled plan of a given procedure. It inserts each piece of information into a
system global temporary table named EXPLAIN_CALL_PLANS. The result is visible only within the session where the EXPLAIN
PLAN call is executed.
EXPLAIN PLAN generates the plan information by using the given SQLScript Engine Plan structure. It traverses the plan
structure and records each information corresponding to the current SQLScript Engine Operator.
In the case of invoking another procedure inside of a procedure, EXPLAIN PLAN inserts the results of the invoked procedure
(callee) under the invoke operator (caller), although the actual invoked procedure is a sub-plan which is not located under the
invoke operator.
Another case is the else operator. EXPLAIN PLAN generates a dummy else operator to represent alternative operators in
the condition operator.
Example
You can retrieve the result by selecting from the table EXPLAIN_CALL_PLANS.
The EXPLAIN PLAN FOR select query deletes its temporary table by HDB client but in the case of EXPLAIN PLAN FOR call, it is
not yet supported. To delete rows in the table, execute a delete query from EXPLAIN_CALL_PLANS table or close the current
This is custom documentation. For more information, please visit the SAP Help Portal 232
12/23/2022
session.
Note
Client integration is not available yet. You need to use the SQL statement above to retrieve the plan information.
Syntax
Description
To improve supportability, SQLScript now provides more detailed information on the SQLScript Table User-De ned Function
(TUDF) native operator in EXPLAIN PLAN.
TUDF is automatically unfolded when applicable. If unfolding is blocked, the cause is listed in EXPLAIN PLAN. This feature
automatically applies to EXPLAIN PLAN FOR select statements under the following conditions:
If the two conditions are met, an SQL PLAN is automatically generated along with an SQLScript Engine Plan of the TUDF.
Behavior
EXPLAIN PLAN for SQLScript TUDF native operator provides the following compiled plans:
EXPLAIN PLAN FOR select statement from SQL PLAN. The result is retrievable from the table EXPLAIN_PLAN_TABLE.
EXPLAIN PLAN FOR CALL from SQLScript Plan. The result is retrievable from the table EXPLAIN_CALL_PLANS.
EXPLAIN_PLAN_TABLE EXPLAIN_CALL_PLANS
OPERATOR_PROPERTIES eld: The internal SQLScript plan of the outermost TUDF is explained. It
is automatically generated along with EXPLAIN_PLAN_TABLE with
lists the detailed reasons why the SQLScript TUDF is not
the same STATEMENT_NAME.
unfolded (see the table below)
Reasons Explanation
NOT UNFOLDED BECAUSE FUNCTION BODY CANNOT BE Multiple statements in TUDF body cannot be simpli ed into a
SIMPLIFIED TO A SINGLE STATEMENT single statement.
NOT UNFOLDED DUE TO ANY TABLE TUDF uses ANY TABLE type.
NOT UNFOLDED DUE TO BINARY TYPE PARAMETER TUDF has a binary type as its parameter.
This is custom documentation. For more information, please visit the SAP Help Portal 233
12/23/2022
Reasons Explanation
NOT UNFOLDED DUE TO DEV_NO_SQLSCRIPT_SCENARIO HINT The caller of TUDF disables unfolding with the
DEV_NO_PREPARE_SQLSCRIPT_SCENARIO hint.
NOT UNFOLDED DUE TO IMPERATIVE LOGICS TUDF has an imperative logic, including SQLScript IF, FOR,WHILE,
or LOOP statements.
NOT UNFOLDED DUE TO INTERNAL SQLSCRIPT OPERATOR TUDF unfolding is blocked by an internal SQLScript operator.
NOT UNFOLDED DUE TO INPUT PARAMETER TYPE MISMATCH The type of the input argument does not match the de ned type of
the TUDF input parameter.
NOT UNFOLDED DUE TO JSON OR SYSTEM FUNCTION TUDF uses JSON or system function.
NOT UNFOLDED DUE TO NATIVE SQLSCRIPT OPERATOR TUDF has a SQLScript native operator, which does not have an
appropriate SQL counterpart.
NOT UNFOLDED DUE TO NO CALCULATION VIEW UNFOLDING The caller of TUDF disables Calculation View unfolding.
NOT UNFOLDED DUE TO PRIMARY KEY CHECK TUDF has a primary key check.
NOT UNFOLDED DUE TO RANGE RESTRICTION Table with RANGE RESTRICTION is used within the TUDF.
NOT UNFOLDED DUE TO SEQUENCE OBJECT A SEQUENCE variable is used within the TUDF.
NOT UNFOLDED DUE TO SEQUENTIAL EXECUTION TUDF is executed with SEQUENTIAL EXECUTION clause.
NOT UNFOLDED DUE TO SPATIAL TYPE PARAMETER TUDF has a spatial type as its parameter.
NOT UNFOLDED DUE TO TIME TRAVEL OPTION TUDF uses a history table OR the time travel option is used.
NOT UNFOLDED DUE TO WITH HINT TUDF uses a WITH HINT clause that cannot be unfolded.
NOT UNFOLDED DUE TO WITH PARAMETERS CLAUSE TUDF uses a WITH PARAMETERS clause.
Example
Sample Code
create function func() returns table (a int)
as begin
declare k int = 0;
declare x int = 0;
for x in 1..4 do -- imperative logic
k := :k + :x;
end for;
return select :k as a from dummy;
end;
Sample Code
explain plan set statement_name = 'TUDF_PLAN' for select * from func();
This is custom documentation. For more information, please visit the SAP Help Portal 234
12/23/2022
You can retrieve the SQL Plan from the EXPLAIN_PLAN_TABLE.
Sample Code
ACCESSED_OBJECT_NAMES:
SYS.DUMMY, PUBLIC.DUMMY
You can retrieve the SQL Plan from the table EXPLAIN_CALL_PLANS.
Sample Code
Limitations
This is custom documentation. For more information, please visit the SAP Help Portal 235
12/23/2022
EXPLAIN PLAN is generated once per statement. It will not be regenerated regardless of con guration changes. To
regenerate EXPLAIN PLAN, the SQL PLAN CACHE should be cleared via ALTER SYSTEM CLEAR SQL PLAN CACHE.
EXPLAIN_CALL_PLAN accumulates execution plans over time. That content is not be automatically deleted.
Description
SAP HANA stores the results of a code coverage session in the M_SQLSCRIPT_CODE_COVERAGE_RESULTS monitoring view
and stores the de nitions of objects that were used during a code coverage session in the
M_SQLSCRIPT_CODE_COVERAGE_OBJECT_DEFINITIONS monitoring view.
Syntax
Syntax Elements
<token_id>: speci es the token that the code coverage applies to.
<user_id>: speci es the database user ID that the code coverage applies to.
<application_user_id>: speci es the ID of the application user that the code coverage applies to.
<session_id>: speci es the ID of the session that the code coverage applies to.
Select from the monitoring views at any time, and from any column, you are interested in after starting code coverage.
However, the full content of code coverage run is visible only after the query triggered in the second session (which is being
covered) nishes (described in the second example, below).
The content in the monitoring views is overwritten in these views each time you stop a SQLScript code coverage session and
start a new one. Since the data is temporary, copy or export the content from these views to retain data recorded by a
SQLScript code coverage session before executing ALTER SYSTEM STOP SQLSCRIPT CODE COVERAGE.
You must have at least two connections for code coverage. In the rst session you execute the codes on which you run code
coverage, and in the second session you start the code coverage for a speci c connection ID to record the coverage.
Caution
You must have the EXECUTE, DEBUG, and ATTACH_DEBUGGER privileges to perform code coverage.
Example
This is custom documentation. For more information, please visit the SAP Help Portal 236
12/23/2022
SAP HANA requires two sessions to perform the code coverage. The examples below use session A to execute the code on
which you run code coverage, and session B starts the code coverage for a speci c connection ID to record the coverage.
3. In session B, start code coverage by using the connection ID of the user who is executing the code in session A (this
example uses a connection ID of 203247):
CALL dummy_proc();
5. From session B, view the code coverage by querying the M_SQLSCRIPT_CODE_COVERAGE_RESULTS and
M_SQLSCRIPT_CODE_COVERAGE_OBJECT_DEFINITIONS monitoring views
If required, store the contents of the monitoring views for future reference (this can be a regular or a local temporary
table):
6. From session B, disable the code coverage (this also clears the existing code coverage):
This is custom documentation. For more information, please visit the SAP Help Portal 237
12/23/2022
Interface
The view SQLSCRIPT_ANALYZER_RULES listing the available rules is de ned in the following way:
RULE_NAMESPACE VARCHAR(16)
RULE_NAME VARCHAR(64)
CATEGORY VARCHAR(16)
SHORT_DESCRIPTION VARCHAR(256)
LONG_DESCRIPTION NVARCHAR(5000)
RECOMMENDATION NVARCHAR(5000)
Procedure ANALYZE_SQLSCRIPT_DEFINITION
The procedure ANALYZE_SQLSCRIPT_DEFINITION can be used to analyze the source code of a single procedure or a single
function that has not been created yet. If not yet existing objects are referenced, the procedure or function cannot be analyzed.
Sample Code
CREATE PROCEDURE ANALYZE_SQLSCRIPT_DEFINITION(IN OBJECT_DEFINITION NCLOB,
IN RULES TABLE(RULE_NAMESPACE VARCHAR(16), RULE_NAM
OUT FINDINGS TABLE(RULE_NAMESPACE VARCHAR(16), RULE
SHORT_DESCRIPTION NVARCHAR(256),
) AS BUILTIN
Parameter Description
OBJECT_DEFINITION Contains the DDL string of the SQLScript function or procedure that
should be analyzed
RULES Rules to be used for the analysis. Available rules can be retrieved
from the view SQLSCRIPT_ANALYZER_RULES
Procedure ANALYZE_SQLSCRIPT_OBJECTS
The procedure ANALYZE_SQLSCRIPT_OBJECTS can be used to analyze the source code of multiple already existing procedures
or functions.
Sample Code
Parameter Description
This is custom documentation. For more information, please visit the SAP Help Portal 238
12/23/2022
Parameter Description
RULES Rules that should be used for the analysis. Available rules can be
retrieved from the view SQLSCRIPT_ANALYZER_RULES.
OBJECT_DEFINITIONS Contains the names and de nitions of all objects that were
analyzed, including those without any ndings
Rules
The following rules, provided by SAP, are currently available:
UNNECESSARY_VARIABLE CONSISTENCY
UNUSED_VARIABLE_VALUE CONSISTENCY
UNCHECKED_SQL_INJECTION_SAFETY SECURITY
SINGLE_SPACE_LITERAL CONSISTENCY
COMMIT_OR_ROLLBACK_IN_DYNAMIC_SQL STYLE
USE_OF_SELECT_IN_SCALAR_UDF PERFORMANCE
USE_OF_UNASSIGNED_SCALAR_VARIABLE CONSISTENCY
DML_STATEMENTS_IN_LOOPS PERFORMANCE
USE_OF_CE_FUNCTIONS PERFORMANCE
USE_OF_DYNAMIC_SQL PERFORMANCE
ROW_COUNT_AFTER_SELECT BEHAVIOR
ROW_COUNT_AFTER_DYNAMIC_SQL BEHAVIOR
UNNECESSARY_VARIABLE
For each variable, it is tested if it is used by any output parameter of the procedure or if it in uences the outcome of the
procedure. Statements relevant for the outcome could be DML statements, implicit result sets, conditions of control
statements.
UNUSED_VARIABLE_VALUE
If a value, assigned to a variable, is not used in any other statement, the assignment can be removed. In case of default
assignments in DECLARE statements, the default is never used.
UNCHECKED_SQL_INJECTION_SAFETY
Parameters of type string should always be checked for SQL injection safety, if they are used in dynamic SQL. This rule checks if
the function is_sql_injection_safe is called for every parameter of that type.
This is custom documentation. For more information, please visit the SAP Help Portal 239
12/23/2022
For a simple conditional statement like IF is_sql_injection_safe(:var) = 0 THEN..., the control ow in the true
branch is checked. The procedure should either end (by returning or by throwing an error) or the unsafe parameter value should
be escaped with the functions escape_single_quotes or escape_double_quotes, depending on where the value is
used.
If the condition is more complex (for example, more than one variable is checked in one condition), a warning will be displayed
because it is only possible to check if any execution of the dynamic SQL has passed the SQL injection check.
SINGLE_SPACE_LITERAL
This rule searches for string laterals consisting of only one space. If ABAP VARCHAR MODE is used, such string literals are
treated as empty strings. In this case CHAR(32) can be used instead of ' '.
COMMIT_OR_ROLLBACK_IN_DYNAMIC_SQL
This rule detects dynamic SQL that uses the COMMIT or ROLLBACK statements. It is recommended to use COMMIT and
ROLLBACK directly in SQLScript, thus eliminating the need of dynamic SQL.
It can only check dynamic SQL that uses a constant string (for example, EXEC 'COMMIT';). It cannot detect dynamic SQL
that evaluates any expression (for example, EXEC 'COM' || 'MIT';)
It can only detect simple strings containing COMMIT or ROLLBACK and whitespaces, as well as simple comments. More
complex strings might not be detected by this rule.
USE_OF_SELECT_IN_SCALAR_UDF
This rule detects and reports SELECT statements in scalar UDFs. SELECT statements in scalar UDFs can affect performance. If
table operations are really needed, procedures or table UDFs should be used instead.
Sample Code
USE_OF_SELECT_IN SCALAR_UDF
DO BEGIN
tab = SELECT RULE_NAMESPACE, RULE_NAME, category FROM SQLSCRIPT_ANALYZER_RULES where rule_name
CALL ANALYZE_SQLSCRIPT_DEFINITION('
CREATE FUNCTION f1(a INT) RETURNS b INT AS
BEGIN
DECLARE x INT;
SELECT count(*) into x FROM _sys_repo.active_object;
IF :a > :x THEN
SELECT count(*) INTO b FROM _sys_repo.inactive_object;
ELSE
b = 100;
END IF;
END;', :tab, res);
SELECT * FROM :res;
END;
This is custom documentation. For more information, please visit the SAP Help Portal 240
12/23/2022
USE_OF_UNASSIGNED_SCALAR_VARIABLE
The rule detects variables which are used but were never assigned explicitly. Those variables still have their default value when
used, which might be unde ned. It is recommended to assign a default value (that can be NULL) to be sure that you get the
intended value when you read from the variable. If this rule returns a warning or an error, check in your code if have not assigned
a value to the wrong variable. Always rerun this rule after changing code, since it is possible that multiple errors trigger only a
single message and the error still persists.
For every DECLARE statement this rule returns one of the following:
<nothing>: if the variable is always assigned before use or not used. Everything is correct.
Variable <variable> may be unassigned: if there is at least one branch, where the variable is unassigned when used, even
if the variable is assigned in other branches.
Variable <variable> is used but was never assigned explicitly: if the variable will never have a value assigned when used.
DML_STATEMENTS_IN_LOOPS
The rule detects the following DML statements inside loops - INSERT, UPDATE, DELETE, REPLACE/UPSERT. Sometimes it is
possible to rewrite the loop and use a single DML statement to improve performance instead.
In the following example a table is updated in a loop. This code can be rewritten to update the table with a single DML
statement.
Sample Code
DML Statements in Loops
DO BEGIN
tab = select rule_namespace, rule_name, category from sqlscript_analyzer_rules;
call analyze_sqlscript_definition('
This is custom documentation. For more information, please visit the SAP Help Portal 241
12/23/2022
', :tab, res);
select * from :res;
end;
// Optimized version
USE_OF_CE_FUNCTIONS
The rule checks whether Calculation Engine Plan Operators (CE Functions) are used. Since they make optimization more
difficult and lead to performance problems, they should be avoided. For more information and how to replace them using only
plain SQL, see Calculation Engine Plan Operators
USE_OF_DYNAMIC_SQL
The rule checks and reports, if dynamic SQL is used within a procedure or a function.
ROW_COUNT_AFTER_SELECT
The rule checks, if the system variable ::ROWCOUNT is used after a SELECT statement.
ROW_COUNT_AFTER_DYNAMIC_SQL
The rule checks, if the system variable ::ROWCOUNT is used after the use of dynamic SQL.
Examples
Sample Code
DO BEGIN
tab = SELECT rule_namespace, rule_name, category FROM SQLSCRIPT_ANALYZER_RULES; -- selects all
CALL ANALYZE_SQLSCRIPT_DEFINITION('
CREATE PROCEDURE UNCHECKED_DYNAMIC_SQL(IN query NVARCHAR(500)) AS
BEGIN
DECLARE query2 NVARCHAR(500) = ''SELECT '' || query || '' from tab'';
EXEC :query2;
query2 = :query2; --unused variable value
END', :tab, res);
SELECT * FROM :res;
END;
Sample Code
This is custom documentation. For more information, please visit the SAP Help Portal 242
12/23/2022
DO BEGIN
tab = SELECT rule_namespace, rule_name, category FROM SQLSCRIPT_ANALYZER_RULES;
to_scan = SELECT schema_name, procedure_name object_name, definition
FROM sys.procedures
WHERE procedure_type = 'SQLSCRIPT2' AND schema_name IN('MY_SCHEMA','OTHER_SCHEMA')
ORDER BY procedure_name;
You can use SQLScript Pragmas to de ne which rules should be suppressed. The pragma name is AnalyzerSuppress and it
must at least one argument describing which rule should be suppressed.
Sample Code
create procedure proc as begin
@AnalyzerSuppress('SAP.UNNECESSARY_VARIABLE.CONSISTENCY')
declare a int;
end
Related Information
Limitations in the SQLScript Code Analyzer
Sample Code
The Code Analyzer will return a nding that the parameter 'tablename' is used within DSQL, although the example is safe
against injections.
If you look into the following example, you will see that the the handler block is analyzed on its own:
This is custom documentation. For more information, please visit the SAP Help Portal 243
12/23/2022
Sample Code
In this case the Code Analyzer will not return a nding because the injection handling is performed in the handler block itself.
Sample Code
In this case it is expected that the Code Analyzer will return a nding stating that that the value of 'var2' is not used.
However, currently most checks related to library member variables are not supported, including the following scenario:
Sample Code
In this case the Code Analyzer does not return a warning stating that 'query1' is used in dynamic SQL without being checked.
Limitations of UNCHECKED_SQL_INJECTION_SAFETY
The following issues are limited only to the UNCHECKED_SQL_INJECTION_SAFETY rule:
1. Pure SQL queries are not analyzed. This means that expressions inside those queries are not taken into consideration,
for example validators for SQL injection.
Sample Code
Validator in pure SQL
This is custom documentation. For more information, please visit the SAP Help Portal 244
12/23/2022
The example above returns a nding even though the procedure is injection safe.
If a SQLScript variable is used within a query, the Code Analyzer assumes that it is contained in the result.
Sample Code
SQLScript variable as input for pure SQL
In the example above 'query' is not contained in 'some_value' but is considered unsafe. There is no further analysis
whether the output of the query possibly contains (parts of) the SQLScript variable inputs.
Sample Code
Nested Procedure Call Example
In example above, the Code Analyzer also returns a nding because it does not analyze the inner procedure
'escape_proc'.
3. There are also limitations for structured types, like array variables, row variables or table variables.
A variable of structured type is considered one unit. It is either affected by an unchecked input completely, or not at all.
Sample Code
Container Example
This is custom documentation. For more information, please visit the SAP Help Portal 245
12/23/2022
exec :r.b;
end
In the example above, the Code Analyzer will return a nding because the row variable 'r' is considered one unit.
Because the in parameter 'query' is assigned directly (without escaping) to 'r.a', the variable 'r' as a whole is
considered affected by the input variable. Thus every operation that uses any part of 'r' is assumed to use the
unescaped version of 'query'.
Related Information
SQLScript Code Analyzer
Note
Currently, only stored procedures are supported.
ALTER SYSTEM
You can use the ALTER SYSTEM command with the following syntax:
Code Syntax
Note
You cannot lter by both session ID and procedure name.
START
When the START command is executed, the pro ler checks if the exact same lter has already been applied and if so, the
command is ignored. You can check the status of enabled pro lers in the monitoring view
M_SQLSCRIPT_PLAN_PROFILERS. Results are available only after the procedure execution has nished. If you apply a
lter by procedure name, only the outermost procedure calls are returned.
This is custom documentation. For more information, please visit the SAP Help Portal 246
12/23/2022
Sample Code
STOP
When the STOP command is executed, the pro ler disables all started commands, if they are included in the lter
condition (no exact lter match is needed). The STOP command does not affect the results that are already pro led.
CLEAR
The CLEAR command is independent of the status of pro lers (running or stopped). The CLEAR command clears pro led
results based on the PROCEDURE_CONNECTION_ID, PROCEDURE_SCHEMA_NAME, and PROCEDURE_NAME in
M_SQLSCRIPT_PLAN_PROFILER_RESULTS. If the results are not cleared, the oldest data will be automatically deleted
when the maximum capacity is reached.
j) ALTER SYSTEM CLEAR SQLSCRIPT PLAN PROFILER FOR SESSION 222222; -- deletes records with PROC
k) ALTER SYSTEM CLEAR SQLSCRIPT PLAN PROFILER FOR PROCEDURE S1.P1; -- delete records with PROC
l) ALTER SYSTEM CLEAR SQLSCRIPT PLAN PROFILER; -- deletes all records
Note
The <filter> does not check the validity or existence of <session id> or <procedure_id>.
SQL Hint
You can use the SQL HINT command to start the pro ler with the following syntax:
Code Syntax
SQL Hint is the most convenient way to enable the pro ler. In that way, the pro ling result is returned as an additional result
set. If the pro ler has already been enabled by means of the ALTER SYSTEM command, the result will be also visible in the
monitoring view.
Currently both hint and system commands can be used to enable the SQLScript Plan Pro ler for anonymous blocks.
Sample Code
Example using SQL Hint
This is custom documentation. For more information, please visit the SAP Help Portal 247
12/23/2022
DO BEGIN
select * from dummy;
END WITH HINT(SQLSCRIPT_PLAN_PROFILER); -- returns additional result set
Sample Code
Example using system command
Sample Code
Example
M_SQLSCRIPT_PLAN_PROFILER_RESULTS View
The M_SQLSCRIPT_PLAN_PROFILER_RESULTS view contains the following columns:
This is custom documentation. For more information, please visit the SAP Help Portal 248
12/23/2022
This is custom documentation. For more information, please visit the SAP Help Portal 249
12/23/2022
Memory Usage
Description
The following columns are used to track the memory usage of each operator (similarly to CPU times and ACTIVE times):
USED_MEMORY_SIZE_SELF: Memory used in the operation itself, excluding its children (in bytes)
USED_MEMORY_SIZE_CUMULATIVE: Total memory used in the operation itself and its children (in bytes)
Those columns show the memory usage of each SQL statement, such as STATEMENT_EXECUTION_MEMORY_SIZE and
STATEMENT_MATERIALIZATION_MEMORY_SIZE in M_ACTIVE_PROCEDURES. For entries whose memory consumption is not
collected or not calculated, the value displayed is '-1'.
The following two con gurations must be enabled to activate the resource tracking:
Example
Sample Code
do begin
v1 = select * from small_table with hint(no_inline);
v2 = select * from big_table with hint(no_inline);
select * from :v1 union all select * from :v2;
end with hint(sqlscript_plan_profiler);
Do -1 4084734
Execute -1 4084734
SePlan
Sequential Op -1 4084734
Initial Op -1 -1
Parallel Op -1 4084734
This is custom documentation. For more information, please visit the SAP Help Portal 250
12/23/2022
Flow Control -1 -1
Op
Terminal Op -1 -1
Nested Calls
Description
The following columns provide more detailed information about nested calls:
OPERATOR_DATABASE_NAME
OPERATOR_SCHEMA_NAME
OPERATOR_LIBRARY_NAME
OPERATOR_PROCEDURE_NAME
OPERATOR_LINE
OPERATOR_COLUMN
OPERATOR_POSITION
Example
Sample Code
The example illustrates the content of the columns above.
as begin
This is custom documentation. For more information, please visit the SAP Help Portal 251
12/23/2022
insert into t1 values (2);
end;
as begin
end;
SYSTEM P1 Compile
SYSTEM P1 Execute
SePlan
SYSTEM P1 Initial Op
SYSTEM P1 Compile
SYSTEM P1 Execute
SePlan
SYSTEM P1 Initial Op
SYSTEM P1 Terminal
Op
SYSTEM P1 Terminal
Op
SQLScript Pragmas
This is custom documentation. For more information, please visit the SAP Help Portal 252
12/23/2022
With pragmas SQLScript offers a new way for providing meta information. Pragmas can be used to annotate SQLScript code,
but they do not have a function themselves and only affect other statements and declarations. Pragmas are clearly distinct
syntax elements similar to comments, but while comments provide information to the reader of the code, pragmas provide
information to the compiler and the code analyzer.
Syntax
Code Syntax
Procedure Head
Code Syntax
Procedure Body
Note
The keywords pushscope and popscope are not case sensitive. PuShScopE is equal to pushscope and PUSHSCOPE.
Semantics
While the exact semantics depend on the speci c pragma type, there are rules that apply to pragmas in general. The identi er
is case insensitive, which means that pragma and PrAgMa are recognized as the same pragma. However, pragma arguments
are case sensitive.
Pragma scopes affect all declarations or statements between one pushscope and the next popscope with all the pragmas
that are speci ed in the pushscope.
Sample Code
do begin
@pushscope(@AnalyzerSuppress('SAP.UNNECESSARY_VARIABLE.CONSISTENCY'))
declare a int;
declare b nvarchar(500);
@popscope()
declare c date;
This is custom documentation. For more information, please visit the SAP Help Portal 253
12/23/2022
select :c from dummy;
end
In the example above the declarations for a and b will be affected by the pragma 'AnalyzerSuppress', while the declaration for c
and the SELECT statement, are not affected.
Pragma scopes are independent of the logical structure of the code. This means that irrespective of which parts of the code are
executed, the pragma scopes always affect the same statements and declarations.
Sample Code
In this example, the assignment on line 9 will never be affected by the pragma. The SELECT statement, on the other hand, will
always be affected by the pragma.
When using both pushscopes and single pragmas before declarations or statements, all pushscopes must precede the rst
single pragma. It is not allowed to mix pushscopes and single pragmas arbitrarily. For more information, see the examples in the
section Limitations.
Single pragmas affect the next statement or declaration. This includes everything that is contained by the statement or
declaration.
Sample Code
do begin
@AnalyzerSuppress('SAP.UNNECESSARY_VARIABLE.CONSISTENCY')
declare a, b, c int;
@AnalyzerSuppress('SAP.USE_OF_UNASSIGNED_SCALAR_VARIABLE.CONSISTENCY')
a = :b + 1;
end
In this example the single pragma on line 2 will affect the declarations of the three variables a, b and c. The single pragma on
line 4 will affect the assignment and all parts of it. This also includes the expression :b + 1 on the right hand side.
There is an exception for statements that contain blocks, that is basic blocks, loops and conditionals. The pragmas that are
attached to a basic block, a loop or a conditional will not affect the declarations and statements within those blocks.
Sample Code
do begin
@AnalyzerSupress('SAP.UNNECESSARY_VARIABLE.CONSISTENCY')
begin
This is custom documentation. For more information, please visit the SAP Help Portal 254
12/23/2022
declare a nvarchar(50);
select * from dummy;
end;
end
In this example neither the declaration of a, nor the SELECT statement are affected by the pragma. Since such blocks belong to
the normal SQLScript code, you can add a pragma or pragma scopes directly.
Available Pragmas
AnalyzerSuppress('NAME_SPACE.RULE_NAME.CATEGORY', ...)
Limitations
Single pragmas may not be followed directly by pragma scopes.
Sample Code
do begin /*allowed*/
@pushScope(@AnalyzerSuppress('SAP.UNUSED_VARIABLE_VALUE.CONSISTENCY'))
@AnalyzerSuppress('SAP.UNNECESSARY_VARIABLE.CONSISTENCY')
declare a, b int = 5;
@popscope()
end
do begin /*allowed*/
@pushScope(@AnalyzerSuppress('SAP.UNUSED_VARIABLE_VALUE.CONSISTENCY'))
declare a int;
@AnalyzerSuppress('SAP.UNNECESSARY_VARIABLE.CONSISTENCY')
declare b int = 5;
@popscope()
end
do begin /*allowed*/
@pushScope(@AnalyzerSuppress('SAP.UNUSED_VARIABLE_VALUE.CONSISTENCY'))
declare a int;
@AnalyzerSuppress('SAP.UNNECESSARY_VARIABLE.CONSISTENCY')
@someOtherPragma()
This is custom documentation. For more information, please visit the SAP Help Portal 255
12/23/2022
declare b int = 5;
@popscope()
end
It is not allowed to use pragma scopes within the parameter declaration list and in the declaration list before the initial begin of
a procedure.
Sample Code
-- not allowed
create procedure wrong_proc(@pushscope(@AnalyzerSuppress('SAP.UNNECESSARY_VARIABLE.CONSISTENCY')
as begin
select * from dummy;
end
-- not allowed
create procedure wrong_proc as
@pushscope(@AnalyzerSuppress('SAP.UNNECESSARY_VARIABLE.CONSISTENCY'))
a int;
b nvarchar;
@popscope()
begin
select * from dummy;
end
Related Information
SQLScript Code Analyzer
Note
To ensure a clear separation between productive and test-only coding, libraries of that language type cannot be used in any
function, procedure or library that does not utilize the language type SQLSCRIPT TEST.
Within the body of such a test library, you can use some of the SQLScript pragmas to mark a library member procedure as a
test or test-related coding: @Test(), @TestSetup(), @TestTeardown(), @TestSetupConfig('ConfigName'),
@TestTeardownConfig('ConfigName'), @TestSetupLibrary() as well as @TestTearDownLibrary().
Those pragmas are supported only for library member procedures and the procedures may not have any parameters.
Note
All of these pragmas are optional and not required by default within an SQLSCRIPT TEST library. But to enable a library
member procedure to be invoked as end-user test by the SQLScript Test Framework, at least the @Test() pragma is
This is custom documentation. For more information, please visit the SAP Help Portal 256
12/23/2022
required.
Sample Code
@TestTearDownLibrary()
public procedure TearDownLibrary() as
begin
select 'whatever' from dummy;
end;
@TestClassification('FAST','base')
@TestSetUpConfig('config1')
public procedure SetUpConfig1() as
begin
truncate table tab_test;
insert into tab_test values(1, 'first entry');
insert into tab_test values(2, 'second entry');
insert into tab_test values(3, 'third entry');
end;
@TestSetUpConfig('config2')
public procedure SetUpConfig2() as
begin
truncate table tab_test;
insert into tab_test values(5, 'fifth entry');
insert into tab_test values(6, 'sixth entry');
insert into tab_test values(7, 'seventh entry');
end;
@TestSetUpConfig('config3')
public procedure SetUpConfig3() as
begin
truncate table tab_test;
insert into tab_test values(5, 'some pattern string');
end;
@TestSetUpTest()
public procedure SetUpTest() as
begin
using sqlscript_test as testing;
declare num_entries int = record_count(tab_test);
This is custom documentation. For more information, please visit the SAP Help Portal 257
12/23/2022
testing:expect_ne(0, num_entries);
end;
@TestTearDownTest()
public procedure TearDownTest() as
begin
select 'whatever' from dummy;
end;
@TestClassification('SLOW')
@Test()
public procedure TestA as
begin
using sqlscript_test as testing;
tab1 = select 'A1' as A from dummy;
tab2 = select 'A2' as A from dummy;
testing:expect_table_eq(:tab1, :tab2);
end;
@Test()
public procedure TestC as
begin
using sqlscript_test as testing;
declare str nclob;
call proc_test(:str);
testing:expect_eq('some replaced string', :str);
end;
END;
To run the example SQLSCRIPT TEST library above, you would also need an object to be tested, for example the following
procedure:
Sample Code
When invoking end-user tests, the SQLScript Test Framework considers member procedures of the SQLSCRIPT TEST library,
marked with one of the pragmas mentioned above. It is, however, still possible to have additional member functions or
procedures in such a library without any pragmas. These could then serve as helpers or be used to separate common coding.
The order of execution of library member procedures having these pragmas is de ned as follows:
This is custom documentation. For more information, please visit the SAP Help Portal 258
12/23/2022
1. @TestSetupLibrary()
2. @TestSetupConfig('Config1')
3. @TestSetup()
4. @Test()
5. @TestTeardown()
6. @TestSetUp()
7. @Test()
8. @TestTeardown()
9. [...]
10. @TestTeardownConfig('Config1')
11. @TestSetupConfig('Config2')
12. @TestSetup()
13. @Test()
14. @TestTeardown()
15. @TestSetUp()
16. @Test()
17. @TestTeardown()
18. [...]
19. @TestTeardownConfig('Config2')
20. [...]
21. @TestTeardownLibrary()
Note
In case the execution of a library member procedure having one of the SetUp pragmas fails, the corresponding TearDown,
as well as the tests, will not be executed. With the @TestClassification(…) pragma, SetUpLibrary,
SetUpConfiguration and Test procedures can be assigned additional tags that can be used in test lters.
Related Information
Invoking End-User Tests
Listing End-User Tests
Matchers for End-User Tests
Note
As the name of the procedure indicates, the tests are run on the existing data in the system. You need to pay special
attention when writing tests that change or delete objects or data in the system because others may be in uenced by these
changes. Tests themselves may also be in uenced by other tests running in parallel on the same system.
Users do not have the EXECUTE privilege for the built-in procedure SYS.SQLSCRIPT_RUN_TESTS_ON_ORIGINAL_DATA by
default. You need to get this privilege granted (for example, by a SYSTEM user).
To invoke end-user tests in the SQLScript test framework, the following CALL statement has to be executed.
CALL SYS.SQLSCRIPT_RUN_TESTS_ON_ORIGINAL_DATA('<json_string>', ?, ?, ?)
This is custom documentation. For more information, please visit the SAP Help Portal 259
12/23/2022
The rst parameter of SYS.SQLSCRIPT_RUN_TESTS_ON_ORIGINAL_DATA speci es the test plan to be executed and has to be
provided in JSON format. The test plan speci es which tests and with what con guration shall be run. It also contains
information about which test libraries are to be executed by the test framework.
Note
Wildcards can be used to specify values in the JSON string ('*' for multiple wildcard characters, '?' for exactly one wildcard
character).
CALL SYS.SQLSCRIPT_RUN_TESTS_ON_ORIGINAL_DATA('{"schema":"MY_SCHEMA","library":"*"}', ?, ?, ?)
CALL SYS.SQLSCRIPT_RUN_TESTS_ON_ORIGINAL_DATA('{"schema":"MY_SCHEMA","library":"LIB*TEST"}', ?, ?,
CALL SYS.SQLSCRIPT_RUN_TESTS_ON_ORIGINAL_DATA('[{"schema":"MY_SCHEMA","library":"SOME_PREFIX_*"},{"
The rst call to SYS.SQLSCRIPT_RUN_TESTS_ON_ORIGINAL_DATA will run all tests (in all their con gurations respectively) of all
libraries with language type SQLSCRIPT TEST in the schema MY_SCHEMA. The second call will do the same but applies a lter
to the libraries that are to be executed. Here, only SQLSCRIPT TEST libraries having a name starting with 'LIB' and ending with
'TEST' will be executed by the test framework. For the third call, also libraries with language type SQLSCRIPT TEST in the
schema OTHER_SCHEMA will be executed but their name has to end with '_SOME_SUFFIX'.
The complete de nition of what can be provided in the JSON string of the test plan is described below.
<lib_spec> ::= '{' ["schema":"' <wildcard_pattern> '",] "library":"' <wildcard_pattern> '"' [', "cl
Note
<wildcard_pattern> is always case-sensitive.
Examples:
Sample Code
[{
"schema":"MY_SCHEMA",
"library":"*"
},
{
"library": "MY_LIB",
"run": [{
"exclude-tests": ["A", "B"],
"configurations": ["config1", "config3"]
},
{
"tests": ["A", "B"],
"exclude-configurations": ["config2"]
This is custom documentation. For more information, please visit the SAP Help Portal 260
12/23/2022
}]
},
{
"schema": "MY_SCHEMA",
"library": "*",
"run": [{
"tests": ["*TEST*KERNEL*"],
"exclude-tests": ["DISABLED_*"],
"exclude-configurations": ["*SCALE_OUT*"]
},
{
"configurations": ["*SINGLE_NODE*", "*SCALE_OUT*"],
"exclude-configurations": ["*STRESS_TEST*"]
}]
}]
Behavior
Invalid syntax or semantics result in an error.
The property library is mandatory but there are default values for other properties:
If "run" is not speci ed, all con gurations and tests will be selected. That is identical to "run": [{ "tests": [
"*" ], "configurations": [ "*" ] }].
When "tests" and "exclude-tests" match exactly the same values, an error will be thrown. The same applies to
"con gurations" and "exclude-con gurations".
When both "exclude-tests" and "tests" are given, "exclude-tests" will always have higher precedence. The same applies
to "exclude-con gurations" and "con gurations".
If a library or a con guration does not contain any tests (after applying the lter), neither the setup, nor the teardown of
this library or con guration will be executed.
An empty test plan will be generated if the input does not match any tests and no error will be thrown. Also no entries
will be added to the output tables.
Note
Each entry in <run_spec_list> will cause a separate list of tests and con gurations to be added to the test plan
depending on the values of the inner <run_spec_member> entries. In that way some tests as well as con gurations of the
same library may be executed repeatedly by the test framework.
If a classi cation speci er of a library member (the classi cation speci ed with the pragma) matches a pattern in the
exclude-speci cation, this member and everything it includes will not be executed. For example, if a SetUpLibrary
matches an exclude-classi cation, nothing in this library will be executed. For a config it means that no test will be
executed in this config. And for a test it just means that this test is not executed.
This is custom documentation. For more information, please visit the SAP Help Portal 261
12/23/2022
If the classi cations speci er does not match the exclude-speci cation, the library, the con guration or the test is
executed.
If a classi cations speci er of a library member matches a pattern in the speci cation this member and everything it
includes, it will be executed unless an exclude speci cation matches.
If the classi cation speci er does not match the speci cation, only the members included that match the speci cation
will be executed.
Sample Code
@TestClassification('clas1')
@TestSetUpConfig('A')
PUBLIC PROCEDURE SETUPCONFIGA AS BEGIN END;
@TestSetUpConfig('B')
PUBLIC PROCEDURE SETUPCONFIGB AS BEGIN END;
@TestClassification('clas2')
PUBLIC PROCEDURE TESTA AS BEGIN END;
If classi cation 'clas0' is included, everything will be executed. If classi cation 'clas1' is included, everything in con guration 'A'
will be executed. If classi cation 'clas2' is included, only 'TESTA' will be executed but in both con gurations - 'A' and 'B'.
If classi cation 'clas0' is included and 'clas1' excluded, only the con guration 'B' will be executed (with both tests). If
classi cation 'clas0' is included and 'clas2' is excluded, only 'TESTB' will be executed but in both con gurations - 'A' and 'B'. If
classi cation 'clas1' is included and 'clas2' excluded, only 'TESTB' in con guration 'A' will be executed.
If classi cation 'clas2' is included and 'clas0' excluded, nothing will be executed. If classi cation 'clas2' is included and 'clas1'
excluded, only 'TESTA' will be executed and only in con guration 'B'. If classi cation 'clas1' is included and 'clas0' excluded,
nothing will be executed.
Output
The three output parameters of SYS.SQLSCRIPT_RUN_TESTS_ON_ORIGINAL_DATA have the following table structures.
Results
This is custom documentation. For more information, please visit the SAP Help Portal 262
12/23/2022
Details
Call Stacks
CALL SYS.SQLSCRIPT_TEST:LIST_TESTS('<json_string>')
CALL SYS.SQLSCRIPT_TEST:LIST_CONFIGURATIONS('<json_string>')
Sample Code
Examples
CALL SYS.SQLSCRIPT_TEST:LIST_TESTS('{"schema":"MY_SCHEMA","library":"*"}', ?)
CALL SYS.SQLSCRIPT_TEST:LIST_TESTS('{"schema":"MY_SCHEMA","library":"LIB*TEST"}', ?)
CALL SYS.SQLSCRIPT_TEST:LIST_CONFIGURATIONS('[{"schema":"MY_SCHEMA","library":"SOME_PREFIX_*"},{"
Currently, there are several matchers for scalar variables, one matcher for table variables and one that aborts the execution of
the current test. The matchers for scalar variables are:
EXPECT_GE Checks if the rst input is greater than or equal to the second input
EXPECT_GT Checks if the rst input is greater than the second input
EXPECT_LE Checks if the rst input is less than or equal to the second input
EXPECT_LT Checks if the rst input is less than the second input
All scalar matchers, except EXPECT_NULL, take exactly two scalar input arguments. The data types of these two inputs must be
comparable in SQLScript. Most of the data types can be categorized in three classes: string types, numeric types and date
types. While all types within the same class are comparable to each other, it is not possible to compare date and numeric types.
This is custom documentation. For more information, please visit the SAP Help Portal 264
12/23/2022
String types can be compared to every other data type but will be converted to a non-string type prior to the comparison.
Whenever two different data types are compared, at least one of the inputs will be converted. When the conversion fails, it is
considered a normal execution error instead of reporting a matcher failure.
The table matcher (EXPECT_TABLE_EQ) has three input arguments. Besides the two table variables that should be compared,
there is a third optional input - IGNORE_ORDER. This parameter is TRUE by default and will compare the table variables without
considering the order of rows. For example row 2 of the rst input might match row 5 of the second input. However, every row
will be matched at most to one row in the other table variable. The two input table variables must have an equal number of
columns and the columns must have same names. The data types of the columns have to be comparable as well. If the types of
the table columns are different, one of the columns will be converted before the comparison. Unlike in scalar comparisons, this
will not lead to a run-time error if such a conversion fails. Instead, the row will always be considered a mismatch. One additional
difference to scalar matchers is the handling of NULL values. For scalar matchers, anything compared to NULL is false (even
NULL). The table matcher assumes that NULL is equal to NULL.
In case a matcher fails, a human-readable output will be added to the Details output table of the built-in procedure
SYS.SQLSCRIPT_RUN_TESTS_ON_ORIGINAL_DATA. A call stack is also generated for such a matcher failure to make it possible
to determine its exact code location. The table matcher will report a maximum of 100 row mismatches for the sake of
readability.
The built-in library SQLSCRIPT_TEST also contains a procedure named FAIL. This procedure will (similarly to a matcher) add an
entry to the Details output table of SYS.SQLSCRIPT_RUN_TESTS_ON_ORIGINAL_DATA whereby the error message that was
provided as an input argument to the procedure FAIL will be included as a message. After that, this procedure will abort the
execution of the current test. The subsequent tests will still be executed.
The following optimizations all apply to statements in SQLScript. The optimizations presented here cover how data ow exploits
parallelism in the SAP HANA database.
Reduce Complexity of SQL Statements: Break up a complex SQL statement into many simpler ones. This makes a
SQLScript procedure easier to comprehend.
Identify Common Sub-Expressions: If you split a complex query into logical sub queries it can help the optimizer to
identify common sub expressions and to derive more efficient execution plans.
Multi-Level-Aggregation: In the special case of multi-level aggregations, SQLScript can exploit results at a ner grouping
for computing coarser aggregations and return the different granularities of groups in distinct table variables. This could
save the client the effort of reexamining the query result.
Reduce Dependencies: As SQLScript is translated into a data ow graph, and independent paths in this graph can be
executed in parallel, reducing dependencies enables better parallelism, and thus better performance.
Avoid Using Cursors: Check if use of cursors can be replaced by (a ow of) SQL statements for better opportunities for
optimization and exploiting parallel execution.
Avoid Using Dynamic SQL: Executing dynamic SQL is slow because compile time checks and query optimization must be
done for every invocation of the procedure. Another related problem is security because constructing SQL statements
without proper checks of the variables used may harm security.
This is custom documentation. For more information, please visit the SAP Help Portal 265
12/23/2022
Writing this query as a single SQL statement requires either the de nition of a temporary view (using WITH), or the multiple
repetition of a sub-query. The two statements above break the complex query into two simpler SQL statements that are linked
by table variables. This query is much easier to understand because the names of the table variables convey the meaning of the
query and they also break the complex query into smaller logical pieces.
The SQLScript compiler will combine these statements into a single query or identify the common sub-expression using the
table variables as hints. The resulting application program is easier to understand without sacri cing performance.
It is very complicated for query optimizers to detect common sub-expressions in SQL queries. If you break up a complex query
into logical subqueries it can help the optimizer to identify common sub-expressions and to derive more efficient execution
plans. If in doubt, you should employ the EXPLAIN plan facility for SQL statements to investigate how the SAP HANA database
handles a particular statement.
Multi-Level Aggregation
Computing multi-level aggregation can be achieved by using grouping sets. The advantage of this approach is that multiple
levels of grouping can be computed in a single SQL statement.
For example:
To retrieve the different levels of aggregation, the client must typically examine the result repeatedly, for example, by ltering
by NULL on the grouping attributes.
In the special case of multi-level aggregations, SQLScript can exploit results at a ner grouping for computing coarser
aggregations and return the different granularities of groups in distinct table variables. This could save the client the effort of
re-examining the query result. Consider the above multi-level aggregation expressed in SQLScript:
This is custom documentation. For more information, please visit the SAP Help Portal 266
12/23/2022
Reduce Dependencies
One of the most important methods for speeding up processing in the SAP HANA database is through massively parallelized
query execution.
Parallelization is exploited at multiple levels of granularity. For example, the requests of different users can be processed in
parallel, and single relational operators within a query can also be executed on multiple cores in parallel. It is also possible to
execute different statements of a single SQLScript procedure in parallel if these statements are independent of each other.
Remember that SQLScript is translated into a data ow graph, and independent paths in this graph can be executed in parallel.
As an SQLScript developer, you can support the database engine in its attempt to parallelize execution by avoiding unnecessary
dependencies between separate SQL statements, and by using declarative constructs if possible. The former means avoiding
variable references, and the latter means avoiding imperative features, such as cursors.
Read-Only Access
For read-only access to a cursor, consider using simple selects or joins:
Computing this aggregate in the SQL engine may result in parallel execution on multiple CPUs inside the SQL executor.
Computing this in the SQL engine reduces the calls through the runtime stack of the SAP HANA database. It also potentially
bene ts from internal optimizations like buffering and parallel execution.
Like updates and deletes, computing this statement in the SQL engine reduces the calls through the runtime stack of the SAP
HANA database. It also potentially bene ts from internal optimizations like buffering and parallel execution.
This is custom documentation. For more information, please visit the SAP Help Portal 268
12/23/2022
Another related problem is security because constructing SQL statements without proper checks of the variables used can
create a security vulnerability, like an SQL injection, for example. Using variables in SQL statements prevents these problems
because type checks are performed at compile time and parameters cannot inject arbitrary SQL code.
The table below summarizes potential use cases for dynamic SQL:
Appendix
For information about the capabilities available for your contract type and provisioning scenario, refer to the Feature Scope
Description for SAP Cloud Platform, SAP HANA Service.
This is custom documentation. For more information, please visit the SAP Help Portal 269