.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);
 
.CM *-END-* define --------------------------------------
 
Use     :
 
        FROM
              Build_Strategy : VAK70;
 
        VAR
              a70_glob_zstrat_rec : tak70_strategy_record;
 
      ------------------------------ 
 
        FROM
              Build_Strategy_2 : VAK71;
 
        VAR
              a71blankline            : tsp00_Line;
 
        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_error_handling : VAK07;
 
        PROCEDURE
              a07ak_system_error (
                    VAR acv  : tak_all_command_glob;
                    modul_no : integer;
                    id       : integer);
 
      ------------------------------ 
 
        FROM
              AK_Index : VAK24;
 
        FUNCTION
              a24LookForFunctionBasedIndex (
                    VAR acv        : tak_all_command_glob;
                    stackStart     : integer;
                    stackEnd       : integer;
                    VAR stackNext  : integer) : boolean;
 
      ------------------------------ 
 
        FROM
              Trace_Strategy_2 : VAK727;
 
        PROCEDURE
              a727L1_terms_trace (
                    VAR acv      : tak_all_command_glob;
                    VAR L1_terms : tak70_term);
 
      ------------------------------ 
 
        FROM
              Configuration_Parameter : VGG01;
 
        VAR
              g01vtrace    : tgg00_VtraceState;
 
      ------------------------------ 
 
        FROM
              GG_edit_routines : VGG17;
 
        PROCEDURE
              g17int4to_line (
                    int       : tsp00_Int4;
                    with_zero : boolean;
                    int_len   : integer;
                    ln_pos    : integer;
                    VAR ln    : tsp00_Line);
 
        PROCEDURE
              g17sname_to_line (
                    n             : tsp00_Sname;
                    VAR ln_len    : integer;
                    VAR ln        : tsp00_Line (*ptocSynonym char**));
 
      ------------------------------ 
 
        FROM
              Trace_Help_Procedures : VGG041;
 
        PROCEDURE
              g041c30_to_trace (
                    VAR t : tgg00_TransContext;
                    msg : tsp00_C30);
 
        PROCEDURE
              g041name_to_trace (
                    VAR t  : tgg00_TransContext;
                    name   : tsp00_Name);
 
        PROCEDURE
              g041int4_to_trace (
                    VAR t  : tgg00_TransContext;
                    name   : tsp00_Name;
                    intval : tsp00_Int4);
 
        PROCEDURE
              g041line_to_trace (
                    VAR t      : tgg00_TransContext;
                    VAR line   : tsp00_Line);
 
        PROCEDURE
              g041p2int4_to_trace (
                    VAR t   : tgg00_TransContext;
                    name1   : tsp00_Name;
                    intval1 : tsp00_Int4;
                    name2   : tsp00_Name;
                    intval2 : tsp00_Int4);
 
      ------------------------------ 
 
        FROM
              Kernel_move_and_fill : VGG101;
 
        PROCEDURE
              SAPDB_PascalMove   (
                    mod_id         : tsp00_C6;
                    mod_intern_num : tsp00_Int4;
                    size1          : tsp00_Int4;
                    size2          : tsp00_Int4;
                    val1           : tsp00_MoveObjPtr;
                    p1             : tsp00_Int4;
                    val2           : tsp00_MoveObjPtr;
                    p2             : tsp00_Int4;
                    cnt            : tsp00_Int4;
                    VAR e          : tgg00_BasisError);
 
        PROCEDURE
              SAPDB_PascalFill  (
                    mod_id         : tsp00_C6;
                    mod_intern_num : tsp00_Int4;
                    size           : tsp00_Int4;
                    m              : tsp00_MoveObjPtr;
                    pos            : tsp00_Int4;
                    len            : tsp00_Int4;
                    fillchar       : char;
                    VAR e          : tgg00_BasisError);
      ------------------------------ 
 
        FROM
              Trace : VBD120;
 
        PROCEDURE
              b120MessBlockTrace (
                    VAR Trans     : tgg00_TransContext;
                    TraceType     : tgg00_VtraceType;
                    VAR MessBlock : tgg00_MessBlock);
 
      ------------------------------ 
 
        FROM
              RTE_kernel : VEN101;
 
        PROCEDURE
              vfrawopen (
                    VAR hostfile   : tsp00_VFilename;
                    VAR hostfileno : tsp00_Int4;
                    VAR error      : tsp00_VfReturn;
                    VAR errtext    : tsp00_ErrText);

        PROCEDURE
              vfwrite (hostfileno : tsp00_Int4;
                    buf           : tsp_vf_bufaddr;
                    VAR error     : tsp00_VfReturn;
                    VAR errtext   : tsp00_ErrText);
 
        PROCEDURE
              vfclose (hostfileno : tsp00_Int4;
                    VAR error     : tsp00_VfReturn;
                    VAR errtext   : tsp00_ErrText);
 
&       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_levelfound : 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_level_max)
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_level_max)) 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_levelfound' 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_levelfound':
 
 
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_level_max) 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_level_max'
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_level_max', 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_levelfound', which, in the first case, is greater than
'c_level_max', 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_level_max  =  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_levelfound  : tsp00_Int2;
            lv_levelstart  : tsp00_Int2;
            lv_levelend    : ARRAY [ 1..c_level_max ] 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);
 
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*) 
&   ifdef TRACE
    t01int4 (ak_strat, 'lv_levelstrt', _levelrec.lv_levelstart);
&   endif
    END;
(* initialize predicate nesting information *)
(*ENDIF*) 
;
&ifdef TRACE
t01int4 (ak_strat, 'lv_levelstrt', _levelrec.lv_levelstart);
&endif
IF  ( g01vtrace.vtrStrategy_gg00 )
THEN
    BEGIN
    g041name_to_trace( acv.a_transinf.tri_trans,
          '>> A724ALL_L1_TERM' );
    END;
(*ENDIF*) 
;
(* initialize predicate nesting information *)
_levelrec.lv_levelfound := 0;
FOR _ix := 1 TO c_level_max DO
    BEGIN
    _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 );
    (* ak724one_L1_term stops qualification loop in case of *)
    (* a. end of qualification        or                    *)
    (* b. lv_levelend[2] = TRUE       or                    *)
    (* c. lv_levelfound = 1                                 *)
    IF  ( _levelrec.lv_levelfound = 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
        BEGIN
        IF  ( L1_terms.trm_L1terms[ _ix ].
            l1t_L2terms[ L1_terms.trm_L1terms[ _ix ].l1t_L2pL3tcnt - 1 ].
            l2l3p_predcnt = 0 )
        THEN
            BEGIN
            L1_terms.trm_L1terms[ _ix ].l1t_L2pL3tcnt :=
                  pred( L1_terms.trm_L1terms[ _ix ].l1t_L2pL3tcnt );
&           ifdef trace
            t01sname(ak_strat, 'rm one L2pL3');
&           endif
            END;
        (*ENDIF*) 
        IF  ( L1_terms.trm_L1terms[ _ix ].l1t_L2pL3tcnt = 1 ) AND
            ( L1_terms.trm_L1terms[ _ix ].
            l1t_L2terms[ L1_terms.trm_L1terms[ _ix ].l1t_L2pL3tcnt - 1 ].
            l2l3p_predcnt > 0 )
        THEN
            (* there have to be minimal 2 terms 'A OR B'                  *)
            (* l2l3p_predcnt = 0 means: there are L4 terms!! - see vak726 *)
            BEGIN
            ak724ak_system_error( acv, 1 );
            END;
        (*ENDIF*) 
        END;
    (*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
IF  ( g01vtrace.vtrStrategy_gg00 )
THEN
    BEGIN
    a727L1_terms_trace( acv, L1_terms );
    END;
(*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);
 
VAR
      _condition_found  : boolean;
 
BEGIN
&ifdef TRACE
t01int4 (ak_strat, 'qs_start    ', qualscanner.qs_start );
t01int4 (ak_strat, 'qs_stop     ', qualscanner.qs_stop  );
&endif
qualscanner.qs_actpos := qualscanner.qs_start;
levelrec.lv_predicate.ps_put_l2term   := false;
levelrec.lv_predicate.ps_put_l3term   := false;
REPEAT
    BEGIN
    ak724analyze_condition( acv, dmli.d_sparr, qualscanner.qs_actpos, levelrec.lv_predicate,
          upd_col_with_expr, qualscanner.qs_stop );
    (* ======================================================== *)
    (* 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  ( qualscanner.qs_actpos <= qualscanner.qs_stop ) AND
        ( acv.a_mblock.mb_st^[ qualscanner.qs_actpos ].eop = op_not )
    THEN (* recently analyzed condition is operand of a NOT. *)
        BEGIN
        levelrec.lv_predicate.ps_indexfield := false;
        levelrec.lv_predicate.ps_keyfield   := false;
        qualscanner.qs_actpos     := succ( qualscanner.qs_actpos );
        END;
    (*ENDIF*) 
    IF  ( ak724check_level( acv, levelrec, qualscanner.qs_actpos,
        qualscanner.qs_stop, c_skip ))
    THEN
        BEGIN
        (* term exists in level 1, 2 or 3 *)
&       ifdef TRACE
        t01int4 (ak_strat, 'act. LEVEL: ', levelrec.lv_levelfound);
&       endif
        CASE levelrec.lv_levelfound OF
            1 :
                BEGIN
                IF  ( levelrec.lv_predicate.ps_keyfield )
                    AND
                    ( NOT ( cs_keyscan in
                    access_info.srec_config.cfg_switches ))
                THEN
                    a71key_strat( acv, access_info,
                          levelrec.lv_predicate.ps_startpos,
                          levelrec.lv_predicate.ps_stoppos );
                (*ENDIF*) 
                IF  ( levelrec.lv_predicate.ps_indexfield )
                    AND
                    ( NOT ( cs_indexscan in
                    access_info.srec_config.cfg_switches ))
                THEN
                    a71index_strat( acv, access_info,
                          levelrec.lv_predicate.ps_startpos,
                          levelrec.lv_predicate.ps_stoppos );
                (*ENDIF*) 
                END;
            2 :
                IF  ( NOT levelrec.lv_predicate.ps_keyfield AND
                    NOT levelrec.lv_predicate.ps_indexfield )
                THEN
                    BEGIN
                    levelrec.lv_levelend[ 2 ] := true;
&                   ifdef TRACE
                    t01name(ak_strat, 'level 2 knockout  ');
&                   endif
                    ak724skip_stack_entries( acv, qualscanner.qs_actpos,
                          levelrec, qualscanner.qs_stop );
                    IF  ( levelrec.lv_predicate.ps_put_l2term )
                    THEN
                        L1_terms.trm_L1termcnt :=
                              pred( L1_terms.trm_L1termcnt );
                    (*ENDIF*) 
                    END
                ELSE
                    ak724build_lower_preds( acv, L1_terms, levelrec );
                (*ENDIF*) 
            3 :
                BEGIN
                ak724build_lower_preds( acv, L1_terms, levelrec );
&               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  ', levelrec.lv_predicate.ps_put_l2term );
        t01bool (ak_strat, 'put_l3term  ', levelrec.lv_predicate.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               *)
            levelrec.lv_predicate.ps_put_l2term := false;
            levelrec.lv_predicate.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*)
            IF  ( L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                l1t_L2pL3tcnt > 0 )
            THEN
                IF  ( levelrec.lv_levelend[ 3 ] AND
                    ( L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                    l1t_L2terms[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                    l1t_L2pL3tcnt - 1 ].l2l3p_predcnt = 0 ))
                THEN
                    levelrec.lv_predicate.ps_put_l3term := true;
                (*ENDIF*) 
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            IF  ( levelrec.lv_levelend[ 3 ] ) AND ( levelrec.lv_levelstart = 2 )
            THEN
                BEGIN
&               ifdef trace
                t01sname (ak_strat, 'close l2    ');
&               endif
                levelrec.lv_predicate.ps_put_l3term    := false;
                levelrec.lv_predicate.ps_put_l2term    := false;
                levelrec.lv_levelend[ 2 ] := true;
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  ( levelrec.lv_levelend[ 3 ] AND levelrec.lv_predicate.ps_put_l3term )
        THEN
            BEGIN
            IF  ( L1_terms.trm_L1termcnt > 0 ) AND
                ( L1_terms.trm_L1termcnt <= cak70_max_L1terms )
            THEN
                ak724init_one_l3term( L1_terms, levelrec );
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  ( levelrec.lv_levelend[ 2 ] AND levelrec.lv_predicate.ps_put_l2term )
        THEN
            ak724init_one_l2term( L1_terms, levelrec );
        (*ENDIF*) 
        END; (* level > 3 *)
    (*ENDIF*) 
&   ifdef TRACE
    t01sname (ak_strat, '------------');
    a725L1_terms_output( ak_strat, L1_terms );
    t01bool (ak_strat, 'put_l2term  ', levelrec.lv_predicate.ps_put_l2term );
    t01bool (ak_strat, 'put_l3term  ', levelrec.lv_predicate.ps_put_l3term );
&   endif
    _condition_found := false;
    WHILE NOT _condition_found AND ( qualscanner.qs_actpos <= qualscanner.qs_stop ) DO
        IF  ( acv.a_mblock.mb_st^[ qualscanner.qs_actpos ].etype in
            [ st_jump_false, st_jump_true ] )
        THEN
            qualscanner.qs_actpos := succ( qualscanner.qs_actpos )
        ELSE
            IF  ( acv.a_mblock.mb_st^[ qualscanner.qs_actpos ].eop in
                [ op_and, op_upd_view_and, op_or ] )
            THEN
                qualscanner.qs_actpos := succ( qualscanner.qs_actpos )
            ELSE
                _condition_found := true
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDWHILE*) 
    END
UNTIL
    ( levelrec.lv_levelend[ 2 ] OR ( levelrec.lv_levelfound = 1 ) OR
    ( qualscanner.qs_actpos > qualscanner.qs_stop ))
(*ENDREPEAT*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak724build_lower_preds (
            VAR acv        : tak_all_command_glob;
            VAR L1_terms   : tak70_term;
            VAR levelrec   : t_leveltype);
 
BEGIN
&ifdef TRACE
ak724print_levelinfo(levelrec);
IF  levelrec.lv_predicate.ps_keyfield
THEN
    t01sname (ak_strat, 'KEYFIELD    ');
(*ENDIF*) 
IF  levelrec.lv_predicate.ps_indexfield
THEN
    t01sname (ak_strat, 'INDEXFIELD  ');
(*ENDIF*) 
t01int4 (ak_strat, 'cnt L1 Terms', L1_terms.trm_L1termcnt);
&endif
IF  ( g01vtrace.vtrStrategy_gg00 )
THEN
    BEGIN
    g041name_to_trace( acv.a_transinf.tri_trans,
          '>> AK724BUILD_LOWE' );
    ak724trace_levelinfo(acv, levelrec);
    END;
(*ENDIF*) 
IF  ( L1_terms.trm_L1termcnt = 0 )
THEN
    BEGIN
    (* initialize first level-1-term *)
    levelrec.lv_predicate.ps_put_l2term := false;
    L1_terms.trm_L1termcnt := 1;
    L1_terms.trm_L1terms[ 0 ].l1t_L2pL3tcnt := 0;
    L1_terms.trm_L1terms[ 0 ].l1t_is_usable := true
    END;
(*ENDIF*) 
IF  ( L1_terms.trm_L1termcnt <= cak70_max_L1terms )
THEN
    BEGIN
    IF  L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].l1t_is_usable
    THEN
        BEGIN
        IF  ( L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
            l1t_L2pL3tcnt = 0 )
        THEN
            BEGIN
&           ifdef TRACE
            t01sname ( ak_strat, 'init l2t    ');
&           endif
            (* initialize first level-2-term of actual level-1-term *)
            L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                  l1t_L2pL3tcnt := 1;
            levelrec.lv_predicate.ps_put_l2term := true;
            levelrec.lv_predicate.ps_put_l3term := false;
            L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                  l1t_L2terms[ 0 ].l2l3p_predcnt := 0
            END;
        (*ENDIF*) 
        ;
&       ifdef TRACE
        t01int4 ( ak_strat, 'cnt L2p L3t ',
              L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].l1t_L2pL3tcnt);
&       endif
        IF  levelrec.lv_predicate.ps_keyfield OR
            levelrec.lv_predicate.ps_indexfield
        THEN
            BEGIN
            IF  ( L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                l1t_L2terms[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                l1t_L2pL3tcnt - 1 ].l2l3p_predcnt < cak70_max_predicates )
            THEN
                BEGIN
&               ifdef TRACE
                t01sname ( ak_strat, 'add predicat' );
&               endif
                L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2terms[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2pL3tcnt - 1 ].l2l3p_predcnt :=
                      succ( L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2terms[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2pL3tcnt - 1 ].l2l3p_predcnt );
                levelrec.lv_predicate.ps_put_l3term   := true;
                L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2terms[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2pL3tcnt - 1 ].
                      l2l3p_preds[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2terms[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2pL3tcnt - 1 ].l2l3p_predcnt - 1 ].
                      pred_start      := levelrec.lv_predicate.ps_startpos;
                L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2terms[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2pL3tcnt - 1 ].
                      l2l3p_preds[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2terms[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2pL3tcnt - 1 ].l2l3p_predcnt - 1 ].
                      pred_stop       := levelrec.lv_predicate.ps_stoppos;
                L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2terms[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2pL3tcnt - 1 ].
                      l2l3p_preds[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2terms[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2pL3tcnt - 1 ].l2l3p_predcnt - 1 ].
                      pred_key        := levelrec.lv_predicate.ps_keyfield;
                L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2terms[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2pL3tcnt - 1 ].
                      l2l3p_preds[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2terms[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                      l1t_L2pL3tcnt - 1 ].l2l3p_predcnt - 1 ].
                      pred_inv        := levelrec.lv_predicate.ps_indexfield;
                END;
            (*ENDIF*) 
            ;
&           ifdef TRACE
            t01int4 ( ak_strat, 'cnt predicat',
                  L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                  l1t_L2terms[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                  l1t_L2pL3tcnt - 1 ].l2l3p_predcnt);
&           endif
            END
        ELSE
            BEGIN
            IF  ( levelrec.lv_levelend[ 3 ] AND
                ( L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                l1t_L2terms[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
                l1t_L2pL3tcnt - 1 ].l2l3p_predcnt = 0 ))
            THEN
                BEGIN
&               ifdef TRACE
                t01sname ( ak_strat, 'put l3term  ');
&               endif
                levelrec.lv_predicate.ps_put_l3term := true;
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        (* up to now no useful pred found for this term *)
        IF  levelrec.lv_levelend[ 3 ] AND levelrec.lv_predicate.ps_put_l3term
        THEN
            ak724init_one_l3term( L1_terms, levelrec );
        (*ENDIF*) 
        ;
&       ifdef TRACE
        t01int4 ( ak_strat, 'cnt L2p L3t ', L1_terms.
              trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].l1t_L2pL3tcnt);
&       endif
        END
    ELSE
        BEGIN
&       ifdef TRACE
        t01sname(ak_strat, 'l2term unuse');
&       endif
        END
    (*ENDIF*) 
    END
ELSE
    BEGIN
&   ifdef TRACE
    t01int4(ak_strat, 'trm_L1termcn', L1_terms.trm_L1termcnt);
&   endif
    END;
(*ENDIF*) 
IF  levelrec.lv_levelend[ 2 ] AND levelrec.lv_predicate.ps_put_l2term
THEN
    ak724init_one_l2term( L1_terms, levelrec );
(*ENDIF*) 
;
&ifdef TRACE
t01int4 (ak_strat, 'cnt L1 Terms', L1_terms.trm_L1termcnt);
a725L1_terms_output (ak_strat, L1_terms);
&endif
IF  ( g01vtrace.vtrStrategy_gg00 )
THEN
    BEGIN
    a727L1_terms_trace( acv, L1_terms );
    END;
(*ENDIF*) 
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);
 
VAR
      upd_col_with_expr_found : boolean;
      _access_path            : boolean;
      _found                  : boolean;
      _functionBasedIndexFound: boolean;
      _ix                     : integer;
      _col_ptr                : tak00_colinfo_ptr;
 
BEGIN
&ifdef trace
FOR _ix := stpos TO stop DO
    t01stackentry (ak_strat, acv.a_mblock.mb_st^[_ix], _ix);
(*ENDFOR*) 
&endif
_functionBasedIndexFound := false;
one_and_var.ps_startpos   := stpos;
one_and_var.ps_indexfield := false;
(* check first stack entry *)
CASE acv.a_mblock.mb_st^[ stpos ].etype OF
    st_fixkey, st_varkey,
    st_fixprimkey, st_varprimkey :
        BEGIN
        _access_path := true;
        one_and_var.ps_keyfield  := true
        END;
    st_fixcol, st_varcol,
    st_fixinv, st_varinv,
    st_varlongchar:
        BEGIN
        _access_path := true;
        one_and_var.ps_keyfield  := false
        END;
    OTHERWISE
        BEGIN
        _access_path := false;
        one_and_var.ps_keyfield  := false
        END
    END;
(*ENDCASE*) 
IF  ( _access_path )
THEN
    BEGIN
&   ifdef trace
    t01sname( ak_strat, 'access found' );
&   endif
    _ix := stpos;
    IF  acv.a_mblock.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
        BEGIN
        IF  ( acv.a_mblock.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*) 
        END;
    (*ENDIF*) 
    ;
    (* search for next operator and skip 'like'-dummies *)
    WHILE ( _ix <= stop )
          AND
          (( acv.a_mblock.mb_st^[ _ix ].eop   = op_none )  OR
          ( acv.a_mblock.mb_st^[ _ix ].etype = st_dummy )) DO
        BEGIN
        IF  acv.a_mblock.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
        (
        (acv.a_mblock.mb_st^[ _ix ].etype = st_result) OR
        ( (acv.a_mblock.mb_st^[ _ix ].etype = st_build_in_func) AND
        (acv.a_mblock.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;
            one_and_var.ps_startpos  := stpos;
            END
        ELSE
            _access_path := false;
        (*ENDIF*) 
        one_and_var.ps_keyfield := false;
        END;
    (*ENDIF*) 
    _found := false;
    IF  ( _ix <= stop )
    THEN
        BEGIN
        IF  (( acv.a_mblock.mb_st^[ _ix   ].etype = st_subquery )
            AND
            (
            (( acv.a_mblock.mb_st^[ _ix   ].ecol_tab[ 1 ] = chr( 0 ) (* no ALL*)
            ) AND ( acv.a_mblock.mb_st^[ _ix ].eop in [ op_eq, op_in ] ))
            OR
            (( acv.a_mblock.mb_st^[ _ix ].eop = op_get_sub_value ) AND
            ( acv.a_mblock.mb_st^[ _ix + 1 ].etype = st_op ) AND
            ( acv.a_mblock.mb_st^[ _ix + 1 ].eop in [ op_eq, op_in ]))
            ))
        THEN
            _found := true
        ELSE
            BEGIN
            IF  ( acv.a_mblock.mb_st^[ _ix   ].etype = st_value )
                OR
                (( acv.a_mblock.mb_st^ [ _ix   ].etype = st_op )     AND
                (acv.a_mblock.mb_st^  [ _ix-1 ].etype = st_value ))
            THEN
                BEGIN
                IF  ( acv.a_mblock.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  
                            ( acv.a_mblock.mb_st^[ _ix - 2 ].etype = st_dummy ) AND
                            ( acv.a_mblock.mb_st^[ _ix - 1 ].etype = st_value ) AND
                            ( acv.a_mblock.mb_st^[ _ix     ].eop   = op_like )
                        THEN
                            _found := true;
                        (*ENDIF*) 
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( NOT _found )
    THEN
        BEGIN
&       ifdef trace
        t01sname( ak_strat, 'not found   ' );
&       endif
        _access_path := false;
        one_and_var.ps_keyfield  := false
        END
    (*ENDIF*) 
    END;
&ifdef TRACE
(*ENDIF*) 
t01int4 (ak_strat, 'ps_startpos ', one_and_var.ps_startpos );
IF  ( _access_path )
THEN
    BEGIN
    t01int4 (ak_strat, 'ACCESS PATH ', stpos );
    IF  one_and_var.ps_keyfield
    THEN
        t01int4 (ak_strat, 'KEYFIELD    ', stpos )
    ELSE
        t01int4 (ak_strat, 'INDEX POSSIB', stpos );
    (*ENDIF*) 
    END
ELSE
    t01int4 (ak_strat, 'NO ACCESS   ', stpos );
(*ENDIF*) 
&endif
IF  NOT _access_path
THEN
    BEGIN
    (* loop to next condition *)
    WHILE ( stpos <= stop )
          AND
          ( acv.a_mblock.mb_st^[ stpos ].etype <> st_jump_false )
          AND
          ( acv.a_mblock.mb_st^[ stpos ].etype <> st_jump_true )
          AND
          ( (( acv.a_mblock.mb_st^[ stpos ].eop <> op_and ) AND
          ( acv.a_mblock.mb_st^[ stpos ].eop <> op_or )) OR
          ( acv.a_mblock.mb_st^[ stpos ].etype = st_dummy ) OR
          ( acv.a_mblock.mb_st^[ stpos ].etype = st_bool )) DO
        (* PTS 1117523 E.Z. *)
        IF  (acv.a_mblock.mb_st^[stpos].etype = st_build_in_func) AND
            (acv.a_mblock.mb_st^[stpos].eop_build_in = op_b_case_start)
        THEN
            stpos := stpos + acv.a_mblock.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'      *)
    one_and_var.ps_indexfield := false;
    one_and_var.ps_keyfield   := false;
    one_and_var.ps_stoppos    := 0;
&   ifdef TRACE
    t01name (ak_strat, 'skipping notfield ');
    t01int4 (ak_strat, 'new stpos   ', stpos );
&   endif
    END
ELSE
    (* it seems to be a usable condition *)
    BEGIN
    IF  ( acv.a_mblock.mb_st^[ stpos + 1 ].etype <> st_dummy )
    THEN
        BEGIN
&       ifdef TRACE
        t01int4 (ak_strat, 'no dummy    ', stpos + 1);
&       endif
        stpos := succ(stpos);
        (* analyze righthand operand *)
        IF  ( acv.a_mblock.mb_st^[ stpos ].etype in [ st_value, st_subquery ] )
        THEN
            BEGIN
&           ifdef trace
            t01sname( ak_strat, 'value, subq ' );
&           endif
            IF  ( acv.a_mblock.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  ( acv.a_mblock.mb_st^[ stpos ].etype = st_subquery ) AND
                    ( acv.a_mblock.mb_st^[ stpos ].eop = op_get_sub_value )
                THEN
                    (* operator lays behind *)
                    stpos := succ( stpos );
                (*ENDIF*) 
                one_and_var.ps_stoppos := stpos;
                IF  _functionBasedIndexFound
                THEN
                    BEGIN
                    one_and_var.ps_indexfield := true;
                    END
                ELSE
                    BEGIN
                    IF  ( ord(acv.a_mblock.
                        mb_st^[ one_and_var.ps_startpos ].ecol_tab[ 2 ]) > 100 )
                    THEN
                        one_and_var.ps_indexfield := true;
                    (*ENDIF*) 
                    END
                (*ENDIF*) 
                END
            ELSE
                IF  ( acv.a_mblock.mb_st^[ stpos ].eop = op_none )
                THEN
                    BEGIN
&                   ifdef trace
                    t01sname( ak_strat, 'op_none     ' );
&                   endif
                    WHILE (( acv.a_mblock.mb_st^[ stpos ].eop  = op_none ) AND
                          ( acv.a_mblock.mb_st^[ stpos ].etype = st_value )) DO
                        stpos := succ( stpos );
                    (*ENDWHILE*) 
                    one_and_var.ps_stoppos := stpos;
                    IF  ( acv.a_mblock.mb_st^[ stpos ].etype = st_value )
                    THEN
                        BEGIN
                        IF  ( acv.a_mblock.mb_st^[ stpos ].eop = op_between ) AND
                            ( stpos - one_and_var.ps_startpos = 2 )
                        THEN
                            BEGIN
&                           ifdef trace
                            t01sname( ak_strat, 'op_between 1' );
&                           endif
                            IF  ( ord( acv.a_mblock.
                                mb_st^[ one_and_var.ps_startpos ].ecol_tab[ 2 ] ) > 100 )
                            THEN
                                one_and_var.ps_indexfield := true;
                            (*ENDIF*) 
                            END
                        ELSE
                            IF  ( acv.a_mblock.mb_st^[ stpos ].eop = op_not_between )
                                AND ( stpos - one_and_var.ps_startpos = 2 )
                            THEN
                                BEGIN
&                               ifdef trace
                                t01sname( ak_strat, 'op_between 2' );
&                               endif
                                one_and_var.ps_indexfield := false;
                                one_and_var.ps_keyfield   := false
                                END
                            (*ENDIF*) 
                        (*ENDIF*) 
                        END
                    ELSE
                        IF  ( acv.a_mblock.mb_st^[ stpos ].eop = op_in ) AND
                            ( stpos-one_and_var.ps_startpos - 1 =
                            acv.a_mblock.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.    *)
                            IF  ( ord( acv.a_mblock.
                                mb_st^[ one_and_var.ps_startpos ].ecol_tab[ 2 ] ) > 100 )
                            THEN
                                BEGIN
                                a06find_colinfo( sparr.pbasep,
                                      acv.a_mblock.mb_st^[ one_and_var.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
                                    acv.a_mblock.
                                          mb_st^[ one_and_var.ps_startpos ].
                                          ecol_tab[ 2 ] :=
                                          chr( ord( acv.a_mblock.mb_st^[ one_and_var.ps_startpos ].ecol_tab[ 2 ] ) -
                                          100 );
                                    END;
                                (*ENDIF*) 
                                END;
                            (*ENDIF*) 
                            IF  ( ord( acv.a_mblock.
                                mb_st^[ one_and_var.ps_startpos ].ecol_tab[ 2 ] ) > 100 )
                            THEN
                                one_and_var.ps_indexfield := true;
                            (*ENDIF*) 
                            END
                        ELSE
                            IF  ( acv.a_mblock.mb_st^[ stpos ].eop = op_not_in ) AND
                                ( stpos-one_and_var.ps_startpos - 1 =
                                acv.a_mblock.mb_st^[ stpos ].elen_var )
                            THEN
                                BEGIN
&                               ifdef trace
                                t01sname( ak_strat, 'op_not_in   ' );
&                               endif
                                one_and_var.ps_indexfield := false;
                                one_and_var.ps_keyfield   := false
                                END
                            (*ENDIF*) 
                        (*ENDIF*) 
                    (*ENDIF*) 
                    END
                ELSE
                    BEGIN
                    (* op_ne *)
&                   ifdef trace
                    t01sname( ak_strat, 'op_ne       ' );
&                   endif
                    one_and_var.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 );
&       endif
        stpos := stpos + 4; (* skip st_dummies *)
        one_and_var.ps_stoppos  := stpos;
        IF  ( ord( acv.a_mblock.mb_st^[ one_and_var.ps_startpos ].ecol_tab[ 2 ] ) > 100 )
        THEN
            one_and_var.ps_indexfield := true;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  (( acv.a_mblock.mb_st^[ stpos ].etype = st_value )
        OR
        (( acv.a_mblock.mb_st^[ stpos ].etype = st_op ) AND
        ( acv.a_mblock.mb_st^[ stpos ].eop = op_in )))
        AND
        ( acv.a_mblock.mb_st^[ stpos ].ecol_tab[ 2 ] <> chr( 0 ) )
    THEN
        BEGIN
&       ifdef trace
        t01sname( ak_strat, 'skip ecoltab' );
&       endif
        stpos := stpos + ord( acv.a_mblock.mb_st^[ stpos ].ecol_tab[ 2 ] );
        END;
    (*ENDIF*) 
    stpos := succ( stpos );
&   ifdef TRACE
    IF  one_and_var.ps_indexfield
    THEN
        t01int4 (ak_strat, 'INDEXFIELD  ', one_and_var.ps_stoppos )
    ELSE
        t01int4 (ak_strat, 'NO INDEX    ', one_and_var.ps_stoppos );
    (*ENDIF*) 
    IF  one_and_var.ps_keyfield
    THEN
        t01int4 (ak_strat, 'KEYFIELD    ', one_and_var.ps_stoppos )
    ELSE
        t01int4 (ak_strat, 'NO KEYFIELD ', one_and_var.ps_stoppos );
    (*ENDIF*) 
&   endif
    END;
(*ENDIF*) 
&ifdef TRACE
IF  one_and_var.ps_stoppos <> 0
THEN
    t01p2int4(ak_strat, 'okcond start', one_and_var.ps_startpos,
          'okcond stop ', one_and_var.ps_stoppos );
&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
(* precondition: levelrec.lv_levelfound is 'c_level_max + 1' or '2' *)
(* conditions with a level more than c_level_max are skipped        *)
(* this is repeated until level c_level_max is reached              *)
&ifdef TRACE
t01int4 (ak_strat, 'pos to skip ', pos);
&endif
_oldpos := pos;
_circle := true;
IF  ( levelrec.lv_levelfound > c_level_max )
THEN
    BEGIN
    WHILE _circle AND
          NOT ak724check_level (acv, levelrec, pos, stop, NOT c_skip) DO
        BEGIN
        IF  ( acv.a_mblock.mb_st^[ pos ].etype in
            [ st_jump_false, st_jump_true ] )
        THEN
            pos := pos + acv.a_mblock.mb_st^[ pos ].epos;
        (*ENDIF*) 
        IF  ( _oldpos = pos )
        THEN
            BEGIN
            _circle := false;
            pos     := stop + 1
            END
        ELSE
            _oldpos := pos
        (*ENDIF*) 
        END;
    (*ENDWHILE*) 
    END
ELSE
    (* lv_levelfound <= c_level_max *)
    BEGIN
    (* One term of level 2 is skipped. Therefore only a *)
    (* jump_true, oder an op_or can be found            *)
    IF  NOT (
        ( acv.a_mblock.mb_st^[ pos ].etype = st_jump_true )
        OR
        (( acv.a_mblock.mb_st^[ pos ].etype = st_op ) AND
        (acv.a_mblock.mb_st^[ pos ].eop = op_or ))
        )
    THEN
        ak724ak_system_error( acv, 2 );
    (*ENDIF*) 
    IF  ( acv.a_mblock.mb_st^[ pos ].etype = st_jump_true )
    THEN
        pos := pos + acv.a_mblock.mb_st^[ pos ].epos;
    (*ENDIF*) 
    WHILE ( acv.a_mblock.mb_st^[ pos ].etype = st_op ) AND
          ( acv.a_mblock.mb_st^[ pos ].eop = op_or ) AND
          ( pos <= stop ) DO
        pos := succ( pos );
    (*ENDWHILE*) 
    END;
(*ENDIF*) 
;
&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;
      _testlvl       : tsp00_Int2;
      _ix            : tsp00_Int2;
      _lpos          : tsp00_Int2;
      _jmp           : tsp00_Int2;
 
BEGIN
(* 'pos' is after the considered predicat *)
&ifdef TRACE
t01int4 (ak_strat, 'pos to check', pos);
t01int4 (ak_strat, 'pos to stop ', stop);
ak724print_levelinfo(levelrec);
&endif
FOR _ix := c_level_max DOWNTO 2 DO
    BEGIN
    IF  ( levelrec.lv_levelend[ _ix ] )
    THEN
        BEGIN
        levelrec.lv_levelend    [ _ix ]   := false;
&       ifdef TRACE
        t01int4(ak_strat, 'reopen level', _ix);
        t01int4(ak_strat, 'add predic  ', _ix-1);
&       endif
        END;
    (*ENDIF*) 
    END;
(*ENDFOR*) 
_testlvl       := 0;
_qual_scanned := false;
_knockout     := false;
(* step to c_level_max *)
WHILE ( _testlvl < c_level_max ) AND
      ( NOT _qual_scanned ) AND ( NOT _knockout ) AND
      ( acv.a_returncode = 0 ) DO
    BEGIN
&   ifdef TRACE
    t01int4 (ak_strat, 'test level  ', succ(_testlvl));
&   endif
    _testlvl := succ(_testlvl);
    _lpos    := pos;
    _ix      := _testlvl;
    IF  ( _lpos <= stop )
    THEN
        BEGIN
        WHILE ( _ix >= levelrec.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
&               ifdef trace
                t01sname(ak_strat, 'OR level    ');
&               endif
                IF  ( acv.a_mblock.mb_st^[ _lpos ].etype = st_jump_true )
                    OR
                    (* 'col <> value' handling!         *)
                    (* --> (col < value) OR (col > value)   *)
                    (( _lpos < stop ) AND
                    ( acv.a_mblock.mb_st^[ _lpos ].etype = st_op ) AND
                    ( acv.a_mblock.mb_st^[ _lpos ].eop = op_or ) AND
                    ( acv.a_mblock.mb_st^[ _lpos + 1 ].etype = st_jump_true ))
                THEN
                    BEGIN
                    (* left OR participant found *)
                    IF  (( _lpos < stop ) AND
                        ( acv.a_mblock.mb_st^[ _lpos ].etype = st_op ) AND
                        ( acv.a_mblock.mb_st^[ _lpos ].eop = op_or ) AND
                        ( acv.a_mblock.mb_st^[ _lpos + 1 ].etype = st_jump_true ))
                    THEN
                        BEGIN
&                       ifdef TRACE
                        t01sname(ak_strat, 'special <>  ');
&                       endif
                        (* 'col <> value' handling! *)
                        (* count 'col <> value'     *)
                        _lpos := succ( _lpos );
                        END;
                    (*ENDIF*) 
                    ;
                    _jmp := acv.a_mblock.mb_st^[ _lpos ].epos;
                    IF  ( _lpos + _jmp < stop ) AND
                        ( acv.a_mblock.mb_st^[ _lpos + _jmp ].etype = st_op ) AND
                        ( acv.a_mblock.mb_st^[ _lpos + _jmp ].eop = op_not ) AND
                        ( acv.a_mblock.mb_st^[ _lpos + _jmp + 1 ].etype = st_op ) AND
                        ( acv.a_mblock.mb_st^[ _lpos + _jmp + 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 outer while loop*)
                        ak724check_level := false;
                        _knockout        := true;
                        pos := _lpos + acv.a_mblock.mb_st^[ _lpos ].epos + 1;
&                       ifdef TRACE
                        t01name(ak_strat, 'NOT <OR> knockout ');
&                       endif
                        END
                    ELSE
                        BEGIN
                        _lpos := _lpos + _jmp;
                        ;
&                       ifdef TRACE
                        t01name(ak_strat, 'lft OR, jump rght ');
                        t01int4(ak_strat, 'new _lpos   ', _lpos);
&                       endif
                        WHILE ( _lpos <= stop ) AND
                              ( acv.a_mblock.mb_st^[ _lpos ].etype = st_jump_true )
                              (* 'col <> value' handling!             *)
                              (* --> (col < value) OR (col > value)   *)
                              DO
                            BEGIN
                            _lpos := _lpos + acv.a_mblock.mb_st^[ _lpos ].epos;
&                           ifdef trace
                            t01int4(ak_strat, 'jump _lpos  ', _lpos);
&                           endif
                            END;
                        (*ENDWHILE*) 
&                       ifdef TRACE
                        t01sname(ak_strat, 'OR          ');
&                       endif
                        WHILE ( acv.a_mblock.mb_st^[ _lpos ].etype = st_op ) AND
                              ( acv.a_mblock.mb_st^[ _lpos ].eop = op_or ) AND
                              ( _lpos <= stop ) DO
                            _lpos := succ( _lpos );
                        (*ENDWHILE*) 
                        IF  (( _lpos - 1 > stop ) OR
                            NOT (
                            ( acv.a_mblock.mb_st^[ _lpos - 1 ].etype = st_op ) AND
                            ( acv.a_mblock.mb_st^[ _lpos - 1 ].eop = op_or )))
                        THEN
                            ak724ak_system_error( acv, 3 );
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    END
                ELSE
                    (* NOT st_jump_true AND NOT special '<>' ) *)
                    BEGIN
                    IF  ( acv.a_mblock.mb_st^[ _lpos ].etype = st_op ) AND
                        ( acv.a_mblock.mb_st^[ _lpos ].eop = op_or )
                    THEN
                        BEGIN
                        (* right OR participant found *)
                        levelrec.lv_levelend[ _ix ] := true;
                        WHILE ( acv.a_mblock.mb_st^[ _lpos ].etype = st_op ) AND
                              ( acv.a_mblock.mb_st^[ _lpos ].eop = op_or ) AND
                              ( _lpos <= stop ) DO
                            _lpos := succ( _lpos );
                        (*ENDWHILE*) 
&                       ifdef TRACE
                        t01sname(ak_strat, 'END OR lvl  ');
                        t01int4(ak_strat, 'new _lpos   ', _lpos);
&                       endif
                        END
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END
            ELSE
                BEGIN
                (* odd level, i.e. AND qualifications *)
&               ifdef trace
                IF  ( _ix = 1 )
                THEN
                    t01name(ak_strat, 'first AND level   ')
                ELSE
                    t01name(ak_strat, 'second AND level  ');
                (*ENDIF*) 
&               endif
                IF  ( acv.a_mblock.mb_st^[ _lpos ].etype = st_jump_false )
                    OR
                    (* special 'col IS NOT NULL' handling!         *)
                    (* added by ak684add_not_null_qualification()  *)
                    (( _lpos < stop ) AND
                    ( acv.a_mblock.mb_st^[ _lpos ].etype = st_op ) AND
                    ( acv.a_mblock.mb_st^[ _lpos ].eop = op_and ) AND
                    ( acv.a_mblock.mb_st^[ _lpos + 1 ].etype = st_jump_false ))
                THEN
                    BEGIN
                    IF  (( _lpos < stop ) AND
                        ( acv.a_mblock.mb_st^[ _lpos ].etype = st_op ) AND
                        ( acv.a_mblock.mb_st^[ _lpos ].eop = op_and ) AND
                        ( acv.a_mblock.mb_st^[ _lpos + 1 ].etype = st_jump_false ))
                    THEN
                        BEGIN
&                       ifdef TRACE
                        t01name(ak_strat, 'special AND hndlng');
&                       endif
                        _lpos := succ( _lpos );
                        END;
                    (*ENDIF*) 
                    ;
                    _jmp := acv.a_mblock.mb_st^[ _lpos ].epos;
&                   ifdef trace
                    t01int4(ak_strat, 'jmp relative', _jmp );
&                   endif
                    (* left AND participant found *)
                    IF  ( _lpos + _jmp < stop ) AND
                        ( acv.a_mblock.mb_st^[ _lpos + _jmp ].etype = st_op ) AND
                        ( acv.a_mblock.mb_st^[ _lpos + _jmp ].eop = op_not ) AND
                        ( acv.a_mblock.mb_st^[ _lpos + _jmp + 1 ].etype = st_op ) AND
                        ( acv.a_mblock.mb_st^[ _lpos + _jmp + 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 outer while loop*)
                        ak724check_level := false;
                        _knockout        := true;
                        pos              := _lpos + _jmp + 1;
&                       ifdef TRACE
                        t01name(ak_strat, 'NOT <AND> knockout');
&                       endif
                        END
                    ELSE
                        BEGIN
                        _lpos := _lpos + _jmp;
                        ;
&                       ifdef TRACE
                        t01name(ak_strat, 'lft AND, jump rght');
                        t01int4(ak_strat, 'new _lpos   ', _lpos);
&                       endif
                        WHILE ( _lpos <= stop ) AND
                              ( acv.a_mblock.mb_st^[ _lpos ].etype = st_jump_false )
                              DO
                            BEGIN
                            _lpos := _lpos + acv.a_mblock.mb_st^[ _lpos ].epos;
&                           ifdef trace
                            t01int4(ak_strat, 'jump _lpos  ', _lpos);
&                           endif
                            END;
                        (*ENDWHILE*) 
                        WHILE ( acv.a_mblock.mb_st^[ _lpos ].etype = st_op ) AND
                              ( acv.a_mblock.mb_st^[ _lpos ].eop in
                              [ op_and, op_upd_view_and ] ) AND
                              ( _lpos <= stop ) DO
                            _lpos := succ( _lpos );
                        (*ENDWHILE*) 
                        IF  (( _lpos - 1 > stop ) OR
                            NOT (
                            ( acv.a_mblock.mb_st^[ _lpos - 1 ].etype = st_op ) AND
                            ( acv.a_mblock.mb_st^[ _lpos - 1 ].eop in 
                            [ op_and, op_upd_view_and ])))
                        THEN
                            ak724ak_system_error( acv, 4 );
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    END
                ELSE
                    BEGIN
                    IF  ( acv.a_mblock.mb_st^[ _lpos ].etype = st_op ) AND
                        ( acv.a_mblock.mb_st^[ _lpos ].eop in
                        [ op_and, op_upd_view_and ] )
                    THEN
                        BEGIN
                        (* right AND participant found *)
                        levelrec.lv_levelend[ _ix ] := true;
                        WHILE ( acv.a_mblock.mb_st^[ _lpos ].etype = st_op ) AND
                              ( acv.a_mblock.mb_st^[ _lpos ].eop in
                              [ op_and, op_upd_view_and ] ) AND
                              ( _lpos <= stop ) DO
                            _lpos := succ( _lpos );
                        (*ENDWHILE*) 
&                       ifdef TRACE
                        t01sname(ak_strat, 'END AND lvl ');
                        t01int4(ak_strat, 'new _lpos   ', _lpos);
&                       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 >= levelrec.lv_levelstart
            THEN
                t01int4(ak_strat, 'jmp to level', _ix)
            ELSE
                t01name(ak_strat, 'jump completed    ');
            (*ENDIF*) 
&           endif
            END; (* step through levels *)
        (*ENDWHILE*) 
        END;
    (*ENDIF*) 
    ;
&   ifdef trace
    t01int4(ak_strat, 'chck nxt lvl', succ(_testlvl));
&   endif
    IF  ( _lpos = stop + 1)
    THEN
        BEGIN
&       ifdef TRACE
        t01sname(ak_strat, 'qual scanned');
&       endif
        _qual_scanned := true; (* break through while loop *)
        FOR _ix := 1 TO c_level_max - 1 DO
            BEGIN
            IF      levelrec.lv_levelend[ _ix   ] AND
                NOT levelrec.lv_levelend[ _ix+1 ] AND
                NOT ( _ix = _testlvl )
            THEN
                BEGIN
&               ifdef trace
                t01int4(ak_strat, 'reopen lvl  ', _ix);
&               endif
                levelrec.lv_levelend[ _ix ] := false;
                END;
            (*ENDIF*) 
            END;
        (*ENDFOR*) 
        END
    ELSE
        (* we are still in qualification        *)
        (* try to jump out with one level above *)
        (* initial jump in if lv_levelstart = 2 *)
        BEGIN
&       ifdef trace
        t01sname(ak_strat, 'reopen lvls ');
&       endif
        FOR _ix := 1 TO c_level_max DO
            BEGIN
            levelrec.lv_levelend[ _ix ] := false;
            END;
        (*ENDFOR*) 
        _qual_scanned := false;
        IF  ( _lpos > stop )
        THEN
            ak724ak_system_error( acv, 5 );
        (*ENDIF*) 
        END
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
IF  ( acv.a_returncode = 0 )
THEN
    BEGIN
    IF  ( NOT _qual_scanned AND ( acv.a_mblock.mb_st^[ _lpos ].eop = op_not ))
    THEN
        BEGIN
&       ifdef TRACE
        t01sname(ak_strat, 'low lvl NOT ');
&       endif
        levelrec.lv_levelfound := c_level_max + 1;
        ak724check_level := false;
        _lpos            := succ(_lpos); (* skip NOT stack entry *)
        ak724skip_stack_entries (acv, _lpos, levelrec, stop);
        pos             := _lpos;
        IF  ( levelrec.lv_levelfound = 1 )
        THEN
            BEGIN
            levelrec.lv_levelfound  := 2;
            levelrec.lv_levelend[1] := true
            END
        ELSE
            IF  ( levelrec.lv_levelfound = 2 )
            THEN
                BEGIN
                levelrec.lv_levelfound  := 3;
                levelrec.lv_levelend[2] := true;
                END
            ELSE
                levelrec.lv_levelfound := c_level_max + 1;
            (*ENDIF*) 
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        IF  ( _qual_scanned AND NOT _knockout )
        THEN
            BEGIN
&           ifdef TRACE
            t01sname(ak_strat, 'no knockout ');
&           endif
            levelrec.lv_levelfound := _testlvl;
            ak724check_level       := true;
            (* close all level except the found level *)
            FOR _ix := levelrec.lv_levelfound TO c_level_max - 1 DO
                BEGIN
&               ifdef trace
                t01int4(ak_strat, 'close level ', _ix+1);
&               endif
                levelrec.lv_levelend[ _ix + 1 ] := true;
                END;
            (*ENDFOR*) 
            END
        ELSE
            (* NOT _qual_scanned OR _knockout *)
            BEGIN
            IF  ( NOT _qual_scanned )
            THEN
                BEGIN
&               ifdef TRACE
                t01sname(ak_strat, 'irrelev lvl ');
&               endif
                ak724check_level       := false;
                levelrec.lv_levelfound := c_level_max + 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_level_max *)
                    END
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
;
&ifdef TRACE
ak724print_levelinfo(levelrec);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak724init_one_l2term(
            VAR L1_terms   : tak70_term;
            VAR levelrec   : t_leveltype);
 
BEGIN
IF  ( L1_terms.trm_L1termcnt < cak70_max_L1terms )
THEN
    BEGIN
&   ifdef trace
    t01sname (ak_strat, 'init l1term ');
&   endif
    levelrec.lv_predicate.ps_put_l2term := false;
    ;
    IF  ( L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].l1t_is_usable )
    THEN
        L1_terms.trm_L1termcnt := succ(L1_terms.trm_L1termcnt);
    (*ENDIF*) 
    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*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak724init_one_l3term(
            VAR L1_terms   : tak70_term;
            VAR levelrec   : t_leveltype);
 
BEGIN
IF  ( L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
    l1t_L2pL3tcnt < cak70_max_L2preds_L3terms )
THEN
    BEGIN
&   ifdef trace
    t01sname (ak_strat, 'init l2pl3t ');
&   endif
    levelrec.lv_predicate.ps_put_l3term := false;
    ;
    L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].l1t_L2pL3tcnt :=
          succ(L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].l1t_L2pL3tcnt);
    (* initialize next predicate structure *)
    L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
          l1t_L2terms[ L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].
          l1t_L2pL3tcnt - 1 ].l2l3p_predcnt := 0
    END
ELSE
    (* there's no more space *)
    IF  NOT levelrec.lv_levelend[ 2 ]
    THEN
        L1_terms.trm_L1terms[ L1_terms.trm_L1termcnt - 1 ].l1t_is_usable := false;
    (*ENDIF*) 
(*ENDIF*) 
END;
 
&ifdef TRACE
(*------------------------------*) 
 
PROCEDURE
      ak724print_levelinfo(VAR levelrec : t_leveltype);

CONST
    _c_line_start  = 17;
    _c_line_offset = 20;
 
VAR
      _i, _tmp  : tsp00_Int4;
      _line     : tsp00_Line;
 
BEGIN
t01name(ak_strat, '--- levelinfo --- ');
t01p2int4(ak_strat, 'act. level  ', levelrec.lv_levelfound,
      'level start ', levelrec.lv_levelstart);
_line := a71blankline;
_tmp  := 0;
g17sname_to_line( 'level state:', _tmp, _line );
FOR _i := 0 TO c_level_max - 1 DO
    IF  _i * _c_line_offset < sizeof(tsp00_Line)
    THEN
        BEGIN
        g17int4to_line( _i, false, 2, _c_line_start + _i*_c_line_offset, _line);
        _tmp := _c_line_start + _i*_c_line_offset + 2;
        IF  ( levelrec.lv_levelend[ _i + 1 ] )
        THEN
            g17sname_to_line( '(closed)    ', _tmp, _line )
        ELSE
            g17sname_to_line( '(open)      ', _tmp, _line );
        (*ENDIF*) 
        END;
    (*ENDIF*) 
(*ENDFOR*) 
t01line(ak_strat, _line);
END;
 
&endif
(*------------------------------*) 
 
PROCEDURE
      ak724trace_levelinfo(
            VAR acv      : tak_all_command_glob;
            VAR levelrec : t_leveltype);
 
CONST
    _c_line_start  = 17;
    _c_line_offset = 20;
 
VAR
      _i, _tmp  : tsp00_Int4;
      _line     : tsp00_Line;
 
BEGIN
g041name_to_trace( acv.a_transinf.tri_trans, '--- levelinfo --- ' );
g041p2int4_to_trace( acv.a_transinf.tri_trans,
      'act. level        ', levelrec.lv_levelfound,
      'level start       ', levelrec.lv_levelstart );
_line := a71blankline;
_tmp  := 0;
g17sname_to_line( 'level state:', _tmp, _line );
FOR _i := 0 TO c_level_max - 1 DO
    IF  _i * _c_line_offset < sizeof(tsp00_Line)
    THEN
        BEGIN
        g17int4to_line( _i, false, 2, _c_line_start + _i*_c_line_offset, _line);
        _tmp := _c_line_start + _i*_c_line_offset + 2;
        IF  ( levelrec.lv_levelend[ _i + 1 ] )
        THEN
            g17sname_to_line( '(closed)    ', _tmp, _line )
        ELSE
            g17sname_to_line( '(open)      ', _tmp, _line );
        (*ENDIF*) 
        END;
    (*ENDIF*) 
(*ENDFOR*) 
g041line_to_trace(acv.a_transinf.tri_trans, _line);
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak724ak_system_error (
            VAR acv  : tak_all_command_glob;
            id       : integer);
 
VAR
      _ilen       : tsp00_Int4;
      _ix         : tsp00_Int4;
      _hostfileno : tsp00_Int4;
      _textpos    : tsp00_Int4;
      _dmp_pos    : tsp00_Int4;
      _movelen    : tsp00_Int4;
      _error      : tsp00_VfReturn;
      _errtext    : tsp00_ErrText;
      _dmp_buf    : tsp00_Page;
      _b_err      : tgg00_BasisError;
 
      _hostfile   : RECORD
            CASE boolean OF
                true :
                    (fn : tsp00_VFilename);
                false :
                    (c16 : tsp00_C16);
                END;
            (*ENDCASE*) 
 
 
BEGIN
(* dump SQL statement *)
IF  (( acv.a_cmd_part <> NIL ) AND
    (* a70strategy call from a680search_sequence() *)
    ( acv.a_init_ex_kind <> only_executing ))
THEN
    BEGIN
    FOR _ix := 1 TO sizeof(_hostfile.fn) DO
        _hostfile.fn[_ix] := ' ';
    (*ENDFOR*) 
    _hostfile.c16 := 'SQL.dump        ';
    vfrawopen( _hostfile.fn, _hostfileno, _error, _errtext );
    IF  ( _error = vf_ok )
    THEN
        BEGIN
        _dmp_pos := 1;
        (* generic code for _dmp_pos <> 1 *)
        _textpos := 1;
        WHILE ( _textpos < acv.a_cmd_part^.sp1p_buf_len ) AND
              ( _error = vf_ok ) DO
            BEGIN
            IF  ( acv.a_cmd_part^.sp1p_buf_len - _textpos + 1 )
                > (sizeof( _dmp_buf ) - _dmp_pos + 1)
            THEN
                _movelen := sizeof(_dmp_buf) - _dmp_pos + 1
            ELSE
                _movelen := acv.a_cmd_part^.sp1p_buf_len - _textpos + 1;
            (*ENDIF*) 
            SAPDB_PascalMove ('VAK724',   1,    
                  acv.a_cmd_part^.sp1p_buf_size, sizeof(_dmp_buf),
                  @acv.a_cmd_part^.sp1p_buf, _textpos,
                  @_dmp_buf, _dmp_pos, _movelen, _b_err);
            _dmp_pos := _dmp_pos + _movelen;
            IF  ( sizeof(_dmp_buf) > _dmp_pos - 1 )
            THEN
                SAPDB_PascalFill ('VAK724',   2,    
                      sizeof(_dmp_buf), @_dmp_buf, _dmp_pos,
                      sizeof(_dmp_buf) - _dmp_pos + 1, bsp_c1,
                      _b_err);
            (*ENDIF*) 
            vfwrite (_hostfileno, @_dmp_buf, _error, _errtext);
            _dmp_pos := 1;
            _textpos  := _textpos + _movelen;
            END;
        (*ENDWHILE*) 
        vfclose( _hostfileno, _error, _errtext );
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
_ilen := acv.a_mblock.mb_data_len;
b120MessBlockTrace (acv.a_mblock.mb_trns^, ak_send, acv.a_mblock);
acv.a_mblock.mb_data_len := _ilen;
a07ak_system_error( acv, 724, id );
END;
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
.PA 
