.nf
 
 
    ========== licence begin  GPL
    Copyright (c) 2000-2004 SAP AG
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end
 
.fo
*****************************************************
Copyright (c) 2000-2004 SAP AG
SAP Database Technology
 
Release :      Date : 2000-11-22
*****************************************************
modname : VAK724
changed : 2000-11-22
module  : Build_Strategy_term_structure
 
Author  : ElkeZ
Created : 1985-10-16
*****************************************************
 
Purpose : module for recognization of term structure
 
Define  :
 
        PROCEDURE
              a724all_L1_terms (
                    VAR acv         : tak_all_command_glob;
                    VAR dmli        : tak_dml_info;
                    VAR access_info : tak70_strategy_record;
                    VAR L1_terms    : tak70_term;
                    use_subquery    : tgg07_SubqKind);
 
.CM *-END-* define --------------------------------------
 
Use     :
 
        FROM
              Build_Strategy : VAK70;
 
        VAR
              a70_glob_zstrat_rec : tak70_strategy_record;
 
      ------------------------------ 
 
        FROM
              Build_Strategy_2 : VAK71;
 
        PROCEDURE
              a71key_strat (
                    VAR acv         : tak_all_command_glob;
                    VAR access_info : tak70_strategy_record;
                    start           : tsp00_Int2;
                    stop            : tsp00_Int2);
 
        PROCEDURE
              a71index_strat (
                    VAR acv         : tak_all_command_glob;
                    VAR access_info : tak70_strategy_record;
                    start           : tsp00_Int2;
                    stop            : tsp00_Int2);
 
      ------------------------------ 
 
        FROM
              AK_universal_semantic_tools : VAK06;
 
        PROCEDURE
              a06find_colinfo (
                    base_ptr        : tak_sysbufferaddress;
                    VAR stack_entry : tgg00_StackEntry;
                    VAR colinfo_ptr : tak00_colinfo_ptr);
 
      ------------------------------ 
 
        FROM
              AK_Index : VAK24;
 
        FUNCTION
              a24LookForFunctionBasedIndex (
                    VAR acv        : tak_all_command_glob;
                    stackStart     : integer;
                    stackEnd       : integer;
                    VAR stackNext  : integer) : boolean;
&       ifdef TRACE
 
      ------------------------------ 
 
        FROM
              Syntax-Tree-Printer : VAK99;
 
        VAR
              a99blankline : tsp00_Line;
&       endif
 
      ------------------------------ 
 
        FROM
              GG_edit_routines : VGG17;
 
        PROCEDURE
              g17int4to_line (
                    int       : tsp00_Int4;
                    with_zero : boolean;
                    int_len   : integer;
                    ln_pos    : integer;
                    VAR ln    : tsp00_Line);
&       ifdef TRACE
 
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        PROCEDURE
              t01bool (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    curr_bool: boolean);
 
        PROCEDURE
              t01int4 (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    int      : tsp00_Int4);
 
        PROCEDURE
              t01line (
                    level  : tgg00_Debug;
                    VAR ln : tsp00_Line);
 
        PROCEDURE
              t01name (
                    level : tgg00_Debug;
                    nam : tsp00_Name);
 
        PROCEDURE
              t01sname (
                    level : tgg00_Debug;
                    nam : tsp00_Sname);
 
        PROCEDURE
              t01p2int4 (
                    debug : tgg00_Debug;
                    nam_1 : tsp00_Sname;
                    int_1 : tsp00_Int4;
                    nam_2 : tsp00_Sname;
                    int_2 : tsp00_Int4);
 
        PROCEDURE
              t01stackentry (
                    debug          : tgg00_Debug;
                    VAR st         : tgg00_StackEntry;
                    entry_index    : integer);
 
      ------------------------------ 
 
        FROM
              Trace_Strategy_1 : VAK725;
 
        PROCEDURE
              a725output_access_info (
                    level           : tgg00_Debug;
                    nam             : tsp00_Sname;
                    VAR access_info : tak70_strategy_record);
 
        PROCEDURE
              a725L1_terms_output (
                    level        : tgg00_Debug;
                    VAR L1_terms : tak70_term);
&       endif
 
.CM *-END-* use -----------------------------------------
 
Synonym :
 
.CM *-END-* synonym -------------------------------------
***********************************************************
Description:
 
A724ALL_L1_TERMS
----------------------------------
 
Processes the entire qualification, with consideration being given at the
highest level only to terms that are ANDed.
 
After the beginning of the qualification ('qs_start') and the end have been
determined ('qs_stop'), it is checked first of all whether there is a negation
at the highest level. Although, in this case, the entire qualification cannot
be used for finding a strategy, this stack entry is ignored and the rest of the
condition is analyzed normally.
After full analysis, the information in 'z_strat_rec' and 'L1_TERMS'
is destroyed and only in the case of a cost estimate is the value of
'z_qual_value' determined as a complement to the original one. This makes it
possible in the case of an 'EXPLAIN' to give at least an approximate indication
of the costs.
 
If there is no 'AND' at the highest level (last stack entry is 'op_or'), there
cann't be a simple Top_level_term. To indicate this, 'lv_levelstart' = 2 is set;
otherwise, = 1. The other parts of 'levelrec' are given the following entries
and have the following significance:
 
lv_levelcnt : Specifies the nesting depth of the current condition; is initialized
with 0.
 
lv_levelstart : Specifies whether there is an 'AND' or an 'OR' at the highest
level or not; see above for initialization.
 
lv_levelend : ARRAY of BOOLEAN, specifies for each level (1 .. c_maxquallevel)
whether the level is finished or not. The entry is 'false' for all.
 
 
lv_levelpredcnt : ARRAY of int2, specifies for each level how many terms have already
been found at that level. Is initialized with '0'.
 
The processing of conditions which are combined by 'AND' is performed
in a While loop by AK724ONE_L1_term until there are no more conditions ('qs_actpos'
 > 'qs_stop').
 
Since, in various cases, the counters of L1_TERMS have counted on although no
entries have been made, the contents of L1_TERMS are corrected after the While
loop. Then, the negation is handled at the highest level (see above).
 
AK724ONE_L1_TERM
----------------------------------
 
In this procedure, top-level conditions that can be used in the search for
a strategy (on key fields or inverted fields) are entered in 'zstrat';
conditions of other levels (up to at most level 3 (= c_maxquallevel)) are put in
L1_TERMS. All lower levels are jumped, as is a negated term at the second or
third level. In the case of a negated, single condition, no entries are made in
'z_start' or L1_TERMS. In the case of a cost estimate, however, the complement of
the calculated costs is entered in 'ps_qual_value' (cost value of the current
condition).
 
Sequence of actions
 
(1) Calling of AK724ANALYZE_CONDITION in order to analyze the current condition.
After it has been called, 'qs_actpos' is at the next boolean operator ('op_and',
'op_or', 'op_not') or jump command ('st_jump_true', 'st_jump_false' ). If a
usable condition has been found, 'ps_startpos' identifies the beginning and 'ps_stoppos'
identifies the end of the condition, and 'ps_keyfield' and 'ps_indexfield' indicate
whether a keyfield or an inverted field has been found.
 
(2) Handling of a negated condition (see above).
 
(3) Calling of AK724CHECK_LEVEL, in order to determine the nesting depth of the
current condition. AK724CHECK_LEVEL returns 'true' if there was a term at level 1,
2, 3, with 'lv_levelcnt' indicating the level. If there was a lower-level term,
CHECK_LEVEL returns 'false' and has already jumped the corresponding stack
entries, just as in the case of a negated term ('qs_actpos' is then at the first stack
entry after that term).
 
(4) If AK724CHECK_LEVEL was successful, the following actions are performed
depending on 'lv_levelcnt':
 
 
4.1 : If there was a key field ('keyfield' = 'true'), it is entered in
'z_strat' with A71KEY_STRAT. If there was an inverted field, it is entered in
'z_strat' with A71INDEX_STRAT. If a cost estimate is to be performed,'
z_qual_value' is also determined.
 
4.2 : If there was neither a key field nor an inverted field and nor is a cost
estimate desired, the condition must not be entered in L1_TERMS as a level-2-
term. If a condition has already been entered under the current value of
'cntor' (i.e. on the same second level), this entry must be destroyed, since,
in the case of an OR link, all terms must be usable (see also OR_QUAL).
Otherwise, the condition is entered in L1_TERMS with AK724BUILD_LOWER_PREDS.
 
4.3 : The condition that has been found is entered in L1_TERMS as a level-3-term
and lv_levelpredcnt[ 3 ] is increased by one.
 
(5) The control variable 'qs_actpos' is shifted until there is once again the start of
a condition.
 
These actions are repeated until either a top-level term has been found or
until the last term of a second level was the current term, or if the control
variable is 'qs_actpos' > 'qs_stop'. In this case, control is returned to A724ALL_L1_TERMS.
 
AK724ANALYZE_CONDITION
----------------------------------
 
This procedure is called in A70TOP_LEVEL_CONDITIONS (for Ordered Selects) and
in AK724ONE_L1_TERM. It starts with stpos at the first stack entry of a condition.
Only those conditions are of interest for a strategy that contain only one
field on the left-hand side of the operator and that contain only one factor
(one value), no expression and no column on the right-hand side.
The first stack entry is checked for field description; field, keyfield
are initialized.
A search is made for the first operator after this stack entry. If it is a
comparison operator and there is only one value in front of it, it is a
condition that can be used for the strategy (an expression would lead to an
arithmetic operator or similar, e.g. op_concat, op_plus).
The Like conditions must be handled in a special manner, because they may
contain DUMMY stack entries (see VAK65), which are used only for the strategy,
but not for the processing of the qualification.
stpos remains at the first stack entry (of the field description).
If the condition is not one that can be used (NOT field), a jump is made to
the end of that condition (outside of ANALYZE_CONDITION, a jump is made to the
start of the next condition).
If the condition can be used for finding a strategy and if it contains only
one value, it is checked whether the condition is suitable for a key field (IS
NULL is, for example, not suitable) or whether this is a singly inverted field
(ecol_tab[ 1 ] > chr(0)). If so, this condition can be taken for the strategy
search ('indexfield'), provided that this field is not to be updated with an
expression or was specified in FOR UPDATE (upd_col_set).
The condition may also be suitable if the field is part of a multiple index
(ecol_tab[ 2 ] > chr(100)). The check for upd_col_set is performed in
A71_MINDEX_ARR. It cannot yet be performed in ANALYZE_CONDITION, because the
field number is not known for these fields.
If a cost estimate is required, it must be performed for the condition that
has just been found.
Conditions with more than one value (BETWEEN, IN) that can be used for the
strategy search are checked as to whether they are simple values or expressions
(for BETWEEN 2 values => 2 stack entries between the field stack entry and the
last value; for IN as many value stack entries as are specified in the IN stack
entry as list elements (elen_var)).
The conditions with the predicates 'NOTBETWEEN' and 'NOTIN' are
not usable for a strategy ('keyfield' and 'indexfield' to 'false'), but,
since a cost estimate exists for these conditions, this case is also dealt
with.
The conditions are suitable for finding a strategy only if there is an
inverted field (see above) or a key field.
If it is a Like condition, it must be considered that the field stack entry
is followed by 3 value stack entries. These may possibly then be used for Equal
or Between strategies (LIKE 'A*B' => for the strategy: BETWEEN 'A' AND 'A
chr(255) chr(255) ..').
Interrogation for inversions must be performed in this case also.
At the end of the procedure, and if a usable condition has been found,
'ps_startpos' is on the field stack entry and 'ps_stoppos' is on the stack entry that contains
the operator, i.e.the last one. These two entries are used in A71KEY_STRAT,
A71INDEX_STRAT and AK724BUILD_LOWER_PREDS.
 
AK724BUILD_LOWER_PREDS
----------------------------------
 
In this procedure, a condition that could be used for a strategy but that is
not at the highest level of the Search Condition is included in an array so
that it can be processed in OR_QUAL and A71ONE_RECURSION (in the analysis of
the OR parts).
If all conditions are to be evaluated (costcheck), conditions that are
not at the highest level and that are also not useful for finding a strategy,
are also entered in L1_TERMS by this procedure.
 
The decision at which level the next condition is to be entered is
specified by the entry in 'lv_levelend':
 
In the case of lv_levelend[3], the third level is finished and the next term
must be entered under a higher value of 'cntterm'. Then, 'putand' is also
interrogated, because incrementing need take place only if there is already an
entry under the old value of 'cntterm'. 'putand' is then set again to 'false',
so that an analogous course of action can be adopted at the next level end.
 
In the case of lv_levelend[2], precisely the same course of action is adopted
with 'cntor' and 'putor'.
 
If, after a lv_levelend, no further term is entered at the next level, 'cntor'
and, for each OR, 'cntterm' may possibly be one too high. Therefore, after the
entire qualification has been processed, this is put right in A724ALL_L1_TERMS (see
A724ALL_L1_TERMS).
 
AK724CHECK_LEVEL
----------------------------------
 
Checks the nesting depth of the current condition.
 
The nesting depth is determined on the basis of the necessary jumps over the
Jump entries in the stack or the boolean operators. The nesting depth is
incremented from 1 to 3 (= c_maxquallevel) in a While loop and that number of
jumps is performed. If, afterwards, the end of the qualification has been
reached ('lpos' > 'stop'), there was a term at the level that has just been
checked. If a boolean operator is jumped in a jump, this level is finished and
'lv_levelend' is set accordingly.
 
If the end has not been reached with the jumps, there are two possibilities:
 
(1) The operator 'NOT' has been found, which cannot be jumped in the While
loop. In this case, 'lpos' is moved to after the 'NOT' (+ 1) with the stack
pointer and AK724SKIP_STACK_ENTRIES is called in order to skip the stack entries.
Since the 'NOT' may come after a term at any level, the call is necessary in
order to discover the level at which the negation occurred. Since at least one
jump has already been performed in the While loop, the results of
SKIP_STACK_ENTRIES are each increased by one and 'lv_levelend' is set (the entire
term has been skipped).
 
(2) If there was no 'NOT' and, in addition, the end of the qualification has
not been reached with three jumps, there was a term at a level > 'c_maxquallevel'
that is also skipped with AK724SKIP_STACK_ENTRIES.
 
In both cases, there was no condition that is usable for the strategy.
Therefore, AK724CHECK_LEVEL is set to 'false'.
 
As a special case, it is also necessary to intercept conditions that do not fit
into the alternating scheme of AND and OR combinations.
These are all conditions of
the form:
 
BED1 OR NOT (BED2 OR BED3)
and
BED1 AND NOT (BED2 AND BED3)
 
Both qualifications lead to stack entries in which a 'jump_true' (or a
'jump_false') leads to a 'NOT', which is followed directly by an 'op_or' or
'jump_true' (or 'op_and' or 'jump_false'). In these cases, the pointer is
shifted to after the 'NOT' directly in the While loop (in order to check the
depth); Ak724CHECK_LEVEL is set to 'false' and 'done' indicates that everything has
been done.
 
AK724SKIP_STACK_ENTRIES
----------------------------------
 
Skips parts of the qualification.
 
Is called either by AK724CHECK_LEVEL in order to skip a negated term or a term with
deeper nesting than 'c_maxquallevel', or by ONE_AND if there was a level-2-
condition that cannot be used for the strategy and, therefore, the entire
level-2-expression is unusable. A distinction is made between the two cases on
the basis of 'lv_levelcnt', which, in the first case, is greater than
'c_maxquallevel', with it being smaller in the second case. Since, in the second
case, only one jump over an OR condition is required, this is performed
directly. Conversely, in the first case, the pointer is moved by the amount of
'epos' (there can only be jump entries) until a level-3-term is again reached
(Ak724CHECK_LEVEL is successful).
 
In addition, a further check has been incorporated here to check whether the
pointer is in fact being moved. For, in the case of unexpected stack entries
(that cannot be recognized either in CHECK_LEVEL or in ANALYZE_CONDITION), an
endless loop occurs when CHECK_LEVEL is called recursively. This is possible,
for example, if new stack structures are created by new functionality (as
happened in the case 'STAMP'). This emergency exit therefore prevents forgotten
changes from leading to an endless loop in this module.
 
.CM *-END-* description ---------------------------------
***********************************************************
.CM -lll-
Code    :
 
 
CONST
      c_maxquallevel     =  3;
      c_skip             = true;
 
TYPE
 
      t_pred_scanner = RECORD
            ps_startpos    : tsp00_Int2;
            ps_stoppos     : tsp00_Int2;
            ps_keyfield    : boolean;
            ps_indexfield  : boolean;
            ps_put_l3term  : boolean;
            ps_put_l2term  : boolean;
      END;
 
 
      t_leveltype = RECORD
            lv_predicate   : t_pred_scanner;
            lv_levelcnt    : tsp00_Int2;
            lv_levelstart  : tsp00_Int2;
            lv_level2_UNEQ : tsp00_Int2;
            lv_levelpredcnt: ARRAY [ 1..c_maxquallevel ] OF tsp00_Int2;
            lv_levelend    : ARRAY [ 1..c_maxquallevel ] OF boolean;
      END;
 
 
      t_qual_scanner = RECORD
            qs_start  : tsp00_Int2;
            qs_stop   : tsp00_Int2;
            qs_actpos : tsp00_Int2;
      END;
 
 
 
(*------------------------------*) 
 
PROCEDURE
      a724all_L1_terms (
            VAR acv         : tak_all_command_glob;
            VAR dmli        : tak_dml_info;
            VAR access_info : tak70_strategy_record;
            VAR L1_terms    : tak70_term;
            use_subquery    : tgg07_SubqKind);
 
VAR
      _ix                : tsp00_Int2;
      _levelrec          : t_leveltype;
      _qualscanner       : t_qual_scanner;
      _old_access_info   : tak70_strategy_record;
      _upd_col_with_expr : tak_columnset;
      _term_negated      : boolean;
 
BEGIN
(* keep in mind:                                 *)
(* TERM   -> L1TERM AND L1TERM [ AND L1TERM .. ] *)
(* L1TERM -> L2TERM OR  L2TERM [ OR  L2TERM .. ] *)
(* L2TERM -> L3TERM AND L3TERM [ AND L3TERM .. ] *)
(*                                               *)
(* a TERM is a PREDICATE if it doesn't contains  *)
(* boolean operators                             *)
_term_negated         := false;
_qualscanner.qs_start := acv.a_mblock.mb_qual^.mqual_pos;
_qualscanner.qs_stop  := acv.a_mblock.mb_qual^.mqual_pos +
      acv.a_mblock.mb_qual^.mqual_cnt - 1;
IF  ( _qualscanner.qs_start <= _qualscanner.qs_stop )
THEN
    BEGIN
    (* jump over output list *)
    IF  ( acv.a_mblock.mb_st^[ _qualscanner.qs_start ].etype = st_jump_output )
    THEN
        _qualscanner.qs_start := _qualscanner.qs_start +
              acv.a_mblock.mb_st^[ _qualscanner.qs_start ].epos - 1;
    (*ENDIF*) 
    IF  ( acv.a_mblock.mb_st^[ _qualscanner.qs_stop ].etype = st_truth )
    THEN
        (* ALTER TABLE ADD <constraint definition> *)
        (* ALTER TABLE ADD <column definition with constraint> *)
        (* no search for AND *)
        (* no better strategy than *)
        _qualscanner.qs_stop  := pred( _qualscanner.qs_start );
    (*ENDIF*) 
    IF  ( acv.a_mblock.mb_st^[ _qualscanner.qs_stop ].eop = op_not )
    THEN
        BEGIN
        (* negation on top level *)
        _qualscanner.qs_stop := pred( _qualscanner.qs_stop );
        _term_negated        := true;
        END;
    (*ENDIF*) 
    IF  ( acv.a_mblock.mb_st^[ _qualscanner.qs_stop ].eop = op_or )
    THEN
        (* OR term on top level, i.e. L2TERM *)
        _levelrec.lv_levelstart := 2
    ELSE
        (* AND term on top level, i.e. L1TERM *)
        _levelrec.lv_levelstart := 1
    (*ENDIF*) 
    END;
(*ENDIF*) 
;
&ifdef TRACE
t01int4 (ak_strat, 'lv_levelstrt', _levelrec.lv_levelstart);
&endif
(* initialize predicate nesting information *)
_levelrec.lv_levelcnt    := 0;
_levelrec.lv_level2_UNEQ := 0;
FOR _ix := 1 TO c_maxquallevel DO
    BEGIN
    _levelrec.lv_levelpredcnt[ _ix ] := 0;
    _levelrec.lv_levelend    [ _ix ] := false;
    END;
(*ENDFOR*) 
_upd_col_with_expr := [  ]; (* empty for normal selects *)
IF  ( acv.a_init_ex_kind <> only_executing )
THEN
    IF  (( acv.a_mblock.mb_type = m_update ) AND
        ( acv.a_mblock.mb_type2 = mm_qual ))
        OR
        (* SELECT *)
        ( acv.a_ap_tree^[ acv.a_ap_tree^[ 0 ].n_lo_level ].n_proc = a63 )
        OR
        (* EXPLAIN SELECT *)
        (( acv.a_ap_tree^[ acv.a_ap_tree^[ 0 ].n_lo_level ].n_proc = a43) AND
        ( acv.a_ap_tree^[ acv.a_ap_tree^ [ acv.a_ap_tree^[ 0 ].
        n_lo_level ].n_lo_level ].n_proc = a63 ))
    THEN
        (* these columns (colunms for update) aren't relevant for stretegy *)
        _upd_col_with_expr := dmli.d_foundset;
    (*ENDIF*) 
(*ENDIF*) 
_old_access_info       := access_info;
_qualscanner.qs_actpos := _qualscanner.qs_start;
WHILE ( _qualscanner.qs_actpos < _qualscanner.qs_stop ) DO
    BEGIN
    ak724one_L1_term( acv, dmli, access_info, _levelrec,
          L1_terms, _qualscanner, _upd_col_with_expr, use_subquery );
    (* ak724one_L1_term stops qualification loop in case of *)
    (* a. end of qualification        or                    *)
    (* b. lv_levelend[2] = TRUE       or                    *)
    (* c. lv_levelcnt = 1                                   *)
    IF  ( _levelrec.lv_levelcnt = 1 )
    THEN
        BEGIN
        (* top level term found *)
        _old_access_info := access_info;
&       ifdef TRACE
        t01name(ak_strat, 'refresh oldstrat  ');
&       endif
        END
    ELSE
        IF  ( _levelrec.lv_levelend[ 2 ] )
        THEN
            BEGIN
            (* last part of a level-2-term found *)
            _old_access_info.srec_invaccess.ia_inv_root :=
                  access_info.srec_invaccess.ia_inv_root;
            access_info := _old_access_info;
&           ifdef TRACE
            t01name(ak_strat, 'reset access_info ');
&           endif
            END;
        (*ENDIF*) 
    (*ENDIF*) 
    _qualscanner.qs_start := _qualscanner.qs_actpos;
    END;
(*ENDWHILE*) 
IF  ( L1_terms.trm_L1termcnt > 0 )
THEN
    BEGIN
    IF  ( L1_terms.trm_L1termcnt > cak70_max_L1terms )
    THEN
        L1_terms.trm_L1termcnt := cak70_max_L1terms;
    (*ENDIF*) 
    IF  ( L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
        l1t_L2pL3tcnt = 0 )
    THEN
        BEGIN
        L1_terms.trm_L1termcnt := pred( L1_terms.trm_L1termcnt );
&       ifdef trace
        t01sname(ak_strat, 'rm one L1ter');
&       endif
        END;
    (*ENDIF*) 
    FOR _ix := 0 TO L1_terms.trm_L1termcnt - 1 DO
        WITH L1_terms.trm_L1terms[ _ix ] DO
            IF  ( l1t_L2terms[ l1t_L2pL3tcnt - 1 ].l2l3p_predcnt = 0 )
            THEN
                BEGIN
                l1t_L2pL3tcnt := pred( l1t_L2pL3tcnt );
&               ifdef trace
                t01sname(ak_strat, 'rm one L2pL3');
&               endif
                END;
            (*ENDIF*) 
        (*ENDWITH*) 
    (*ENDFOR*) 
    END;
(*ENDIF*) 
IF  ( _term_negated )
THEN
    BEGIN
    L1_terms.trm_L1termcnt     := 0;
    access_info.srec_keyaccess := a70_glob_zstrat_rec.srec_keyaccess;
    access_info.srec_invaccess := a70_glob_zstrat_rec.srec_invaccess;
    END;
(*ENDIF*) 
;
&ifdef TRACE
a725output_access_info( ak_strat, 'A724 strat  ', access_info );
a725L1_terms_output( ak_strat, L1_terms );
t01name( ak_strat, '-END OF STRUCTURE-' );
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak724one_L1_term (
            VAR acv               : tak_all_command_glob;
            VAR dmli              : tak_dml_info;
            VAR access_info       : tak70_strategy_record;
            VAR levelrec          : t_leveltype;
            VAR L1_terms          : tak70_term;
            VAR qualscanner       : t_qual_scanner;
            VAR upd_col_with_expr : tak_columnset;
            use_subquery          : tgg07_SubqKind);
 
VAR
      _condition_found  : boolean;
 
BEGIN
WITH qualscanner, levelrec, lv_predicate DO
    BEGIN
&   ifdef TRACE
    t01int4 (ak_strat, 'qs_start    ', qs_start -
          acv.a_mblock.mb_qual^.mqual_pos + 1);
    t01int4 (ak_strat, 'qs_stop     ', qs_stop  -
          acv.a_mblock.mb_qual^.mqual_pos + 1);
&   endif
    qs_actpos       := qs_start;
    ps_put_l2term   := false;
    ps_put_l3term   := false;
    REPEAT
        BEGIN
        ak724analyze_condition( acv, dmli.d_sparr, qs_actpos, lv_predicate,
              upd_col_with_expr, qs_stop, use_subquery );
        (* ======================================================== *)
        (* checks whether condition that begins at position         *)
        (* 'qs_actpos' in the qual-stack is eligible for strategy   *)
        (* computes :                                               *)
        (*            ps_keyfield                                   *)
        (*            ps_startpos                                   *)
        (*            ps_stoppos                                    *)
        (* afterwards                                               *)
        (* qs_actpos points to first stack entry after an eligible  *)
        (* condition (if one has been detected) or to the next      *)
        (* boolean operator (if none detected)                      *)
        (* ======================================================== *)
        IF  ( qs_actpos <= qs_stop ) AND
            ( acv.a_mblock.mb_st^[ qs_actpos ].eop = op_not )
        THEN (* recently analyzed condition is operand of a NOT. *)
            BEGIN
            ps_indexfield := false;
            ps_keyfield   := false;
            qs_actpos     := succ( qs_actpos );
            END;
        (*ENDIF*) 
        IF  ( ak724check_level( acv, levelrec, qs_actpos, qs_stop, c_skip ))
        THEN
            BEGIN
            (* term exists in level 1, 2 or 3 *)
&           ifdef TRACE
            t01int4 (ak_strat, 'LEVEL cnt:  ', lv_levelcnt);
&           endif
            CASE lv_levelcnt OF
                1 :
                    BEGIN
                    IF  ( ps_keyfield )
                        AND
                        ( NOT ( cs_keyscan in
                        access_info.srec_config.cfg_switches ))
                    THEN
                        a71key_strat( acv, access_info, ps_startpos, ps_stoppos );
                    (*ENDIF*) 
                    IF  ( ps_indexfield )
                        AND
                        ( NOT ( cs_indexscan in
                        access_info.srec_config.cfg_switches ))
                    THEN
                        a71index_strat( acv,
                              access_info, ps_startpos, ps_stoppos );
                    (*ENDIF*) 
                    END;
                2 :
                    IF  ( NOT ps_keyfield AND NOT ps_indexfield )
                    THEN
                        BEGIN
                        lv_levelend[ 2 ] := true;
&                       ifdef TRACE
                        t01name(ak_strat, 'level 2 knockout  ');
&                       endif
                        ak724skip_stack_entries( acv, qs_actpos,
                              levelrec, qs_stop );
                        IF  ( ps_put_l2term )
                        THEN
                            L1_terms.trm_L1termcnt :=
                                  pred( L1_terms.trm_L1termcnt );
                        (*ENDIF*) 
                        END
                    ELSE
                        ak724build_lower_preds( L1_terms, levelrec );
                    (*ENDIF*) 
                3 :
                    BEGIN
                    ak724build_lower_preds( L1_terms, levelrec );
                    lv_levelpredcnt[ 3 ] := succ( lv_levelpredcnt[ 3 ] );
&                   ifdef trace
                    t01name(ak_strat, 'add pred for lvl 3');
&                   endif
                    END;
                OTHERWISE
                    BEGIN
                    END
                END
            (*ENDCASE*) 
            END
        ELSE
            (* term exists in level > 3 *)
            BEGIN
&           ifdef TRACE
            t01sname (ak_strat, 'LEVEL > 3   ');
            a725L1_terms_output( ak_strat, L1_terms );
            t01bool (ak_strat, 'put_l2term  ', ps_put_l2term );
            t01bool (ak_strat, 'put_l3term  ', ps_put_l3term );
&           endif
            IF  ( L1_terms.trm_L1termcnt = 0 )
            THEN
                BEGIN
                (* initialize first level-1-term        *)
                (* create an empty L2term which reminds *)
                (* to l4 terms/predicates               *)
                ps_put_l2term := false;
                ps_put_l3term := true;
                L1_terms.trm_L1termcnt := 1;
                L1_terms.trm_L1terms[ 0 ].l1t_L2pL3tcnt := 1;
                L1_terms.trm_L1terms[ 0 ].l1t_L2terms[ 0 ].l2l3p_predcnt := 0;
                L1_terms.trm_L1terms[ 0 ].l1t_is_usable := true;
                END;
            (*ENDIF*) 
            IF  ( L1_terms.trm_L1termcnt > 0 ) AND
                ( L1_terms.trm_L1termcnt <= cak70_max_L1terms )
            THEN
                BEGIN
                (* first AND term on lower level*)
                WITH L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ] DO
                    IF  ( l1t_L2pL3tcnt > 0 )
                    THEN
                        IF  ( lv_levelend[ 3 ] AND
                            ( l1t_L2terms[ l1t_L2pL3tcnt - 1 ].l2l3p_predcnt = 0 ))
                        THEN
                            ps_put_l3term := true;
                        (*ENDIF*) 
                    (*ENDIF*) 
                (*ENDWITH*) 
                END
            ELSE
                BEGIN
                IF  ( lv_levelend[ 3 ] ) AND ( lv_levelstart = 2 )
                THEN
                    BEGIN
&                   ifdef trace
                    t01sname (ak_strat, 'close l2    ');
&                   endif
                    ps_put_l3term    := false;
                    ps_put_l2term    := false;
                    lv_levelend[ 2 ] := true;
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            IF  ( lv_levelend[ 3 ] AND ps_put_l3term )
            THEN
                BEGIN
                IF  ( L1_terms.trm_L1termcnt > 0 ) AND
                    ( L1_terms.trm_L1termcnt <= cak70_max_L1terms )
                THEN
                    BEGIN
                    WITH L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ] DO
                        IF  ( l1t_L2pL3tcnt < cak70_max_L2preds_L3terms )
                        THEN
                            BEGIN
&                           ifdef trace
                            t01sname (ak_strat, 'add l2pl3t  ');
&                           endif
                            l1t_L2pL3tcnt := succ(l1t_L2pL3tcnt);
                            ps_put_l3term := false;
                            l1t_L2terms[ l1t_L2pL3tcnt - 1 ].
                                  l2l3p_predcnt := 0
                            END
                        ELSE
                            (* there's no more space *)
                            IF  NOT lv_levelend[ 2 ]
                            THEN
                                l1t_is_usable := false;
                            (*ENDIF*) 
                        (*ENDIF*) 
                    (*ENDWITH*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            IF  ( lv_levelend[ 2 ] AND ps_put_l2term )
            THEN
                IF  ( L1_terms.trm_L1termcnt < cak70_max_L1terms )
                THEN
                    BEGIN
                    IF  ( L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].l1t_is_usable )
                    THEN
                        L1_terms.trm_L1termcnt := succ(L1_terms.trm_L1termcnt);
                    (*ENDIF*) 
                    ps_put_l2term := false;
                    L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].l1t_L2pL3tcnt := 0;
                    L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].l1t_is_usable := true
                    END
                ELSE
                    L1_terms.trm_L1termcnt := cak70_max_L1terms + 1;
                (*ENDIF*) 
            (*ENDIF*) 
            END; (* level > 3 *)
        (*ENDIF*) 
&       ifdef TRACE
        t01sname (ak_strat, '------------');
        a725L1_terms_output( ak_strat, L1_terms );
        t01bool (ak_strat, 'put_l2term  ', ps_put_l2term );
        t01bool (ak_strat, 'put_l3term  ', ps_put_l3term );
&       endif
        _condition_found := false;
        WHILE NOT _condition_found AND ( qs_actpos <= qs_stop ) DO
            IF  ( acv.a_mblock.mb_st^[ qs_actpos ].etype in
                [ st_jump_false, st_jump_true ] )
            THEN
                qs_actpos := succ( qs_actpos )
            ELSE
                IF  ( acv.a_mblock.mb_st^[ qs_actpos ].eop in
                    [ op_and, op_upd_view_and, op_or ] )
                THEN
                    qs_actpos := succ( qs_actpos )
                ELSE
                    _condition_found := true
                (*ENDIF*) 
            (*ENDIF*) 
        (*ENDWHILE*) 
        END
    UNTIL
        ( lv_levelend[ 2 ] OR ( lv_levelcnt = 1 ) OR ( qs_actpos > qs_stop ))
    (*ENDREPEAT*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak724build_lower_preds (
            VAR L1_terms   : tak70_term;
            VAR levelrec   : t_leveltype);
 
BEGIN
WITH L1_terms, levelrec, lv_predicate DO
    BEGIN
&   ifdef TRACE
    ak724print_levelinfo(levelrec);
    IF  ps_keyfield
    THEN
        t01sname (ak_strat, 'KEYFIELD    ');
    (*ENDIF*) 
    IF  ps_indexfield
    THEN
        t01sname (ak_strat, 'INDEXFIELD  ');
    (*ENDIF*) 
    t01int4 (ak_strat, 'cnt L1 Terms', trm_L1termcnt);
&   endif
    IF  ( trm_L1termcnt = 0 )
    THEN
        BEGIN
        (* initialize first level-1-term *)
        ps_put_l2term := false;
        trm_L1termcnt := 1;
        trm_L1terms[ 0 ].l1t_L2pL3tcnt := 0;
        trm_L1terms[ 0 ].l1t_is_usable := true
        END;
    (*ENDIF*) 
    IF  ( trm_L1termcnt <= cak70_max_L1terms )
    THEN
        BEGIN
        WITH trm_L1terms[ trm_L1termcnt - 1 ] DO
            IF  l1t_is_usable
            THEN
                BEGIN
                IF  ( l1t_L2pL3tcnt = 0 )
                THEN
                    BEGIN
&                   ifdef TRACE
                    t01sname ( ak_strat, 'init l2t    ');
&                   endif
                    (* initialize first level-2-term of actual level-1-term *)
                    l1t_L2pL3tcnt := 1;
                    ps_put_l2term := true;
                    ps_put_l3term := false;
                    l1t_L2terms[ 0 ].l2l3p_predcnt := 0
                    END;
                (*ENDIF*) 
                ;
&               ifdef TRACE
                t01int4 ( ak_strat, 'cnt L2p L3t ', l1t_L2pL3tcnt);
&               endif
                IF  ps_keyfield OR ps_indexfield
                THEN
                    WITH l1t_L2terms[ l1t_L2pL3tcnt - 1 ] DO
                        BEGIN
                        IF  ( l2l3p_predcnt < cak70_max_predicates )
                        THEN
                            BEGIN
&                           ifdef TRACE
                            t01sname ( ak_strat, 'add predicat' );
&                           endif
                            l2l3p_predcnt := succ( l2l3p_predcnt );
                            WITH l2l3p_preds[ l2l3p_predcnt - 1 ] DO
                                BEGIN
                                ps_put_l3term   := true;
                                pred_start      := ps_startpos;
                                pred_stop       := ps_stoppos;
                                pred_key        := ps_keyfield;
                                pred_inv        := ps_indexfield;
                                END;
                            (*ENDWITH*) 
                            END;
                        (*ENDIF*) 
                        ;
&                       ifdef TRACE
                        t01int4 ( ak_strat, 'cnt predicat', l2l3p_predcnt);
&                       endif
                        END
                    (*ENDWITH*) 
                ELSE
                    BEGIN
                    IF  ( lv_levelend[ 3 ] AND
                        ( l1t_L2terms[ l1t_L2pL3tcnt - 1 ].l2l3p_predcnt = 0 ))
                    THEN
                        BEGIN
&                       ifdef TRACE
                        t01sname ( ak_strat, 'put l3term  ');
&                       endif
                        ps_put_l3term := true;
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                (* up to now no useful pred found for this term *)
                IF  lv_levelend[ 3 ] AND ps_put_l3term
                THEN
                    BEGIN
&                   ifdef TRACE
                    t01sname (ak_strat, 'put L2pL3t  ');
&                   endif
                    IF  ( l1t_L2pL3tcnt < cak70_max_L2preds_L3terms )
                    THEN
                        BEGIN
                        l1t_L2pL3tcnt := succ( l1t_L2pL3tcnt );
                        ps_put_l3term := false;
                        (* initialize next predicate structure *)
                        l1t_L2terms[ l1t_L2pL3tcnt - 1 ].l2l3p_predcnt := 0
                        END
                    ELSE
                        (* no more space *)
                        IF  NOT lv_levelend[ 2 ]
                        THEN
                            l1t_is_usable := false;
                        (*ENDIF*) 
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                ;
&               ifdef TRACE
                t01int4 ( ak_strat, 'cnt L2p L3t ', l1t_L2pL3tcnt);
&               endif
                END
            ELSE
                BEGIN
&               ifdef TRACE
                t01sname(ak_strat, 'l2term unuse');
&               endif
                END
            (*ENDIF*) 
        (*ENDWITH*) 
        END
    ELSE
        BEGIN
&       ifdef TRACE
        t01int4(ak_strat, 'trm_L1termcn', trm_L1termcnt);
&       endif
        END;
    (*ENDIF*) 
    IF  lv_levelend[ 2 ] AND ps_put_l2term
    THEN
        IF  (trm_L1termcnt < cak70_max_L1terms)
        THEN
            BEGIN
            IF  trm_L1terms[ trm_L1termcnt - 1 ].l1t_is_usable
            THEN
                BEGIN
&               ifdef TRACE
                t01sname(ak_strat, 'init new l1t');
&               endif
                trm_L1termcnt := succ( trm_L1termcnt );
                END;
            (*ENDIF*) 
            ps_put_l2term := false;
            trm_L1terms[ trm_L1termcnt - 1 ].l1t_L2pL3tcnt := 0;
            trm_L1terms[ trm_L1termcnt - 1 ].l1t_is_usable := true
            END
        ELSE
            trm_L1termcnt := cak70_max_L1terms + 1;
        (*ENDIF*) 
&   ifdef TRACE
    (*ENDIF*) 
    t01int4 (ak_strat, 'cnt L2 Terms', trm_L1termcnt);
    a725L1_terms_output (ak_strat, L1_terms);
&   endif
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak724analyze_condition (
            VAR acv               : tak_all_command_glob;
            VAR sparr             : tak_syspointerarr;
            VAR stpos             : tsp00_Int2;
            VAR one_and_var       : t_pred_scanner;
            VAR upd_col_with_expr : tak_columnset;
            stop                  : tsp00_Int2;
            use_subquery          : tgg07_SubqKind);
 
VAR
      upd_col_with_expr_found : boolean;
      _access_path            : boolean;
      _found                  : boolean;
      _functionBasedIndexFound: boolean;
      _ix                     : integer;
      _col_ptr                : tak00_colinfo_ptr;
 
BEGIN
WITH acv.a_mblock, one_and_var DO
    BEGIN
&   ifdef trace
    FOR _ix := stpos TO stop DO
        t01stackentry (ak_strat, mb_st^[_ix], _ix);
    (*ENDFOR*) 
&   endif
    _functionBasedIndexFound := false;
    ps_startpos   := stpos;
    ps_indexfield := false;
    (* check first stack entry *)
    CASE mb_st^[ stpos ].etype OF
        st_fixkey, st_varkey,
        st_fixprimkey, st_varprimkey :
            BEGIN
            _access_path := true;
            ps_keyfield  := true
            END;
        st_fixcol, st_varcol,
        st_fixinv, st_varinv,
        st_varlongchar:
            BEGIN
            _access_path := true;
            ps_keyfield  := false
            END;
        OTHERWISE
            BEGIN
            _access_path := false;
            ps_keyfield  := false
            END
        END;
    (*ENDCASE*) 
    IF  ( _access_path )
    THEN
        BEGIN
&       ifdef trace
        t01sname( ak_strat, 'access found' );
&       endif
        _ix := stpos;
        IF  mb_st^[ _ix ].eop in [ op_unique, op_order_asc,
            op_unique_desc, op_order_desc ]
        THEN
            (* OK: column with index function *)
            _ix := succ(_ix)
        ELSE
            IF  ( mb_st^[ _ix ].eop <> op_none )
            THEN
                (* BAD: other column function found *)
                BEGIN
                _access_path := false;
&               ifdef trace
                t01sname( ak_strat, 'col function' );
&               endif
                END
            ELSE
                (* OK: normal column found *)
                _ix    := succ( _ix );
            (*ENDIF*) 
        (*ENDIF*) 
        ;
        (* search for next operator and skip 'like'-dummies *)
        WHILE ( _ix <= stop )
              AND
              (( mb_st^[ _ix ].eop   = op_none )  OR
              ( mb_st^[ _ix ].etype = st_dummy )) DO
            BEGIN
            IF  mb_st^[ _ix ].etype in [ st_fixkey, st_varkey,
                st_fixcol, st_varcol, st_varlongchar ]
            THEN
                (* BAD: "column op column"  condition found *)
                (* we need "column op value" conditions     *)
                BEGIN
                _access_path := false;
&               ifdef trace
                t01sname( ak_strat, 'col op col  ' );
&               endif
                END;
            (*ENDIF*) 
            _ix := succ( _ix )
            END;
        (*ENDWHILE*)
        IF  _access_path AND sparr.pbasep^.sbase.bindexexist AND
            (
            (mb_st^[ _ix ].etype = st_result) OR
            ( (mb_st^[ _ix ].etype = st_build_in_func) AND (mb_st^[ _ix ].eop_build_in = op_b_uni_trans) )
            )
        THEN
            BEGIN
            _functionBasedIndexFound := a24LookForFunctionBasedIndex (acv, stpos, stop, _ix);
            IF  _functionBasedIndexFound
            THEN
                BEGIN
                _access_path := true;
                stpos        := _ix - 1;
                ps_startpos  := stpos;
                END
            ELSE
                _access_path := false;
            (*ENDIF*) 
            ps_keyfield := false;
            END;
        (*ENDIF*) 
        _found := false;
        IF  ( _ix <= stop )
        THEN
            BEGIN
            IF  (( mb_st^[ _ix   ].etype = st_subquery )
                AND
                ( use_subquery > no_subquery )
                AND
                (
                (( mb_st^[ _ix   ].ecol_tab[ 1 ] = chr( 0 ) (* no ANY, ALL*)
                ) AND ( mb_st^[ _ix ].eop in [ op_eq, op_in ] ))
                OR
                (( mb_st^[ _ix ].eop = op_get_sub_value ) AND 
                ( mb_st^[ _ix + 1 ].etype = st_op ) AND
                ( mb_st^[ _ix + 1 ].eop in [ op_eq, op_in ]))
                ))
            THEN
                _found := true
            ELSE
                IF  ( mb_st^[ _ix   ].etype = st_value )
                    OR
                    (( mb_st^ [ _ix   ].etype = st_op )     AND
                    (mb_st^  [ _ix-1 ].etype = st_value ))
                THEN
                    BEGIN
                    IF  ( mb_st^[ _ix ].eop in [ op_null,
                        op_eq, op_eq_all, op_gt, op_ge, op_lt, op_le,
                        op_ne, op_between, op_in,
                        op_not_between, op_not_in ] )
                    THEN
                        _found := true
                    ELSE
                        BEGIN
                        IF  ( _ix > 2 )
                        THEN
                            IF  
                                ( mb_st^[ _ix - 2 ].etype = st_dummy ) AND
                                ( mb_st^[ _ix - 1 ].etype = st_value ) AND
                                ( mb_st^[ _ix     ].eop   = op_like )
                            THEN
                                _found := true;
                            (*ENDIF*) 
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  ( NOT _found )
        THEN
            BEGIN
&           ifdef trace
            t01sname( ak_strat, 'not found   ' );
&           endif
            _access_path := false;
            ps_keyfield  := false
            END
        (*ENDIF*) 
        END;
&   ifdef TRACE
    (*ENDIF*) 
    t01int4 (ak_strat, 'ps_startpos ', ps_startpos - mb_qual^.mqual_pos + 1);
    IF  ( _access_path )
    THEN
        BEGIN
        t01int4 (ak_strat, 'ACCESS PATH ', stpos - mb_qual^.mqual_pos + 1);
        IF  ps_keyfield
        THEN
            t01int4 (ak_strat, 'KEYFIELD    ', stpos - mb_qual^.mqual_pos + 1)
        ELSE
            t01int4 (ak_strat, 'INDEX POSSIB', stpos - mb_qual^.mqual_pos + 1);
        (*ENDIF*) 
        END
    ELSE
        t01int4 (ak_strat, 'NO ACCESS   ', stpos - mb_qual^.mqual_pos + 1);
    (*ENDIF*) 
&   endif
    IF  NOT _access_path
    THEN
        BEGIN
        (* loop to next condition *)
        WHILE ( stpos <= stop )
              AND
              ( mb_st^[ stpos ].etype <> st_jump_false )
              AND
              ( mb_st^[ stpos ].etype <> st_jump_true )
              AND
              ( (( mb_st^[ stpos ].eop <> op_and ) AND
              ( mb_st^[ stpos ].eop <> op_or )) OR
              ( mb_st^[ stpos ].etype = st_dummy ) OR
              ( mb_st^[ stpos ].etype = st_bool )) DO
            (* PTS 1117523 E.Z. *)
            IF  (mb_st^[stpos].etype = st_build_in_func) AND
                (mb_st^[stpos].eop_build_in = op_b_case_start)
            THEN
                stpos := stpos + mb_st^[stpos].epos + 1
            ELSE
                stpos := succ( stpos );
            (*ENDIF*) 
        (*ENDWHILE*) 
        (* stpos points to first boolean stack operator  *)
        (* following the condition / or to 'stop+1'      *)
        ps_indexfield := false;
        ps_keyfield   := false;
        ps_stoppos    := 0;
&       ifdef TRACE
        t01name (ak_strat, 'skipping notfield ');
        t01int4 (ak_strat, 'new stpos   ', stpos - mb_qual^.mqual_pos + 1);
&       endif
        END
    ELSE
        (* it seems to be a usable condition *)
        BEGIN
        IF  ( mb_st^[ stpos + 1 ].etype <> st_dummy )
        THEN
            BEGIN
&           ifdef TRACE
            t01int4 (ak_strat, 'no dummy    ',
                  stpos - mb_qual^.mqual_pos + 1 + 1);
&           endif
            stpos := succ(stpos);
            (* analyze righthand operand *)
            IF  ( mb_st^[ stpos ].etype in [ st_value, st_subquery ] )
            THEN
                BEGIN
&               ifdef trace
                t01sname( ak_strat, 'value, subq ' );
&               endif
                IF  ( mb_st^[ stpos ].eop in [ op_eq, op_eq_all, op_gt,
                    op_ge, op_lt, op_le, op_null, op_get_sub_value ] )
                THEN
                    BEGIN
                    IF  ( mb_st^[ stpos ].etype = st_subquery ) AND
                        ( mb_st^[ stpos ].eop = op_get_sub_value )
                    THEN
                        (* operator lays behind *)
                        stpos := succ( stpos );
                    (*ENDIF*) 
                    ps_stoppos := stpos;
                    IF  _functionBasedIndexFound
                    THEN
                        BEGIN
                        ps_indexfield := true;
                        END
                    ELSE
                        BEGIN
                        WITH mb_st^[ ps_startpos ] DO
                            BEGIN
                            IF  ( ord(ecol_tab[ 2 ]) > 100 )
                            THEN
                                ps_indexfield := true;
                            (*ENDIF*) 
                            END;
                        (*ENDWITH*) 
                        END
                    (*ENDIF*) 
                    END
                ELSE
                    IF  ( mb_st^[ stpos ].eop = op_none )
                    THEN
                        BEGIN
&                       ifdef trace
                        t01sname( ak_strat, 'op_none     ' );
&                       endif
                        WHILE (( mb_st^[ stpos ].eop  = op_none ) AND
                              ( mb_st^[ stpos ].etype = st_value )) DO
                            stpos := succ( stpos );
                        (*ENDWHILE*) 
                        ps_stoppos := stpos;
                        IF  ( mb_st^[ stpos ].etype = st_value )
                        THEN
                            BEGIN
                            IF  ( mb_st^[ stpos ].eop = op_between ) AND
                                ( stpos - ps_startpos = 2 )
                            THEN
                                BEGIN
&                               ifdef trace
                                t01sname( ak_strat, 'op_between 1' );
&                               endif
                                WITH mb_st^[ ps_startpos ] DO
                                    BEGIN
                                    IF  ( ord( ecol_tab[ 2 ] ) > 100 )
                                    THEN
                                        ps_indexfield := true;
                                    (*ENDIF*) 
                                    END
                                (*ENDWITH*) 
                                END
                            ELSE
                                IF  ( mb_st^[ stpos ].eop = op_not_between )
                                    AND ( stpos - ps_startpos = 2 )
                                THEN
                                    BEGIN
&                                   ifdef trace
                                    t01sname( ak_strat, 'op_between 2' );
&                                   endif
                                    ps_indexfield := false;
                                    ps_keyfield   := false
                                    END
                                (*ENDIF*) 
                            (*ENDIF*) 
                            END
                        ELSE
                            IF  ( mb_st^[ stpos ].eop = op_in ) AND
                                ( stpos-ps_startpos - 1 =
                                mb_st^[ stpos ].elen_var )
                            THEN
                                BEGIN
&                               ifdef trace
                                t01sname( ak_strat, 'op_in       ' );
&                               endif
                                (* In-Strategies can't be used, if the   *)
                                (* indexed column will be updated by the *)
                                (* command: 'UPDATE f WHERE f IN (5,7)'. *)
                                (* So we better erase the index info.    *)
                                WITH mb_st^[ ps_startpos ] DO
                                    BEGIN
                                    IF  ( ord( ecol_tab[ 2 ] ) > 100 )
                                    THEN
                                        BEGIN
                                        a06find_colinfo( sparr.pbasep,
                                              mb_st^[ ps_startpos ], _col_ptr );
                                        upd_col_with_expr_found :=
                                              ( _col_ptr <> NIL );
                                        IF  ( upd_col_with_expr_found )
                                        THEN
                                            upd_col_with_expr_found :=
                                                  ord( _col_ptr^.cextcolno )
                                                  in upd_col_with_expr;
                                        (*ENDIF*) 
                                        ;
&                                       ifdef trace
                                        t01bool (ak_strat, 'upd_col_fnd ',
                                              upd_col_with_expr_found);
&                                       endif
                                        IF  upd_col_with_expr_found
                                        THEN
                                            BEGIN
                                            ecol_tab[ 2 ] :=
                                                  chr( ord( ecol_tab[ 2 ] ) -
                                                  100 );
                                            END;
                                        (*ENDIF*) 
                                        END;
                                    (*ENDIF*) 
                                    IF  ( ord( ecol_tab[ 2 ] ) > 100 )
                                    THEN
                                        ps_indexfield := true;
                                    (*ENDIF*) 
                                    END;
                                (*ENDWITH*) 
                                END
                            ELSE
                                IF  ( mb_st^[ stpos ].eop = op_not_in ) AND
                                    ( stpos-ps_startpos - 1 =
                                    mb_st^[ stpos ].elen_var )
                                THEN
                                    BEGIN
&                                   ifdef trace
                                    t01sname( ak_strat, 'op_not_in   ' );
&                                   endif
                                    ps_indexfield := false;
                                    ps_keyfield   := false
                                    END
                                (*ENDIF*) 
                            (*ENDIF*) 
                        (*ENDIF*) 
                        END
                    ELSE
                        BEGIN
                        (* op_ne *)
&                       ifdef trace
                        t01sname( ak_strat, 'op_ne       ' );
&                       endif
                        ps_stoppos := stpos;
                        END
                    (*ENDIF*) 
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            (* ===================================== *)
            (* case '<field> like <value>' detected; *)
            (* will be used for EQUAL- or BETWEEN-   *)
            (* strategy                              *)
            (* ===================================== *)
&           ifdef TRACE
            t01int4 (ak_strat, 'like found  ', stpos - mb_qual^.mqual_pos + 1);
&           endif
            stpos := stpos + 4; (* skip st_dummies *)
            ps_stoppos  := stpos;
            WITH mb_st^[ ps_startpos ] DO
                BEGIN
                IF  ( ord( ecol_tab[ 2 ] ) > 100 )
                THEN
                    ps_indexfield := true;
                (*ENDIF*) 
                END
            (*ENDWITH*) 
            END;
        (*ENDIF*) 
        WITH mb_st^[ stpos ] DO
            IF  (( etype = st_value ) OR (( etype = st_op ) AND ( eop = op_in )))
                AND
                ( ecol_tab[ 2 ] <> chr( 0 ) )
            THEN
                BEGIN
&               ifdef trace
                t01sname( ak_strat, 'skip ecoltab' );
&               endif
                stpos := stpos + ord( ecol_tab[ 2 ] );
                END;
            (*ENDIF*) 
        (*ENDWITH*) 
        stpos := succ( stpos );
&       ifdef TRACE
        IF  ps_indexfield
        THEN
            t01int4 (ak_strat, 'INDEXFIELD  ', ps_stoppos - mb_qual^.mqual_pos + 1)
        ELSE
            t01int4 (ak_strat, 'NO INDEX    ', ps_stoppos - mb_qual^.mqual_pos + 1);
        (*ENDIF*) 
        IF  ps_keyfield
        THEN
            t01int4 (ak_strat, 'KEYFIELD    ', ps_stoppos - mb_qual^.mqual_pos + 1)
        ELSE
            t01int4 (ak_strat, 'NO KEYFIELD ', ps_stoppos - mb_qual^.mqual_pos + 1);
        (*ENDIF*) 
&       endif
        END
    (*ENDIF*) 
    END;
(*ENDWITH*) 
&ifdef TRACE
IF  one_and_var.ps_stoppos <> 0
THEN
    t01p2int4(ak_strat, 'okcond start', one_and_var.ps_startpos -
          acv.a_mblock.mb_qual^.mqual_pos + 1,
          'okcond stop ', one_and_var.ps_stoppos -
          acv.a_mblock.mb_qual^.mqual_pos + 1);
&endif
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak724skip_stack_entries (
            VAR acv     : tak_all_command_glob;
            VAR pos      : tsp00_Int2;
            VAR levelrec : t_leveltype ;
            stop         : tsp00_Int2);
 
VAR
      _circle : boolean;
      _oldpos : tsp00_Int2;
 
BEGIN
WITH acv.a_mblock, levelrec DO
    BEGIN
&   ifdef TRACE
    t01int4 (ak_strat, 'pos to skip ', pos);
&   endif
    (*Conditions with a level more than 3 (below level 3) are skipped *)
    (*This is repeated until level 3 is reached *)
    _oldpos := pos;
    _circle := false;
    IF  (lv_levelcnt > c_maxquallevel)
    THEN
        WHILE NOT _circle AND
              NOT ak724check_level (acv, levelrec, pos, stop, NOT c_skip) DO
            BEGIN
            IF  (mb_st^[ pos ].etype in [ st_jump_false, st_jump_true ])
            THEN
                pos := pos + mb_st^[ pos ].epos;
            (*ENDIF*) 
            IF  (_oldpos = pos)
            THEN
                BEGIN
                _circle := true;
                pos    := stop + 1
                END
            ELSE
                _oldpos := pos
            (*ENDIF*) 
            END
        (*ENDWHILE*) 
    ELSE
        (* One term of level 2 is skipped. Therefore only a *)
        (* jump_true, oder an op_or can be found            *)
        IF  (mb_st^[ pos ].etype = st_jump_true)
        THEN
            pos := pos + mb_st^[ pos ].epos + lv_levelpredcnt[ lv_levelcnt ] - 1
        ELSE
            IF  (mb_st^[ pos ].eop = op_or)
            THEN
                pos := pos + lv_levelpredcnt[ lv_levelcnt ] - 1
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    END;
(*ENDWITH*) 
&ifdef TRACE
t01int4 (ak_strat, 'skiped to   ', pos);
&endif
END;
 
(*------------------------------*) 
 
FUNCTION
      ak724check_level (
            VAR acv      : tak_all_command_glob;
            VAR levelrec : t_leveltype;
            VAR pos      : tsp00_Int2;
            stop         : tsp00_Int2;
            skip         : boolean) :  boolean;
 
VAR
      _knockout      : boolean;
      _qual_scanned  : boolean;
      _hlevel        : tsp00_Int2;
      _ix            : tsp00_Int2;
      _lpos          : tsp00_Int2;
 
BEGIN
WITH acv.a_mblock, levelrec DO
    BEGIN
&   ifdef TRACE
    t01int4 (ak_strat, 'pos to check', pos);
    t01int4 (ak_strat, 'pos to stop ', stop);
    ak724print_levelinfo(levelrec);
&   endif
    FOR _ix := c_maxquallevel DOWNTO 2 DO
        BEGIN
        IF  lv_levelend[ _ix ]
        THEN
            BEGIN
            lv_levelpredcnt[ _ix ]   := 0;
            lv_levelend    [ _ix ]   := false;
            lv_levelpredcnt[ _ix-1 ] := succ(lv_levelpredcnt[ _ix-1 ]);
&           ifdef TRACE
            t01int4(ak_strat, 'reopen level', _ix);
            t01int4(ak_strat, 'add predic  ', _ix-1);
&           endif
            IF  ( _ix = 2 )
            THEN
                lv_level2_UNEQ := 0;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDFOR*) 
    _hlevel       := 0;
    _qual_scanned := false;
    _knockout     := false;
    (* step to c_maxquallevel *)
    WHILE (_hlevel < c_maxquallevel) AND (NOT _qual_scanned) AND (NOT _knockout) DO
        BEGIN
        _hlevel := succ(_hlevel);
&       ifdef TRACE
        t01int4 (ak_strat, 'test level  ', _hlevel);
&       endif
        _lpos := pos;
        _ix   := _hlevel;
        IF  (_lpos <= stop)
        THEN
            BEGIN
            (* step downto lv_levelstart *)
            WHILE (_ix >= lv_levelstart) DO
                (* skip possibly non existent 1. level         *)
                (* level 1 don't exist if qualification        *)
                (* looks like "<term> OR <term>" in WHERE part *)
                (* i.e. work for all existant levels           *)
                BEGIN
&               ifdef TRACE
                t01int4(ak_strat, 'check pos   ', _lpos);
&               endif
                IF  (_ix MOD 2 = 0)
                THEN
                    (* even level, i.e. OR qualifications *)
                    BEGIN
                    IF  (mb_st^[ _lpos ].etype = st_jump_true)
                        OR
                        (* 'col <> value' handling!         *)
                        (* --> (col < value) OR (col > value)   *)
                        (( mb_st^[ _lpos ].etype = st_op ) AND
                        ( mb_st^[ _lpos ].eop = op_or ) AND
                        ( mb_st^[ _lpos + 1 ].etype = st_jump_true ))
                    THEN
                        BEGIN
                        (* left OR participant found *)
                        IF  (( mb_st^[ _lpos ].etype = st_op ) AND
                            ( mb_st^[ _lpos ].eop = op_or ) AND
                            ( mb_st^[ _lpos + 1 ].etype = st_jump_true ))
                        THEN
                            BEGIN
&                           ifdef TRACE
                            t01sname(ak_strat, 'special <>  ');
&                           endif
                            (* 'col <> value' handling! *)
                            (* count 'col <> value'     *)
                            lv_level2_UNEQ := succ( lv_level2_UNEQ );
                            _lpos          := succ( _lpos );
                            END;
                        (*ENDIF*) 
                        ;
                        IF  (mb_st^[ _lpos + mb_st^[ _lpos ].epos ].eop = op_not) AND
                            (mb_st^[ _lpos + mb_st^[ _lpos ].epos + 1 ].eop = op_or)
                        THEN
                            BEGIN
                            (* prerequisite: <term> OR NOT <C1 OR C2> *)
                            (* and <term> was relevant for strategy   *)
                            (* we check level of condition C1         *)
                            _ix             := 0; (* break through while loop*)
                            ak724check_level := false;
                            _knockout       := true;
                            pos             := _lpos + mb_st^[ _lpos ].epos + 1;
                            lv_levelpredcnt[ 2 ] := succ(lv_levelpredcnt[ 2 ]);
&                           ifdef TRACE
                            t01name(ak_strat, 'NOT <OR> knockout ');
&                           endif
                            END
                        ELSE
                            BEGIN
                            IF  ( mb_st^[ _lpos + mb_st^[ _lpos ].epos ].etype =
                                st_jump_true )
                                (* 'col <> value' handling!             *)
                                (* --> (col < value) OR (col > value)   *)
                            THEN
                                BEGIN
&                               ifdef TRACE
                                t01sname(ak_strat, 'ST_JUMP_TRUE');
&                               endif
                                _lpos := _lpos + mb_st^[ _lpos ].epos +
                                      mb_st^[ _lpos + mb_st^[ _lpos ].epos ].epos +
                                      lv_levelpredcnt[ _ix ] - lv_level2_UNEQ;
                                END
                            ELSE
                                BEGIN
&                               ifdef TRACE
                                t01sname(ak_strat, 'OR          ');
&                               endif
                                _lpos := _lpos + mb_st^[ _lpos ].epos +
                                      lv_levelpredcnt[ _ix ] - lv_level2_UNEQ;
                                END;
                            (*ENDIF*) 
&                           ifdef TRACE
                            t01name(ak_strat, 'lft OR, jump rght ');
                            t01int4(ak_strat, 'predic cnt  ', lv_levelpredcnt[_ix]);
                            t01int4(ak_strat, 'new _lpos   ', _lpos);
                            t01int4(ak_strat, '<> cnt      ', lv_level2_UNEQ);
&                           endif
                            END;
                        (*ENDIF*) 
                        END
                    ELSE
                        BEGIN
                        IF  (mb_st^[ _lpos ].eop = op_or)
                        THEN
                            BEGIN
                            (* right OR participant found *)
                            lv_levelend[ _ix ] := true;
                            _lpos := _lpos + lv_levelpredcnt[ _ix ] -
                                  lv_level2_UNEQ;
&                           ifdef TRACE
                            t01sname(ak_strat, 'END OR lvl  ');
                            t01int4(ak_strat, 'predic cnt  ', lv_levelpredcnt[_ix]);
                            t01int4(ak_strat, 'new _lpos   ', _lpos);
                            t01int4(ak_strat, '<> cnt      ', lv_level2_UNEQ);
&                           endif
                            END
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    END
                ELSE
                    BEGIN
                    (* odd level, i.e. AND qualifications *)
                    IF  (mb_st^[ _lpos ].etype = st_jump_false)
                    THEN
                        BEGIN
                        (* left AND participant found *)
                        IF  (_lpos + mb_st^[ _lpos ].epos < stop) AND
                            (mb_st^[ _lpos + mb_st^[ _lpos ].epos ].eop = op_not) AND
                            (mb_st^[ _lpos + mb_st^[ _lpos ].epos + 1 ].eop = op_and)
                        THEN
                            BEGIN
                            (* prerequisite: <term> AND NOT <C1 AND C2>      *)
                            (* <term> don't have to be relevant for strategy *)
                            (* we check level for C1                         *)
                            _ix              := 0; (* break through while loop*)
                            ak724check_level := false;
                            _knockout        := true;
                            pos              := _lpos + mb_st^[ _lpos ].epos + 1;
                            lv_levelpredcnt[ 3 ] := succ(lv_levelpredcnt[ 3 ]);
&                           ifdef TRACE
                            t01name(ak_strat, 'NOT <AND> knockout');
&                           endif
                            END
                        ELSE
                            BEGIN
                            _lpos := _lpos + mb_st^[ _lpos ].epos +
                                  lv_levelpredcnt[ _ix ];
&                           ifdef TRACE
                            t01name(ak_strat, 'lft AND, jump rght');
                            t01int4(ak_strat, 'predic cnt  ', lv_levelpredcnt[_ix]);
                            t01int4(ak_strat, 'new _lpos   ', _lpos);
                            t01int4(ak_strat, '<> cnt      ', lv_level2_UNEQ);
&                           endif
                            END;
                        (*ENDIF*) 
                        END
                    ELSE
                        BEGIN
                        IF  (mb_st^[ _lpos ].eop in [ op_and, op_upd_view_and ])
                        THEN
                            BEGIN
                            (* right AND participant found *)
                            lv_levelend[ _ix ] := true;
                            _lpos              := _lpos +
                                  lv_levelpredcnt[ _ix ];
&                           ifdef TRACE
                            t01sname(ak_strat, 'END AND lvl ');
                            t01int4(ak_strat, 'predic cnt  ', lv_levelpredcnt[_ix]);
                            t01int4(ak_strat, 'new _lpos   ', _lpos);
                            t01int4(ak_strat, '<> cnt      ', lv_level2_UNEQ);
&                           endif
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                (* maybe we are on one level above *)
                (* try to jump this level          *)
                _ix := pred(_ix);
&               ifdef trace
                IF  _ix >= lv_levelstart
                THEN
                    t01int4(ak_strat, 'jmp level   ', _ix)
                ELSE
                    t01name(ak_strat, 'jump completed    ');
                (*ENDIF*) 
&               endif
                END;
            (*ENDWHILE*) 
            END;
        (*ENDIF*) 
        ;
&       ifdef trace
        t01int4(ak_strat, 'chck nxt lvl', succ(_hlevel));
&       endif
        IF  (_lpos > stop)
        THEN
            BEGIN
&           ifdef TRACE
            t01sname(ak_strat, 'qual scanned');
&           endif
            _qual_scanned := true; (* break through while loop *)
            FOR _ix := 1 TO c_maxquallevel - 1 DO
                BEGIN
                IF      lv_levelend[ _ix   ] AND
                    NOT lv_levelend[ _ix+1 ] AND
                    NOT ( _ix = _hlevel )
                THEN
                    BEGIN
&                   ifdef trace
                    t01int4(ak_strat, 'reopen lvl  ', _ix);
&                   endif
                    lv_levelend[ _ix ] := false;
                    END;
                (*ENDIF*) 
                END;
            (*ENDFOR*) 
            END
        ELSE
            (* we are still in qualification        *)
            (* try to jump out with one level above *)
            BEGIN
&           ifdef trace
            t01sname(ak_strat, 'reopen lvls ');
&           endif
            FOR _ix := 1 TO c_maxquallevel DO
                BEGIN
                lv_levelend[ _ix ] := false;
                END;
            (*ENDFOR*) 
            _qual_scanned := false
            END
        (*ENDIF*) 
        END;
    (*ENDWHILE*) 
    IF  NOT _qual_scanned AND (mb_st^[ _lpos ].eop = op_not)
    THEN
        BEGIN
&       ifdef TRACE
        t01sname(ak_strat, 'low lvl NOT ');
&       endif
        lv_levelcnt     := c_maxquallevel + 1;
        ak724check_level := false;
        _lpos           := succ(_lpos); (* skip NOT stack entry *)
        ak724skip_stack_entries (acv, _lpos, levelrec, stop);
        pos             := _lpos;
        IF  (lv_levelcnt = 1)
        THEN
            BEGIN
            lv_levelcnt    := 2;
            lv_levelend[1] := true
            END
        ELSE
            IF  (lv_levelcnt = 2)
            THEN
                BEGIN
                lv_levelcnt    := 3;
                lv_levelend[2] := true
                END
            ELSE
                BEGIN
                lv_levelcnt                     := c_maxquallevel + 1;
                lv_levelpredcnt[c_maxquallevel] :=
                      succ(lv_levelpredcnt[c_maxquallevel])
                END
            (*ENDIF*) 
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        IF  _qual_scanned AND NOT _knockout
        THEN
            BEGIN
&           ifdef TRACE
            t01sname(ak_strat, 'no knockout ');
&           endif
            lv_levelcnt      := _hlevel;
            ak724check_level := true;
            (* close all level except the found level *)
            FOR _ix := lv_levelcnt TO c_maxquallevel - 1 DO
                BEGIN
&               ifdef trace
                t01int4(ak_strat, 'close level ', _ix+1);
&               endif
                lv_levelend[ _ix + 1 ] := true;
                END;
            (*ENDFOR*) 
            END
        ELSE
            BEGIN
            IF  NOT _qual_scanned
            THEN
                BEGIN
&               ifdef TRACE
                t01sname(ak_strat, 'irrelev lvl ');
&               endif
                ak724check_level := false;
                lv_levelcnt      := c_maxquallevel + 1;
                IF  skip
                THEN
                    BEGIN
&                   ifdef TRACE
                    t01name(ak_strat, 'skip irrelev level');
&                   endif
                    ak724skip_stack_entries(acv, pos, levelrec, stop);
                    (* all lower predicates counts for c_maxquallevel *)
                    lv_levelpredcnt[ c_maxquallevel ] :=
                          succ(lv_levelpredcnt[ c_maxquallevel ])
                    END
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    ;
&   ifdef TRACE
    ak724print_levelinfo(levelrec);
&   endif
    END;
(*ENDWITH*) 
END;
 
&ifdef TRACE
(*------------------------------*) 
 
PROCEDURE
      ak724print_levelinfo(VAR levelrec : t_leveltype);
 
VAR
      _i    : integer;
      _line : tsp00_Line;
 
BEGIN
WITH levelrec DO
    BEGIN
    _line := a99blankline;
    t01name(ak_strat, '--- LEVELINFO --- ');
    t01int4(ak_strat, 'level count ', lv_levelcnt);
    _line[1] := 'L';
    _line[2] := 'E';
    _line[3] := 'V';
    _line[4] := 'E';
    _line[5] := 'L';
    FOR _i := 0 TO c_maxquallevel-1 DO
        IF  ((_i*20)+5) < sizeof(tsp00_Line)
        THEN
            g17int4to_line(_i+1, false, 2, 10+_i*20, _line);
        (*ENDIF*) 
    (*ENDFOR*) 
    t01line(ak_strat, _line);
    _line := a99blankline;
    _line[1] := 'P';
    _line[2] := 'R';
    _line[3] := 'D';
    _line[4] := 'C';
    _line[5] := 'N';
    _line[6] := 'T';
    FOR _i := 0 TO c_maxquallevel-1 DO
        IF  _i * 20 < sizeof(tsp00_Line)
        THEN
            g17int4to_line(lv_levelpredcnt[_i+1], false, 2, 10+_i*20, _line);
        (*ENDIF*) 
    (*ENDFOR*) 
    t01line(ak_strat, _line);
    _line := a99blankline;
    _line[1] := 'L';
    _line[2] := 'E';
    _line[3] := 'N';
    _line[4] := 'D';
    FOR _i := 0 TO c_maxquallevel-1 DO
        IF  _i * 20 < sizeof(tsp00_Line)
        THEN
            g17int4to_line(ord(lv_levelend[_i+1]), false, 2, 10+_i*20, _line);
        (*ENDIF*) 
    (*ENDFOR*) 
    t01line(ak_strat, _line);
    END;
(*ENDWITH*) 
END;
 
&endif
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
.PA 
