Skip to Content
Author's profile photo Horst Keller

ABAP Language News for Release 7.40, SP05

Release news for a support package? Yes. My last blog ABAP Language News for Release 7.40 was about 7.40, SP02.  SP02 came with kernel release 740. 7.40, SP05 is a bundled support package that comes with a new kernel release 741.  And a new kernel release means new ABAP language features.

Read this blog where I cover the most important language news for SP05 to learn why it makes sense to get 7.40, SP05 as soon as possible!

Internal Tables

MOVE-CORRESPONDING for Internal Tables

You can use MOVE-CORRESPONDING not only for structures but also for internal tables now. Components of the same name are are assigned row by row. New additions EXPANDING NESTED TABLES and KEEPING TARGET LINES allow to resolve tabular components of structures and to append lines instead of overwriting existing lines.

Example

MOVE-CORRESPONDING itab1 TO itab2 EXPANDING NESTED TABLES

                                  KEEPING TARGET LINES.

More About

http://help.sap.com/abapdocu_740/en/index.htm?file=abapmove-corresponding.htm

Expressions and Functions

LET Expressions in Constructor Expressions

New LET expressions as sub expressions of constructor expressions allow you to define local variables or field symbols as auxiliary fields of constructor expressions.

Example

LET expression in a table construction using the VALUE operator.

cl_demo_output=>new( )->write(

  VALUE text( LET it = `be` IN

                 ( |To { it } is to do|          )

                 ( |To { it }, or not to { it }| )

                 ( |To do is to { it }|          )

                 ( |Do { it } do { it } do|      ) ) )->display( ).

More About

http://help.sap.com/abapdocu_740/en/index.htm?file=abaplet.htm

CORRESPONDING Operator

The new constructor operator CORRESPONDING allows to execute  a “MOVE-CORRESPONDING” for structures or internal tables at operand positions. Besides assigning components of the same name you can define your own mapping rules.

Example

struct2 = CORRESPONDING #( struct1 MAPPING b4 = a3 ).

More About

http://help.sap.com/abapdocu_740/en/index.htm?file=abenconstructor_expr_corresponding.htm

Table Comprehensions

A new FOR sub expression for constructor expressions with operators NEW and VALUE allows to read existing internal tables and to construct new tabular contents from the lines read.

Example

Construction of an internal table itab2 from lines and columns of an internal table itab1. You can of course also use the CORRESPONDING operator to construct the lines.

DATA(itab2) = VALUE t_itab2( FOR wa IN itab1 WHERE ( col1 < 30 )

                             ( col1 = wa-col2 col2 = wa-col3 ) ).

More About

http://help.sap.com/abapdocu_740/en/index.htm?file=abentable_comprehensions.htm

Meshes

This one is a little bit tricky. Meshes are special structures whose components are internal tables, which can be linked to

each other using associations. Associations are evaluated by specifying mesh paths in suitable expressions and statements.The full power of meshes will become more clear in the monent when associations will be supported by Open SQL for database views (CDS views, see below) in the future.

Example

A mesh flights is declared from a mesh type t_flights. In t_flights you have tabular components as so called mesh nodes that are linked by associations. A structured data object root  is constructed to serve as the start line for the following LOOP over a mesh path. The results are lines from sflight that are found by following the mesh path evaluating the associations between its mesh nodes.

TYPES:
  t_scarr   TYPE SORTED TABLE OF scarr
            WITH UNIQUE KEY carrid,
  t_spfli   TYPE SORTED TABLE OF spfli
            WITH UNIQUE KEY carrid connid,
  t_sflight TYPE SORTED TABLE OF sflight
            WITH UNIQUE KEY carrid connid fldate.

TYPES:
  BEGIN OF MESH t_flights,
    scarr   TYPE t_scarr
      ASSOCIATION to_spfli TO spfli
               ON carrid = carrid USING KEY primary_key,
    spfli   TYPE t_spfli
      ASSOCIATION to_sflight TO sflight
               ON carrid = carrid AND
                  connid = connid USING KEY primary_key,
    sflight TYPE t_sflight,
  END OF MESH t_flights.

DATA:
  flights TYPE t_flights.

DATA(root) = flights-scarr[ carrname = ‘United Airlines’ ].

LOOP AT
  flights-scarr\to_spfli[ root ]\to_sflight[ ]
    INTO DATA(wa).
  …
ENDLOOP.

More About

http://help.sap.com/abapdocu_740/en/index.htm?file=abenabap_meshes.htm

Open SQL

New Syntax

From 7.40, SP05

  • Lists in Open SQL statements can and should be separated by a comma.
  • Host variables in Open SQL statements can and should be escaped by a @.

Only then you will be able to use other new functions that are based on a new SQL parser in the ABAP kernel.

Example

SELECT carrid, connid, fldate

       FROM sflight

       INTO CORRESPONDING FIELDS OF TABLE @sflight_tab

       WHERE carrid = @carrier AND

             connid = @connection

       ORDER BY carrid, connid.

More About

http://help.sap.com/abapdocu_740/en/index.htm?file=ABENNEWS-740_SP05-OPEN_SQL.htm

SQL Expressions

Yo can use SQL expressions in a column list behind SELECT. The result of such an expression is calculated on the database (code push down!) and written into the respective columns of the result set. Operands can be data base columns or host variables.

Possible expressions are

  • elementary values
  • arithmetic expressions
  • arithmetic functions abs, ceil, floor, div, mod
  • castings with cast
  • string concatenations with &&
  • coalesce
  • case

Expressions can be mixed and proritized with parentheses.

Examples

SELECT id, num1, num2,

       cast( num1 AS fltp ) / cast( num2 AS fltp ) AS ratio,

       div( num1, num2 ) AS div,

       mod( num1, num2 ) AS mod,

       @offset + abs( num1 – num2 ) AS sum

       FROM demo_expressions

       INTO CORRESPONDING FIELDS OF TABLE @results

       ORDER BY SUM DESCENDING.

SELECT id, CASE char1

             WHEN ‘aaaaa’ THEN ( char1 && char2 )

             WHEN ‘xxxxx’ THEN ( char2 && char1 )

             ELSE @else

           END AS text

       FROM demo_expressions

       INTO CORRESPONDING FIELDS OF TABLE @results.

More About

http://help.sap.com/abapdocu_740/en/index.htm?file=ABAPSQL_EXPR.htm

CDS Views

The new CDS (Core Data Services) enable you to define Views of the ABAP Dictionary with a DDL (Data Definition Language) in ADT. This DDL encompasses the DDL of SQL and enhances it with the possibility to define annotations and associations. CDS-Views in the Dictionary are not bound to a specific database platform. They provide another way of database independent code push down.You can acces CDS-Views with Open SQL.

Example

Definitiion of a simple view based on only one database table. Of course, you can join as you like …

@AbapCatalog.sqlViewName: ‘BPA_VW’
define view
business_partner as
  select from snwd_bpa
         { key bp_id, company_name, bp_role }

You can access the view in ABAP programs e.g. as follows:

SELECT * FROM business_partner INTO TABLE itab …

More About

http://help.sap.com/abapdocu_740/en/index.htm?file=ABENCDS.htm

See also the dedicated blog http://scn.sap.com/community/abap/eclipse/blog/2014/02/04/new-data-modeling-features-in-abap-for-hana by Chris Swanepoel.

ABAP Managed Database Procedures

ABAP Managed Database Procedures (AMDP) are a class based framework for maintaining and calling stored procedures as so called AMDP procedures from ABAP. An AMDP procedure is implemented in its native DB-language in an AMDP method of an AMDP class. Currently, the only database that suports AMDP is SAP’s HANA database.

An AMDP class must implement a specific tag interface. Currently, there is only one namely IF_AMDP_MARKER_HDB. An AMDP class can be maintained in ADT only. An AMDP method looks from its declaration like a normal ABAP method and can be used like that. Only when implementing the method, you denote the database and the DB language. You also must denote the entities to be used. The following is an example for using the language SQLScript of the HANA database:

CLASS cl_demo_amdp DEFINITION PUBLIC.
  PUBLIC SECTION.
    INTERFACES if_amdp_marker_hdb .
    METHODS increase_price
      IMPORTING
        VALUE(clnt) TYPE sy-mandt
        VALUE(inc)  TYPE sflight-price .
ENDCLASS.

CLASS cl_demo_amdp IMPLEMENTATION.
  METHOD increase_price BY DATABASE PROCEDURE FOR HDB
                        LANGUAGE SQLSCRIPT
                        USING sflight.
    update sflight set price = price + :inc
                   where mandt = :clnt;
  ENDMETHOD.
ENDCLASS.

Please note that a simple example as the above one is only to show the syntax. Implementing functionality in an AMDP method means the usage of Native SQL. And for the usage of Native SQL the same holds as before: Stay open as long as possible! It makes absolutely no sense to push down statements to the database that you can also express in Open SQL, because those are pushed down by the Native SQL Interface in exactly the same way or even better!

You use AMDP as a convenient way of programming and handling Native SQL in ABAP only if you really gain something from it. And for that, simple examples are not too easy to find, especially since Open SQL is empowered by new features now (see above).

Example

A simple example of a database functionality that is not readily available in Open SQL is the predefined currency conversion of HANA. An AMDP method that uses this conversion might look as follows:

METHOD convert BY DATABASE PROCEDURE FOR HDB

                           LANGUAGE SQLSCRIPT

                           USING demo_prices.

  PRICES = select * from DEMO_PRICES;

  PRICES =

    CE_CONVERSION (

      :PRICES,

      [ family             = ‘currency’,

        method             = ‘ERP’,

        steps              = ‘shift,convert,shift_back’,

        target_unit        = :TO_CURRENCY,

        client             = :MANDT,

        source_unit_column = “CURRENCY”,

        reference_date     = :DATE,

        output_unit_column = “CURRENCY”,

        error_handling     = ‘keep unconverted’ ],

      [ amount AS amount ] );

   replace DEMO_PRICES select * from :PRICES;

ENDMETHOD.

An alternative implementation for databases other than the SAP HANA database must then be provided, e.g. as follows:

METHOD abap_convert.

  DATA prices TYPE STANDARD TABLE OF demo_prices.

  SELECT *

         FROM demo_prices

         INTO TABLE prices.

  LOOP AT prices ASSIGNING FIELD-SYMBOL(<price>).

    CALL FUNCTION ‘CONVERT_TO_LOCAL_CURRENCY’

      EXPORTING

        client           = mandt

        date             = date

        foreign_amount   = <price>-amount

        foreign_currency = <price>-currency

        local_currency   = to_currency

      IMPORTING

        local_amount     = <price>-amount

      EXCEPTIONS

        OTHERS           = 4.

    IF sy-subrc <> 0.

      CONTINUE.

    ENDIF.

    <price>-currency = to_currency.

  ENDLOOP.

  MODIFY demo_prices FROM table prices.

ENDMETHOD.

ABAP code calling these methods could look as follows:

IF cl_db_sys=>is_in_memory_db = abap_true.

    NEW cl_demo_sqlscript_curr_conv(

      )->convert(

           EXPORTING

             to_currency      = to_upper( currency )

             mandt            = sy-mandt

             date             = sy-datlo ).

ELSE.

   NEW cl_demo_sqlscript_curr_conv(

     )->abap_convert(

          EXPORTING

            to_currency      = to_upper( currency )

            mandt            = sy-mandt

            date             = sy-datlo ).

ENDIF.

More About

http://help.sap.com/abapdocu_740/en/index.htm?file=ABENAMDP.htm

Further Information

For a complete overview of all ABAP Language News for Release 7.40, SP05 see

If you are especially interested in ABAP for HANA, also have a look at Jens Weiler’s blog New ABAP for HANA features in SAP NW 7.4 SP5. The ABAP Keyword Documentation summarizes the respective ABAP language features under http://help.sap.com/abapdocu_740/en/index.htm?file=ABENABAP_HANA.htm.

Outlook

The next bundled release will be 7.40, SP08 with kernel release 742. Expect some nice features from that one too. I’m already very busy documenting them.

Assigned Tags

      90 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Former Member
      Former Member

      Hi,

      Looks quite impressive. It seems that in 2-3 years, we won't be able to recognize our old ABAP code anymore.

      Personally, I was most impressed by the new SQL parser.

      It brings us to a new SQL era, in which we can (finally) make advantage of some basic SQL-native features.

      What about expressions in WHERE clause? 😳

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      What about expressions in WHERE clause?

      In preparation for SP08 ...

      Author's profile photo Former Member
      Former Member

      Hello Horst Keller,

      Thank you very much for sharing information about new release 7.40 and SP05 of ABAP language.

      Author's profile photo Wouter Lemaire
      Wouter Lemaire

      Hi,

      Future is looking good!  Thank you for sharing!

      Is HANA required for the SQL Expressions or will this work with any database on ABAP 7.40 SP5 ?

      Kind regards,

      Wouter

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Is HANA required for the SQL Expressions or will this work with any database on ABAP 7.40 SP5 ?

      Hi Wouter,

      Its Open SQL, it works on all databases (my colleagues are working hard to produce the same results for all supportet DBs. Especially for calculations the task is not trivial).

      Best

      Horst

      Author's profile photo Peter Inotai
      Peter Inotai

      Hi Horst,

      Thanks for this great new feature overview.

      It's good to see that currently with SPs so many features are added to ABAP as earlier with new releases 🙂

      I have some questions (as usual 🙂 ):

      • Can you already share something about SP08 with kernel release 742? Or it's too early?
      • I also don't really understand what was the main motivation with AMDP that SQLscript is mixed up with ABAP instead of keeping SQLscript as a new, separated repository object like XLST transformation for example?

      Thanks,

      Peter

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Hi Peter,

      Can you already share something about SP08 with kernel release 742?

      Hmm, officially I'm not allowed to speak about deatails of future releases, but what I can tell you is that ABAP will continue its evolution and that again many new nice features will come that will close existing gaps and enhance the language with new functionality.

      I also don't really understand what was the main motivation with AMDP that SQLscript is mixed up with ABAP instead of keeping SQLscript as a new, separated repository object like XLST transformation for example?

      AMDP is not about SQLScript. AMDP is about Native SQL or other DB languages. AMDP can be seen as an advanced way of embedding Native SQL into ABAP - a modern EXEC SQL so to say. SQLScript of HANA is simply the first language supported by AMDP. AMDP offers an open API to any DB. If other DB platforms then HANA will support AMDP, AMDP can also support their languages. You also cannot compare DB procedures to XSLT programs. While an XSLT program is compiled and excuted on the application server, dabase procedures are entities of their DB. Before running an AMDP method from ABAP the first time, the system checks if the corresponding DB procedure is available in the DB and if it has the most recent version. If necessary the DB procedure is created or replaced and then executed. You can even examine and call the AMDP managed DB procedure in the HANA Studio. But its lifecycle management is completely governed by ABAP and therefore  by ABAP's transport management. And this is the main advantage. Regarding the execution of the AMDP managed DB procedure, there is no difference to any native DB procedure created in the HANA Studio. But for calling and software logistics there is no difference to a normal ABAP method.

      Best

      Horst

      Author's profile photo Peter Inotai
      Peter Inotai

      Thanks a lot for the detailed answer.

      For point 1) I'm sure you will share it here, once it can be shared. 🙂

      For point 2) now the picture is more clear. I'm looking forward to be able to play around with it.

      Peter

      Author's profile photo Peter Inotai
      Peter Inotai

      Hi Horst,

      It seems ABAP 7.40 SP08 is officially available on SMP.

      Can you blog about the new ABAP features when you have some time (I guess it's a pretty important condition 🙂 )?

      Thanks a lot,

      Peter

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      I wanted to do it more spontaneously  😉   ...

      In fact, no blogs needed since everything is documented here (refresh your browser's caches).

      Author's profile photo Former Member
      Former Member

      Horst Keller wrote:

      I wanted to do it more spontaneously  😉   ...

      In fact, no blogs needed since everything is documented here (refresh your browser's caches).

      But not with examples 😥

      That's why we need your blogs 😛 . You describe the cool new features with appropriate examples 😎

      Author's profile photo Peter Inotai
      Peter Inotai

      I agree, examples make life easier. Usually I also like screenshots (although there is no screenshot in this blog).

      Plus we can also comment/ask on blogs 🙂

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Not with examples?

      I guess, I have enough examples ...

      What you need is simple examples 😛

      Author's profile photo Former Member
      Former Member

      Horst Keller wrote:

      I guess, I have enough examples ...

      What you need is simple examples 😛

      Let me rephrase. I need examples which don't give me inferiority complex 😉

      Author's profile photo Peter Inotai
      Peter Inotai

      Thanks. I should have checked it before asking it. 😳

      Author's profile photo Former Member
      Former Member

      Hello Horst,

      Is it safe to say "meshes" are like "joins" on internal tables?

      BR,

      Suhas

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Hi Suhas,

      The concepts are  similar but not the same. The conditions of associations are simiilar to join conditions. But when working with  a mesh path the result is always a set of lines of the last node (table) of the path and not a joined result set of all  tables in the path. You can also have inverse associations (going back) and reflexive associaitions (where start and target node are the same table and where you have a rellationship between the lines of one table) .

      From a technical point of view a mesh as a data object is simply a structure with tabular components. In ABAP you can treat it like that. e.g. for addressing and filling the components. There is no join relation instantiated between the components. The relation between the components is defined in the mesh type only. The only way of using these relations is using a mesh path in the program. The mesh path is evaluated at runtime of the program. You could program the same with normal internal tables and normal table statements yourself. But meshes and mesh pathes offer a more convenient and more efficient way to solve related tasks.

      Kind regards,

      Horst

      PS: B.T.W. here is an example how to achieve a  join between two internal tables http://help.sap.com/abapdocu_740/en/index.htm?file=ABENTABLE_CMPRHNSNS_JOIN_ABEXA.htm

      Author's profile photo Graham Robinson
      Graham Robinson

      Whoo hoo - more ABAP coolness 😎

      Author's profile photo Former Member
      Former Member

      Wow!!! What an array of new features !!!

      Regards

      Abhi

      Author's profile photo Abdul Hakim
      Abdul Hakim

      ABAP rocks 🙂

      Author's profile photo Vikas Singh
      Vikas Singh

      I remember writing move-corresponding for tables using RTTI in a somewhat painful way. Good to see these features as part of the language !

      Author's profile photo Former Member
      Former Member

      that is all nice unless you realize your customers are all on ECC 6.0 and they will not go on in upcoming years

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Well, following this line of argument, we could stop development at all ...

      And  ECC 6.0 is SAP ERP while we speak about Netweaver here.

      ABAP 7.40 is largely downward compatible to ABAP 7.0 (disregarding bug fixes). It emerged from 7.0 by EHPs and is further developed in SPs now (see also http://scn.sap.com/community/abap/blog/2013/05/22/abap-news-for-release-740).

      ECC 6.0 should be able to run on NW 7.40 ....

      Author's profile photo Former Member
      Former Member

      Hi,

      Not sure I've understand.

      Is it possible to install NW 7.4 on ERP 6 EhP0 (Or more precisely, upgrading NW to 7.40 without upgrading any ERP components)?

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Technically it should be possible. But don't ask me what happens in real life (and I would also say its another wa around: ERP runs on Netweaver and not Netweaver on ERP).

      Author's profile photo Former Member
      Former Member

      Well, that's what I meant to ask actually (Real life scenario)... 😳

      Author's profile photo Peter Inotai
      Peter Inotai

      You need Ehp7 or Ehp6 on HANA to have Netweaver release 7.40.

      Author's profile photo Former Member
      Former Member

      Thanks.

      I know that EhP7 (EhP6 on HANA) runs on NW 7.4.

      I was curious whether it is possible to run EhP0 on NW 7.4, as Horst has suggested.

      Author's profile photo Former Member
      Former Member

      Is it possible to install NW 7.4 on ERP 6 EhP0 (Or more precisely, upgrading NW to 7.40 without upgrading any ERP components)?

      Our SAP landscape is on ERP6, EhP7 and is running ABAP Kernel 740, Patch level 4.

      /wp-content/uploads/2014/05/2014_05_02_201715_445200.jpg/wp-content/uploads/2014/05/2014_05_02_201756_445201.jpg

      BR,

      Suhas

      Author's profile photo Former Member
      Former Member

      Yeap, Thanks for the info. This is the standard installation for ERP EhP7.

      My (theoretical) question was about EhP0.

      Author's profile photo Krzysztof Ziniewicz
      Krzysztof Ziniewicz

      You can check https://service.sap.com/pam for EHP dependencies.

      Author's profile photo Former Member
      Former Member
      That argument was not meant to be disrespectful or not giving honors to the improvment. Only to underline my jealousy at the people that can give a touch of the modern new stuff.
      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Oh, I see 😳

      But maybe, you want to get your hands dirty?

      See: Developer & Trial Editions: SAP Application Server ABAP and SAP Business Warehouse

      Author's profile photo Former Member
      Former Member

      Hi Sir,

      Thanks for this valuable blog for great new feature of ABAP.

      It's good to see many features are added to ABAP with new releases 🙂 It's right time for enjoying ABAP.

      Thanks,

      Sudhir

      Author's profile photo Uwe Fetzer
      Uwe Fetzer

      Hello Horst,

      I've finally managed to install a NW7.40 SP5 to play around with the new ABAP features.

      Currently I'm trying out DDLs and have a (maybe) stupid question:

      why don't the cds_entity names (the view names) have to be in the customers namespace?

      If I create a "business_partner" view like in the above example, SAP may create another one in the upcoming SPs and voilá we have a problem (don't we?).

      Author's profile photo Uwe Fetzer
      Uwe Fetzer

      I've opened a separate thread for this question: DDL and customer namespace

      Author's profile photo Uwe Fetzer
      Uwe Fetzer

      Important: Answered: Re: DDL and customer namespace -> create your DDL in customer namespace (or move, if already created).

      Author's profile photo Jacques Nomssi
      Jacques Nomssi

      Hello Horst

      can I use the MAPPING option in the CORRESPONDING operator to create sub-structures in the target ? e.g. is there a replacement for the following method?

      METHODS convert_struct IMPORTING is_trace  TYPE ts_sat

                                  RETURNING VALUE(rs_sat) TYPE ts_trace.

           METHOD convert_struct.

          MOVE-CORRESPONDING is_trace TO rs_sat.

          rs_sat-caller = VALUE #( prog = is_trace-caller

                                   type = is_trace-caller_type

                                   inst = is_trace-caller_inst ).

        ENDMETHOD.

      regards,

      JNN

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Nested mapping:

      rs_sat =

        CORRESPONDING #(
          is_trace mapping ( caller = caller
                               mapping prog = caller
                                              type = caller_type
                                              inst = caller_inst ) ) .

      See: mapping

      Author's profile photo Jacques Nomssi
      Jacques Nomssi

      many thanks Horst!

      after reading the documentation, I could not express this logic correctly until I saw your code. Note: CALLER is not defined in the source as a structure, so your proposal does not compile verbatim. I had to use the TABLE_LINE keyword.


      rs_sat =

        CORRESPONDING #(
          is_trace mapping ( caller = table_line
                               mapping prog = caller
                                              type = caller_type
                                              inst = caller_inst ) ) .


      Kind regards,

      JNN

      P.S.

      Unfortunately the resulting code behavior is incorrect. I have created a test report with an unit test in the SCN Wiki to demo the problem.

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      after reading the documentation, I could not express this logic correctly

      OK, OK, 'twasn't a master piece, but documenting these expressions ... 😥

      I  changed the syntax diagram to

      MAPPING {t1 = s1}|( t1 = s1 [MAPPING ...] [EXCEPT ...] )

                        {t2 = s2}|( t2 = s2 [MAPPING ...] [EXCEPT ...] )

                         ...

      placed the text about nesting more prominently and added a  simple example directly to the text. This will be available in 7.40, SP012.

      You find example code already now (Example) but maybe not too clear?

      Horst

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Hi,

      Unfortunately the resulting code behavior is incorrect. I have created a test report with an unit test in the SCN Wiki to demo the problem.

      Now looking at your example I understand your initial question better. You want to construct a substructure from direct components. Sorry to say, but no that's not yet possible. Nested mapping only works for substructures on both sides. And you cannot write

      struct2 =
        CORRESPONDING #(
          struct1 MAPPING comp1    = mcomp1
                          comp2    = mcomp2
                          substruc-comp1 = substruc_subcomp1
                          ... ).

      But, you found quite a bug here! 😯

      Specifying table_line at this position, where there is no table at all, and the preceding syntax error when specifying CALLER are pure nonsense!

      I showed it to the responsible kernel developers and they will take care of it in an upcoming kernel patch.

      Best

      Horst

      Author's profile photo SAP ITR ENTWICKLUNG
      SAP ITR ENTWICKLUNG

      Horst,

      when I presented the new ABAP features in our team, one of the questions I could not answer was how to track a table access error in a complex read statement, like this one from your fun example:

          ev_result = it_table[ 2 ]-col2[ 1 ][ 2 ]-col1.

      In case something goes wrong, the exception CX_SY_ITAB_LINE_NOT_FOUND is issued. The attribute INDEX gives the index value for which the read access failed - 2, say - but which one was it? it_table[ 2 ] or ...col2[ 1 ][ 2 ]? Is there a way to find this out on base of the exception object, that is: in the CATCH clause?

      Regards,

      Rüdiger

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Hi Rüdiger,

      The exception object also contains attributes for the table keys used. If you can distinguish the table expressions by different keys, you can find out which has failed, otherwise (index access) there's no way.

      Best

      Horst

      Author's profile photo Adi Sieker
      Adi Sieker

      Hello Horst,

      I just ran into a weird behaviour

      the following code snippet will produce an empty table instead of a filled table as I would expect:

      data(lt_lines) = value erdz_tab(         ( nettobtr = '50.00-' )         ( nettobtr = '50.00-' )         ( nettobtr = '100.00-' )         ( nettobtr = '80.00-' )         ( nettobtr = '50.00-' )         ( nettobtr = '100.00-' )         ( nettobtr = '50.00-' )         ( nettobtr = '50.00-' )         ).

      lt_lines = value erdz_tab( for ls_line in lt_lines where ( nettobtr lt 0 ) ( ls_line ) ).

      Is this expected behaviour?

      If I replace the last line with

      data(lt_lines2) = value erdz_tab(...)

      lt_lines2 is filled.

      Regards

         Adi

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Hello Adi,

      see the respective ABAP Keyword Documentation.

      "In an assignment of the constructor expression to an internal table, its

      existing rows cannot be used directly as an argument in line_spec. This is because this table is deleted before

      line_spec is evaluated or overwritten by the content of

      itab. If the entire internal table or rows from the

      left side are needed on the right side, however, they can be saved in local

      auxiliary variables using a LET

      expression, since this expression is evaluated first".

      So, do something like (I didn't make a syntax check)

      lt_lines = value erdz_tab( let it = lt_lines in

                                 for ls_line in it

                                     where ( nettobtr lt 0 )

                                     ( ls_line ) ).

      and it should work.

      Regards

      Horst

      PS: that's also something for the new FILTER operator.

      Author's profile photo Adi Sieker
      Adi Sieker

      Hi Horst,

      thanks for the info. I must admit I didn't look in the docs.

      I don't think my customer is on SP08 yet. I don't really keep track of that. 🙂

      Regards

         Adi

      Author's profile photo Ramananda L N
      Ramananda L N

      Hi,

      I have one question. If have str1 and srt2 deep structure it has several internal tables in it. In this str1 can be enhanced and str2 is cannot be enhanced.

      In this case move corresponding can move data to relevant fields/tables between structures? Is it is supported in lower releases below 7.4 ?

      Best Regard,

      Ramananda

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      In this case move corresponding can move data to relevant fields/tables between structures?

      Yes, because the enhanced structure is known at compile time. In fact, MOVE-CORRESPONDING even works for generically typed field symbols or formal parameters. Then the comparison of names takes place at runtime.

      Is it is supported in lower releases below 7.4 ?

      MOVE-CORRESPONDING for structures is supported since long time. MOVE-CORRESPONDING for internal tables, see blog above.

      Author's profile photo Jesus Antonio Santos Giraldo
      Jesus Antonio Santos Giraldo

      Hi,

      BTW, very nice post about the new ABAP features in Release 7.40.

      We recently upgraded to EHP7 and we gain some of these features.

      Particularly the enhancements of open sql suits us very well with programs we are developing now.

      However a SELECT I'm trying to do is not working. By the ABAP online help it should work, I think, but it is not.

      I explain myself:

      In the online help it states that you do a SELECT like this:

      SELECT result

      Where result is ... lines select_list ...

      And select_list could be a col_spec

      And col_spec could be aggregate

      And aggregate could be SUM( [DISTINCT] col|sql_exp )

      And sql_exp could be sql_case

      And sql_case could be CASE operand

                              WHEN operand1 THEN result1

                             [WHEN operand2 THEN result2]

                              ...

                             [ELSE resultn]

                         END

      So, I think, I can do something this:

      SELECT some_field, SUM( CASE ... END ) ...

      FROM some_table

      GROUP BY some_field

      But the ABAP editor keep saying that there is a syntax error after CASE given the message  ')'  was expected here. no matter what I write after the word CASE.

      I'm sure ABAP is using the new syntax 'cause in fact I can use CASE in a SELECT, but not SUM( CASE... as I said.

      So:

      am I missing something?,

      SUM( CASE... isn't supported and it's a glitch in the syntax help?

      Maybe the ABAP 7.4 SP4 I have does not support it and a later one does?

      Any hint would be highly appreciated.

      J.

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Hi,

      see modification 3, sql expressions together with aggregates works since SP08.

      H.

      Author's profile photo Jesus Antonio Santos Giraldo
      Jesus Antonio Santos Giraldo

      A question (a basis one):

      I'm on SP5 is ti much trouble to upgrade to SP08... where can I find documentation about this?... to share with my basis team.

      SP08 has great new features but I suppose basis team won't upgrade if there are much work/trouble.

      J.

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Hmm, for such a question, I'd say contact your basis team, should't they know?

      😕

      Author's profile photo Former Member
      Former Member

      Dear Horst, could you kindly comment on this one?

      VALUE with LET - is this a bug?

      The examples were created in 740 SP08.

      Thank you

      Michal

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Hi Michal,

      Thanks for notifying.

      The bug is known (if I remember it right, it was brought to our attention in SCN) and is meanwhile fixed. It should be OK with kernel version PL 116.

      Best

      Horst

      Author's profile photo Jacques Nomssi
      Jacques Nomssi

      Hello,

      I found

      READ TABLE mt_vertices ASSIGNING <ls_graph_vertex>

        WITH KEY v = v.

      INSERT w INTO TABLE <ls_graph_vertex>-adj.

      passed the syntax check but

      INSERT w INTO TABLE mt_vertices[ v = v ]-adj.

      triggers "Invalid syntax for an association".

      What am I missing here? the documentation gives the impression INSERT INTO TABLE is only for meshes. Is the parser confused?

      regards,

      JNN

      P.S. for testing:

      TYPES tv_vertex TYPE syindex.

      TYPES tt_path TYPE STANDARD TABLE OF tv_vertex WITH NON-UNIQUE DEFAULT KEY.

      TYPES: BEGIN OF ts_graph_vertex,

               v TYPE tv_vertex,

               adj TYPE tt_path,

             END OF ts_graph_vertex.

      TYPES tt_graph_vertex TYPE SORTED TABLE OF ts_graph_vertex WITH UNIQUE KEY v.

      DATA mt_vertices TYPE tt_graph_vertex.

      DATA v TYPE tv_vertex

      DATA w TYPE tv_vertex

      Author's profile photo Adi Sieker
      Adi Sieker

      As far as I know, the new syntax does not create a field symbol so it is not the same as the old syntax version. table[ v = v ] will create a "copy" it does not assign a field symbol.

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Table expressions, as writable expressions, can only be placed at a handful of result positions. The position behind INSERT INTO TABLE is not such a result position.

      You can INSERT INTO a mesh path and since there are square brackets too, the parser thinks, you want to do that.

      Best

      Horst

      PS: .B.T.W., the syntax diagrams of the next docu release will distinguish between BNF brackets and brackets that are part of the syntax, yes!

      Author's profile photo Former Member
      Former Member

      Maybe I just can't find it, but...
      When I get my internal table defined by the fields which I select - where (and how) can I define potential secondary keys for that table?

      e.g.

      SELECT

           pgmid,

           object,

           obj_name

           INTO TABLE @DATA(lt_tadir WITH NON-UNIQUE SORTED KEY obj COMPONENTS obj_name)

      FROM tadir

      WHERE obj_name LIKE 'Z%'.

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      where (and how) can I define potential secondary keys for that table


      you can't.


      INTO TABLE @DATA(itab) declares a standard table itab of this row type with an empty table key.



      Author's profile photo Christiaan Edward Swanepoel
      Christiaan Edward Swanepoel

      But the idea is interesting 🙂

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Hmm, doesn't work for CREATE DATA either ...

      And in SELECt the compiler must do it, no dynamic specification anyhow.

      Author's profile photo Former Member
      Former Member

      Well in that case the whole advantage of getting the tables created by the compiler is gone, as I can only create standard tables (no sorted / hashed / secondary keys)
      So in the end, I will have to declare the tables by myself as before

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      So in the end, I will have to declare the tables by myself as before


      'xactly!


      Inline declarations are a convenience tool that should make your code shorter and more readable. If we start to transfer the TYPES/DATA syntax for table kind and secondary keys into the SELECT statement we do the opposite by blowing up that statement.  Therefore it was decided to KISS in that case.

      Author's profile photo Former Member
      Former Member

      Let's play

      *MAKE A WISH* 😉

      What would be a really great feature (maybe HANA can do so already?)

      SELECT ...

           INTO TABLE @DATA(lt....)

           FROM bkpf AS ex1

           INNER JOIN bkpf AS ex2

                on ex2~AWKEY = { ex1~belnr }{  ex1~bukrs }{ ex1~gjahr }.

      Currently if i want to realise such an requirement, I have to do this:

      SELECT belnr, bukrs, gjahr from BKPF into table @DATA(lt_tmp).

      lt_sel = VALUE #( FOR ls_tmp IN lt_tmp ( awkey = { ls_tmp-belnr }{  ls_tmp-bukrs }{ ls_tmp-gjahr } ) ).

      SELECT ... FROM bkpf INTO TABLE @DATA(lt_results)

           FOR ALL ENTRIES IN lt_sel

           WHERE awkey = lt_sel-awkey.

      (Yeah I know that's a stupid example, but hopefully you understand the Idea... Especially in EH&S you get such requirements quite often thanks to table AUSP)

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      What about?

      DATA: BEGIN OF ls_sel,

               awkey TYPE bkpf-awkey,

             END OF ls_sel,

             lt_sel LIKE TABLE OF ls_sel WITH EMPTY KEY.

        SELECT belnr, bukrs, gjahr

              FROM bkpf

              INTO TABLE @DATA(lt_tmp).

        lt_sel = VALUE #( FOR ls_tmp IN lt_tmp

         ( awkey = |{ ls_tmp-belnr }{  ls_tmp-bukrs }{ ls_tmp-gjahr }| ) ).

      SELECT * FROM bkpf

            FOR ALL ENTRIES IN @lt_sel

            WHERE awkey = @lt_sel-awkey

            ORDER BY PRIMARY KEY

            INTO TABLE @DATA(lt_results1).

      SELECT * FROM bkpf

              WHERE awkey IN

               ( SELECT CONCAT( belnr, CONCAT( bukrs, gjahr ) ) AS awkey

                        FROM bkpf )

              ORDER BY PRIMARY KEY

              INTO TABLE @DATA(lt_results2).

      ASSERT lt_results2 = lt_results1.

      CONCAT is available with ABAP 7.50 ...

      If you want to join, you will be able to use a GTT and "Common Table Expressions (CTE)" are under consideration ...

      Author's profile photo Former Member
      Former Member

      I'm glad, that we have at least ONE NW740 system 😉

      But I'll keep that in mind, as soon we get NW750 somewhere...

      Thank you very much!

      Author's profile photo Former Member
      Former Member

      Hi Horst,

      What about the performance point of view for these new features ( Like @DATA , Move-Corresponding etc ) assuming that we are still not in HANA DB ? Should we use them or continue with the conventional statements ?

      Thanks

      Rakesh

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Since the same kernel functions are used, performance is same or better (where you can't express it in one go).

      But do not use the same expression manyfold within one statement or a loop.

      Author's profile photo Former Member
      Former Member

      Thanks a lot Horst.

      Author's profile photo Former Member
      Former Member

      Hi Horst,

      According the help file on the new SQL syntax it should be possible to use LIKE and IN in JOIN conditions after ON as of SP08 (we are running 7.4 SP09)

      However, when I do so I get a syntax error (@so_org not allowed here, tried different positions without success)

      I would like to check whether there is a performance difference if I set the 'IN' after the respective ON clause vs the WHERE

      Thanks in advance

      Johan

      IN opertor after ON.jpg

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Hi Johan,

      Sorry for being too unspecific. It is this IN and not that IN that is allowed from 7.40, SP08 on. The latter is still abolished in SELECT- JOIN.

      Horst

      Author's profile photo Former Member
      Former Member

      Ok, cheers for the clarification Horst

      Author's profile photo Former Member
      Former Member

      Hi Horst,

      Is there any way to control the generic type that a mesh path evaluates too?

      For example, suppose you have the mesh below:

      BEGIN OF MESH tym_flight_mesh,

        scarr TYPE t_scarr " SORTED TABLE OF scarr WITH UNIQUE KEY carrid

          ASSOCIATION to_spfli TO spfli

            ON carrid = carrid,

         spfli TYPE t_spfli, " SORTED TABLE OF spfli WITH UNIQUE KEY carrid connid,

      END OF MESH tym_flight_mesh.

      DATA: lt_carr_pfli_mesh TYPE tym_flight_mesh.

      If it is in an RH assignment position, it seems to behave as a structure:

      DATA: ls_spfli LIKE LINE OF lt_carr_pfli_mesh-spfli.

      ASSIGN lt_carr_pfli_mesh-scarr[ carrid = 'AA' ] TO FIELD-SYMBOL(<fs_carr>).

      ls_pfli = lt_carr_pfli_mesh-scarr\to_spfli[ <fs_carr> ]. " <--


      If it is a loop target, it seems to behave as a table:

      LOOP AT lt_carr_pfli_mesh-scarr\to_spfli[ <fs_carr> ] INTO ls_pfli.

      ENDLOOP.

      It will not behave as a table in an assignment positions. For example, this produces a syntax error:

      DATA: lt_pfli_carr LIKE lt_carr_pfli_mesh-spfli.

      lt_pfli_carr = lt_carr_pfli_mesh-scarr\to_spfli[ <fs_carr> ].

      This all seems to be consistent with the way an internal table with header line behaves. Is there anyway to make something like this work?

      lt_pfli_carr = lt_carr_pfli_mesh-scarr\to_spfli[ <fs_carr> ][].

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Hi Thomas,

      Yes, that's a little bit tricky.

      The result of a mesh path generally consists of a set of lines. It depends on the operand position, how that set is evaluated.

      • Behind LOOP or other table statements/expressions it is interpreted as a table.
      • As a standalone expression at other operand positions it stands for the first line of the result set

      You're right. There's no way to access the result set as a whole in operand positions other than behind LOOP etc.

      The reason is, that the result set of a mesh path is not materialized but evaluated for each usage. If there would be a syntax that allows access to the result set as a whole and you use it several times, you would start to ask, where your performance goes. Therefore, you must do it explicitly: Extract the result set with LOOP or FOR into a helper table once and use that.

      Best

      Horst

      PS: And yes, it's a bit unfortunate that it is similar to header lines 😕

      Author's profile photo Former Member
      Former Member

      I appreciate your reply, Horst! As it happens, the application I had in mind, was accessing the "table" usage of a mesh path within a LET expression, and using FOR fulfills my need perfectly.

      lt_spfli_carr = VALUE #(

                          for <fs>

                          in lt_carr_pfli_mesh-scarr\to_spfli[ <fs_carr> ]

                          ( <fs> ) ).


      AHA! and given that the mesh path aren't materialized, I see now how not providing a syntax to evaluate as a table really protects against performance problems associated with a repeated "lazy" evaluation that would occur in something like:


      LOOP AT ...

           READ TABLE lt_carr_pfli_mesh-scarr\to_spfli[ <fs_carr> ][]...

      ENDLOOP.

      Thanks, much!



      Author's profile photo Former Member
      Former Member

      That Meshes are killing me 🙂 (or maybe it's EH&S classification)

      So now I have a mesh which looks like:

      BEGIN OF MESH...

      characteristics

           ASSOC _to_values,

      values

           ASSOC _to_cawn

           ASSOC _to_estpp

           ASSOC _to_estausp,

      cawn,

      estpp,

      estausp,

      END OF MESH.

      Then I have

      LOOP AT mesh-characteristics ASSIGNING FIELD-SYMBOL(<ls_char>).

         

           "This works fine:

           l_atflv = mesh-characteristics\_to_values[ <ls_char> ]-atflv.


           "This gives a Dump: MOVE_TO_LIT_NOTALLOWED_NODATA

           LOOP AT mesh-characteristics\_to_values[ <ls_char> ]\_to_estpp[ ] ASSIGNING FIELD-SYMBOL(<fs>).

           ENDLOOP.

           "where the dump says: Assignment error: Overwriting of a protected field.

           "Field "MESH-ESTPP" was to assigned a new value but this field is at least partly protected against changes.


      ENDLOOP.

      Anyone has a clue what I did wrong here?

      PS: It doesn't matter if I use LOOP...ASSIGNING or LOOP...INTO - both give the same dump

      Author's profile photo Jacques Nomssi
      Jacques Nomssi

      Hello Jakob,

      sorry I have no solution, but it maybe another version of the

      Short Dump While Changing Non-KeyField of Sorted Table?

      JNN

      Author's profile photo Former Member
      Former Member

      But I don't change anything - I'm just reading!
      That is what confuses me so much...

      Author's profile photo Former Member
      Former Member

      Mmmmh...
      If I use:

      LOOP AT mesh-characteristics\_to_values[ <ls_char> ]\_to_estpp[ ] ASSIGNING FIELD-SYMBOL(<fs>).

      I'm getting a Dump...

      But if I do it like this:

      LOOP AT mesh-characteristics\_to_values[ <ls_char> ] ASSIGNING FIELD-SYMBOL(<val>).

      LOOP AT mesh-values\_to_estpp[ <val> ] ASSIGNING FIELD-SYMBOL(<estpp>).

      ENDLOOP.

      ENDLOOP.

      then it works fine!?

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      I tried to reproduce the error as follows:

      TYPES:

         t_scarr    TYPE HASHED TABLE OF scarr

                    WITH UNIQUE KEY carrid,

         t_spfli    TYPE HASHED TABLE OF spfli

                    WITH UNIQUE KEY carrid connid,

         t_sflight  TYPE HASHED TABLE OF sflight

                    WITH UNIQUE KEY carrid connid fldate,

         BEGIN OF MESH t_flights,

           scarr    TYPE t_scarr

             ASSOCIATION _spfli TO spfli

                      ON carrid = carrid,

           spfli    TYPE t_spfli

             ASSOCIATION _sflight TO sflight

                      ON carrid = carrid AND

                         connid = connid,

           sflight  TYPE t_sflight,

         END OF MESH t_flights.

      DATA mesh TYPE t_flights.


      SELECT * FROM scarr INTO TABLE mesh-scarr WHERE carrid = 'LH'.

      SELECT * FROM spfli INTO TABLE mesh-spfli WHERE carrid = 'LH'.

      SELECT * FROM sflight INTO TABLE mesh-sflight WHERE carrid = 'LH'.

      LOOP AT mesh-scarr ASSIGNING FIELD-SYMBOL(<fs1>).

         LOOP AT mesh-scarr\_spfli[ <fs1> ]\_sflight[ ] ASSIGNING FIELD-SYMBOL(<fs2>).

         ENDLOOP.

      ENDLOOP.


      This runs in my systems. If it doesn't run in your system, the problem was fixed meanwhile.  If it runs in your system too, please modify it in a way to produce the error and post the code here, that I can try again, thx.

      Author's profile photo Former Member
      Former Member

      Ok - weird, but problem is solved now...

      First I tried your code - worked fine!
      So I did mine from scratch in a local program - also fine!

      Then I again had a look at my "issue" code, and saw, that there the mesh is passed to the method as an importing-parameter (as I don't change anything within the mesh, but only read it) but unfortunately internally SAP seems to DO some changes in the mesh anyhow, if the subnode doesn't have data according the association - even if there is just a READ / LOOP.

      So solution for my issue is just: change the parameter from IMPORTING to CHANGING

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      It's a bug. SAP does not "DO some changes in the mesh anyhow".


      I was able to reproduce the error but couldn't explain it and therefore forwarded to development. The reason are conflicting write restrictions. The loop over the mesh path wants to impose a write restriction on the table but there is already a write restriction for an importing parameter.


      The bug is under investigation and should be resolved with a kernel patch.


      Thanks for notifying!

      Author's profile photo Former Member
      Former Member

      In that case I'm glad, that my initial concept should have worked 😉

      Anyway, MESHES are really great, and fun to use,

      once you get your head around the syntax and mesh paths!

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Anyway, MESHES are really great, and fun to use,

      Forwarded to the guys who did it 🙂

      once you get your head around the syntax and mesh paths

      Yeah, there's room for improvement in the documentation too. I should adjust the explanation of mesh paths more to the explanation of path expressions in ABAP CDS. The concepts are similar.


      Author's profile photo Former Member
      Former Member

      Hi Horst,

      I`ll use corresponding with except, to move data from different structures and fields in one new.

      But now each CORRESPONDING override the other fields. Even with or without exept the other fields als empty.

          ls_data = CORRESPONDING ty_data( ls_data1 MAPPING field_001 = my_field1
                                                            field_002 = my_field2
                                                          EXCEPT * ).
      
          ls_data = CORRESPONDING ty_data( ls_data2 MAPPING field_003 = field_a
                                                            field_004 = field_b
                                                    EXCEPT * ).

      After the second corresponding ls_data-field_001 and field_002 are inital.

      Are there any simple solution?

       

      kind regards

      Christian

       

      Author's profile photo Horst Keller
      Horst Keller
      Blog Post Author

      Use the BASE addition?

      Author's profile photo Martin Ceronio
      Martin Ceronio

      Hello Horst,

      I am using CORRESPONDING with MAPPING because the one specified LHS/target field is a table.

      For this, I want to use VALUE # to construct the value for this field, but it does not pass the syntax check. As a result, I am ending up specifying the values individually (which works) but this nullifies the point of having CORRESPONDING.

      For example, I expect to be able to do this:

      CORRESPONDING #(
        ls_source MAPPING
        T_TABLE = VALUE #(
      * Expression to fill T_TABLE accordingly
        )
      )

      This is not permitted, however.

      Author's profile photo Masoom Ahmad
      Masoom Ahmad

      Hello Horst,

      Is there any performance difference between

      MOVE-CORRESPONDING itab1 TO itab2 EXPANDING NESTED TABLES

      KEEPING TARGET LINES.

       

      &

       

      loop at itab1 into wa1.

      append wa1 to itab2.

      endloop.

       

      Author's profile photo Patrick Duchesneau
      Patrick Duchesneau

      After 15 years as an abaper, I moved to SAP management for 10 years. I'm now back because you know, you can remove a guy from programming but not the programming from the guy! But, reading this, I surely missed quite a lot in the interim. I know most of it is optional but looking at recent code in the system, from dudes which have been trained in the new syntax and features, my code will definitely look old school and betray my seniority........