.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-10
*****************************************************
modname : VKB75
changed : 2000-11-10
module  : KB_Fetch
 
Author  : ElkeZ
Created : 1985-10-16
*****************************************************
 
Purpose : This module is used for fetches for
          result sets which are not physically build
 
 
 
Define  :
 
        PROCEDURE
              k75_fetch (VAR m : tgg00_MessBlock);
 
        PROCEDURE
              k75pre_fetch (
                    VAR t        : tgg00_TransContext;
                    VAR tree_id  : tgg00_FileId;
                    VAR key      : tgg00_Lkey);
 
.CM *-END-* define --------------------------------------
***********************************************************
 
Use     :
 
&       ifdef TRACE
        FROM
              Test_Procedures : VTA01;
 
        PROCEDURE
              t01name (
                    debug : tgg00_Debug;
                    nam   : tsp00_Name);
 
        PROCEDURE
              t01key (
                    debug   : tgg00_Debug;
                    nam     : tsp00_Sname;
                    VAR k   : tgg00_Lkey);
 
        PROCEDURE
              t01basis_error (
                    debug : tgg00_Debug;
                    nam   : tsp00_Sname;
                    b_err : tgg00_BasisError);
 
        PROCEDURE
              t01int4 (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    int      : tsp00_Int4);
 
        PROCEDURE
              t01fetch_desc(
                    debug       : tgg00_Debug;
                    nam         : tsp00_Sname;
                    VAR mf_desc : tgg00_FetchDesc);
&       endif
 
      ------------------------------ 
 
        FROM
              Scanner : VAK01;
 
        VAR
              a01diag_monitor_on : boolean;
              a01diag_analyze_on : boolean;
 
      ------------------------------ 
 
        FROM
              Single_Select : VKB720;
 
        PROCEDURE
              k720monitor (
                    VAR trans         : tgg00_TransContext;
                    VAR sel           : tgg00_SelectFieldsParam;
                    start_sec         : tsp00_Int4;
                    start_microsec    : tsp00_Int4;
                    start_phys_ios    : tsp00_Int4;
                    start_suspends    : tsp00_Int4;
                    start_waits       : tsp00_Int4;
                    put_strat         : boolean;
                    arr_index         : tgg00_RefInfoIndex;
                    strat_cnt         : boolean);
 
        PROCEDURE
              k720_maxresult_get (
                    VAR data           : tsp00_MoveObj;
                    strat_maxcnt       : tsp00_Int2;
                    VAR maxresult      : tsp00_Int4;
                    VAR b_err          : tgg00_BasisError);
 
      ------------------------------ 
 
        FROM
              KB_sender_receiver : vkb90;
 
        PROCEDURE
              k90send (
                    VAR mblock       : tgg00_MessBlock;
                    VAR remote_trans : tgg00_TransChild);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_1   : VBD01;
 
        VAR
              b01fullkey    : tsp00_Key;
              b01zerokey    : tsp00_Key;
 
        PROCEDURE
              b01vstate_fileversion (
                    VAR t       : tgg00_TransContext;
                    VAR file_id : tgg00_FileId);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_2   : VBD02;
 
        PROCEDURE
              b02kb_select_rec (
                    VAR t            : tgg00_TransContext;
                    VAR file_id      : tgg00_FileId;
                    VAR RecKey       : tsp00_Key;
                    VAR RecKeyLen    : tsp00_Int2;
                    VAR StopKey      : tsp00_Key;
                    StopKeyLen       : tsp00_Int4;
                    recbuf_size      : tsp00_Int4;
                    recbuf_ptr       : tsp00_MoveObjPtr;
                    ignore_vwait     : boolean;
                    VAR sel          : tgg00_SelectFieldsParam;
                    VAR stack_desc   : tgg00_StackDesc;
                    VAR unqualified  : boolean;
                    VAR granted_lock : tgg00_LockReqMode);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_3 : VBD03;
 
        PROCEDURE
              b03select_invrec (
                    VAR t            : tgg00_TransContext;
                    VAR ftrees       : tgg00_TwoFileIds;
                    VAR keypair      : tgg00_TwoKeys;
                    VAR stop_keypair : tgg00_TwoKeys;
                    VAR startkey     : tgg00_Lkey;
                    VAR invrange_set : tgg00_BdInvSet;
                    recbuf_size      : tsp00_Int4;
                    recbuf_ptr       : tsp00_MoveObjPtr;
                    VAR sel          : tgg00_SelectFieldsParam;
                    VAR stack_desc   : tgg00_StackDesc;
                    VAR granted_lock : tgg00_LockReqMode;
                    count_usage      : boolean);
 
      ------------------------------ 
 
        FROM
              ref_statistic : VBD73;
 
        VAR
              b73spage_ref_statistic : boolean;
 
      ------------------------------ 
 
        FROM
              RTE_kernel : VEN101;
 
        PROCEDURE
              vclock (
                    VAR sec      : tsp00_Int4;
                    VAR microsec : tsp00_Int4);
 
        PROCEDURE
              vmonitor (
                    pid          : tsp00_TaskId;
                    VAR phys_ios : tsp00_Int4;
                    VAR suspends : tsp00_Int4;
                    VAR waits    : tsp00_Int4);
&       ifdef trace
 
        PROCEDURE
              vabort (write_core : boolean);
&       endif
 
      ------------------------------ 
 
        FROM
              Configuration_Parameter : VGG01;
 
        PROCEDURE
              g01mblock_init (
                    VAR source_trans : tgg00_TransContext;
                    mess_type  : tgg00_MessType;
                    mess2_type : tgg00_MessType2;
                    VAR mblock : tgg00_MessBlock);
 
      ------------------------------ 
 
        FROM
              Select_Help_Procedures : VGG04;
 
        PROCEDURE
              g04init_select_fields (
                    VAR sel       : tgg00_SelectFieldsParam;
                    data_addr     : tsp00_MoveObjPtr;
                    data_size     : tsp00_Int4;
                    valarr_addr   : tgg00_ValueListPtr;
                    validx_max    : tsp00_Int4;
                    work_st_addr  : tgg00_StackListPtr;
                    work_st_max   : tsp00_Int2;
                    work_buf_addr : tsp00_MoveObjPtr;
                    work_buf_size : tsp00_Int4;
                    curr_sqlmode  : tsp00_SqlMode);
 
      ------------------------------ 
 
        FROM
              Kernel_move_and_fill : VGG101;
 
        PROCEDURE
              SAPDB_PascalFill  (
                    mod_id         : tsp00_C6;
                    mod_intern_num : tsp00_Int4;
                    source_upb     : tsp00_Int4;
                    source         : tsp00_MoveObjPtr;
                    source_pos     : tsp00_Int4;
                    length         : tsp00_Int4;
                    fill_char      : char;
                    VAR e          : tgg00_BasisError);
 
        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);
 
        PROCEDURE
              SAPDB_PascalOverlappingMove  (
                    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);
 
        PROCEDURE
              g10mv (
                    mod_id      : tsp00_C6;            
                    mod_num     : tsp00_Int4;
                    source_upb  : tsp00_Int4;          
                    dest_upb    : tsp00_Int4;
                    source      : tsp00_MoveObjPtr;       
                    src_pos     : tsp00_Int4;
                    destin      : tsp00_MoveObjPtr;       
                    dest_pos    : tsp00_Int4;
                    length      : tsp00_Int4;
                    VAR e       : tgg00_BasisError);
 
.CM *-END-* use -----------------------------------------
***********************************************************
 
Synonym :
 
.CM *-END-* synonym -------------------------------------
***********************************************************
 
Description:
 
K75_FETCH
 
The type vax_optimizer_help was introduced solely to outwit the VAX
compiler. If one were to define help_buf and rec_buf individually as
variables, although both are used merely as parameters of s30gad
within the procedure, the compiler would assume that the buffers were
not needed and would assign both to the same stack address. However,
since both are needed (in VKB71), one has to trick the compiler.
.br;All the information concerning start- and stopkeys, record
lengths, etc. is contained in the following structure that is filed in
part2 of the mess buffer. In contrast to common practice, the data
part for the qualifications is behind the stack entries in part1.
 
           m_use_inv        : boolean;
           m_use_stop       : boolean;
           m_single         : boolean;
           m_use_recs       : boolean;
           m_keylen         : int2;
           m_cnt            : int2;
           m_leng           : int2;
           m_fns1           : tree_id;  (*pos 11*)
           m_fns2           : tree_id;  (*pos 43*)
           m_startkeys      : two_keys; (*pos 75, 333*)
           m_stopkeys       : two_keys; (*pos 591, 849*)
           m_firstkeys      : two_keys; (*pos 1107, 1365*)
           m_start          : lkey;     (*pos 1623*)
 
The meanings of the elements are as follows :
 
-  m_use_inv : search via an inversion
 
-  m_use_stop : stopkeys should be considered
 
-  m_single : only one result record is to be sought; i.e. with key
 
-  m_use_recs : results have to be passed to AK and are not used for
jumping to the desired position (POS [  ])
 
-  m_keylen : length of the key of the result record
 
-  m_cnt : number of desired results
 
-  m_leng : length of a result
 
-  m_fns1 : Name of the primary file
 
-  m_fns2 : Name of the secondary file
 
-  m_startkeys : Secondary key value and primary key value at which
the search is to start
 
-  m_stopkeys : Secondary key value and primary key value at which
the search is to end
 
-  m_firstkeys : Secondary key value and primary key value of the
first result found (output parameter)
 
-  m_start : Primary key value at which the search is to start in the
next inversion list
 
Loopmtype receives the information indicating the direction
in which the search will proceed as of the second result record.
SEL, a record passed to BD and VKB71 by KB, is initialized :
starting address of the stack entries of the qualification and the
data part (together in a single buffer) and two auxiliary buffers for
intermediate results (addresses in a record because it would not be
desirable for all of these buffers to travel through half the BD layer
as single parameters).
The command (fetch) and the search direction are given. ISTOP contains
the information indicating whether start- and/or stopkeys are to be
obeyed.
The desired number of results (m_cnt) are sought in a loop;
B03SELECT_INVREC is used for a search via an inversion,
B02SELECT_RECORD is used for a search without inversion.
If a requested lock is not immediately available, K53WAIT is
used to implement a wait. K53WAIT may return KB-TIMEOUT if the lock
remains unavailable despite the wait.
Once the lock is obtained, the same record (mm_direct) has to
be searched for again, so that the qualification can be checked. This
is necessary because the reason for the lock of the other process
may have been an
update. Direct searching is possible because at this juncture, the key
values of the record to be searched are already contained in the
parameters passed on as variables. Hence, it is no longer necessary to
conduct the search with the aid of an inversion.
If a record that fulfills the conditions is found, it is
transferred to part1, if the transfer is desired (m_use_recs). The
transfer is possible because the stack entries and the data part were
held in an auxiliary buffer and thus the results do not destroy the
stack entries used.
The number of results and the total length of all the results are
incremented and m_firstkeys is occupied when the first result is
available.
Any insignificant errors that arise in the repeat search after
K53WAIT are forgotten.
The direction of search is again correctly assigned (it may have
been changed in the repeat search after K53WAIT and in any case it
would have to be changed in response to FIRST/LAST following the first
result).
The loop, the search for all desired or discoverable results, may
be followed by the destruction of warning 14 that is set by BD every
time there is a change of inversion list, but that is not passed on to
the user except in the case of Ordered Selects via inversions.
Different errors are summarized in one to facilitate queries (also
in AK).
If the desired number of results have been found, (e_ok) or even
if fewer have been found (0 is possible with MFETCH if the records are
not merely to be skipped) the procedure is deemed to have run
correctly and the mess buffer is filled up accordingly. If this is not
so, the error is returned to AK.
 
.CM *-END-* description ---------------------------------
***********************************************************
.CM -lll-
Code    :
 
 
CONST
      c_usage_count      = true (* b03select_invrec *); (* h.b. PTS 1104210 *)
 
 
(*------------------------------*) 
 
PROCEDURE
      k75_fetch (VAR m : tgg00_MessBlock);
 
CONST
      c_ignore_vwait  = true;
      c_not_put_strat = false;
      c_not_strat_cnt = false;
 
VAR
      _istop          : tgg00_BdInvSet;
      _is_not_ok      : boolean;
      _fill_char      : char;
      _loopmtype      : tgg00_MessType2; (* loop only with distinct optim *)
      _work_mtype     : tgg00_MessType2; (* loop only with distinct optim *)
      _dummy_mode     : tgg00_LockReqMode;
      _strat_str_pos  : integer;
      _tmp_cnt        : tsp00_Int4;
      _mfetch_cnt     : tsp00_Int4;
      _start_sec      : tsp00_Int4;
      _start_microsec : tsp00_Int4;
      _start_phys_ios : tsp00_Int4;
      _start_suspends : tsp00_Int4;
      _start_waits    : tsp00_Int4;
      _ori_data_size  : tsp00_Int4;
      _data_ptr       : tsp00_MoveObjPtr;
      _strat_string   : tsp00_C40;
      _m_ftr_help     : tgg00_TwoFileIds;
      _aux_stack_desc : tgg00_StackDesc;
      _searchkeys     : tgg00_TwoKeys;
      _tmpkeys        : tgg00_TwoKeys;
      _sel            : tgg00_SelectFieldsParam;
      _fill_key       : tsp00_Key;
      _rowno          : tsp00_Int4;
 
BEGIN
&ifdef trace
t01fetch_desc(kb, 'fetch desc 1', m.mb_qual^.mf_desc);
&endif
WITH m.mb_qual^.mf_desc DO
    BEGIN
    m_firstkeys.reckey.len  := 0;
    m_firstkeys.listkey.len := 0;
    m.mb_trns^.trRteCommPtr_gg00^.file_root       := NIL_PAGE_NO_GG00;
    m.mb_trns^.trRteCommPtr_gg00^.file_record_cnt := m_searched_pages;
    (* PTS 1001469 E.Z. *)
    IF  ( b73spage_ref_statistic OR a01diag_monitor_on OR a01diag_analyze_on )
    THEN
        BEGIN
        vclock (_start_sec, _start_microsec);
        vmonitor (m.mb_trns^.trTaskId_gg00, _start_phys_ios, _start_suspends,
              _start_waits);
        END
    (* PTS 1001518 E.Z. *)
    ELSE
        _start_sec := 0;
    (*ENDIF*) 
    _work_mtype := m.mb_type2;
    IF  ( m.mb_type2 = mm_first )
    THEN
        (* fetch first with mm_first then with mm_next *)
        _loopmtype := mm_next
    ELSE
        IF  ( m.mb_type2 = mm_direct )
        THEN
            BEGIN
            (* fetch first with mm_first then with mm_next *)
            _loopmtype := mm_next;
            _work_mtype:= mm_first;
            END
        ELSE
            IF  ( m.mb_type2 = mm_last )
            THEN
                (* fetch first with mm_last then with mm_prev *)
                _loopmtype := mm_prev
            ELSE
                IF  ( m.mb_type2 = mm_last_rowno )
                THEN
                    BEGIN
                    _loopmtype  := mm_next;
                    _work_mtype := mm_next;
                    END
                ELSE
                    _loopmtype := m.mb_type2;
                (*ENDIF*) 
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    IF  ( m_startkeys.reckey.len = 0 ) AND ( _work_mtype =  mm_next )
    THEN
        _work_mtype := mm_first;
    (*ENDIF*) 
    _aux_stack_desc          := m.mb_qual^.mstack_desc;
    _aux_stack_desc.mst_addr := m.mb_st;
    _ori_data_size := m.mb_data_size;
    IF  ( m_data = NIL )
    THEN (* remote call, qualification data is stored in m.mb_data *)
        IF  ( m.mb_data_size - m.mb_data_len < m_leng )
        THEN
            m.mb_trns^.trError_gg00 := e_too_many_mb_data
        ELSE
            BEGIN
            SAPDB_PascalOverlappingMove ('VKB75 ',   1,
                  m.mb_data_size, m.mb_data_size,
                  @m.mb_data^.mbp_buf, 1,
                  @m.mb_data^.mbp_buf, m.mb_data_size - m.mb_data_len + 1,
                  m.mb_data_len, m.mb_trns^.trError_gg00);
            _data_ptr := @m.mb_data^.mbp_buf [m.mb_data_size - m.mb_data_len + 1 ];
            m.mb_data_size  := m.mb_data_size - m.mb_data_len;
            END
        (*ENDIF*) 
    ELSE (* local call, qualification data stored in m_data^ *)
        _data_ptr := @m_data^;
    (*ENDIF*) 
    g04init_select_fields( _sel, _data_ptr, m.mb_data_size,
          m.mb_valuearr, m.mb_validx_max,
          m.mb_work_st, m.mb_work_st_max,
          m.mb_workbuf, m.mb_workbuf_size, m.mb_qual^.msqlmode );
    _sel.sfp_acv_addr      := m.mb_trns^.trAcvPtr_gg00;   (* PTS 1121403 E.Z. *)
    _sel.sfp_output_offset := m.mb_st^[ m.mb_qual^.mqual_pos ].elen_var - 1;
    _sel.sfp_bd_mess_type   := m_fetch;
    _sel.sfp_bd_mess2_type  := _work_mtype;
    _sel.sfp_result_wanted  := true;
    _sel.sfp_bd_inv_only    := m_qual_kind;
    _sel.sfp_bd_use_stopkey := m_use_stop;
    _sel.sfp_resrec_maxlen  := m_leng;
    (* PTS 1000801 E.Z. *)
    _sel.sfp_act_cntresult  := m_rescnt + 1;
    (* PTS 1112079 E.Z. *)
    _sel.sfp_check_for_result := false;
    _m_ftr_help.file_id     := m_fns1;
    (* prevent from checking count of treeleafnodes *)
    (* when fetching a virtual result set  *)
    _m_ftr_help.file_id.fileLeafNodes_gg00 := cgg_nil_leafnodes;
    (* m_startkeys.reckey -> _searchkeys.reckey *)
    _searchkeys.reckey.len := m_startkeys.reckey.len;
    g10mv ('VKB75 ',   2,
          sizeof( m_startkeys.reckey.k ), sizeof( _searchkeys.reckey.k ),
          @m_startkeys.reckey.k, 1,
          @_searchkeys.reckey.k, 1, _searchkeys.reckey.len,
          m.mb_trns^.trError_gg00);
    IF  ( m_use_inv OR ( _sel.sfp_bd_inv_only = inv_only ))
    THEN
        BEGIN
        (* m_startkeys.listkey -> _searchkeys.listkey *)
        _searchkeys.listkey.len := m_startkeys.listkey.len;
        g10mv ('VKB75 ',   3,
              sizeof( m_startkeys.listkey.k ),
              sizeof( _searchkeys.listkey.k ),
              @m_startkeys.listkey.k, 1,
              @_searchkeys.listkey.k, 1, _searchkeys.listkey.len,
              m.mb_trns^.trError_gg00);
        _istop := [  ];
        IF  ( _sel.sfp_bd_mess2_type in [ mm_first, mm_next ] )
        THEN
            BEGIN
            _fill_key  := b01fullkey;
            _fill_char := chr( 255 );
            IF  ( m_start.len > 0 )
            THEN
                _istop := _istop + [ primary_start ];
            (*ENDIF*) 
            IF  ( m_stopkeys.reckey.k[ 1 ] <> chr( 255 ))
            THEN
                _istop := _istop + [ primary_stop ];
            (*ENDIF*) 
            IF  ( m_stopkeys.listkey.k[ 1 ] <> chr( 255 ))
            THEN
                _istop := _istop + [ secondary_stop ]
            ELSE
                IF  (( m_stopkeys.listkey.len > 1 ) AND
                    ( m_stopkeys.listkey.k[ 2 ] <> chr( 255 )))
                THEN
                    _istop := _istop + [ secondary_stop ]
                (*ENDIF*) 
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            _fill_key  := b01zerokey;
            _fill_char := chr (0);
            IF  ( m_start.k[ 1 ] <> chr( 255 ))
            THEN
                _istop := _istop + [ primary_start ];
            (*ENDIF*) 
            IF  m_stopkeys.reckey.len > 0
            THEN
                _istop := _istop + [ primary_stop ];
            (*ENDIF*) 
            IF  ( m_stopkeys.listkey.len > 0 )
            THEN
                _istop := _istop + [ secondary_stop ]
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        _m_ftr_help.inv_id := m_fns2;
        (* check for index strategies root of primary file      *)
        (* to prevent structure mismatch between secondary file *)
        (* and primary file                                     *)
        IF  ( m.mb_trns^.trError_gg00 = e_ok )
        THEN
            b01vstate_fileversion( m.mb_trns^, _m_ftr_help.file_id );
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    m.mb_data_len := 0;
    _mfetch_cnt   := 0;
    _sel.sfp_m_result_addr := @m.mb_data^.mbp_buf;
    _sel.sfp_m_result_size := m.mb_data_size;
    k720_maxresult_get( _data_ptr^, m_rowno, _rowno, m.mb_trns^.trError_gg00 );
    (* adjust m_cnt according to wanted result count (ROWNO)*)
    IF  ( m.mb_trns^.trError_gg00 = e_ok ) AND
        (( _rowno > 0 ) AND ( _rowno <> csp_maxint4 )) AND
        (* try to step foreward *)
        ( _work_mtype in [ mm_next, mm_first ] ) AND
        ( m_cnt > _rowno - m_rescnt )
    THEN
        BEGIN
        IF  ( _rowno - m_rescnt ) > 0  (* h.b. PTS 1001537 *)
        THEN
            m_cnt := _rowno - m_rescnt
        ELSE
            BEGIN
            (* _rowno - m_rescnt should be at most 0 *)
            IF  (m.mb_type2 in [ mm_next, mm_first ])
            THEN
                BEGIN
&               ifdef trace
                t01name(kb, 'set no_next_record' );
&               endif
                m.mb_trns^.trError_gg00 := e_no_next_record;
                m_cnt                   := 0;
                _sel.sfp_m_result_cnt   := 0;
                END
            ELSE
                BEGIN
                (* do nothing !! *)
                (* mm_direct (within result set!) and mm_last_rowno *)
                (* should get last record                           *)
                (* mm_prev move backward and should get records     *)
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
&   ifdef TRACE
    (*ENDIF*) 
    t01int4 (kb, 'mb_data_size', m.mb_data_size);
    t01int4 (kb, 'm_rowno     ', m_rowno);
    t01int4 (kb, 'rowno       ', _rowno);
    t01int4 (kb, 'm_cnt       ', m_cnt);
    t01int4 (kb, 'm_rescnt    ', m_rescnt);
    t01int4 (kb, 'outp offset ', _sel.sfp_output_offset);
    t01int4 (kb, 'm_dist_optim', m_dist_optim);
    t01int4 (kb, 'm_use_inv   ', ord(m_use_inv));
    t01int4 (kb, 'mb_datasize ', m.mb_data_size);
&   endif
    IF  ( NOT ( m_dist_optim in
        [ NO_DISTINCT_OPTIM_GG07, AUTO_DISTINCT_OPTIM_GG07 ] ))
        AND
        ( m_use_inv )
    THEN
        BEGIN
        WHILE (( m.mb_trns^.trError_gg00 = e_ok ) AND
              ( _mfetch_cnt < m_cnt )) DO
            BEGIN
            (* foreach loop get one record *)
            IF  ( _sel.sfp_bd_mess2_type IN [ mm_next,mm_prev ] )
            THEN
                (* foreach loop adjust invkey/primkey startkey *)
                BEGIN
                IF  ( m_dist_optim < KEYSEQLEN_OFFSET_GG07 )
                THEN
                    (* part of index in output columns *)
                    BEGIN
                    _searchkeys.reckey.len := MAX_KEYLEN_GG00;
                    _searchkeys.reckey.k   := _fill_key;
&                   ifdef trace
                    t01name(kb, '< KEYSEQLEN_OFFSET' );
                    IF  (  _searchkeys.listkey.len - m_dist_optim <= 0  )
                    THEN
                        vabort( true );
&                   endif
                    (*ENDIF*) 
                    IF  ( m_dist_optim <> INV_DISTINCT_OPTIM_GG07 ) AND
                        ( _searchkeys.listkey.len - m_dist_optim > 0 )
                    THEN
                        (* not complete index columns in output columns *)
                        SAPDB_PascalFill ('VKB75 ',   4,
                              sizeof( _searchkeys.listkey.k ),
                              @_searchkeys.listkey.k,
                              m_dist_optim + 1,
                              _searchkeys.listkey.len - m_dist_optim,
                              _fill_char, m.mb_trns^.trError_gg00);
                    (*ENDIF*) 
                    END
                ELSE
                    (* all columns of index and start sequence of   *)
                    (* key columns in output                        *)
                    IF  (( m_dist_optim - KEYSEQLEN_OFFSET_GG07 ) <
                        _searchkeys.reckey.len )
                    THEN
                        BEGIN
&                       ifdef trace
                        t01name(kb, 'fill _searchkey r ' );
&                       endif
                        SAPDB_PascalFill ('VKB75 ',   5,
                              sizeof( _searchkeys.reckey.k ),
                              @_searchkeys.reckey.k,
                              m_dist_optim - KEYSEQLEN_OFFSET_GG07 + 1,
                              _searchkeys.reckey.len - ( m_dist_optim -
                              KEYSEQLEN_OFFSET_GG07 ),
                              _fill_char, m.mb_trns^.trError_gg00);
                        END;
                    (*ENDIF*) 
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            IF  ( m.mb_trns^.trError_gg00 = e_ok )
            THEN
                BEGIN
                IF  ( m_use_inv )
                THEN
                    BEGIN
                    REPEAT
                        (* h.b. PTS 1104210 *)
                        b03select_invrec( m.mb_trns^, _m_ftr_help, _searchkeys,
                              m_stopkeys, m_start, _istop, 0, NIL, _sel,
                              _aux_stack_desc, _dummy_mode, c_usage_count );
&                       ifdef trace
                        t01basis_error( kb, 'b03slect_inv', m.mb_trns^.trError_gg00 );
                        t01key(kb, '_searchkey l', _searchkeys.listkey);
                        t01key(kb, '_searchkey r', _searchkeys.reckey);
&                       endif
                    UNTIL
                        m.mb_trns^.trError_gg00 <> e_key_not_found;
                    (*ENDREPEAT*) 
                    END
                ELSE
                    m.mb_trns^.trError_gg00 := e_not_implemented;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            IF  ( m.mb_trns^.trRteCommPtr_gg00^.to_cancel )
            THEN
                m.mb_trns^.trError_gg00 := e_cancelled;
            (*ENDIF*) 
            IF  ( m.mb_trns^.trError_gg00 = e_ok )
            THEN
                BEGIN
                (* _searchkeys.reckey -> m_startkeys.reckey *)
                m_startkeys.reckey.len := _searchkeys.reckey.len;
                g10mv ('VKB75 ',   6,
                      sizeof( _searchkeys.reckey.k ),
                      sizeof( m_startkeys.reckey.k ),
                      @_searchkeys.reckey.k, 1,
                      @m_startkeys.reckey.k, 1, m_startkeys.reckey.len,
                      m.mb_trns^.trError_gg00);
                IF  ( m_use_inv OR ( _sel.sfp_bd_inv_only = inv_only )) AND
                    ( warn14_next_invlist in m.mb_trns^.trWarning_gg00 )
                THEN
                    BEGIN
                    m.mb_trns^.trWarning_gg00 := m.mb_trns^.trWarning_gg00 -
                          [ warn14_next_invlist ];
                    IF  ( m.mb_trns^.trWarning_gg00 = [ warn0_exist ] )
                    THEN
                        m.mb_trns^.trWarning_gg00 := [  ];
                    (*ENDIF*) 
                    ;
                    (* _searchkeys.listkey -> m_startkeys.listkey *)
                    m_startkeys.listkey.len := _searchkeys.listkey.len;
                    g10mv ('VKB75 ',   7,
                          sizeof( _searchkeys.listkey.k ),
                          sizeof( m_startkeys.listkey.k ),
                          @_searchkeys.listkey.k, 1,
                          @m_startkeys.listkey.k, 1,
                          m_startkeys.listkey.len, m.mb_trns^.trError_gg00);
                    END;
                (*ENDIF*) 
                IF  ( m_use_recs )
                THEN
                    BEGIN
                    m.mb_data_len          := m.mb_data_len + m_leng;
                    _sel.sfp_m_result_addr := @m.mb_data^.mbp_buf[m.mb_data_len + 1];
                    _sel.sfp_m_result_size := m.mb_data_size - m.mb_data_len;
                    _sel.sfp_m_result_len  := 0;
                    _sel.sfp_result_length := 0
                    END;
                (*ENDIF*) 
                _mfetch_cnt := succ( _mfetch_cnt );
                IF  ( _mfetch_cnt = 1 )
                THEN
                    m_firstkeys := m_startkeys;
                (*ENDIF*) 
                END
            ELSE
                IF  (( m.mb_trns^.trError_gg00 = e_inv_list_not_found ) OR (* PTS 1114833 UJ *)
                    ( m.mb_trns^.trError_gg00 = e_key_not_found ) OR
                    ( m.mb_trns^.trError_gg00 = e_qual_violation ) OR
                    ( m.mb_trns^.trError_gg00 = e_view_violation ))
                THEN
                    m.mb_trns^.trError_gg00 := e_ok;
                (*ENDIF*) 
            (*ENDIF*) 
            _sel.sfp_bd_mess2_type := _loopmtype;
            END;
        (*ENDWHILE*) 
        _sel.sfp_m_result_cnt := _mfetch_cnt;
        IF  (m.mb_type2 = mm_last_rowno) AND
            (m.mb_trns^.trError_gg00 = e_no_next_record)
        THEN
            BEGIN
&           ifdef trace
            t01name(kb, 'special last rowno' );
&           endif
            m.mb_trns^.trError_gg00 := e_ok;
            END;
        (*ENDIF*) 
        IF  (( m.mb_trns^.trError_gg00 = e_no_next_invkey ) OR
            ( m.mb_trns^.trError_gg00 = e_no_prev_record ) OR
            ( m.mb_trns^.trError_gg00 = e_no_prev_invkey ))
        THEN
            m.mb_trns^.trError_gg00 := e_no_next_record;
        (*ENDIF*) 
        END
    ELSE
        (* not inv_only *)
        BEGIN
        IF  ( m.mb_trns^.trError_gg00 = e_ok )
        THEN
            BEGIN
            _sel.sfp_m_result_cnt     := m_cnt;
            _sel.sfp_m_firstkeys_addr := @m_firstkeys;
            IF  ( m_use_inv )
            THEN
                BEGIN
                (* h.b. PTS 1104210 *)
                b03select_invrec( m.mb_trns^, _m_ftr_help, _searchkeys,
                      m_stopkeys, m_start, _istop, 0, NIL, _sel,
                      _aux_stack_desc, _dummy_mode, c_usage_count );
                IF  (m.mb_type2 = mm_last_rowno) AND
                    (m.mb_trns^.trError_gg00 = e_no_next_record)
                THEN
                    (* dieser code kann entfallen, wenn b03select_invrec *)
                    (* in diesem Fall auch aktualisierte Startschlssel  *)
                    (* zurckgibt                                        *)
                    BEGIN
&                   ifdef trace
                    t01name(kb, 'special last rowno' );
&                   endif
                    m.mb_trns^.trError_gg00 := e_ok;
                    _sel.sfp_bd_mess2_type  := mm_last;
                    _tmp_cnt                := _sel.sfp_m_result_cnt;
                    _sel.sfp_m_result_cnt   := 1;
                    _tmpkeys                := m_stopkeys;
                    b03select_invrec( m.mb_trns^, _m_ftr_help, _tmpkeys,
                          _searchkeys, m_start, _istop, 0, NIL, _sel,
                          _aux_stack_desc, _dummy_mode, c_usage_count );
                    _searchkeys           := _tmpkeys;
                    _sel.sfp_m_result_cnt := _tmp_cnt;
                    END;
                (*ENDIF*) 
                END
            ELSE
                BEGIN
                IF  ( _sel.sfp_bd_inv_only = inv_and_primary )
                THEN
                    _sel.sfp_bd_inv_only := primary_only;
                (*ENDIF*) 
                b02kb_select_rec( m.mb_trns^, _m_ftr_help.file_id,
                      _searchkeys.reckey.keyVal_gg00, _searchkeys.reckey.keyLen_gg00,
                      m_stopkeys.reckey.keyVal_gg00, m_stopkeys.reckey.keyLen_gg00,
                      0, NIL,  NOT c_ignore_vwait, _sel, _aux_stack_desc, _is_not_ok,
                      _dummy_mode );
                IF  (m.mb_type2 = mm_last_rowno) AND
                    (m.mb_trns^.trError_gg00 = e_no_next_record)
                THEN
                    BEGIN
&                   ifdef trace
                    t01name(kb, 'special last rowno' );
&                   endif
                    m.mb_trns^.trError_gg00 := e_ok;
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
&           ifdef trace
            IF  m_use_inv
            THEN
                t01key(kb, '_searchkey l', _searchkeys.listkey);
            (*ENDIF*) 
            t01key(kb, '_searchkey r', _searchkeys.reckey);
&           endif
            IF  (( m.mb_trns^.trError_gg00 = e_no_next_invkey ) OR
                ( m.mb_trns^.trError_gg00 = e_no_prev_record ) OR
                ( m.mb_trns^.trError_gg00 = e_no_prev_invkey ))
            THEN
                m.mb_trns^.trError_gg00 := e_no_next_record;
            (*ENDIF*) 
            IF  ( m.mb_trns^.trError_gg00 = e_ok )
            THEN
                BEGIN
                m_startkeys.reckey.len := _searchkeys.reckey.len;
                g10mv ('VKB75 ',   8,
                      sizeof(_searchkeys.reckey.k),
                      sizeof(m_startkeys.reckey.k),
                      @_searchkeys.reckey.k, 1,
                      @m_startkeys.reckey.k, 1, m_startkeys.reckey.len,
                      m.mb_trns^.trError_gg00);
                IF  ( m_use_inv OR ( _sel.sfp_bd_inv_only = inv_only )) AND
                    ( warn14_next_invlist in m.mb_trns^.trWarning_gg00 )
                THEN
                    BEGIN
                    m.mb_trns^.trWarning_gg00 := m.mb_trns^.trWarning_gg00 -
                          [ warn14_next_invlist ];
                    IF  m.mb_trns^.trWarning_gg00 = [ warn0_exist ]
                    THEN
                        m.mb_trns^.trWarning_gg00 := [  ];
                    (*ENDIF*) 
                    m_startkeys.listkey.len := _searchkeys.listkey.len;
                    g10mv ('VKB75 ',   9,
                          sizeof( _searchkeys.listkey.k ),
                          sizeof( m_startkeys.listkey.k ),
                          @_searchkeys.listkey.k, 1,
                          @m_startkeys.listkey.k, 1,
                          m_startkeys.listkey.len, m.mb_trns^.trError_gg00);
                    END
                (*ENDIF*) 
                END;
            (* PTS 1105717 E.Z. *)
            (*ENDIF*) 
            IF  ( m_use_recs )
            THEN
                m.mb_data_len := _sel.sfp_m_result_len;
            (*ENDIF*) 
            END;
        (* PTS 1103481 E.Z. *)
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    ;
    IF  ( m.mb_trns^.trError_gg00 = e_no_next_record )
    THEN
        BEGIN
        IF  ( _loopmtype = mm_next ) AND
            ( m_stopkeys.reckey.len > 1 )
        THEN
            BEGIN
            _is_not_ok := false;
            IF  ( m_stopkeys.reckey.len > 0 )
            THEN
                REPEAT
                    IF  ( m_stopkeys.reckey.k[ m_stopkeys.reckey.len ] =
                        chr( 255 ))
                    THEN
                        m_stopkeys.reckey.len := pred( m_stopkeys.reckey.len )
                    ELSE
                        _is_not_ok := true
                    (*ENDIF*) 
                UNTIL
                    ( m_stopkeys.reckey.len = 0 ) OR _is_not_ok;
                (*ENDREPEAT*) 
            (*ENDIF*) 
            IF  ( m_stopkeys.reckey.len > 0 )
            THEN
                m_stopkeys.reckey.k[ m_stopkeys.reckey.len ] :=
                      chr( ord( m_stopkeys.reckey.k[ m_stopkeys.reckey.len ] ) + 1 );
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        m_startkeys.reckey.len := m_stopkeys.reckey.len;
        g10mv ('VKB75 ',  10,
              sizeof( m_stopkeys.reckey.k ),
              sizeof( m_startkeys.reckey.k ),
              @m_stopkeys.reckey.k, 1,
              @m_startkeys.reckey.k, 1, m_startkeys.reckey.len,
              m.mb_trns^.trError_gg00);
        IF  ( m_use_inv OR (_sel.sfp_bd_inv_only = inv_only )) AND
            ( warn14_next_invlist in m.mb_trns^.trWarning_gg00 )
        THEN
            BEGIN
            m.mb_trns^.trWarning_gg00 := m.mb_trns^.trWarning_gg00 -
                  [ warn14_next_invlist ];
            IF  ( m.mb_trns^.trWarning_gg00 = [ warn0_exist ] )
            THEN
                m.mb_trns^.trWarning_gg00 := [  ];
            (*ENDIF*) 
            m_startkeys.listkey.len := m_stopkeys.listkey.len;
            g10mv ('VKB75 ',  11,
                  sizeof( m_stopkeys.listkey.k ),
                  sizeof( m_startkeys.listkey.k ),
                  @m_stopkeys.listkey.k, 1,
                  @m_startkeys.listkey.k, 1,
                  m_startkeys.listkey.len, m.mb_trns^.trError_gg00);
            END
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    m.mb_data_size := _ori_data_size;
    IF  ( m_use_inv OR ( _sel.sfp_bd_inv_only = inv_only)) AND
        ( _mfetch_cnt > 0 )
    THEN
        IF  ( warn14_next_invlist in m.mb_trns^.trWarning_gg00 )
        THEN
            BEGIN
            m.mb_trns^.trWarning_gg00 := m.mb_trns^.trWarning_gg00 -
                  [ warn14_next_invlist ];
            IF  ( m.mb_trns^.trWarning_gg00 = [ warn0_exist ] )
            THEN
                m.mb_trns^.trWarning_gg00 := [  ]
            (*ENDIF*) 
            END;
        (*ENDIF*) 
    (*ENDIF*) 
    m_searched_pages := m.mb_trns^.trRteCommPtr_gg00^.file_record_cnt;
    IF  (( m.mb_trns^.trError_gg00 = e_ok )
        OR
        (* real MFETCH ? *)
        (( m.mb_trns^.trError_gg00 = e_no_next_record ) AND
        NOT m_single AND m_use_recs ))
    THEN
        BEGIN
        IF  ( _sel.sfp_m_result_cnt = 0 )
        THEN
            m_firstkeys := m_startkeys;
        (*ENDIF*) 
        m.mb_trns^.trError_gg00 := e_ok;
        m_cnt             := _sel.sfp_m_result_cnt;
        m.mb_struct       := mbs_result;
        m.mb_type         := m_return_result;
        m.mb_type2        := mm_nil;
        END
    ELSE
        (* PTS 1002020 E.Z. *)
        IF  ( _sel.sfp_m_result_cnt = ( m_cnt - 1 )) AND
            (* positioning for FETCH POS ? *)
            ( NOT m_use_recs ) AND ( NOT m_single ) AND
            ( _sel.sfp_bd_mess2_type = mm_prev )
        THEN
            BEGIN
            (* prev to go one BEFORE the first needed row *)
            (* in case of fetch pos, fetch relative (<0)  *)
            m.mb_trns^.trError_gg00 := e_no_prev_record;
            END
        ELSE
            BEGIN
            m.mb_type      := m_return_error;
            m.mb_type2     := mm_nil;
            m.mb_data_len  := 0;
            m.mb_qual_len  := MB_PART1_HEAD_MXGG00 + 4
                  (*sizeof(m.mb_qual^.m_searched_pages) *)
            END;
        (*ENDIF*) 
    (*ENDIF*) 
    (* PTS 1001518 E.Z. *)
    IF  ( _start_sec > 0 )
    THEN
        BEGIN
        k720monitor( m.mb_trns^, _sel, _start_sec,
              _start_microsec, _start_phys_ios, _start_suspends,
              _start_waits, c_not_put_strat,
              m.mb_qual^.mf_desc.m_strat_info, c_not_strat_cnt );
        END
    (*ENDIF*) 
    END;
(*ENDWITH*) 
&ifdef trace
t01fetch_desc(kb, 'fetch desc 2', m.mb_qual^.mf_desc);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      k75pre_fetch (
            VAR t         : tgg00_TransContext;
            VAR tree_id   : tgg00_FileId;
            VAR key       : tgg00_Lkey);
 
VAR
      mblock      : tgg00_MessBlock;
      child_trans : tgg00_TransChild;
      trans_ptr   : tgg00_UnivTransPtr;
 
BEGIN
t.trError_gg00 := e_ok;
trans_ptr       := @t;
child_trans := trans_ptr^.utrChild;
g01mblock_init (t, m_get, mm_pages, mblock);
mblock.mb_struct    := mbs_buf;
mblock.mb_qual      := @tree_id;
mblock.mb_qual_size := sizeof (tree_id);
mblock.mb_qual_len  := sizeof (tree_id);
mblock.mb_data      := @key;
mblock.mb_data_size := sizeof (key);
mblock.mb_data_len  := sizeof (key) - sizeof (key.k) + key.len;
mblock.mb_reply     := false;
k90send (mblock, child_trans);
IF  t.trError_gg00 = e_too_many_net_requests
THEN
    t.trError_gg00 := e_ok
(*ENDIF*) 
END;
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
.PA 
