Skip to Content
<<06: Unstructured returns, sorting and performance 08: Data types, Operation table, ……. >>

Hello everybody,

due to work on other things I had to stopped my blog series on BPath quite some time ago with lesson 6. Unfortunately there are – beside several nice additional features – some features pending which are quite useful when working with BPath. So I will give an insight on the main features for designing BPath statements here and may continue with additional features in some further lesson.

The old blog series was published under my personal blog, but starting with this blog I moved the blogs to the Webclient UI Framework blog as BPath is actually a feature realized together with BOL / GenIL.

All described features require BPath of version 2.3 at least, but I suppose there is hardly a lesser version out somewhere.

Before we take a look on the main part of this lesson, we do a brief look on a new feature which in a way rounds up the performance considerations described in lesson 6.

Parser Reuse

This is a change to improve performance in certain use cases.

When started, the parser has to build up the parse table and when the parser receives the source code a preparsing is done. The first step is unnecessary for all but the first execution if several BPATH statements are executed in a sequence, the second step is unecessary in case the source code has not changed.

To allow a reuse of the parser object and consequently an omitting of the unecessary steps, the parser object might be instantiated under the control of the application and handed over to the corresponding BOL method as in the following ABAP example:

Data MyParser type ref to CL_WCF_BPATH_PARSER.
create object MyParser.
LV_SOURCECODE = 'SearchResFlightRel/*$'.
MyResult1 = lv_object->GET_PROPERTIES_BY_BPATH(
  IV_BPATH_STATEMENT = LV_SOURCECODE
  IO_PARSER          = MyParser ).
MyResult2 = lv_other_object->GET_PROPERTIES_BY_BPATH( 
  IV_BPATH_STATEMENT = LV_SOURCECODE 
  IO_PARSER          = MyParser ).

The second call reuses the parsing tables of the first call and – since the source code is the same – the preparsing tables also.

Model Check Mode

There was demand for a mode which does not execute the query as such but …

  • checks syntax
  • checks validity of used relations and attributes against model
  • returns the (empty) data structure

Till version 2.2 the parser knew two modi, 1 which checks the syntax of the source code (and does some preparsing) and 3 which executes the query. Now there is a new mode 2, which attempts to fulfill above requirements. Please note that the modi 2 and 3 do a preparsing before execution, this means internally a run in mode 1 is executed before.

Since mode 2 runs against the model and not against actual objects/collections, the object name (plus namespace which is otherwise defaulted with ”) is required instead of object or collection instance. An example syntax looks as follows:

DATA: lv_bol_core TYPE REF TO cl_crm_bol_core.
lv_bol_core = cl_crm_bol_core=>get_instance( ).
MyResult = lv_bol_core->GET_PROPERTIES_BY_BPATH(
  IV_BPATH_STATEMENT = LV_SOURCECODE
  IV_BASE_NAMESPACE  = ''
  IV_BASE_OBJECTNAME = 'UIFSearchResFlight'
  IV_EVAL_MODE = 2 ).

Please note that the GET_PROPERTIES_BY_BPATH of BOL core is called, the above can not work on an instantiated BOL object or collection, as the signature of the corresponding methods do not have a IV_BASE_OBJECTNAME parameter. Btw, you may call GET_PROPERTIES_BY_BPATH on the BOL core directly also in execution mode (default or 3). You have to handover the object/collection using the IV_BASE_ENTITY or IV_BASE_COLLECTION parameter then.

Some technical comments to the mode:

  • the syntax check is the same in all three modi
  • in case the return type is a table, the table will contain exactly one row. The fields in this row should be empty except the cases described below. The same applies to returned structures.
  • The relation check as well as the data structure return has some limitations due to the flexibility of GenIL as well as BPATH:
    • The parent relation leads to an unambiguous object type only with an instantiated object. As for the model the relation may be ambiguous (the parent of an address might be a contact or a business partner). Since it is unclear with which object type to proceed and whether the relations / attribute accesses which are following are correct, the model checks stops whenever a parent relation is used with more then 1 possible parent. It is recommended to make the parent relation unique in these cases (see next chapter).
    • The return type of some functions may be unknown at design time, e.g. in the following example:
      ~*/SearchResFlightRel{!RetVal:=if(@CONNID=14,1,”Hello”)}
      At run time the type is determined with the first access.
    • Dereferenced targets on the left side of an assignment are leading to fields where the name is not known at design time, as in:
      ~*/SearchResFlightRel{!1:=”F_”+@FLDATE;!1^!=1}
      The model check generates a field named ‘UNKNOWNFIELDNAME n ‘ into the result structure, the type information should be correct. Note that several dereferenced assignments will lead to several entries as above and that one dereferenced assignment may lead to more than one added field at run time but only to one within model check.
    • Dereferenced targets on the right side of an assignment are leading to fields where the type is not known at design time, as in:
      ~*/SearchResFlightRel{!1:=if(@CONNID=14,”CONNID”,”FLDATE”);!Ret=!1^!}
      In these cases the model check creates a field with type string containing the value: ‘UNKNOWN DATATYPE’.

To use the syntax check or model check the exceptions caused by snytax errors have to be caught.

Parser Exceptions

Exception
Syntax Check
Model Check
Execution
Description
Example
CX_CRM_GENIL_MODEL_ERROR2
X
attribute unknown
~*/./@NoAttribute
CX_CRM_UNSUPPORTED_RELATION
X
X
relation unknown
~*/PlumpaQuatsch
CX_WCF_BPATH_PARSING_ERROR
X
X
X
General parsing error
~*/+-*^1

The CX_WCF_BPATH_PARSING_ERROR exception provides more information with the TEXT_ID according to the following table:

TextID
1
2
3
Description
CX_WCF_BPATH_PARSING_ERROR
X
X
X
Current token is not allowed at this place
(possible entries will be listed)
Example: ~*/$
INCOMPATIBLE_OPERATION_TYPES
X
X
operation is not supported with
specified types
Example: ~*/.{!A=Today()*”Hello”}
NUMBER_OF_PARAMS_MISSMATCH
X
X
Number of parameters in statement
does not match function declaration
Example: ~*/.{!A=Upper()}
PARAMETER_WRONG
X
X
Parameter type does not match
function declaration
Example: ~*/.{!A=Upper(1)}
PARENT_OBJECT_NAME_INCORRECT
X
*)
specified parent object name is incorrect
Example: ~*/.._NoNsEnSe
PARENT_REL_NOT_UNAMBIGOUS
X
*)
parent is either not there (we are already
on root) or not unambiguous
Example: ~*/..
UNSUPP_TYPE_IN_TARGET_STRUCT
X
X
creation of a target of used type is
not supported
UNSUPPORTED_FUNCTION
X
X
There is no such thing as a function
with this name
Example: ~*/.{!A=Test(1)}

*) both dumps do not appear in code execution (more exactly PARENT_REL_NOT_UNAMBIGOUS only if no parent was found), but it is likely that the code is not fitting to the object structures and consequently it can not be guaranteed that the code is executed without problems and/or dumps.

Typically the dumps returns the code position as source code extract, where the program pointer is visualized with ‘_^_’.

Attributed parent relation

To avoid the problems described above, the parent relation (‘..’) may have an attribute which should hold the object name of the parent as in the following (hardly usable) example:

~*/SearchResFlightRel/FlightBookRel/.._UIFFlight/*$
Code Example 33, .._OBJECT, attributed parent relation

Please note, that this is not a syntax change, for BPATH the relation name is ‘.._UIFFlight’. The object name of the parent object is used to identify the object on which the check is proceeded during model check. As for normal statement execution, the object name information is ignored.

Attribute Longtext

Using a double @ as prefix, BPATH will return the result of the GET_TEXT method as result, instead of the attribute directly. This is the longtext, if available, otherwise an empty string. Result type will be always string.

~*/SearchResFlightRel/FlightBookRel{!A=@@CUSTTYPE;!B=@@CARRID;!D=@@CLASS;!E=@@FORCURKEY}$
Code Example 34, @@CARRID, attribute longtext

That’s it for today. The content of the next lesson has to be assembled first. The remaining part of version 2.3 contains rather technical stuff. And with version 2.4 it gets really complicated, and also a bit in pretty unexplored universes.

Best regards, Juergen

To report this post you need to login first.

14 Comments

You must be Logged on to comment or reply to a post.

  1. Andrey Vishnevskiy

    Welcome back Juergen!! Nice to see that this very interesting series continues.

    I may have missed something but how to check the BPath version we have in the system?

    (0) 
    1. Juergen Gatter Post author

      Hello Andrei,

      thanks for the feedback. To get the parser version simply check attribute GV_PARSERVERSION of class CL_WCF_BPATH_PARSER (the main class actually) in code / SE80. I assume it has an initial value ‘2.4’, so it is the latest version.

      Best regards, Juergen

      (0) 
    1. Juergen Gatter Post author

      Hi Luis,

      sorry for the delay, we had an important deadline last week.

      Actually I do not remember providing something special for raw data and our UIF sample does not contain fields of type raw. I made a brief check with the component “SAMPLE”,  where the result of the Advanced Query has a field GUID in the attribute set, which is returned properly.

      But in respect to your question, as far as I remember there is no way to hand over raw parameters to work with the data. I did another brief test with a simple string “GUID”, but this returned an incompatible Parameter error.  So sorry, this is not supported.

      Best regards, Juergen

      (0) 
      1. Luís Pérez Grau

        Hi again Juergen,

        I also test it with Date type parameters and also didn’t work, I can understand with raw data is not working, but with date types…is quite harder to understand. Right know I can use BPath where the target fields are CHAR, STRING, NUMC or INT, I think is a good idea to update one of your blogs with this info, don’t you?

        Cheers!

        Luis

        (0) 
        1. Juergen Gatter Post author

          Hi Luis,

          Date literals have to be surrounded by #-symbols, the following query worked with a quick test:

          ./SearchResFlightRel/FlightBookRel[@FLDATE>#20100714#]/@FLDATE$

          Today() function is also supported, as well as Date – integer (or date + int) operations.

          But I guess you are right, I did miss out this point in the blog yet, maybe it is a good idea to publish the table of data types ( it is actually B Boolean, S String, N Numeric, D Date and internally I have reserved placeholders for R reference, O Object Reference and X Invalid [used with the get function]) as well as the operations table with the next blog.

          Unfortunately (and hardly forseeable) time is a key problem at the moment, so it might take more time then expected to proceed the blog series.

          Best regards, Juergen

          (0) 
          1. Luís Pérez Grau

            yup, time is allways a problem 🙂 , I tested the # and works fine, thanks, now the problem looks like the string is too long:

            ./BuilHNodeBPAssignmentRel[(@BP_NUMBER=”8100114261″)&(@VALID_TO=#20131231#)&(@VALID_FROM=#20130201#)]/*$

            This does’nt works while this works:

            ./BuilHNodeBPAssignmentRel[(@BP_NUMBER=”8100114261″)&(@VALID_TO=#20131231#)]/*$

            or

            ./BuilHNodeBPAssignmentRel[(@BP_NUMBER=”8100114261″)&(@VALID_FROM=#20130201#)]/*$

            I read all your blog and I didn’t find if there’s a limit of parameters, but maybe I’m missing something…

            (0) 
            1. Juergen Gatter Post author

              Hi Luis,

              size is not the problem here (and in fact not at all to my knowledge).

              I suppose it is one of the traps the language has, which is that it supports only expressions with two operands, using three without brackets as in your example is not supported.

              Expressions like ((x=1)&(y=1)&(z=1)) need one additional bracket level:

              (((x=1)&(y=1))&(z=1)), then it should work.

              Regards, Juergen

              (0) 
                1. Juergen Gatter Post author

                  you’re right. Sometimes one gets used to step around the traps that one forgets that they are hardly visible to others. I think I even thought about extending the syntax to support arbritrary expressions, but I had to realize that it is quite some work with unknown result as it increases complexity 😐

                  (0) 
  2. Amal Aravind

    Hi Juergen,

         I was going to all your blog posts, the kind of detailing in each is blog is really helpful that you can easily understanding the things, especially for newbies like me!

    (0) 

Leave a Reply