.nf
 
 .nf

    ========== licence begin  GPL
    Copyright (c) 2000-2005 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

 
.fo
*****************************************************
Copyright (c) 2000-2005 SAP AG
SAP Database Technology
 
Release :      Date : 2000-11-17
*****************************************************
modname : VAK726
changed : 2000-11-17
module  : Build_Strategy_Level1_terms
 
Author  : GertG / HolgerB
Created : 1985-10-16
*****************************************************
 
Purpose : module for handling strategy search within level-1-terms
 
Define  :
 
        PROCEDURE
              a726combine_terms (
                    VAR acv          : tak_all_command_glob;
                    VAR dmli         : tak_dml_info;
                    VAR sparr        : tak_syspointerarr;
                    VAR access_info  : tak70_strategy_record;
                    VAR gg_strategy  : tgg07_StrategyInfo;
                    VAR used_strats  : tak70_all_strat;
                    VAR order_fields : tak00_ord_fields;
                    VAR L1_terms     : tak70_term;
                    VAR nextstratpos : tsp00_Int4;
                    act_L1term       : tsp00_Int2;
                    act_L2pL3t       : tsp00_Int2;
                    L1_pageIO        : tsp00_Int4;
                    VAR strat_status : tak70_l2l3_strat_status);
 
.CM *-END-* define --------------------------------------
 
Use     :
 
        FROM
              AK_error_handling : VAK07;
 
        PROCEDURE
              a07_b_put_error (
                    VAR acv : tak_all_command_glob;
                    b_err : tgg00_BasisError;
                    err_code : tsp00_Int4);
 
        PROCEDURE
              a07ak_system_error (
                    VAR acv  : tak_all_command_glob;
                    modul_no : integer;
                    id       : integer);
 
      ------------------------------ 
 
        FROM
              AK_error_handling : VAK071;
 
        FUNCTION
              a071_return_code (
                    b_err   : tgg00_BasisError;
                    sqlmode : tsp00_SqlMode) : tsp00_Int2;
 
      ------------------------------ 
 
        FROM
              Systeminfo_cache : VAK10;
 
        PROCEDURE
              a10new (
                    VAR acv  : tak_all_command_glob;
                    obj_size : tsp00_Int4;
                    VAR p    : tak70_stratrec_ptr);
 
        PROCEDURE
              a10dispose (
                    VAR acv : tak_all_command_glob;
                    VAR p : tak70_stratrec_ptr);
 
      ------------------------------ 
 
        FROM
              Build_Strategy   : VAK70;
 
        VAR
              a70glob_key_strats        : tgg07_StratEnumSet;
              a70glob_inv_strats        : tgg07_StratEnumSet;
 
      ------------------------------ 
 
        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
              Build_Strategy_Decision : VAK720;
 
        PROCEDURE
              a720strategy_decision (
                    VAR acv              : tak_all_command_glob;
                    VAR sparr            : tak_syspointerarr;
                    VAR access_info      : tak70_strategy_record;
                    VAR gg_strategy      : tgg07_StrategyInfo;
                    VAR chosen_strat     : tak70_one_strat;
                    VAR order_fields     : tak00_ord_fields;
                    VAR StratInfo_len    : tsp00_Int2;
                    call_for_L1          : boolean);
 
      ------------------------------ 
 
        FROM
              Configuration_Parameter : VGG01;
 
        VAR
              g01vtrace    : tgg00_VtraceState;
 
      ------------------------------ 
 
        FROM
              Select_Help_Procedures : VGG04;
 
        PROCEDURE
              g04limitprimkeys (
                    VAR mblock      : tgg00_MessBlock;
                    VAR startkeyarr : tgg07_ColPosArr;
                    VAR start_key   : tgg00_Lkey;
                    VAR stopkeyarr  : tgg07_ColPosArr;
                    VAR stop_key    : tgg00_Lkey;
                    VAR use_stopkey : boolean;
                    in_stpos_hint   : tsp00_Int2;
                    in_value_idx    : tsp00_Int2);
 
        PROCEDURE
              g04limitinvkeys (
                    VAR mblock      : tgg00_MessBlock;
                    VAR inv_strat   : tgg07_StrInvInRange;
                    VAR startkey    : tgg00_Lkey;
                    VAR stopkey     : tgg00_Lkey;
                    in_stpos_hint   : tsp00_Int2;
                    in_value_idx    : tsp00_Int2);
 
      ------------------------------ 
 
        FROM
              Trace_Help_Procedures : VGG041;
 
        PROCEDURE
              g041c30_to_trace (
                    VAR t  : tgg00_TransContext;
                    msg    : tsp00_C30);
 
        PROCEDURE
              g041int4_to_trace (
                    VAR t  : tgg00_TransContext;
                    name   : tsp00_Name;
                    intval : tsp00_Int4);
 
      ------------------------------ 
 
        FROM
              Kernel_move_and_fill : VGG101;
 
        PROCEDURE
              SAPDB_PascalMove  (
                    mod_id         : tsp00_C6;
                    mod_intern_num : tsp00_Int4;
                    source_upb     : tsp00_Int4;
                    destin_upb     : tsp00_Int4;
                    source         : tsp00_MoveObjPtr;
                    source_pos     : tsp00_Int4;
                    destin         : tsp00_MoveObjPtr;
                    destin_pos     : tsp00_Int4;
                    length         : tsp00_Int4;
                    VAR e          : tgg00_BasisError);
 
      ------------------------------ 
 
        FROM
              RTE-Extension-20 : VSP20;
 
        PROCEDURE
              s20int4_to_buf (val      : tsp00_Int4;
                    VAR destin : tsp00_MoveObj;
                    destin_pos : tsp00_Int4);
 
      ------------------------------ 
 
        FROM
              RTE-Extension-30 : VSP30;
 
        PROCEDURE
              s30cmp (
                    VAR buf1     : tgg07_StrInvInRange;
                    fieldpos1    : tsp00_Int4;
                    fieldlength1 : tsp00_Int4;
                    VAR buf2     : tgg07_StrInvInRange;
                    fieldpos2    : tsp00_Int4;
                    fieldlength2 : tsp00_Int4;
                    VAR l_result : tsp00_LcompResult);
 
        PROCEDURE
              s30cmp1 (
                    VAR buf1     : tsp00_Key;
                    fieldpos1    : tsp00_Int4;
                    fieldlength1 : tsp00_Int4;
                    VAR buf2     : tsp00_Key;
                    fieldpos2    : tsp00_Int4;
                    fieldlength2 : tsp00_Int4;
                    VAR l_result : tsp00_LcompResult);
 
        PROCEDURE
              s30cmp2 (
                    VAR buf1     : tgg07_StrRaw;
                    fieldpos1    : tsp00_Int4;
                    fieldlength1 : tsp00_Int4;
                    VAR buf2     : tgg07_StrRaw;
                    fieldpos2    : tsp00_Int4;
                    fieldlength2 : tsp00_Int4;
                    VAR l_result : tsp00_LcompResult);
 
      ------------------------------ 
 
        FROM
              Trace_Strategy_2 : VAK727;
 
        PROCEDURE
              a727trace_access_info (
                    VAR transid     : tgg00_TransContext;
                    proc_name       : tsp00_Name;
                    VAR access_info : tak70_strategy_record);
&       ifdef TRACE
 
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        PROCEDURE
              t01sname (
                    debug : tgg00_Debug;
                    nam : tsp00_Sname);
 
        PROCEDURE
              t01key (
                    debug   : tgg00_Debug;
                    nam     : tsp00_Sname;
                    VAR k   : tgg00_Lkey);
 
        PROCEDURE
              t01strat_enum (
                    debug : tgg00_Debug;
                    nam   : tsp00_Sname;
                    strat : tgg07_StratEnum);
 
        PROCEDURE
              t01int4 (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    int      : tsp00_Int4);
 
        PROCEDURE
              t01name (
                    level : tgg00_Debug;
                    nam : tsp00_Name);
 
        PROCEDURE
              t01p2int4 (
                    debug : tgg00_Debug;
                    nam_1 : tsp00_Sname;
                    int_1 : tsp00_Int4;
                    nam_2 : tsp00_Sname;
                    int_2 : tsp00_Int4);
 
        PROCEDURE
              t01comp_result (
                    debug     : tgg00_Debug;
                    nam       : tsp00_Sname;
                    comp_res  : tsp00_LcompResult);
 
      ------------------------------ 
 
        FROM
              Trace_Strategy_1 : VAK725;
 
        PROCEDURE
              a725output_access_info (
                    level           : tgg00_Debug;
                    nam             : tsp00_Sname;
                    VAR access_info : tak70_strategy_record);
 
        PROCEDURE
              a725output_colposarr (
                    debug       : tgg00_Debug;
                    nam         : tsp00_Sname;
                    VAR keypos  : tgg07_ColPosArr);
 
        PROCEDURE
              a725output_one_strat (
                    layer           : tgg00_Debug;
                    VAR one_strat   : tak70_one_strat);
&       endif
 
.CM *-END-* use -----------------------------------------
 
Synonym :
 
        PROCEDURE
              a10new;
 
              tak_sysbufferaddress tak70_stratrec_ptr
 
        PROCEDURE
              a10dispose;
 
              tak_sysbufferaddress tak70_stratrec_ptr
 
        PROCEDURE
              s30cmp;
 
              tsp00_MoveObj tgg07_StrInvInRange
 
        PROCEDURE
              s30cmp1;
 
              tsp00_MoveObj tsp00_Key
 
        PROCEDURE
              s30cmp2;
 
              tsp00_MoveObj tgg07_StrRaw
 
.CM *-END-* synonym -------------------------------------
***********************************************************
 
Description:
 
A726COMBINE_TERMS
---------------------------------------
 
This procedure is called if there are one or more nested OR-terms in the
qualification that need to be examined to find out if a combination of
strategies might be the best choice to access the records specified by a
qualification.
A726COMBINE_TERMS is invoked first from within a WHILE-loop of A70_STRATEGY.
 
Input at beginning of this WHILE-loop:
 
L1_terms- syntactic structure of the qualification (3 levels)
 
Output at end of this WHILE-loop:
 
astrats - list of strategies that have to be used in combination to access all
          records qualified.
seq     - flag indicating that combination of strategies is too
          expensive; stops further calls of A726COMBINE_TERMS.
 
 
Qualification represented by L1_terms and processed by A726COMBINE_TERMS:
 
 ((a and b) or (c and d))  and ((e and f) or g) and (h or i))
 |----------------------------------------------------------|
  outer-AND-term
 
 |----------------------|      |--------------|     |------|
  OR-terms
 
 |--------|    |-------|        |-------|  |-|       |-| |-|
  inner-AND-terms
 
A726COMBINE_TERMS linearizes the nested terms of L1_terms by recursive evaluation:
The parameter 'L1term_index' represents the recursion depth (the number of the OR-term).
The parameter 'L2pL3t_index' gives the index of the inner-AND-term within the
'L1term_index'st OR-term that has to be evaluated next.
 
A sequence of nested one_recursion-calls (from first call till end of recursion) is
equivalent to exactly one strategy in astrat.
 
Example:
  A726COMBINE_TERMS [ ..1,2,. ]
      A726COMBINE_TERMS [ ...2,1,. ]
          A726COMBINE_TERMS [ ...3,1. ]
finds the best strategy for:
 
                 c and d    and   e and f   and   h
L1term_index=    1                2         3
l2l3p_preds =    2                1         1
 
In the example above there is the
  second inner-AND-term of first  OR-term combined with
  first  inner_AND-term of second OR-term combined with ... .
 
If at any point the access-costs (i.e. the costs for applying the set of
strategies collected so far) grow too expensive, then further search is aborted
by setting the 'key_range'-flag. The threshold is (2/3) * (maxpercentage/100). This
value is smaller than the usual threshold (maxpercentage/100) because by using
a combination of strategies some additional costs occur for eliminating
duplicates.
 
The search is also aborted if A726COMBINE_TERMS discovers that one of the combined
strategies would have to be sequential anyway.
The sequence of actions is as follows: AK70BUILD_LOWER_PREDS (VAK70) has entered in
L1_terms a description of a condition in which it is also recorded whether it is a
condition for a key field (pkey) or not.
The current term in the current Or part is identified by L1term_index and
L2pL3t_index. For all conditions in this term, A71KEY_STRAT and A71INDEX_STRAT
write this information to the other information already in zstrat (relating to the
conditions at the highest level and to those that are current in the other Or
parts).
Unless the special strategy keyin has been detected in A71KEY_STRAT, then,
if a new key-field condition has been entered in zstrat, the arrays ka_startfields
and z_stopfields must be sorted by ascending key fields in order, during
processing, to be able easily to recognize for which x first key fields there
are restricting conditions.
In A230ANALYSE_ACCESS_PATH, the best strategy is then determined from the
information in zstrat and is entered in astrats. For A230ANALYSE_ACCESS_PATH it
is irrelevant whether zstrat contains the descriptions of top-level conditions
(calling of A71STRAT_SEARCH_LEVEL1) or of more than one OR part.
If a term has been used from each Or part (maximum recursion depth reached;
o = L1_terms.l2pl3tcnt), the strategy cannot be improved and must be used
(good_enough).
If a strategy has been found in which there is no need for a sequential
search, this strategy is considered good (good_enough). Likewise, it is good
if, in the case of a sequential strategy, a maximum of 10 primary pages or
1/1000 of the total number of primary pages has to be searched.
In all these cases, the cost of the strategy found so far is added to the
cost of the others. If this cost is greater than that of the sequential search,
the sequential search is made.
If the special strategy keyin has been detected (direct accessing of one or
few records), this, too, is considered good enough and, because of its
negligibility, does not even have an impact on the search costs.
Unless the previous costs are already higher than those of the sequential
search (NOT seq) and if a good strategy has already been found (i.e. if the
next Or part need not yet be considered, good_enough), also
the key-field conditions
are transferred to astrats and it is then checked whether this condition is not
already contained in astrats . In this case, it would be
removed.
If no strategy has been good enough, seq still does not apply and
there is still a next Or part (o < L1_terms.l2pl3pcnt), the same course of action is
adopted in this Or part as in VAK70 for the first one:
The set of conditions that has come together through the previous Or parts
(each Or part contributing one term) is combined
one after the other with each term
in the next Or part by calling A726COMBINE_TERMS and can then build a strategy
(or more than one if there are still further Or parts that have to be
appended).
For this purpose, the conditions that have so far come together must be
saved and must be used again for each term.
If there is no further Or part or if the entries in it are no longer valid
(NOT iook), then the entire strategy search is aborted with seq = true and a
sequential search is made. It is, of course, possible in this connection to use
the key-field conditions that were at the highest level of the Search
Condition.
 
.CM *-END-* description ---------------------------------
***********************************************************
.CM -lll-
Code    :
 
 
TYPE
      t_strat_compare =
            ( no_including,
            equal_strats,
            oldstrat_includes_newstrat,
            newstrat_includes_oldstrat );
 
 
(*------------------------------*) 
 
PROCEDURE
      a726combine_terms (
            VAR acv          : tak_all_command_glob;
            VAR dmli         : tak_dml_info;
            VAR sparr        : tak_syspointerarr;
            VAR access_info  : tak70_strategy_record;
            VAR gg_strategy  : tgg07_StrategyInfo;
            VAR used_strats  : tak70_all_strat;
            VAR order_fields : tak00_ord_fields;
            VAR L1_terms     : tak70_term;
            VAR nextstratpos : tsp00_Int4;
            act_L1term       : tsp00_Int2;
            act_L2pL3t       : tsp00_Int2;
            L1_pageIO        : tsp00_Int4;
            VAR strat_status : tak70_l2l3_strat_status);
 
VAR
      _combination_evaluated : boolean;
      _act_L2pL3t            : tsp00_Int2;
      _m_strat_rec           : tak70_stratrec_ptr;
      _all_keys              : tak70_all_key_record;
 
BEGIN
(* keep in mind :                                               *)
(* Level-x-term ( x = 2*n+1 ) are concatenated with AND         *)
(* Level-y-term ( y = 2*n )   are concatenated with OR          *)
(* hence                                                        *)
(* whole qualification predicate ->                             *)
(* Level-1-term AND Level-1-term ...                            *)
(* Level-1-term ->                                              *)
(* Level-2-term OR Level-2-term ...                             *)
(* example :                                                    *)
(* X = ( A AND B ), A and B are Level-1-terms                   *)
(* assume B is Level-1-predicate                                *)
(* hence                                                        *)
(* X = ( ( C OR D ) AND B ), C and D are Level-2-terms          *)
(* assume C is Level-2-predicate                                *)
(* hence                                                        *)
(* X = ( ( C OR ( E AND F AND G ) ) AND B ),                    *)
(* same as X = ( ( C OR EFG ) AND B ),                          *)
(* E, F, and G are Level-3-terms                                *)
(*                                                              *)
(* in order to use Level-1-term A as access path                *)
(* E, F, and G have to be Level-3-predicates                    *)
(*                                                              *)
(* with this example there could be two access pathes which     *)
(* have to evaluated:                                           *)
(* first combination of C and B, means (C AND B)                *)
(* second combination is EFG and B, means E AND F AND G AND B   *)
(* are costs for both strategies higher than cost for relation  *)
(* relation use relation scan as access path                    *)
(**)
(* example: ( A OR B OR C ) AND ( D OR E OR F )                 *)
(* program run:                                                 *)
(* - analyse A                                                  *)
(* - analyse AD, get key range AD                               *)
(* - analyse AE, get key range AE                               *)
(* - analyse AF, get key range AF                               *)
(* - analyse B                                                  *)
(* - analyse BD, get key range BD                               *)
(* - analyse BE, get key range BE                               *)
(* - analyse BF, get key range BF                               *)
(* - analyse C                                                  *)
(* - analyse CD, get key range CD                               *)
(* - analyse CE, get key range CE                               *)
(* - analyse CF, get key range CF                               *)
(**)
(* assertion: *)
(* strat_status in [ lss_several_strats, lss_one_key_range ]*)
&ifdef TRACE
t01name( ak_strat, 'strat combine with' );
t01p2int4( ak_strat, 'act L1term  ', act_L1term, 'act L2pL3t  ', act_L2pL3t );
IF  ( act_L1term = 0 )
THEN
    a725output_access_info( ak_strat, 'orig. access', access_info );
(*ENDIF*) 
IF  ( act_L1term = 2 )
THEN
    t01name( ak_strat, 'one complete combi' )
ELSE
    t01name( ak_strat, 'part of one combi ' );
(*ENDIF*) 
&endif
IF  ( g01vtrace.vtrStrategy_gg00 )
THEN
    BEGIN
    g041c30_to_trace( acv.a_transinf.tri_trans,
          '>>A726COMBINE_TERMS>>         ' );
    IF  ( act_L1term = 0 )
    THEN
        a727trace_access_info( acv.a_transinf.tri_trans,
              'A726COMBINE_TERM 0', access_info );
    (*ENDIF*) 
    END;
(*ENDIF*) 
_combination_evaluated         := false;
(* backup srec_keyaccess ?? unnecessary ?? *)
_all_keys.akr_startcnt  := access_info.srec_keyaccess.ka_startcnt;
_all_keys.akr_stopcnt   := access_info.srec_keyaccess.ka_stopcnt;
_all_keys.akr_startkeys := access_info.srec_keyaccess.ka_startfields;
_all_keys.akr_stopkeys  := access_info.srec_keyaccess.ka_stopfields;
(* initialize srec_keyaccess *)
access_info.srec_keyaccess.ka_startcnt := 0;
access_info.srec_keyaccess.ka_stopcnt  := 0;
;
IF  ( act_L1term > 0 )
THEN
    ak726decide_strat_combine( acv, sparr, access_info, gg_strategy,
          used_strats, order_fields, L1_terms, nextstratpos,
          act_L1term, act_L2pL3t,
          L1_pageIO, strat_status,
          _all_keys,
          _combination_evaluated );
(*ENDIF*) 
;
(* fill ka_keyaccess with combined access path information ?? unnecessary ?? *)
access_info.srec_keyaccess.ka_startcnt    := _all_keys.akr_startcnt;
access_info.srec_keyaccess.ka_stopcnt     := _all_keys.akr_stopcnt;
access_info.srec_keyaccess.ka_startfields := _all_keys.akr_startkeys;
access_info.srec_keyaccess.ka_stopfields  := _all_keys.akr_stopkeys;
;
IF  ( ( NOT _combination_evaluated ) AND
    ( strat_status <> lss_use_L1_strat ) )
    OR
    (* 'root' call of procedure *)
    ( act_L1term = 0 )
THEN
    BEGIN
    IF  ( L1_terms.trm_L1terms[ act_L1term ].l1t_is_usable )
    THEN
        BEGIN
        _m_strat_rec := NIL;
        a10new( acv, sizeof ( access_info ), _m_strat_rec );
        IF  (( acv.a_returncode = 0 ) AND
            ( _m_strat_rec <> NIL ))
        THEN
            BEGIN
            (* create copy of actual access_info *)
            _m_strat_rec^ := access_info;
&           ifdef TRACE
            t01name( ak_strat, 'save access_info 2' );
&           endif
            _act_L2pL3t := 1;
            WHILE ( _act_L2pL3t <=
                  L1_terms.trm_L1terms[ act_L1term ].l1t_L2pL3tcnt )
                  AND
                  ( acv.a_returncode = 0 )
                  AND
                  ( strat_status <> lss_use_L1_strat ) DO
                BEGIN
                IF  ( _act_L2pL3t > 1 )
                THEN
                    BEGIN
                    (* restore previous access_info,   *)
                    (* possible with other index roots *)
                    access_info := _m_strat_rec^;
&                   ifdef TRACE
                    t01name( ak_strat, 'rsto. access info1' );
&                   endif
                    END;
                (*ENDIF*) 
                ;
                a726combine_terms( acv, dmli, sparr,
                      access_info, gg_strategy,
                      used_strats, order_fields, L1_terms,
                      nextstratpos,
                      act_L1term + 1, _act_L2pL3t,
                      L1_pageIO, strat_status );
                ;
&               ifdef TRACE
                t01name( ak_strat, 'loop over L2pL3t  ' );
                a725output_access_info( ak_strat, 'combined    ',  access_info );
&               endif
                IF  ( g01vtrace.vtrStrategy_gg00 )
                THEN
                    BEGIN
                    a727trace_access_info( acv.a_transinf.tri_trans,
                          'A726COMBINE_TERM 1', access_info );
                    END;
                (*ENDIF*) 
                ;
                (* remark actual index roots            *)
                (* possibly we have some more collected *)
                _m_strat_rec^.srec_invaccess.ia_inv_root :=
                      access_info.srec_invaccess.ia_inv_root;
                IF  ( act_L1term = 0 ) AND
                    ( qp_missing_value in
                    access_info.srec_query_prop.qps_switches )
                THEN
                    BEGIN
                    (* restore original access_info   *)
                    (* because we don't run next loop *)
                    (* with strat restore             *)
                    access_info := _m_strat_rec^;
                    access_info.srec_query_prop.qps_switches  :=
                          access_info.srec_query_prop.qps_switches +
                          [ qp_missing_value ];
&                   ifdef TRACE
                    t01name( ak_strat, 'orig access_info  ' );
                    a725output_access_info( ak_strat, 'original    ', access_info );
&                   endif
                    IF  ( g01vtrace.vtrStrategy_gg00 )
                    THEN
                        BEGIN
                        a727trace_access_info( acv.a_transinf.tri_trans,
                              'A726COMBINE_TERM 2', access_info );
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                _act_L2pL3t := succ( _act_L2pL3t );
                END;
            (*ENDWHILE*) 
            END
        ELSE
            BEGIN
            IF  (_m_strat_rec = NIL )
            THEN
                a07_b_put_error (acv, e_no_more_memory, 1);
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  ( _m_strat_rec <> NIL )
        THEN
            BEGIN
            IF  NOT ( qp_missing_value in access_info.srec_query_prop.qps_switches )
            THEN
                BEGIN
                access_info := _m_strat_rec^;
&               ifdef TRACE
                a725output_access_info( ak_strat, 'restored 2  ', access_info );
&               endif
                IF  ( g01vtrace.vtrStrategy_gg00 )
                THEN
                    BEGIN
                    a727trace_access_info( acv.a_transinf.tri_trans,
                          'A726COMBINE_TERM 3', access_info );
                    END;
                (*ENDIF*) 
                END
            ELSE
                BEGIN
                (* we don't need to restore access_info    *)
                (* 'root' strategy will be restored at end *)
&               ifdef trace
                t01name( ak_strat, 'avoid rsto. access' );
&               endif
                END;
            (*ENDIF*) 
            a10dispose( acv, _m_strat_rec );
            END;
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        (* actual level-1-term not useable *)
        (* break through recursion         *)
        strat_status := lss_use_L1_strat;
&       ifdef TRACE
        t01name( ak_strat, 'one_r: l1t unuseab' );
&       endif
        IF  ( g01vtrace.vtrStrategy_gg00 )
        THEN
            BEGIN
            g041c30_to_trace( acv.a_transinf.tri_trans,
                  'L1 term unusable / use L1 stra' );
        END;
    (*ENDIF*) 
    END;
    (*ENDIF*) 
    END;
(* process next level-2-predicate/level-3-term  *)
(*ENDIF*) 
;
&ifdef TRACE
t01name( ak_strat,'one_recursion end:' );
t01p2int4( ak_strat, 'act L1term  ', act_L1term, 'act L2pL3t  ', act_L2pL3t );
IF  strat_status = lss_several_strats
THEN
    t01name( ak_strat,'several strats   b' )
ELSE
    IF  strat_status = lss_use_L1_strat
    THEN
        t01name( ak_strat,'use L1 strat     b' )
    ELSE
        t01name( ak_strat,'key range poss   b' );
    (*ENDIF*) 
(*ENDIF*) 
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak726decide_strat_combine (
            VAR acv              : tak_all_command_glob;
            VAR sparr            : tak_syspointerarr;
            VAR access_info      : tak70_strategy_record;
            VAR gg_strategy      : tgg07_StrategyInfo;
            VAR used_strats      : tak70_all_strat;
            VAR order_fields     : tak00_ord_fields;
            VAR L1_terms         : tak70_term;
            VAR nextstratpos     : tsp00_Int4;
            act_L1term           : tsp00_Int2;
            act_L2pL3t           : tsp00_Int2;
            L1_pageIO            : tsp00_Int4;
            VAR strat_status     : tak70_l2l3_strat_status;
            VAR all_keys         : tak70_all_key_record;
            VAR eval_combination : boolean);
 
VAR
      _strat_compare : t_strat_compare;
      _used_stratpos : tsp00_Int2;
      _StratInfo_len : tsp00_Int2;
      _ix            : tsp00_Int2;
      _chosen_strat  : tak70_one_strat;
 
BEGIN
IF  ( g01vtrace.vtrStrategy_gg00 )
THEN
    BEGIN
    g041c30_to_trace( acv.a_transinf.tri_trans,
          '>>AK726DECIDE_STRAT_COMBINE>> ' );
    END;
(* assertion: *)
(* strat_status in [ lss_several_strats, lss_one_key_range ]*)
(*ENDIF*) 
IF  ( L1_terms.trm_L1terms[ act_L1term - 1 ].
    l1t_L2terms[ act_L2pL3t - 1 ].l2l3p_predcnt = 0 )
THEN
    BEGIN
    (* level-4-terms exists -->                             *)
    (* skip level-2-term because only possible access path  *)
    (* for this level-2-term is a scan over the relation    *)
    (* hence there will be only a table scan as access path *)
    (* for given SQL query                                  *)
    (* break through recursion                              *)
    strat_status := lss_use_L1_strat;
&   ifdef TRACE
    t01name( ak_strat, 'level-4-terms !!! ' );
&   endif
    IF  ( g01vtrace.vtrStrategy_gg00 )
    THEN
        BEGIN
        g041c30_to_trace( acv.a_transinf.tri_trans,
              'level-4-terms / use L1 strat  ' );
        END;
    (*ENDIF*) 
    END
ELSE
    BEGIN
    (* initialize strategy *)
&   ifdef TRACE
    t01int4( ak_strat, 'l2l3p_predcn', L1_terms.
          trm_L1terms[ act_L1term - 1 ].
          l1t_L2terms[ act_L2pL3t - 1 ].l2l3p_predcnt );
&   endif
    _ix := 1;
    (* get access information for either level-2-predicate             *)
    (* or level-2-term ( formed as level-3-pred AND level-3-pred ... ) *)
    WHILE ( _ix <= L1_terms.trm_L1terms[ act_L1term - 1 ].
          l1t_L2terms[ act_L2pL3t - 1 ].l2l3p_predcnt ) DO
        BEGIN
        IF  ( L1_terms.trm_L1terms[ act_L1term - 1 ].
            l1t_L2terms[ act_L2pL3t - 1 ].
            l2l3p_preds[ _ix - 1 ].pred_start > 0 )
        THEN
            BEGIN
            IF  ( L1_terms.trm_L1terms[ act_L1term - 1 ].
                l1t_L2terms[ act_L2pL3t - 1 ].
                l2l3p_preds[ _ix - 1 ].pred_key )
                AND
                ( NOT ( cs_keyscan in
                access_info.srec_config.cfg_switches ))
            THEN
                a71key_strat( acv, access_info,
                      L1_terms.trm_L1terms[ act_L1term - 1 ].
                      l1t_L2terms[ act_L2pL3t - 1 ].
                      l2l3p_preds[ _ix - 1 ].pred_start,
                      L1_terms.trm_L1terms[ act_L1term - 1 ].
                      l1t_L2terms[ act_L2pL3t - 1 ].
                      l2l3p_preds[ _ix - 1 ].pred_stop );
            (*ENDIF*) 
            IF  ( L1_terms.trm_L1terms[ act_L1term - 1 ].
                l1t_L2terms[ act_L2pL3t - 1 ].
                l2l3p_preds[ _ix - 1 ].pred_inv )
                AND
                ( NOT ( cs_indexscan in
                access_info.srec_config.cfg_switches ))
            THEN
                a71index_strat( acv, access_info,
                      L1_terms.trm_L1terms[ act_L1term - 1 ].
                      l1t_L2terms[ act_L2pL3t - 1 ].
                      l2l3p_preds[ _ix - 1 ].pred_start,
                      L1_terms.trm_L1terms[ act_L1term - 1 ].
                      l1t_L2terms[ act_L2pL3t - 1 ].
                      l2l3p_preds[ _ix - 1 ].pred_stop );
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        _ix := succ( _ix );
        END;
    (*ENDWHILE*) 
&   ifdef TRACE
    a725output_access_info( ak_strat, 'new access  ', access_info );
&   endif
    IF  ( g01vtrace.vtrStrategy_gg00 )
    THEN
        BEGIN
        a727trace_access_info( acv.a_transinf.tri_trans,
              'AK726DECIDE new   ', access_info );
        END;
    (*ENDIF*) 
    IF  NOT ( qp_missing_value in access_info.srec_query_prop.qps_switches )
    THEN
        BEGIN
        (* copy original access_info information behind *)
        (* actual access_info information               *)
        (* this shures the use of new information       *)
        (* i.e. combine old with new information        *)
        FOR _ix := 0 TO all_keys.akr_startcnt - 1 DO
            IF  ( access_info.srec_keyaccess.ka_startcnt <
                MAX_STRATEGY_KEYS_GG04 )
            THEN
                BEGIN
                access_info.srec_keyaccess.ka_startfields
                      [ access_info.srec_keyaccess.ka_startcnt ] :=
                      all_keys.akr_startkeys[ _ix ];
                access_info.srec_keyaccess.ka_startcnt :=
                      succ( access_info.srec_keyaccess.ka_startcnt );
                END;
            (*ENDIF*) 
        (*ENDFOR*) 
        ;
        (* save combined raw information *)
        all_keys.akr_startkeys := access_info.srec_keyaccess.
              ka_startfields;
        all_keys.akr_startcnt  := access_info.srec_keyaccess.
              ka_startcnt;
        (**)
        (* copy original access_info information behind *)
        (* actual access_info information               *)
        (* this shures the use of new information       *)
        (* i.e. combine old with new information        *)
        FOR _ix := 0 TO all_keys.akr_stopcnt - 1 DO
            IF  ( access_info.srec_keyaccess.ka_stopcnt <
                MAX_STRATEGY_KEYS_GG04 )
            THEN
                BEGIN
                access_info.srec_keyaccess.ka_stopfields
                      [ access_info.srec_keyaccess.ka_stopcnt ]
                      := all_keys.akr_stopkeys[ _ix ];
                access_info.srec_keyaccess.ka_stopcnt :=
                      succ( access_info.srec_keyaccess.ka_stopcnt );
                END;
            (*ENDIF*) 
        (*ENDFOR*) 
        ;
        (* save combined raw information *)
        all_keys.akr_stopkeys := access_info.srec_keyaccess.ka_stopfields;
        all_keys.akr_stopcnt  := access_info.srec_keyaccess.ka_stopcnt;
&       ifdef trace
        (* raw access info *)
        a725output_access_info( ak_strat, 'comb access1', access_info );
&       endif
        IF  ( g01vtrace.vtrStrategy_gg00 )
        THEN
            BEGIN
            a727trace_access_info( acv.a_transinf.tri_trans,
                  'AK726DECIDE combin', access_info );
            END;
        (*ENDIF*) 
        ;
        IF  ( strat_status = lss_several_strats )
        THEN
            a720strategy_decision( acv, sparr,
                  access_info, gg_strategy, _chosen_strat,
                  order_fields, _StratInfo_len, false )
        ELSE
            BEGIN
            (* strat_status = lss_one_key_range *)
            (* only widen key range *)
            access_info.srec_config.cfg_switches :=
                  access_info.srec_config.cfg_switches +
                  [ cs_keyaccess, cs_keyrange ];
            a720strategy_decision( acv, sparr,
                  access_info, gg_strategy, _chosen_strat,
                  order_fields, _StratInfo_len, false )
            END;
        (*ENDIF*) 
        IF  ( _chosen_strat.ostr_strategy = strat_key_equal ) OR
            ( qp_no_result_set in access_info.srec_query_prop.qps_switches )
        THEN
            eval_combination := true
        ELSE
            (* no more terms to combine *)
            eval_combination := ( act_L1term = L1_terms.trm_L1termcnt );
        (*ENDIF*) 
        ;
&       ifdef TRACE
        IF  eval_combination
        THEN
            t01name( ak_strat, 'combine completed ' );
&       endif
        (*ENDIF*) 
        IF  ( acv.a_returncode = 0 ) AND ( eval_combination )
        THEN
            BEGIN
            IF  ( strat_status <> lss_one_key_range ) AND
                ( _chosen_strat.ostr_strategy <> strat_no_result ) AND
                NOT ( cs_L2_strat_no_optim in access_info.srec_config.cfg_switches )
            THEN
                ak726test_nested_strat( acv, used_strats,
                      _chosen_strat, _strat_compare, _used_stratpos )
            ELSE
                _strat_compare := no_including;
            (*ENDIF*) 
            ;
            IF  ( _strat_compare = no_including ) AND
                ( _chosen_strat.ostr_strategy <> strat_no_result )
            THEN
                BEGIN
                (* all done, assess/evaluate new information *)
                ak726eval_combined_strat( acv, access_info, _chosen_strat,
                      used_strats, nextstratpos, L1_pageIO, strat_status );
                ;
                IF  ( strat_status = lss_several_strats )
                THEN
                    BEGIN
                    (* write new strategy *)
&                   ifdef TRACE
                    t01int4( ak_strat, 'strat count ', used_strats.ast_cntstrats );
&                   endif
                    ak726write_one_strat( acv,
                          used_strats.ast_strats[ used_strats.ast_cntstrats ],
                          _chosen_strat );
                    END;
                (*ENDIF*) 
                END
            ELSE
                BEGIN
                IF  ( _strat_compare = newstrat_includes_oldstrat )
                THEN
                    BEGIN
                    (* overwrite oldstrat with newstrat *)
                    ak726write_one_strat( acv,
                          used_strats.ast_strats[ _used_stratpos ],
                          _chosen_strat );
                    END
                ELSE
                    BEGIN
                    (* nothing to do *)
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        (* we can't decide it *)
        (* break through recursion *)
        strat_status := lss_use_L1_strat;
&       ifdef TRACE
        t01name( ak_strat, 'broken access     ' );
&       endif
        IF  ( g01vtrace.vtrStrategy_gg00 )
        THEN
            BEGIN
            g041c30_to_trace( acv.a_transinf.tri_trans,
                  'broken access / use L1 strat  ' );
        END;
    (*ENDIF*) 
    END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak726eval_combined_strat(
            VAR acv          : tak_all_command_glob;
            VAR access_info  : tak70_strategy_record;
            VAR chosen_strat : tak70_one_strat; (* IN *)
            VAR used_strats  : tak70_all_strat;
            VAR nextstratpos : tsp00_Int4;
            L1_pageIO        : tsp00_Int4;
            VAR strat_status : tak70_l2l3_strat_status);
 
VAR
      _page_sum  : tsp00_Int4;
 
BEGIN
IF  ( g01vtrace.vtrStrategy_gg00 )
THEN
    BEGIN
    g041c30_to_trace( acv.a_transinf.tri_trans,
          '>>AK726EVAL_COMBINED_STRAT>>  ' );
    END;
(*ENDIF*) 
IF  ( used_strats.ast_key_range_poss )
THEN
    BEGIN
    (* assess any key strategy *)
    IF  ( used_strats.ast_init_key_range )
    THEN
        BEGIN
        (* we remark actual widest key range *)
&       ifdef trace
        a725output_colposarr( ak_strat, 'key start   ',
              access_info.srec_keyaccess.ka_startfields );
        a725output_colposarr( ak_strat, 'key stop    ',
              access_info.srec_keyaccess.ka_stopfields );
        t01int4( ak_strat, 'ka_SUBQ_idx ',
              access_info.srec_keyaccess.ka_SUBQ_idx );
&       endif
&       ifdef TRACE
        t01name( ak_strat, 'init one key_range' );
&       endif
        used_strats.ast_key_range.skir_keystart :=
              access_info.srec_keyaccess.ka_startfields;
        used_strats.ast_key_range.skir_keystop  :=
              access_info.srec_keyaccess.ka_stopfields;
        used_strats.ast_init_key_range := false;
        END
    ELSE
        ak726widen_key_range( acv, access_info, used_strats );
    (*ENDIF*) 
    IF  ( used_strats.ast_key_range.skir_keystart[ 0 ] = 0 ) AND
        ( used_strats.ast_key_range.skir_keystop [ 0 ] = 0 ) AND
        NOT ( cs_L2_strategy in access_info.srec_config.cfg_switches )
    THEN
        BEGIN
        (* widest key range is whole table *)
&       ifdef TRACE
        t01name( ak_strat, 'missing key start!' );
        t01name( ak_strat, 'one krange imposs ' );
&       endif
        used_strats.ast_key_range_poss := false;
        IF  ( g01vtrace.vtrStrategy_gg00 )
        THEN
            BEGIN
            g041c30_to_trace( acv.a_transinf.tri_trans,
                  'enclosing range is whole table' );
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END
ELSE
    BEGIN
    IF  ( strat_status = lss_one_key_range )
    THEN
        BEGIN
        (* break through recursion *)
        strat_status := lss_use_L1_strat;
&       ifdef TRACE
        t01name( ak_strat, 'range_impossible 1' );
&       endif
        IF  ( g01vtrace.vtrStrategy_gg00 )
        THEN
            BEGIN
            g041c30_to_trace( acv.a_transinf.tri_trans,
                  'use L1 strat / range imposs 1 ' );
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
;
(* error handling *)
IF  ( used_strats.ast_cntstrats >= cak70_maxstrats ) AND
    ( strat_status = lss_several_strats )
THEN
    BEGIN
    IF  ( used_strats.ast_key_range_poss )
    THEN
        BEGIN
        strat_status := lss_one_key_range;
        IF  ( g01vtrace.vtrStrategy_gg00 )
        THEN
            BEGIN
            g041c30_to_trace( acv.a_transinf.tri_trans,
                  'max strats / try key range    ' );
            END;
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        (* break through recursion *)
        strat_status := lss_use_L1_strat;
&       ifdef TRACE
        t01name( ak_strat, 'range_inpossible 2' );
&       endif
        IF  ( g01vtrace.vtrStrategy_gg00 )
        THEN
            BEGIN
            g041c30_to_trace( acv.a_transinf.tri_trans,
                  'max strats / use L1 strat     ' );
        END;
    (*ENDIF*) 
    END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
;
IF  ( strat_status = lss_several_strats )
THEN
    BEGIN
    (* ================================== *)
    (* Add up the access costs for all    *)
    (* stratgies necessary so far. Abort  *)
    (* search if costs turn out to be     *)
    (* higher than strategy picked by     *)
    (* a71strat_search_level1             *)
    (* ================================== *)
    _page_sum := used_strats.ast_wholeIO_pages + chosen_strat.ostr_wholeIO_pages;
&   ifdef TRACE
    t01int4( ak_strat, 'addnl. pages', chosen_strat.ostr_wholeIO_pages );
    t01int4( ak_strat, 'page sum    ', _page_sum );
&   endif
    IF  ( _page_sum >= L1_pageIO ) AND
        ( NOT ( cs_L2_more_strategies in access_info.srec_config.cfg_switches ))
    THEN
        (* combination of strategies *)
        (* too expensive.            *)
        BEGIN
&       ifdef TRACE
        t01name( ak_strat, 'comb too expensive' );
        t01int4( ak_strat, '   cntstrats', used_strats.ast_cntstrats + 1 );
&       endif
        IF  ( used_strats.ast_key_range_poss )
        THEN
            BEGIN
            strat_status := lss_one_key_range;
&           ifdef trace
            t01sname( ak_strat, 'try key rng ' );
&           endif
            IF  ( g01vtrace.vtrStrategy_gg00 )
            THEN
                BEGIN
                g041c30_to_trace( acv.a_transinf.tri_trans,
                      'too expensive / try key range ' );
                END;
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            (* break through recursion *)
            strat_status := lss_use_L1_strat;
            IF  ( g01vtrace.vtrStrategy_gg00 )
            THEN
                BEGIN
                g041c30_to_trace( acv.a_transinf.tri_trans,
                      'too expensive / use L1 strat  ' );
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  ( strat_status = lss_several_strats )
THEN
    BEGIN
    used_strats.ast_wholeIO_pages := _page_sum;
    used_strats.ast_readIO_pages := used_strats.ast_readIO_pages +
          chosen_strat.ostr_readIO_pages;
    used_strats.ast_readIO_primpages := used_strats.ast_readIO_primpages +
          chosen_strat.ostr_readIO_primpages;
    IF  ( chosen_strat.ostr_readIO_rows >= 0 ) AND
        ( used_strats.ast_readIO_rows <> IS_UNDEFINED_GG07 )
    THEN
        BEGIN
        used_strats.ast_readIO_rows  := used_strats.ast_readIO_rows +
              chosen_strat.ostr_readIO_rows;
        END
    ELSE
        used_strats.ast_readIO_rows  := IS_UNDEFINED_GG07;
    (*ENDIF*) 
    IF  ( g01vtrace.vtrStrategy_gg00 )
    THEN
        BEGIN
        g041int4_to_trace( acv.a_transinf.tri_trans, 'whole pages       ',
              used_strats.ast_wholeIO_pages );
        g041int4_to_trace( acv.a_transinf.tri_trans, 'read  pages       ',
              used_strats.ast_readIO_pages );
        g041int4_to_trace( acv.a_transinf.tri_trans, 'read  primpages   ',
              used_strats.ast_readIO_primpages );
        IF  ( used_strats.ast_readIO_rows = IS_UNDEFINED_GG07 )
        THEN
            g041c30_to_trace( acv.a_transinf.tri_trans,  'read  rows    undef           ' )
        ELSE
            g041int4_to_trace( acv.a_transinf.tri_trans, 'read  rows        ',
                  used_strats.ast_readIO_rows );
        (*ENDIF*) 
        g041int4_to_trace( acv.a_transinf.tri_trans, 'min read pages    ',
              access_info.srec_readIO_pages_min );
        IF  ( access_info.srec_readIO_rows_min = IS_UNDEFINED_GG07 )
        THEN
            g041c30_to_trace( acv.a_transinf.tri_trans,  'min read rows  undef          ' )
        ELSE
            g041int4_to_trace( acv.a_transinf.tri_trans, 'min read rows     ',
                  access_info.srec_readIO_rows_min );
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    ;
    (* insert found strategy *)
    used_strats.ast_cntstrats := succ( used_strats.ast_cntstrats );
    (* position of strategy *)
    used_strats.
          ast_strats[ used_strats.ast_cntstrats ].osr_stratpos := nextstratpos;
    (* write strategy data *)
    used_strats.ast_strats[ used_strats.ast_cntstrats ].
          osr_strategy := chosen_strat.ostr_strategy;
    (* write strategy data length *)
    IF  ( used_strats.ast_strats[ used_strats.ast_cntstrats ].osr_strategy in
        a70glob_key_strats )
    THEN
        BEGIN
        used_strats.ast_strats[ used_strats.ast_cntstrats ].
              osr_stratlen := sizeof( tgg07_StrKeyInRange );
        END
    ELSE
        BEGIN
        IF  ( used_strats.ast_strats[ used_strats.ast_cntstrats ].osr_strategy
            in a70glob_inv_strats )
        THEN
            BEGIN
            used_strats.ast_strats[ used_strats.ast_cntstrats ].
                  osr_stratlen := sizeof( chosen_strat.ostr_inv_in_range );
            END
        ELSE
            a07ak_system_error( acv, 726, 1 );
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    ;
    (* write stratetgy value *)
    used_strats.ast_strats[ used_strats.ast_cntstrats ].osr_filler := false;
    ;
    (* calculate next strategy position *)
    nextstratpos :=
          used_strats.ast_strats[ used_strats.ast_cntstrats ].
          osr_stratpos +
          used_strats.ast_strats[ used_strats.ast_cntstrats ].
          osr_stratlen + cgg07_stratpos_offs; (* cgg07_stratpos_offs = stratenum, stratlen *)
&   ifdef TRACE
    t01int4( ak_strat, 'nextstratpos', nextstratpos );
&   endif
    (* error handling *)
    IF  ( nextstratpos > acv.a_mblock.mb_strat_size )
    THEN
        (* actual strategy don't fit in strategy storage *)
        BEGIN
        IF  ( used_strats.ast_key_range_poss )
        THEN
            BEGIN
            (* this result in one strategy *)
            strat_status := lss_one_key_range;
            IF  ( g01vtrace.vtrStrategy_gg00 )
            THEN
                BEGIN
                g041c30_to_trace( acv.a_transinf.tri_trans,
                      'error handling / try key range' );
                END;
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            (* break through recursion *)
            strat_status := lss_use_L1_strat;
            IF  ( g01vtrace.vtrStrategy_gg00 )
            THEN
                BEGIN
                g041c30_to_trace( acv.a_transinf.tri_trans,
                      'error handling / use L1 strat ' );
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak726widen_key_range(
            VAR acv          : tak_all_command_glob;
            VAR access_info  : tak70_strategy_record;
            VAR used_strats  : tak70_all_strat);
 
VAR
      _use_stopkey    : boolean;
      _lc_result      : tsp00_LcompResult;
      _old_rangestart : tgg00_Lkey; (* actual smallest start key *)
      _new_rangestart : tgg00_Lkey; (* actual start key          *)
      _old_rangestop  : tgg00_Lkey; (* actual highest stop key   *)
      _new_rangestop  : tgg00_Lkey; (* actual stop key           *)
 
BEGIN
&ifdef trace
a725output_colposarr( ak_strat, 'key start   ',
      used_strats.ast_key_range.skir_keystart );
a725output_colposarr( ak_strat, 'key stop    ',
      used_strats.ast_key_range.skir_keystop );
&endif
acv.a_mblock.mb_trns^.trError_gg00 := e_ok; (* PTS 1114933 *)
;
(* sorting of IN condition was done with *)
(* a71key_strat/a71index_strat           *)
_use_stopkey := true;
g04limitprimkeys( acv.a_mblock,
      used_strats.ast_key_range.skir_keystart,
      _old_rangestart,
      used_strats.ast_key_range.skir_keystop ,
      _old_rangestop,
      _use_stopkey, IS_UNDEFINED_GG07, -1 (* use IN as range *) );
&ifdef trace
t01key( ak_strat, 'old start   ', _old_rangestart );
t01key( ak_strat, 'old stop    ', _old_rangestop );
&endif
IF  ( acv.a_mblock.mb_trns^.trError_gg00 = e_move_error )
THEN
    acv.a_returncode :=
          a071_return_code( e_move_error, acv.a_sqlmode );
(*ENDIF*) 
;
&ifdef trace
a725output_colposarr( ak_strat, 'key start  n',
      access_info.srec_keyaccess.ka_startfields );
a725output_colposarr( ak_strat, 'key stop   n',
      access_info.srec_keyaccess.ka_stopfields );
&endif
;
(* sorting of IN condition was done with *)
(* a71key_strat/a71index_strat           *)
_use_stopkey := true;
g04limitprimkeys( acv.a_mblock,
      access_info.srec_keyaccess.ka_startfields,
      _new_rangestart,
      access_info.srec_keyaccess.ka_stopfields,
      _new_rangestop ,
      _use_stopkey, IS_UNDEFINED_GG07, -1 (* use IN as range *) );
&ifdef trace
t01key( ak_strat, 'new start   ', _new_rangestart );
t01key( ak_strat, 'new stop    ', _new_rangestop );
&endif
IF  ( acv.a_mblock.mb_trns^.trError_gg00 = e_move_error )
THEN
    acv.a_returncode :=
          a071_return_code( e_move_error, acv.a_sqlmode );
(*ENDIF*) 
s30cmp1( _old_rangestart.k, 1, _old_rangestart.len,
      _new_rangestart.k, 1, _new_rangestart.len, _lc_result );
&ifdef TRACE
t01comp_result( ak_strat, 'lc_result   ', _lc_result );
&endif
IF  ( _lc_result = l_greater )
THEN
    (* old_start > new_start *)
    (* chose widden key start *)
    used_strats.ast_key_range.skir_keystart :=
          access_info.srec_keyaccess.ka_startfields;
(*ENDIF*) 
s30cmp1( _old_rangestop.k, 1, _old_rangestop.len,
      _new_rangestop.k, 1, _new_rangestop.len, _lc_result );
&ifdef TRACE
t01comp_result( ak_strat, 'lc_result   ', _lc_result );
&endif
IF  ( _old_rangestop.len > 0 )
THEN
    BEGIN
    IF  ( _lc_result = l_less )
        OR
        ( _new_rangestop.len = 0 )
    THEN
        (* old_stop < new_stop *)
        used_strats.ast_key_range.skir_keystop  :=
              access_info.srec_keyaccess.ka_stopfields;
    (*ENDIF*) 
    END;
(*ENDIF*) 
;
&ifdef TRACE
a725output_colposarr( ak_strat, 'startpos    ',
      used_strats.ast_key_range.skir_keystart );
a725output_colposarr( ak_strat, 'stoppos     ',
      used_strats.ast_key_range.skir_keystop );
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak726test_nested_strat (
            VAR acv          : tak_all_command_glob;
            VAR used_strats  : tak70_all_strat;
            VAR new_strat    : tak70_one_strat;
            VAR comp_result  : t_strat_compare;
            VAR strat_pos    : tsp00_Int2);
 
VAR
      _lc_result1     : tsp00_LcompResult;
      _strat_data     : tak70_one_strat;
 
BEGIN
comp_result := no_including;
strat_pos   := 1;
(* look for strategy, which contains new strategy *)
(* loop over existing strategies                  *)
WHILE ( acv.a_returncode = 0 )
      AND
      ( strat_pos <= used_strats.ast_cntstrats )
      AND
      ( comp_result = no_including ) DO
    BEGIN
    IF  ( new_strat.ostr_strategy =
        used_strats.ast_strats[ strat_pos ].osr_strategy )
    THEN
        BEGIN
&       ifdef trace
        t01sname( ak_strat, 'same strat f' );
&       endif
        (* same strategy kind found *)
        (* get strategy to compare to new_strat *)
        SAPDB_PascalMove ('VAK726',   1,    
              acv.a_mblock.mb_strat_size, sizeof( _strat_data.ostr_raw ),
              @acv.a_mblock.mb_strat^,
              used_strats.ast_strats[ strat_pos ].osr_stratpos + cgg07_stratpos_offs,
              @_strat_data.ostr_raw, 1,
              used_strats.ast_strats[ strat_pos ].osr_stratlen,
              acv.a_returncode);
        ;
        IF  ( acv.a_returncode = 0 )
        THEN
            BEGIN
            IF  ( used_strats.ast_strats[ strat_pos ].osr_strategy in
                a70glob_key_strats )
            THEN
                (* key strategy *)
                BEGIN
                IF  ( used_strats.ast_strats[ strat_pos ].osr_strategy in
                    [ strat_key_equal, strat_key_range ] )
                THEN
                    BEGIN
                    ak726key_range_comp( acv,
                          new_strat, _strat_data, comp_result );
                    END
                ELSE
                    BEGIN
                    s30cmp( new_strat.ostr_inv_in_range, 1,
                          used_strats.ast_strats[ strat_pos ].osr_stratlen,
                          _strat_data.ostr_inv_in_range, 1,
                          used_strats.ast_strats[ strat_pos ].osr_stratlen,
                          _lc_result1 );
                    IF  ( _lc_result1 = l_equal )
                    THEN
                        BEGIN
                        comp_result := equal_strats;
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END
            ELSE
                BEGIN
                IF  ( used_strats.ast_strats[ strat_pos ].osr_strategy in
                    a70glob_inv_strats )
                THEN
                    BEGIN
                    IF  NOT ( used_strats.ast_strats[ strat_pos ].osr_strategy in
                        [ strat_inv_in, strat_inv_subq ] )
                    THEN
                        (* index strategy *)
                        BEGIN
&                       ifdef trace
                        t01sname( ak_strat, 'comp sdata  ' );
&                       endif
                        s30cmp2( new_strat.ostr_raw,
                              MAX_STRATEGY_KEYS_GG04 * 2 * 4 + 1,
                              STRINVINRANGE_START_MXGG07,
                              _strat_data.ostr_raw,
                              MAX_STRATEGY_KEYS_GG04 * 2 * 4 + 1,
                              STRINVINRANGE_START_MXGG07,
                              _lc_result1 );
                        ;
                        IF  ( _lc_result1 = l_equal )
                        THEN
                            BEGIN
                            ak726inv_range_comp( acv, new_strat, _strat_data,
                                  comp_result );
                            (* h.b. PTS 1001813 *)
                            END;
                        (*ENDIF*) 
                        END
                    ELSE
                        BEGIN
                        s30cmp( new_strat.ostr_inv_in_range, 1,
                              used_strats.ast_strats[ strat_pos ].osr_stratlen,
                              _strat_data.ostr_inv_in_range, 1,
                              used_strats.ast_strats[ strat_pos ].osr_stratlen,
                              _lc_result1 );
                        ;
                        IF  ( _lc_result1 = l_equal )
                        THEN
                            BEGIN
                            comp_result := equal_strats;
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    ;
    IF  ( comp_result = no_including )
    THEN
        strat_pos := succ( strat_pos );
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak726key_range_comp (
            VAR acv         : tak_all_command_glob;
            VAR new_strat   : tak70_one_strat;
            VAR old_strat   : tak70_one_strat;
            VAR comp_result : t_strat_compare);
 
VAR
      _use_stopkey    : boolean;
      _compres_start  : tsp00_LcompResult;
      _compres_stop   : tsp00_LcompResult;
      _old_rangestart : tgg00_Lkey;
      _old_rangestop  : tgg00_Lkey;
      _new_rangestart : tgg00_Lkey;
      _new_rangestop  : tgg00_Lkey;
 
BEGIN
comp_result   := no_including;
_use_stopkey  := false;
g04limitprimkeys( acv.a_mblock,
      old_strat.ostr_key_in_range.skir_keystart, _old_rangestart,
      old_strat.ostr_key_in_range.skir_keystop, _old_rangestop,
      _use_stopkey, IS_UNDEFINED_GG07, -1 (* use IN as range *) );
;
_use_stopkey  := false;
g04limitprimkeys( acv.a_mblock,
      new_strat.ostr_key_in_range.skir_keystart, _new_rangestart,
      new_strat.ostr_key_in_range.skir_keystop, _new_rangestop,
      _use_stopkey, IS_UNDEFINED_GG07, -1 (* use IN as range *) );
;
IF  ( acv.a_mblock.mb_trns^.trError_gg00 <> e_ok )
THEN
    a07_b_put_error( acv, acv.a_mblock.mb_trns^.trError_gg00, 1 )
ELSE
    BEGIN
    s30cmp1( _new_rangestart.k, 1, _new_rangestart.len,
          _old_rangestart.k, 1, _old_rangestart.len, _compres_start );
    s30cmp1( _new_rangestop.k, 1, _new_rangestop.len,
          _old_rangestop.k, 1, _old_rangestop.len,  _compres_stop );
&   ifdef TRACE
    t01sname( ak_strat, 'startkey    ' );
    t01comp_result( ak_strat, 'new op old  ', _compres_start );
    t01sname( ak_strat, 'stopkey     ' );
    t01comp_result( ak_strat, 'new op old  ', _compres_stop );
&   endif
    IF  (( _compres_start = l_greater ) OR ( _compres_start = l_equal ))
        AND
        (( _compres_stop = l_less )     OR ( _compres_stop = l_equal ))
    THEN
        BEGIN
        (* new_start >= old_start *)
        (* and                    *)
        (* new_stop  <= old_stop  *)
        comp_result := oldstrat_includes_newstrat;
        END
    ELSE
        BEGIN
        IF  (( _compres_start = l_equal ) OR ( _compres_start = l_less ))
            AND
            (( _compres_stop = l_equal )  OR ( _compres_stop = l_greater ))
        THEN
            BEGIN
            (* new_start <= old_start *)
            (* and                    *)
            (* new_stop  >= old_stop  *)
            comp_result := newstrat_includes_oldstrat;
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _compres_start = l_equal )
        AND
        ( _compres_stop  = l_equal )
    THEN
        BEGIN
        (* new_start = old_start *)
        (* and                    *)
        (* new_stop  = old_stop  *)
        comp_result := equal_strats;
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
&ifdef trace
CASE comp_result OF
    no_including :
        t01name( ak_strat, 'no including      ' );
    equal_strats :
        t01name( ak_strat, 'equal strategies  ' );
    oldstrat_includes_newstrat :
        t01name( ak_strat, 'old incl new strat' );
    newstrat_includes_oldstrat :
        t01name( ak_strat, 'new incl old strat' );
    OTHERWISE
        t01sname( ak_strat, 'unknown     ' );
    END;
(*ENDCASE*) 
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak726inv_range_comp (
            VAR acv            : tak_all_command_glob;
            VAR new_strat      : tak70_one_strat;
            VAR old_strat      : tak70_one_strat;
            VAR compinv_result : t_strat_compare);
 
VAR
      _compkey_result    : t_strat_compare;
      _compres_start     : tsp00_LcompResult;
      _compres_stop      : tsp00_LcompResult;
      _old_invrangestart : tgg00_Lkey;
      _old_invrangestop  : tgg00_Lkey;
      _new_invrangestart : tgg00_Lkey;
      _new_invrangestop  : tgg00_Lkey;
 
BEGIN
compinv_result := no_including;
g04limitinvkeys( acv.a_mblock,
      old_strat.ostr_inv_in_range,
      _old_invrangestart, _old_invrangestop, 
      IS_UNDEFINED_GG07, -1 (* use an IN as range *) );
g04limitinvkeys( acv.a_mblock,
      new_strat.ostr_inv_in_range,
      _new_invrangestart, _new_invrangestop, 
      IS_UNDEFINED_GG07, -1 (* use an IN as range *) );
;
IF  ( acv.a_mblock.mb_trns^.trError_gg00 <> e_ok )
THEN
    a07_b_put_error( acv, acv.a_mblock.mb_trns^.trError_gg00, 1 )
ELSE
    BEGIN
    s30cmp1( _new_invrangestart.k, 1, _new_invrangestart.len,
          _old_invrangestart.k, 1, _old_invrangestart.len, _compres_start );
    s30cmp1( _new_invrangestop.k,  1, _new_invrangestop.len,
          _old_invrangestop.k, 1, _old_invrangestop.len,  _compres_stop );
&   ifdef TRACE
    t01sname( ak_strat, 'startinv    ' );
    t01comp_result( ak_strat, 'new op old  ', _compres_start );
    t01sname( ak_strat, 'stopinv     ' );
    t01comp_result( ak_strat, 'new op old  ', _compres_stop );
&   endif
    IF  (( _compres_start = l_greater ) OR ( _compres_start = l_equal ))
        AND
        (( _compres_stop = l_less )     OR ( _compres_stop = l_equal ))
    THEN
        BEGIN
        (* new_start >= old_start *)
        (* and                    *)
        (* new_stop  <= old_stop  *)
        compinv_result := oldstrat_includes_newstrat;
        END
    ELSE
        BEGIN
        IF  (( _compres_start = l_equal ) OR ( _compres_start = l_less ))
            AND
            (( _compres_stop = l_equal )  OR ( _compres_stop = l_greater ))
        THEN
            BEGIN
            (* new_start <= old_start *)
            (* and                    *)
            (* new_stop  >= old_stop  *)
            compinv_result := newstrat_includes_oldstrat;
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _compres_start = l_equal )
        AND
        ( _compres_stop  = l_equal )
    THEN
        BEGIN
        (* new_start = old_start *)
        (* and                    *)
        (* new_stop  = old_stop  *)
        compinv_result := equal_strats;
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  ( compinv_result <> no_including )
THEN
    BEGIN
    ak726key_range_comp( acv, new_strat, old_strat, _compkey_result );
    IF  (( compinv_result in [ equal_strats, newstrat_includes_oldstrat ] ) AND
        NOT ( _compkey_result in [ equal_strats, newstrat_includes_oldstrat ] ))
        OR
        (( compinv_result in [ equal_strats, oldstrat_includes_newstrat ] ) AND
        NOT ( _compkey_result in [ equal_strats, oldstrat_includes_newstrat ] ))
    THEN
        BEGIN
        compinv_result := no_including;
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak726write_one_strat(
            VAR acv          : tak_all_command_glob;
            VAR strat_ref    : tak70_one_strat_ref;
            VAR chosen_strat : tak70_one_strat);
 
BEGIN
(* write strategy enum *)
acv.a_mblock.mb_strat^[ strat_ref.osr_stratpos ]   :=
      chr( ord( strat_ref.osr_strategy ) );
acv.a_mblock.mb_strat^[ strat_ref.osr_stratpos + 1 ]   := '0';
acv.a_mblock.mb_strat^[ strat_ref.osr_stratpos + 2 ]   := '0';
acv.a_mblock.mb_strat^[ strat_ref.osr_stratpos + 3 ]   := '0';
(* write strategy length *)
s20int4_to_buf( strat_ref.osr_stratlen, acv.a_mblock.mb_strat^,
      strat_ref.osr_stratpos + 4 );
(* write strategy info to strategy storage *)
SAPDB_PascalMove ('VAK726',   2,    
      sizeof( chosen_strat.ostr_raw ), acv.a_mblock.mb_strat_size,
      @chosen_strat.ostr_raw, 1,
      @acv.a_mblock.mb_strat^,
      strat_ref.osr_stratpos + cgg07_stratpos_offs,
      strat_ref.osr_stratlen,
      acv.a_returncode);
&ifdef TRACE
t01strat_enum( ak_strat, 'use strategy', strat_ref.osr_strategy );
t01int4( ak_strat, 'strat pos   ', strat_ref.osr_stratpos );
t01int4( ak_strat, 'strat length', strat_ref.osr_stratlen );
a725output_one_strat( ak_strat, chosen_strat );
&endif
END;
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
.PA 
