1
votes

I'm currently trying to perform a dynamic lossless assignment in an ABAP 7.0v SP26 environment.

Background:

I want to read in a csv file and move it into an internal structure without any data losses. Therefore, I declared the field-symbols:

  • <lfs_field> TYPE any which represents a structure component
  • <lfs_element> TYPE string which holds a csv value

Approach:

My current "solution" is this (lo_field is an element description of <lfs_field>):

IF STRLEN( <lfs_element> ) > lo_field->output_length.
    RAISE EXCEPTION TYPE cx_sy_conversion_data_loss.
ENDIF.

I don't know how precisely it works, but seems to catch the most obvious cases.


Attempts:

MOVE EXACT <lfs_field> TO <lfs_element>.

...gives me...

Unable to interpret "EXACT". Possible causes: Incorrect spelling or comma error

...while...

COMPUTE EXACT <lfs_field> = <lfs_element>.

...results in...

Incorrect statement: "=" missing .

As the ABAP version is too old I also cannot use EXACT #( ... )


Example:

In this case I'm using normal variables. Lets just pretend they are field-symbols:

DATA: lw_element TYPE string VALUE '10121212212.1256',
      lw_field   TYPE p DECIMALS 2.
lw_field = lw_element.

* lw_field now contains 10121212212.13 without any notice about the precision loss

So, how would I do a perfect valid lossless assignment with field-symbols?

1
Totally unrelated: <lfs_> is cranking the level of unnecessary redundancy to a maximum. <> already screams "this is a field symbol", and field symbols always are local... - vwegert
Other than that, what is the exact error situation? What kind of assignment doesn't produce the desired result? - vwegert
@vwegert Thanks, I'll forward that but doing such obsolete FORM-Stuff is still a common practice in my company and then you could possibly declare them in global scope. Nevertheless, you are right - user5653854
For example if the target field is of TYPE p DECIMALS 2 and I have 10121212212.1256 in <lfs_element>. There would be an implicit rounding that I can't really detect. I thought that there maybe is a way of catching general losses so I don't have to go through every case - user5653854
@vwegert Not totally true. Field symbols can be global. - Jagger

1 Answers

0
votes

Don't see an easy way around that. Guess that's why they introduced MOVE EXACT in the first place.

Note that output_length is not a clean solution. For example, string always has output_length 0, but will of course be able to hold a CHAR3 with output_length 3.

Three ideas how you could go about your question:

  1. Parse and compare types. Parse the source field to detect format and length, e.g. "character-like", "60 places". Then get an element descriptor for the target field and check whether the source fits into the target. Don't think it makes sense to start collecting the possibly large CASEs for this here. If you have access to a newer ABAP, you could try generating a large test data set there and use it to reverse-engineer the compatibility rules from MOVE EXACT.

  2. Back-and-forth conversion. Move the value from source to target and back and see whether it changes. If it changes, the fields aren't compatible. This is unprecise, as some formats will change although the values remain the same; for example, -42 could change to 42-, although this is the same in ABAP.

  3. To-longer conversion. Move the field from source to target. Then construct a slightly longer version of target, and move source also there. If the two targets are identical, the fields are compatible. This fails at the boundaries, i.e. if it's not possible to construct a slightly-longer version, e.g. because the maximum number of decimal places of a P field is reached.

    DATA target TYPE char3.
    DATA source TYPE string VALUE `123.5`.
    DATA(lo_target) = CAST cl_abap_elemdescr( cl_abap_elemdescr=>describe_by_data( target ) ).
    DATA(lo_longer) = cl_abap_elemdescr=>get_by_kind(
                          p_type_kind = lo_target->type_kind
                          p_length    = lo_target->length + 1
                          p_decimals  = lo_target->decimals + 1 ).
    DATA lv_longer TYPE REF TO data.
    CREATE DATA lv_longer TYPE HANDLE lo_longer.
    ASSIGN lv_longer->* TO FIELD-SYMBOL(<longer>).
    <longer> = source.
    target = source.
    IF <longer> = target.
      WRITE `Fits`.
    ELSE.
      WRITE `Doesn't fit, ` && target && ` is different from ` && <longer>.
    ENDIF.