.ad 8
.bm 3
.fm 2
.bt $Copyright (c) 2000-2005 SAP AG$$Page %$
.tm 5
.hm 2
.hs 3
.TT 1 $SQL$Project Distributed Database System$VKB74$
.tt 2 $$$
.TT 3 $ElkeZ$KB_Join_Select$2000-11-28$
***********************************************************
.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
.nf
.sp
MODULE  : KB_Join_Select
=========
.sp
Purpose : Processing the join between two tables
.CM *-END-* purpose -------------------------------------
.sp
.cp 3
Define  :
 
        PROCEDURE
              k74_join_select (VAR m : tgg00_MessBlock);
 
        PROCEDURE
              k74finish_catalog_join (
                    VAR m           : tgg00_MessBlock;
                    VAR getrec      : tgg07_get_param;
                    VAR selrec      : tgg07_select_context;
                    strat_maxresult : tsp00_Int4;
                    last_join_tab   : boolean);
 
        PROCEDURE
              k74rowno_position (
                    VAR m      : tgg00_MessBlock;
                    VAR getrec : tgg07_get_param;
                    VAR selrec : tgg07_select_param);
 
        PROCEDURE
              k74start_catalog_join (
                    VAR m           : tgg00_MessBlock;
                    VAR getrec      : tgg07_get_param;
                    VAR selrec      : tgg07_select_context);
 
        PROCEDURE
              k74get_new_positions (
                    VAR m        : tgg00_MessBlock;
                    VAR getrec   : tgg07_get_param);
 
        PROCEDURE
              k74get_join_infos (
                    VAR m      : tgg00_MessBlock;
                    VAR getrec : tgg07_get_param);
 
        PROCEDURE
              k74finish_l_outer_join (
                    VAR m      : tgg00_MessBlock;
                    VAR getrec : tgg07_get_param;
                    VAR selrec : tgg07_select_param);
 
        PROCEDURE
              k74join_with_left_result (
                    VAR m           : tgg00_MessBlock;
                    VAR getrec      : tgg07_get_param;
                    VAR sel         : tgg00_SelectFieldsParam;
                    VAR selrec      : tgg07_select_param);
 
        PROCEDURE
              k74get_last_field_pos (
                    VAR m              : tgg00_MessBlock;
                    VAR last_field_pos : tsp00_Int2;
                    jpath_cnt          : tsp00_Int2);
 
        PROCEDURE
              k74check_inv_conversions (
                    VAR m              : tgg00_MessBlock;
                    VAR conv_st_pos    : tkb07_conv_arr;
                    VAR conv_cnt       : tsp00_Int4;
                    VAR last_field_pos : tsp00_Int2;
                    VAR last_desc_field: boolean;
                    jpath_cnt          : tsp00_Int2);
 
.CM *-END-* define --------------------------------------
.sp;.cp 3
Use     :
 
        FROM
              Scanner : VAK01;
 
        VAR
              a01diag_monitor_on : boolean;
              a01diag_analyze_on : boolean;
 
      ------------------------------ 
 
        FROM
              SQLManager :vak101;
 
        PROCEDURE
              a101_CreateGroupedTempFile(
                    VAR trans      : tgg00_TransContext;
                    VAR tempFileId : tgg00_FileId;
                    tempFileType   : tgg00_TfnTemp);
 
        PROCEDURE
              a101_DestroyGroupedTempFile(
                    VAR trans      : tgg00_TransContext;
                    VAR tempFileId : tgg00_FileId);
 
        PROCEDURE
              a101_DestroyGroupedTempFiles(
                    VAR trans      : tgg00_TransContext;
                    fileType       : tgg00_TfnTemp(*ptocConst*);
                    level          : tsp00_Int4(*ptocConst*);
                    subLevel       : tsp00_Int2(*ptocConst*);
                    VAR fileName   : tgg00_Filename);
 
        PROCEDURE
              a101_GetLogicalFilename(
                    VAR trans      : tgg00_TransContext;
                    VAR tempFileId : tgg00_FileId);
 
      ------------------------------ 
 
        FROM
              Build_Strategy   : VAK70;
 
        VAR
              a70glob_join_inv_strats   : tgg07_StratEnumSet;
              a70glob_join_strats       : tgg07_StratEnumSet;
 
      ------------------------------ 
 
        FROM
              KB_get : VKB71;
 
        PROCEDURE
              k71col_select (
                    VAR t           : tgg00_TransContext;
                    VAR sel         : tgg00_SelectFieldsParam;
                    VAR stack_desc  : tgg00_StackDesc;
                    VAR rec_buf     : tsp00_Buf;
                    VAR unqualified : boolean);
 
        PROCEDURE
              k71join_comparison (
                    VAR sel     : tgg00_SelectFieldsParam;
                    op          : tgg00_StackOpType;
                    VAR workbuf : tkb07_buffer_description;
                    buf1        : tsp00_MoveObjPtr;
                    pos1        : tsp00_Int4;
                    len1        : integer;
                    buf2        : tsp00_MoveObjPtr;
                    pos2        : tsp00_Int4;
                    len2        : integer;
                    VAR ok      : integer);
 
        PROCEDURE
              k71sel_qualification_test (
                    VAR m          : tgg00_MessBlock;
                    VAR sel        : tgg00_SelectFieldsParam;
                    check_new_rec  : boolean;
                    VAR rec        : tgg00_Rec);
 
      ------------------------------ 
 
        FROM
              Single_Select : VKB720;
 
        PROCEDURE
              k720ref_statistic (
                    VAR arr_index : tgg00_RefInfoIndex;
                    VAR strat     : tgg07_StrategyInfo);
 
        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_test_subquery (
                    VAR trans   : tgg00_TransContext;
                    VAR datapart: tgg00_DataPart;
                    datapartsize: tsp00_Int4;
                    VAR mdesc   : tgg00_StackDesc;
                    VAR rec     : tgg00_Rec);
 
        PROCEDURE
              k720_select (
                    VAR m      : tgg00_MessBlock;
                    VAR getrec : tgg07_get_param;
                    VAR selrec : tgg07_select_param);
 
        PROCEDURE
              k720_initialize (
                    VAR m                : tgg00_MessBlock;
                    VAR selrec           : tgg07_select_param;
                    VAR strat            : tgg07_StrategyInfo;
                    VAR use_stopkey      : boolean);
&       ifdef trace
 
        PROCEDURE
              k720trace_selrec (
                    VAR m      : tgg00_MessBlock;
                    VAR selrec : tgg07_select_param);
&       endif
 
      ------------------------------ 
 
        FROM
              Single_Select_Part2 : VKB721;
 
        PROCEDURE
              k721call_later_output (
                    VAR m       : tgg00_MessBlock;
                    VAR res_buf : tsp00_Buf;
                    h_keylen    : integer);
 
        PROCEDURE
              k721do_avg (
                    VAR m        : tgg00_MessBlock;
                    VAR selrec   : tgg07_select_param);
 
        PROCEDURE
              k721null_result (
                    VAR m         : tgg00_MessBlock;
                    VAR selrec    : tgg07_select_param;
                    VAR sel       : tgg00_SelectFieldsParam;
                    act_cntresult : tsp00_Int4;
                    later_output  : boolean;
                    h_keylen      : integer);
 
        PROCEDURE
              k721do_rowno (
                    VAR m      : tgg00_MessBlock;
                    VAR selrec : tgg07_select_param);
 
        FUNCTION
              k721out_entry (
                    st_addr : tgg00_StackListPtr;
                    curr : integer) : integer;
 
        PROCEDURE
              k721add_into_result (
                    VAR t                : tgg00_TransContext;
                    VAR selrec           : tgg07_select_param;
                    VAR next_mblock      : tgg00_MessBlockPtr);
 
        PROCEDURE
              k721function_add (
                    VAR m      : tgg00_MessBlock;
                    VAR selrec : tgg07_select_param;
                    aggr       : boolean);
 
      ------------------------------ 
 
        FROM
              Parallel_Join : VKB742;
 
        PROCEDURE
              k742CloseIterator (
                    pIter  : tgg00_VoidPtr);
 
        FUNCTION
              k742CreateInvIterator (
                    VAR m      : tgg00_MessBlock;
                    VAR sel    : tgg00_SelectFieldsParam;
                    VAR selrec : tgg07_select_param) : tgg00_VoidPtr;
 
        PROCEDURE
              k742DestroyIterator (
                    pIter  : tgg00_VoidPtr);
 
        FUNCTION
              k742Next (
                    pIter  : tgg00_VoidPtr) : tgg00_BasisError;
 
        PROCEDURE
              k742OpenIterator (
                    pIter      : tgg00_VoidPtr;
                    VAR sel    : tgg00_SelectFieldsParam;
                    VAR selrec : tgg07_select_param;
                    bdInvSet   : tgg00_BdInvSet);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_1 : VBD01;
 
        VAR
              b01niltree_id     : tgg00_FileId;
 
        PROCEDURE
              b01move_filecontent (
                    VAR t         : tgg00_TransContext;
                    VAR source_id : tgg00_FileId;
                    VAR target_id : tgg00_FileId);
 
        PROCEDURE
              b01empty_file (
                    VAR t       : tgg00_TransContext;
                    VAR current : 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
              b03get_inv (
                    VAR t              : tgg00_TransContext;
                    VAR act_tree_id    : tgg00_FileId;
                    VAR lk             : tgg00_Lkey;
                    VAR rk             : tgg00_Lkey;
                    VAR stop_rk        : tgg00_Lkey;
                    VAR CurrentPrimKey : tgg00_Lkey;
                    VAR bd_inv_info    : tgg00_BdInvSet;
                    count_only         : boolean;
                    wanted_lock        : tgg00_LockReqMode;
                    VAR b              : tgg00_KeylistBuf;
                    VAR primkeycnt     : tsp00_Int4;
                    VAR ll             : tsp00_Int4);
 
        PROCEDURE
              b03next_invkey (
                    VAR t           : tgg00_TransContext;
                    VAR act_tree_id : tgg00_FileId;
                    incl            : boolean;
                    VAR lk          : tgg00_Lkey);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_7 : VBD07;
 
        PROCEDURE
              b07cnext_record (
                    VAR t           : tgg00_TransContext;
                    VAR act_tree_id : tgg00_FileId;
                    VAR rk          : tgg00_Lkey;
                    VAR set_result  : tgg00_BdSetResultRecord;
                    VAR tree_pos    : tgg00_FilePos;
                    VAR b           : tsp00_Buf);
 
        PROCEDURE
              b07cdel_record (
                    VAR t           : tgg00_TransContext;
                    VAR act_tree_id : tgg00_FileId;
                    VAR rk          : tgg00_Lkey);
 
        PROCEDURE
              b07cadd_record (
                    VAR t       : tgg00_TransContext;
                    VAR file_id : tgg00_FileId;
                    VAR b       : tsp00_Buf);
 
        PROCEDURE
              b07cget_record (
                    VAR t       : tgg00_TransContext;
                    VAR file_id : tgg00_FileId;
                    VAR rk      : tgg00_Lkey;
                    VAR b       : tsp00_Buf);
 
        PROCEDURE
              b07get_result_leaf (
                    VAR t           : tgg00_TransContext;
                    VAR file_id     : tgg00_FileId;
                    VAR rk          : tgg00_Lkey;
                    use_tree_pos    : boolean;
                    prepare_for_upd : boolean;
                    VAR tree_pos    : tgg00_FilePos;
                    VAR nptr        : tbd_node_ptrs);
 
        PROCEDURE
              b07release_result_leaf (
                    VAR t        : tgg00_TransContext;
                    VAR file_id  : tgg00_FileId;
                    node_changed : boolean;
                    VAR nptr     : tbd_node_ptrs);
 
      ------------------------------ 
 
        FROM
              task_temp_data_cache : VBD21;
 
        PROCEDURE
              b21mp_root_put (
                    temp_cache_ptr : tgg00_TempDataCachePtr;
                    root : tsp00_PageNo);
 
      ------------------------------ 
 
        FROM
              ref_statistic : VBD73;
 
        PROCEDURE
              b73cmds_count (
                    statement_kind : tgg00_RefInfoIndex;
                    count : tsp00_Int4);
 
      ------------------------------ 
 
        FROM
              FileDir_Wrapper : vbd998;
 
        FUNCTION
              bd998IsExtendedTempFile(
                    VAR trans  : tgg00_TransContext;
                    VAR fileId : tgg00_FileId) : boolean;
 
        FUNCTION
              bd998GetExtendedTempFileType(
                    VAR trans      : tgg00_TransContext;
                    VAR tempFileId : tgg00_FileId(*ptocConst*)) : tgg00_TfnTemp;
 
        PROCEDURE
              bd998IncrementIndexUsageCount(
                    VAR trans         : tgg00_TransContext;
                    VAR indexFileSurr : tgg00_Surrogate(*ptocConst*));
 
      ------------------------------ 
 
        FROM
              Configuration_Parameter : VGG01;
 
        PROCEDURE
              g01opmsg (
                    msg_prio  : tsp3_priority;
                    msg_type  : tsp3_msg_type;
                    msg_no    : tsp00_Int4;
                    msg_label : tsp00_C8;
                    msg_text  : tsp00_C24;
                    msg_value : tsp00_Int4);
 
      ------------------------------ 
 
        FROM
              Codetransformation_and_Coding : VGG02;
 
        VAR
              g02codetables : tgg04_CodeTables;
 
      ------------------------------ 
 
        FROM
              Select_Help_Procedures : VGG04;
 
        PROCEDURE
              g04index_tree_build (
                    VAR file_id    : tgg00_FileId;
                    VAR index_tree : tgg00_FileId;
                    index_no       : tsp00_Int2);
 
        PROCEDURE
              g04init_select_fields (
                    VAR sel       : tgg00_SelectFieldsParam;
                    data_addr     : tsp00_MoveObjPtr;
                    data_size     : 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;
                    fieldlistptr  : tgg00_FieldListsPtr);
 
      ------------------------------ 
 
        FROM
              Unicode-Utilities: VGG20;
 
        PROCEDURE
              g20unifill (
                    size      : tsp00_Int4;
                    m         : tsp00_MoveObjPtr;
                    pos       : tsp00_Int4;
                    len       : tsp00_Int4;
                    filluchar : tsp00_C2);
 
      ------------------------------ 
 
        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);
 
        PROCEDURE
              vdebug_break (debug_break_pos : tsp00_Int4);
 
      ------------------------------ 
 
        FROM
              Kernel_move_and_fill : VGG101;
 
        PROCEDURE
              SAPDB_PascalFill (
                    mod_id         : tsp00_C6;
                    mod_intern_num : tsp00_Int4;
                    size           : tsp00_Int4;
                    m              : tsp00_MoveObjPtr;
                    pos            : tsp00_Int4;
                    len            : tsp00_Int4;
                    fillchar       : char;
                    VAR e          : tgg00_BasisError);
 
        PROCEDURE
              SAPDB_PascalMove (
                    mod_id         : tsp00_C6;
                    mod_intern_num : tsp00_Int4;
                    size1          : tsp00_Int4;
                    size2          : tsp00_Int4;
                    val1           : tsp00_MoveObjPtr;
                    p1             : tsp00_Int4;
                    val2           : tsp00_MoveObjPtr;
                    p2             : tsp00_Int4;
                    cnt            : tsp00_Int4;
                    VAR e          : tgg00_BasisError);
 
        PROCEDURE
              SAPDB_PascalOverlappingMove (
                    mod_id         : tsp00_C6;
                    mod_intern_num : tsp00_Int4;
                    size1          : tsp00_Int4;
                    size2          : tsp00_Int4;
                    val1           : tsp00_MoveObjPtr;
                    p1             : tsp00_Int4;
                    val2           : tsp00_MoveObjPtr;
                    p2             : tsp00_Int4;
                    cnt            : tsp00_Int4;
                    VAR e          : tgg00_BasisError);
 
        PROCEDURE
              SAPDB_PascalForcedFill (
                    size        : tsp00_Int4;
                    m           : tsp00_MoveObjPtr;
                    pos         : tsp00_Int4;
                    len         : tsp00_Int4;
                    fillchar    : char);
 
      ------------------------------ 
 
        FROM
              RTE-Extension-30 : VSP30;
 
        PROCEDURE
              s30cmp (
                    VAR buf1     : tbd_node;
                    fieldpos1    : tsp00_Int4;
                    fieldlength1 : tsp00_Int4;
                    VAR buf2     : tsp00_Buf;
                    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     : tbd_node;
                    fieldpos2    : tsp00_Int4;
                    fieldlength2 : tsp00_Int4;
                    VAR l_result : tsp00_LcompResult);
 
        PROCEDURE
              s30cmp2 (
                    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
              s30luc (
                    VAR buf1     : tbd_node;
                    fieldpos1    : tsp00_Int4;
                    fieldlength1 : tsp00_Int4;
                    VAR buf2     : tsp00_Buf;
                    fieldpos2    : tsp00_Int4;
                    fieldlength2 : tsp00_Int4;
                    VAR l_result : tsp00_LcompResult);
 
        PROCEDURE
              s30luc1 (
                    VAR buf1     : tbd_node;
                    fieldpos1    : tsp00_Int4;
                    fieldlength1 : tsp00_Int4;
                    VAR buf2     : tsp00_Key;
                    fieldpos2    : tsp00_Int4;
                    fieldlength2 : tsp00_Int4;
                    VAR l_result : tsp00_LcompResult);
 
        PROCEDURE
              s30map (
                    VAR code_t : tsp00_Ctable;
                    VAR source : tsp00_Key;
                    spos       : tsp00_Int4;
                    VAR dest   : tsp00_Key;
                    dpos       : tsp00_Int4;
                    length     : tsp00_Int4);
 
        FUNCTION
              s30lnr_defbyte (
                    str       : tsp00_MoveObjPtr;
                    defbyte   : char;
                    start_pos : tsp00_Int4;
                    length    : tsp00_Int4) : tsp00_Int4;
 
      ------------------------------ 
 
        FROM
              PUT-Conversions : VSP41;
 
        PROCEDURE
              s41p4int (
                    VAR buf : tsp00_ResNum;
                    pos     : tsp00_Int4;
                    source  : tsp00_Int4;
                    VAR res : tsp00_NumError);
 
      ------------------------------ 
 
        FROM
              Patterns : VSP49;
 
        PROCEDURE
              s49build_pattern (
                    VAR pat_buffer  : tsp00_MoveObj;
                    start           : tsp00_Int4;
                    stop            : tsp00_Int4;
                    escape_char     : char;
                    escape          : boolean;
                    string          : boolean;
                    sqlmode         : tsp00_SqlMode;
                    VAR ok          : boolean);
 
        PROCEDURE
              s49uni_build_pattern (
                    VAR pat_buffer  : tsp00_MoveObj;
                    start           : tsp00_Int4;
                    stop            : tsp00_Int4;
                    escape_char     : tsp00_C2;
                    escape          : boolean;
                    sqlmode         : tsp00_SqlMode;
                    VAR ok          : boolean);
&       IFDEF TRACE
 
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        PROCEDURE
              t01char (
                    debug : tgg00_Debug;
                    nam   : tsp00_Sname;
                    c     : char);
 
        FUNCTION
              t01trace (debug : tgg00_Debug) : boolean;
 
        PROCEDURE
              t01line_c60 (
                    debug : tgg00_Debug;
                    ln_p1 : tsp00_C60);
 
        PROCEDURE
              t01line (
                    debug  : tgg00_Debug;
                    VAR ln : tsp00_Line);
 
        PROCEDURE
              t01init_line (
                    VAR ln      : tsp00_Line;
                    VAR ln_len  : integer;
                    nam         : tsp00_Sname);
 
        PROCEDURE
              t01op (
                    debug  : tgg00_Debug;
                    nam    : tsp00_Sname;
                    op     : tgg00_StackOpType);
 
        PROCEDURE
              t01name (
                    debug : tgg00_Debug;
                    nam   : tsp00_Name);
 
        PROCEDURE
              t01p2bool (
                    debug : tgg00_Debug;
                    nam_1 : tsp00_Sname;
                    bool1 : boolean;
                    nam_2 : tsp00_Sname;
                    bool2 : boolean);
 
        PROCEDURE
              t01p2int4 (
                    debug : tgg00_Debug;
                    nam_1 : tsp00_Sname;
                    int_1 : tsp00_Int4;
                    nam_2 : tsp00_Sname;
                    int_2 : tsp00_Int4);
 
        PROCEDURE
              t01sname (
                    debug : tgg00_Debug;
                    nam   : tsp00_Sname);
 
        PROCEDURE
              t01bool (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    curr_bool: boolean);
 
        PROCEDURE
              t01treeid  (
                    level    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    VAR tree : tgg00_FileId);
 
        PROCEDURE
              t01buf  (
                    level     : tgg00_Debug;
                    VAR buf   : tsp00_Buf;
                    pos_start : integer;
                    pos_end   : integer);
 
        PROCEDURE
              t01int4 (
                    layer : tgg00_Debug;
                    nam : tsp00_Sname;
                    int : tsp00_Int4);
 
        PROCEDURE
              t01basis_error (
                    layer : tgg00_Debug;
                    nam   : tsp00_Sname;
                    b_err : tgg00_BasisError);
 
        PROCEDURE
              t01messblock (
                    debug         : tgg00_Debug;
                    nam           : tsp00_Sname;
                    VAR m         : tgg00_MessBlock);
 
        PROCEDURE
              t01stackentry (
                    layer       : tgg00_Debug;
                    VAR st      : tgg00_StackEntry;
                    entry_index : integer);
 
        PROCEDURE
              t01qual (
                    level     : tgg00_Debug;
                    VAR part1 : tgg00_QualBuf);
 
        PROCEDURE
              t01key (
                    debug   : tgg00_Debug;
                    nam     : tsp00_Sname;
                    VAR k   : tgg00_Lkey);
 
        PROCEDURE
              t01comp_result (
                    debug     : tgg00_Debug;
                    nam       : tsp00_Sname;
                    comp_res  : tsp00_LcompResult);
 
        PROCEDURE
              t01buf1  (
                    level     : tgg00_Debug;
                    VAR buf   : tbd_node;
                    pos_start : integer;
                    pos_end   : integer);
 
        PROCEDURE
              t01lkey (
                    layer : tgg00_Debug;
                    VAR k : tgg00_Lkey);
 
        PROCEDURE
              t01mess2type (
                    debug         : tgg00_Debug;
                    nam           : tsp00_Sname;
                    mess2_type    : tgg00_MessType2);
 
      ------------------------------ 
 
        FROM
              GG_edit_routines: VGG17;
 
        PROCEDURE
              g17int4to_line (
                    int       : tsp00_Int4;
                    with_zero : boolean;
                    int_len   : integer;
                    ln_pos    : integer;
                    VAR ln    : tsp00_Line);
 
        PROCEDURE
              g17sname_to_line (
                    n             : tsp00_Sname;
                    VAR ln_len    : integer;
                    VAR ln        : tsp00_Line);
 
      ------------------------------ 
 
        FROM
              join_trace_routines: VAK683;
 
        PROCEDURE
              a683trace_kbjrec (
                    debug      : tgg00_Debug;
                    VAR kbjrec : tgg07_KbJoinRec);
&       ENDIF
 
.CM *-END-* use -----------------------------------------
.sp;.cp 3
Synonym :
 
        PROCEDURE
              b07cadd_record;
 
              tgg00_Rec tsp00_Buf
 
        PROCEDURE
              k71col_select;
 
              tgg00_Rec tsp00_Buf
 
        PROCEDURE
              b07cnext_record;
 
              tsp00_MoveObj tsp00_Buf
 
        PROCEDURE
              b07cget_record;
 
              tgg00_Rec tsp00_Buf
 
        PROCEDURE
              s41p4int;
 
              tsp00_MoveObj tsp00_ResNum
 
        PROCEDURE
              b03get_inv;
 
              tgg00_KeylistBuf tsp00_Buf
 
        PROCEDURE
              s30cmp;
 
              tsp00_MoveObj tbd_node
              tsp00_MoveObj tsp00_Buf
 
        PROCEDURE
              s30cmp1;
 
              tsp00_MoveObj tsp00_Key
              tsp00_MoveObj tbd_node
 
        PROCEDURE
              s30cmp2;
 
              tsp00_MoveObj tsp00_Key;
 
        PROCEDURE
              s30luc;
 
              tsp00_MoveObj tsp00_Buf
              tsp00_MoveObj tbd_node
 
        PROCEDURE
              s30luc1;
 
              tsp00_MoveObj tbd_node
              tsp00_MoveObj tsp00_Key
 
        PROCEDURE
              s30map;
 
              tsp00_MoveObj tsp00_Key

&             ifdef trace
 
        PROCEDURE
              t01buf1;
 
              tsp00_Buf tbd_node
&             endif
 
.CM *-END-* synonym -------------------------------------
.sp;.cp 3
Author  : ElkeZ
.sp
.cp 3
Created : 1985-10-23
.sp
.cp 3
.sp
.cp 3
Release :      Date : 2000-11-28
.sp
***********************************************************
.sp
.cp 10
.fo
.oc _/1
Specification:
 
A join in KB always represents the joining of two tables.
One table is the result of the joins executed beforehand, the other is
the primary table to be joined to the former.
The intermediate results are always sorted by the fields that will
be needed for the next join operation. These fields form the key to an
intermediate-result record. Thus, records with the same join values
are always placed one immediately following the other.
Even if the record directly accessed in a table is the only one
processed, it is transformed into a result record that contains the
join-field values in its key.
 
If there is more than one relevant join field, they are sorted by
selectivity (fields for "=" joins before those for "<" or ">" joins,
which in turn come before those for "<>" joins).
Naturally, this also means that the table that will be the first
in the join is processed individually; in other words, a search is
performed for those records that satisfy the qualifications for the
table concerned, the fields required are selected and the result
records created in this way are written into the intermediate result
after being sorted by the fields required for the join with the 2nd
table.
There are two widely differing methods available for joining. The
first, less complex method is used when the join value in the existing
intermediate-result table allows one to conclude which records in the
new primary table will have suitable join values.
This is true of equality joins, although there are subdivisions :
 
1. The join field in the primary table is the only key field. Once the
join value from the intermediate-result table is available, the record
in the primary table known to satisfy the equality-join condition can
be directly accessed.
 
2. The join field in the primary table is the first key field. A
part of the primary table is thus marked in which all the records
satisfy the join condition.
 
3. The join field in the primary table is a single inverted field.
Once the join value from the intermediate-result table is available,
it determines the list of inversions that contains precisely those
primary keys with records satisfying the equality-join condition.
 
These three cases are the least complex, because only such records are
considered in the primary table which fulfill this one, particularly
selective join condition at least.
 
These three contrast with all other cases and equality conditions in
which the field in the primary table is neither the 1st key field nor
an inverted field, and they contrast with all remaining join
conditions ( >, <, >=, <=, <> ).
Since performance and the I/O-rate render it impossible to process
the primary table for every join value in the intermediate result,
this procedure is conducted once before the join step itself takes
place.
As is the case with the 1st table in the join, the table is
searched for records that satisfy the qualifications for the table
concerned, the fields required are selected and the result records
created in this way are written into a second intermediate result
after having been sorted by the fields required for the join with the
other table.
In both the search through the first table and in this search, use
is made of search strategies (e.g. search using inversion) that accord
to conditions referring to this table in the Search Condition. If a
field is part of an equality join and there are other conditions for
this field referring only to one table, these conditions are used for
the other field of the equality join as well and resort may be made to
them in the strategy.
Once the two intermediate results are obtained, they are processed
in parallel, at which stage differences become apparent on account of
the join condition.
The j_viewkey strategy is a class of its own. The
sole use of this strategy is in change operations on join views, where
it is used to check whether a record clearly identified by its
key in the primary table fulfills the join conditions with the old
intermediate result. In this event, the old intermediate result
consists only of combinations of single records taken from different
tables.
This means that a check is run of x records from x tables with
known keys to establish whether together, they form a logical record
of a Join View.
Rather than values, the anticipated result of the check is a
statement indicating whether or not a record of this nature is formed.
 
The Mess_Buffer for a Join Select is structured as follows:
 
  Part 1
 
                                       mstrat_pos
                                       v
 ----------------------------------------------------
 |Part1-|  Output-    |Qualifications-| 3 Strategy- |
 |Header|Stack entries| Stack entries |Stack entries|
 ----------------------------------------------------
         ______________________________|   |    |
         |                                 |    |
         |                         ________|    |
  Part2  |                         |            |
         v                         v            v
 -----------------------------------------------------------
 |values| strategy_info | m_infos | next_joins | kbjoinrec |
 -----------------------------------------------------------
                         100 bytes
 
The three strategy
stack entries refer to the sections indicated in part2
 
-  strategy_info is the strategy description that is also used for
VKB72, search a table. It contains information concerning the primary
file, any second intermediate result that may have to be generated and
the qualifications that can be used for a strategy.
The appearance of that part of the strategy that is variable in
length differs widely, depending on the strategy.
 
-  m_infos :
 
      m_infos = RECORD
            o_tree   : tree_id;
            n_rec_len: int2;
            n_key_len: int2;
            n_maxcnt : int2;
            n_distinct:boolean;
            n_filler : boolean;
      END;
 
The file name, the tree_id  for the new file if already known,
the length of an intermediate-result
record and its key length are all transferred to KB for both the old
intermediate result and the one to be generated.
(If the join yields an unnamed result set, the "intermediate result" of
the last join step that represents the result desired by the user is
entered in the file for unnamed result sets that always exists
and whose tree_id is known ]
An indicator is given for the number of results the join may have and a message
appears indicating whether a distinct check of the results of the join
is to be carried out.
 
-  The appearance of Next_Joins is as follows:
 
        n_j_cnt  : int2;
        n_filler : int2;
                          -----
            jfrom : int2;     |
            jto   : int2;     > n_j_cnt mal
            jlen  : int2;     |
                          -----
 
Next_Joins indicates the number of fields required for the next join
or (if the join step in question is the last), how many fields have to
be transferred to the key of the result record for the subsequent
ORDER BY.
JFROM indicates the position at which the field concerned begins
in the completed result record (which still retains what will be the
key fields in the info section). In this process, JFROM refers to the
part behind the key (this is easier, because the key lengths vary from
join step to join step).
JTO indicates the position in the key (maximum 255), to which this
field is to be copied.
JLEN contains the length of the field. This information can be
provided because the length is always fixed in result records.
 
-  The appearance of kbjoinrec is as follows:
 
        kbjcnt             : int2;
        kbj_r_outer_join   : boolean;
        kbj_l_outer_join   : boolean;
                                   ----
            kboj_recpos : int2;    |
            kboj_len    : char;    > kbjcnt times
            kboj_op     : char;    |
                                   ----
 
Kbjoinrec contains the join conditions that have to be fulfilled.
The information about keyposition and keylength
is required only once per join field, because the
join fields appear at the same position in the key and they are now of
the same length.
KBOJ_RECPOS indicates the position at which the join fields
begin in the two records.
(KBOJ_RECPOS - 4 would be the position in the key)
KBOJ_LE designates the length of the field.
KBOJ_OP states the join condition. In this statement, the old
intermediate result is considered as the left operand and the new
table to be joined to the former is the right operand.
The operators available are
op_eq, op_et, op_gt,
op_lt (stands for '<='),
op_ge (stands for '>=') and
op_ne (stands for '<> ').
 
 
K74_JOIN_SELECT
 
This is the main procedure that implements all the joins between any
two tables. The Mess_Buffer edited by AK has to be transferred
unaltered. The number of results is returned to part1, whereas
SELECT..INTO returns the result record to part2.
 
.CM *-END-* specification -------------------------------
.sp 2
***********************************************************
Description:
 
K74_JOIN_SELECT
 
Independent of strategies, the procedure is called up by n tables
(n-1) times for every Join-Select. It joins two tables in accordance
with strategies specified by AK: the join intermediate result already
existing with the next primary table not yet included in the join.
GETREC is occupied by information concerning the existing join
intermediate result as well as the one to be generated (minfo
component, located between the first and second strategies, 100 bytes
in length), data concerning the fields required for the next join
(njrec component) and data concerning the extended join conditions
(kbjrec component).(GET_JOIN_INFOS).
GETREC.N_POS_S, a record in which the positions of fields in the
new table to be joined are related to their final positions in the
result of the join, is initilized in KB74GET_NEW_POSITIONS.
 
K74GET_NEW_POSITIONS
 
Only such fields as are required for output or for joins are
transferred from a given primary record to a result record,
irrespective of the strategy selected. In the result record, all the
fields are of fixed length and occupy fixed positions one immediately
after the other.
In each join intermediate result generated, all the fields occupy
their final positions in the order in which they were defined by the
user in the output list of the select.
GETREC.N_POS_S is an array, stating the position in a result
record (build out of a record in the primary table)
(ONFROM) from which a field of length
ONLEN has to be brought to a final position (ONTO) of the
join intermediate result.
To this end, the stack entries are searched for output stack
entries (st_output_.. ]. A join changes these entries:
ETYPE indicates that the operation in question is an output
operation.
Such an operation would usually be identified merely by st_output. The
appendix in the name determines the bytes with which a field will be
filled to the specified length.
This normally appears as a character in ecol_tab[ 1 ]. In a join,
however, the final position of the field will appear in elen_var
(= ecol_tab[ 1..2 ]). Nonetheless, all the information should be/has
to be put in one stack entry. Therefore the data is put in one stack
entry.
In KB when N_POS_S is set up this stack entry has its usual outlook
(st_output, ecol_tab[ 1 ] =
blank/'00'h, ecol_tab[ 2 ] empty).
If two fields that follow each other in the final output appear
consecutively in the intermediate result, their lengths are combined
in a single statement. In K72_DO_ROWNO this
results in a rather complicated scan, but under normal circumstances
this combination of lengths saves time.
 
KB74JOIN_LAST_PART
 
Once the desired number of result sets have been found
(k_enough_resultsets), no error message should be issued to the user
(e_ok).
If ROWNO is expected in the output, this value has to be written
into all the result records after the last join step, at which point
the final set of the result has been determined (K72_DO_ROWNO).
This entry cannot be made while the result record is being set up,
because ORDER BY or DISTINCT options could lead to changes in the
sequence of result records.
If more than one result is anticipated or if a subquery is run,
the number of results and the description of the files generated are
inserted in part1 of the mess buffer.
Under normal circumstances, it is not permissible to destroy part2,
because all the join requests use the same part2 assignment.
If only one result is anticipated, it is transferred either from
the buffer or from the file in part2 of the mess buffer, or else an
error message is issued.
Since restrictions concerning the number of results can apply only
at the end of a complete join involving x tables, in which case part2
is no longer needed, part2 can then be used for feedback.
If an error crops up, it will be transferred to the mess buffer.
If applicable, the temporary file generated for the resorted
primary table due to be joined, and the extra event file that was
generated will be deleted or emptied, if it is the file for the
unnamed result set.
 
KB74DO_JOIN
-----------
 
KB74JOIN_INIT (an extra procedure on account of the local variable of the
strategy info type) implements initializations (see appropriate
section for K72_INITIALIZE), in the join cases within K72_SINGLE_SELECT
that are more complex.
Where applicable, INVINDEX states the number of the inversion that
has to be used for joining. FINDING_POSSIBLE states whether it is at
all possible for a record in the table to satisfy the conditions.
No result file is generated for an unnamed result set or a
SELECT ... INTO (in the last join step); instead, a file (itree) that
exists throughout the entire session is used.
If only one result record is anticipated, it is not even
necessaary to use a file. Holding in a buffer not required for other
purposes in the case in hand is sufficient (otherwise needed for
COUNT, MIN etc ].
Since the differences in processing are so large, there is one
procedure per strategy. Shared subprocedures are used.
Since the 'result record' in a join-view check is of no interest,
although it is stored in the file for SELECT..INTO that is always
available, this file has to be emptied.
KB74JOIN_LAST_PART is called up to structure the feedback mess buffer.
 
KB74JOIN_INIT
-------------
 
This procedure is rendered necessary on account of the local variable
STRAT.
In K72_INITIALIZE, SELREC and FINDING_POSSIBLE are occupied. The
strategy instructions are of no significance for the remainder of the
process, because the strategy itself (e.g. j_inv) determines
everything.
 
KB74GET_RIGHT_RECORD
---------------------
 
Determines a record for 'select'; SEL_TYPE indicates the type
of search (mm_direct .. mm_last). The table name, the stopkey,
etc. are determined from the select-rec S. Startkey indicates the
first key and is updated during the search procedure. The result
buffer is located in RESULT_BUF and the record found is in
S.BUF_REC. This record is exclusive-locked via B02SELECT_RECORD if
the message type M_DELETE or M_UPDATE is specified in the message
buffer. Otherwise, it is shared-locked if the state is
IS_CONSISTENT_LOCK or IS_IMPLICIT_LOCK.
 
DIRECT_SEARCH, NEXT_SEARCH, INV_DIRECT_SEARCH
---------------------------------------------
 
When the qualification stack entries are build, entries are also
made for code conversion, if the type of data on the left side of the
operator is not the same as that on the right side. In this process,
it is always the right side that is code-converted. These entries
extend into the output entries for join fields.
The output position of the first join field is 5. If this join field
is used to access the
1st key field or secondary key of the primary table, code
conversion is necessary. It is also
required in forming the right intermediate-result record.
The first part
(code No. = 0 = > no conversion) serves to indicate whether a code-
conversion table has to be used or not, and if so, which one.
If the access is via an inversion, it is also determined whether
the index is DESC, indicating that the value has to be converted.
 
In this event, a number of records from the old intermediate
result are fetched into a buffer and matching records are identified
in the new table to be joined on.
In this process, it is possible that the same records in the
primary table will be accessed more than once, if there are more
records with a join-field value than will fit in one buffer.
Since null <operator> null can never be true, it is not even
necessary to conduct a search for the join-field value NULL.
 
DIRECT_SEARCH
-------------
 
This procedure is called up if the join field of the new primary table
to be joined on is the only key field. If this procedure
has a record from the
old intermediate result, then it also has the join-field value and is
thus in a position to directly access the record in the new table.
As many old intermediate results as will fit are always fetched
into the left buffer in a given loop.
(buffer_limit means that there are more results). The first two bytes
in the left buffer state the buffer's filled length (including these 2
bytes).
The first join-field value (length <= first_jlen) is fetched and,
if necesary, code-converted.
Subsequent blanks and binary nulls are cut off for the search,
because the variable-length primary keys are also stored in this way.
A direct search is conducted for the corresponding record in the
new table to be joined on; a delay may ensue before it is found
because of a locking conflict.
If a record is found with the key that fulfills the conditions for
this table, it is joined to as many records in the left buffer as
possible (JOIN_L_WITH_LEFT_RECORDS).
In this process, lmaxpos is set so that the next time the loop is
run, the first record that has not yet been processed by
JOIN_L_WITH_LEFT_RECORDS can be accessed from lmaxpos.
In the absence of a record with the key value or if the value
fails to fulfill the conditions, all the records with the same join-
field value in the left buffer are skipped. Here, lmaxpos is used; in
this case, it must be = l_currpos.
Once the entire buffer has been processed, the last key in the
buffer is fetched from l_currpos so that it can be used in filling the
next buffer.
 
NEXT_SEARCH
------------
 
This procedure is called up if the join field of the new primary table
to be joined on is the first, but not the only key field. If
this procedure has a
record from the old intermediate result, it also has the join-field
value and in a loop, it is thus in a position to directly access all
the records in the new table that contain this value as their 1st key
value.
STOPKEY is occupied in this procedure in order to notify KB/BD of
the value at which the loop search should terminate. STOPLENGTH states
the number of bytes to be fetched from the join-field value for this
key. The rest is filled with 'FF'h.
As many old intermediate results as will fit are always fetched
into the left buffer in a given loop (buffer_limit means that there
are more). The first two bytes of the left buffer state the buffer's
filled length (including the two bytes).
The first join-field value (length <= first_jlen) is fetched and,
if necessary, code-converted (first_jlen states the larger of the two
join-field lengths, the right field may therefore be smaller).
The current join-field value is inserted in the first part of the
stop key.
In the new table to be joined on, a search is run with first to
find the first corresponding record; on account of a locking
conflict a delay may ensue before it is found.
The search cannot start with next, because the first record may
contain only binary nulls after the first join-field value and in a
comparison, these nulls would give the impression that there was
nothing after the first join-field value.
The remaining searches take place in a loop with next and continue
until the table contains only records that are larger than the stop
key.
If a record that fulfills the conditions for this table is found,
it is joined with as many records from the left buffer as possible
(JOIN_L_WITH_LEFT_RECORDS).
In this process, lmaxpos is set such that the next time a loop is
run, the first record not yet processed by JOIN_L_WITH_LEFT_RECORDS is
accessed from lmaxpos.
Startpos indicates the first record in the left buffer that has
the join-field value currently under consideration, so that this
position can be used as the home position for each right record in
turn.
In the absence of a record having the key value or if none fulfill
the condition (lstartpos = lmaxpos, i.e. no left records are
processed), all the records having the same join-field value in the
left buffer are skipped. lmaxpos is used, and in this case it must be
= l_currpos.
Once the entire buffer has been processed, the last key in the
buffer is fetched from l_currpos so that the next buffer can be
filled.
 
INV_DIRECT_SEARCH
-----------------
 
This procedure is called up if the join field of the new primary table
to be joined on is a single inverted field. If this procedure
has a record from
the old intermediate result, it also has the join-field value and is
thus in a position to directly access all the records that contain
this value in the new table via the inversion list.
As many old intermediate results as will fit are always fetched
into the left buffer in a given loop (buffer_limit means that there
are more results). The first two bytes in the left buffer state the
buffer's filled length (including these 2 bytes)
The first join-field value (length <= first_jlen) is fetched and,
if necessary, code-converted.
Subsequent blanks and binary nulls are cut off for the search,
because the variable-length secondary keys are also stored in
this way.
If a descending index is used, the secondary key still has to
be converted and adjusted to a fixed length, because descending
indices have to operate with keys of fixed length in order to ensure
correct sorting.
In a loop, one buffer after the other is filled with primary keys
from the inversion list (B03GET_INV), with the first key beginning at
position 1.
The buffer is processed in a subsequent loop - each primary key it
contains is fetched in turn and a search is run for the corresponding
record.
A delay may ensue before the record is found, on account of a
locking conflict.
Once a record that fulfills the conditions for this table has been
found, it is joined to as many records in the left buffer as possible
(JOIN_L_WITH_LEFT_RECORDS).
In this process, lmaxpos is set such that the next time a loop is
run, the first record not yet processed by JOIN_L_WITH_LEFT_RECORDS is
accessed from lmaxpos.
Startpos indicates the first record in the left buffer that has
the join-field value currently under consideration, so that this
position can be used as the home position for each right record in
turn.
In the absence of a record having the key value or if none fulfill
the condition (lstartpos = lmaxpos, i.e. no left records are
processed), all the records having the same join-field value in the
left buffer are skipped. lmaxpos is used, and in this case it must be
= l_currpos.
Once the entire buffer has been processed, the last key in the
buffer is fetched from l_currpos so that the next buffer can be
filled.
 
JOIN_L_WITH_LEFT_RECORDS
------------------------
 
The starting point is a filled left buffer that is interesting as of
l_currpos.
The aim is to join a given record in the right buffer with as many
reords from the left buffer as possible.
COMPARE_TWO_RECORDS analyzes whether the two current records
(starting at l_currpos and r_currpos) fulfill the join conditions.
If they do, they are put into a new result record by
BUILD_NEW_REC and added to the result file by K72_ADD_INTO_RESULT or,
if applicable, merely entered after DISTINCT checking.
FIRST_FULFILLED is set if the first join condition between the two
records is fulfilled. This means that there may still be more records
in the left buffer that could fulfill the first join condition and the
remainder as well.
KBJOP = op_ne indicates that an inequality join condition applied.
In this case, rather than stopping, the comparison had to continue
through the records for which FIRST_FULFILLED was not true. In the
case of all the remaining operators, FIRST_FULFILLED cannot be true
again for this right record once it has been false.
 
KB74COMPARE_TWO_RECORDS
------------------------
 
Two precisely defined records having keys with the same configuaration
are examined in order to ascertain whether they fulfill the join
conditions stated in linkrec.
The two corresponding fields are compared for each join condition
in turn; each comparison leads to a fulfilled or unfulfilled
condition, depending on the join operator.
The variable FIRST_FULFILLED is set for the first condition, to
indicate whether there may be other records in the left buffer that
can be joined to the right record, or whether the end of the area of
interest has already been reached.
 
KB74BUILD_NEW_REC
------------------
 
In its info section, the left record already has the appearance the
user desired for the result of the select. Some parts are not yet
occupied, because they can only be filled with the fields of the
tables joined on in join steps yet to come. Furthermore, there are
fields at the end of each result record required only for the interim
join steps and not for output.
The info part of the new record is written into a new buffer.
All the fields are moved from the right record to their positions
in the new result record.
At this stage, the key part of the new result record has to be
filled with the fields from the info part of the new result record
that are of interest for the next join step.
In the case of the last join step in which the key fields of the
new result record are used for the ORDER BY, it is possible that
sorting may take place in descending order. If output to the info part
was normal, the field value has to be converted. This is indicated by
JFROM < 0.
 
.CM *-END-* description ---------------------------------
.sp 2
***********************************************************
 
Structure:
 
.CM *-END-* structure -----------------------------------
.sp 2
**********************************************************
 
.CM -lll-
Code    :
 
 
CONST
      c_get_next               = true;
      c_count_only             = true;
      c_inclusive              = true;
      c_is_right_outer_join    = true;
      c_right_needed           = true;
      c_node_changed           = true;
      c_first_qual             = true;
      c_check_new_rec          = true;
      c_aggr                   = true (* k721function_add      *);
 
TYPE
 
      t_search_rec = RECORD
            sr_lsearchkey         : tgg00_Lkey;
            sr_rsearchkey         : tgg00_Lkey;
            sr_prepare_for_upd    : boolean;
            sr_refused_by_ophase  : boolean;
            sr_res_cnt            : tsp00_Int4;
            sr_error_l            : tgg00_BasisError;
            sr_error_r            : tgg00_BasisError;
            sr_left_tree_pos      : tgg00_FilePos;
            sr_nptr               : tbd_node_ptrs;
            sr_left_min_index     : integer;
            sr_left_last_pno      : tsp00_PageNo;
            sr_lkey_len           : tsp00_Int4;
      END;
 
 
      t_conv_type = RECORD
            ct_st_pos  : tsp00_Int2;
            ct_codeno  : tsp00_Uint1;
            ct_is_desc : boolean;
      END;
 
      conv_arr = ARRAY [ 1..MAX_JOINS_GG04 ] OF t_conv_type;
 
 
(*------------------------------*) 
 
PROCEDURE
      kb74do_join (
            VAR m           : tgg00_MessBlock;
            VAR getrec      : tgg07_get_param;
            VAR selrec      : tgg07_select_param);
 
CONST
      c_put_strat = true;
      c_strat_cnt = true;
 
VAR
      _gg_strategy      : tgg07_StrategyInfo;
      _invindex         : tsp00_Int4;
      _start_sec        : tsp00_Int4;
      _start_microsec   : tsp00_Int4;
      _start_phys_ios   : tsp00_Int4;
      _start_suspends   : tsp00_Int4;
      _start_waits      : tsp00_Int4;
      _invlen           : tsp00_Int4;
      _available        : tsp00_Int4;
      _invroot          : tsp00_PageNo;
      _selfields        : tgg00_SelectFieldsParam;
      _arr_index        : tgg00_RefInfoIndex;
      _aux_error        : tgg00_BasisError;
      _ok               : boolean;
 
BEGIN
(* PTS 1001469 E.Z. *)
IF  ( 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
    BEGIN
    _start_sec      := 1;
    _start_microsec := 0;
    _start_phys_ios := 0;
    _start_suspends := 0;
    _start_waits    := 0;
    END;
(*ENDIF*) 
g04init_select_fields (_selfields, @m.mb_data^.mbp_buf, m.mb_data_size,
      m.mb_work_st, m.mb_work_st_max, m.mb_workbuf, m.mb_workbuf_size,
      m.mb_qual^.msqlmode, @m.mb_fieldlists);
_selfields.sfp_bd_mess_type    := m_select;
_selfields.sfp_result_wanted   := true;
_selfields.sfp_filler2         := false;
_selfields.sfp_acv_addr        := m.mb_trns^.trAcvPtr_gg00;   (* PTS 1121403 E.Z. *)
kb74join_init( m, _gg_strategy, selrec, _invindex, _invroot, _invlen,
      _selfields.sfp_bd_use_stopkey );
IF  _gg_strategy.str_use_clusterIO AND (m.mb_trns^.trClusterIOPtr_gg00 <> NIL)
THEN
    BEGIN
    _selfields.sfp_cluster_info.clust_pIOBuffer_gg00        := m.mb_trns^.trClusterIOPtr_gg00;
    _selfields.sfp_cluster_info.clust_BufferSize_gg00       := m.mb_trns^.trClusterIOSize_gg00;
    _selfields.sfp_cluster_info.clust_bDoClusteredRead_gg00 := true;
    END;
IF  (m.mb_trns^.trError_gg00 = e_ok) AND
    (m.mb_trns^.trIndex_gg00 = cgg_nil_transindex)
THEN
    m.mb_trns^.trError_gg00 := e_nil_transindex;
(*ENDIF*) 
IF  ( m.mb_trns^.trError_gg00 = e_ok )
THEN
    BEGIN
&   ifdef trace
    k720trace_selrec( m, selrec );
&   endif
    IF  bd998IsExtendedTempFile (m.mb_trns^, selrec.selr.selr_resf_id)
        AND (bd998GetExtendedTempFileType (m.mb_trns^,
        selrec.selr.selr_resf_id) = ttfnInto_egg00 )
    THEN
        BEGIN
        IF  ( selrec.selr.selr_resf_id.fileRoot_gg00 = NIL_PAGE_NO_GG00 )
        THEN
            a101_CreateGroupedTempFile( m.mb_trns^, selrec.selr.selr_resf_id,
                  bd998GetExtendedTempFileType( m.mb_trns^,
                  selrec.selr.selr_resf_id));
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        IF  (( selrec.selr.selr_resf_id.fileRoot_gg00 = NIL_PAGE_NO_GG00 ) AND
            (( selrec.selr.selr_countresult = 0 ) OR selrec.selr.selr_UNION_ALL_append ) AND
            ( hsCreateFile_egg00 in selrec.selr.selr_resf_id.fileHandling_gg00 ))
        THEN
            a101_CreateGroupedTempFile( m.mb_trns^, selrec.selr.selr_resf_id,
                  bd998GetExtendedTempFileType( m.mb_trns^,
                  selrec.selr.selr_resf_id));
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( m.mb_trns^.trError_gg00 = e_ok )
    THEN
        BEGIN
        IF  ( selrec.selr.selr_finding_poss )
        THEN
            BEGIN
            kb74_join( m, _gg_strategy, _invindex, _invroot, _invlen,
                  getrec, selrec, _selfields );
            (* PTS 1001518 E.Z. *)
            IF  ( _start_sec > 0 )
            THEN
                BEGIN
                IF  (m.mb_trns^.trBdTcachePtr_gg00 <> NIL)
                THEN
                    IF  (_gg_strategy.str_strategy in [strat_join_all_inv_equal,
                        strat_join_inv_range, strat_join_inv])
                        AND (selrec.selr.selr_inv_id.fileRoot_gg00
                        <> NIL_PAGE_NO_GG00)
                        AND (selrec.selr.selr_inv_id.fileTfn_gg00
                        = tfnMulti_egg00)
                    THEN
                        b21mp_root_put (m.mb_trns^.trBdTcachePtr_gg00,
                              selrec.selr.selr_inv_id.fileRoot_gg00)
                    ELSE
                        IF  (m.mb_qual^.mtree.fileRoot_gg00
                            <> NIL_PAGE_NO_GG00)
                        THEN
                            b21mp_root_put (m.mb_trns^.trBdTcachePtr_gg00,
                                  m.mb_qual^.mtree.fileRoot_gg00);
                        (*ENDIF*) 
                    (*ENDIF*) 
                (*ENDIF*) 
                k720ref_statistic (_arr_index, _gg_strategy);
                k720monitor (m.mb_trns^, _selfields, _start_sec,
                      _start_microsec, _start_phys_ios, _start_suspends,
                      _start_waits, c_put_strat, _arr_index, c_strat_cnt);
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  ( m.mb_trns^.trError_gg00 = e_enough_resultsets )
        THEN
            m.mb_trns^.trError_gg00 := e_ok;
        (*ENDIF*) 
        IF  ( selrec.selr.selr_join_with_func )
        THEN
            BEGIN
            IF  ( m.mb_trns^.trError_gg00 = e_ok )
            THEN
                BEGIN
                selrec.selr_selectbuffer.result.keylen := selrec.selr.selr_res_keyl;
                selrec.selr_selectbuffer.result.len    :=
                      getrec.gi_result_info.n_res_rec_len;
                m.mb_qual^.mqual_pos        := m.mb_qual^.mresqual_pos;
                m.mb_qual^.mqual_cnt        := m.mb_qual^.mresqual_cnt;
                m.mb_qual^.mresqual_pos     := 0;
                m.mb_qual^.mresqual_cnt     := 0;
                selrec.selr.selr_countresult := selrec.selr.selr_group_count;
                IF  ( selrec.selr.selr_countresult > 0 )
                THEN
                    BEGIN
                    IF  ( selrec.selr.selr_call_avg <> sfh_none)
                    THEN
                        k721do_avg ( m, selrec )
                    ELSE
                        BEGIN
                        IF  ( selrec.selr.selr_call_later_out )
                        THEN
                            BEGIN
                            IF  ( NOT selrec.selr.selr_one_result )
                            THEN
                                BEGIN
                                selrec.selr.selr_invkey.len  := RESCNT_MXGG04;
                                selrec.selr.selr_invkey.k[1] := chr(0);
                                selrec.selr.selr_invkey.k[2] := chr(0);
                                selrec.selr.selr_invkey.k[3] := chr(0);
                                selrec.selr.selr_invkey.k[4] := chr(1);
                                b07cget_record( m.mb_trns^,
                                      selrec.selr.selr_resf_id,
                                      selrec.selr.selr_invkey,
                                      selrec.selr_selectbuffer.lbuf );
                                IF  ( m.mb_trns^.trError_gg00 = e_key_not_found ) OR
                                    ( m.mb_trns^.trError_gg00 = e_ok )
                                THEN
                                    BEGIN
                                    m.mb_trns^.trError_gg00 := e_ok;
                                    b07cdel_record( m.mb_trns^,
                                          selrec.selr.selr_resf_id,
                                          selrec.selr.selr_invkey );
                                    IF  ( m.mb_trns^.trError_gg00 = e_ok )
                                    THEN
                                        BEGIN
                                        k721call_later_output( m,
                                              selrec.selr_selectbuffer.lbuf,
                                              selrec.selr.selr_res_keyl );
                                        b07cadd_record( m.mb_trns^,
                                              selrec.selr.selr_resf_id,
                                              selrec.selr_selectbuffer.lbuf );
                                        END;
                                    (*ENDIF*) 
                                    END;
                                (*ENDIF*) 
                                END
                            ELSE
                                k721call_later_output (m, selrec.
                                      selr_selectbuffer.lbuf,
                                      selrec.selr.selr_res_keyl);
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    END
                ELSE
                    (* selr.selr_countresult = 0 *)
                    BEGIN
                    IF  ((( selrec.selr.selr_distinct <> no_distinct ) AND
                        (selrec.selr.selr_res_keyl = RESCNT_MXGG04 + HASHVAL_MXGG04 ))
                        OR
                        ( selrec.selr.selr_call_later_out )
                        OR
                        ( selrec.selr.selr_res_keyl = RESCNT_MXGG04 )
                        OR
                        (bd998IsExtendedTempFile (m.mb_trns^,
                        selrec.selr.selr_resf_id) AND
                        (bd998GetExtendedTempFileType (m.mb_trns^,
                        selrec.selr.selr_resf_id) = ttfnSubquery_egg00) ))
                        (* an empty grouped table results in error 100 *)
                    THEN
                        BEGIN
                        selrec.selr.selr_keyl := selrec.selr_selectbuffer.result.keylen;
                        selrec.selr.selr_recl := selrec.selr_selectbuffer.result.len;
                        k721null_result (m, selrec, _selfields,
                              selrec.selr.selr_countresult,
                              selrec.selr.selr_call_later_out, selrec.selr.selr_res_keyl);
                        IF  ( m.mb_trns^.trError_gg00 = e_enough_resultsets )
                        THEN
                            m.mb_trns^.trError_gg00 := e_ok;
                        (*ENDIF*) 
                        END
                    ELSE
                        selrec.selr.selr_one_result := false;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                IF  ( selrec.selr.selr_one_result AND ( selrec.selr.selr_maxresult <> 0 ) AND
                    ( m.mb_trns^.trError_gg00 = e_ok ))
                THEN
                    BEGIN
&                   ifdef trace
                    t01name( kb, 'lbuf --> result   ' );
&                   endif
                    SAPDB_PascalMove ('VKB74 ',   1,    
                          sizeof (selrec.selr_selectbuffer.lbuf),
                          sizeof (selrec.selr_selectbuffer.result.buf),
                          @selrec.selr_selectbuffer.lbuf, cgg_rec_key_offset + 1,
                          @selrec.selr_selectbuffer.result.buf, cgg_rec_key_offset + 1,
                          selrec.selr_selectbuffer.result.len,
                          m.mb_trns^.trError_gg00);
&                   ifdef trace
                    t01buf(kb, selrec.selr_selectbuffer.result.recBuf_gg00, 1,
                          selrec.selr_selectbuffer.result.len );
&                   endif
                    b07cadd_record (m.mb_trns^, selrec.selr.selr_resf_id,
                          selrec.selr_selectbuffer.result.recBuf_gg00);
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            _aux_error := m.mb_trns^.trError_gg00;
            IF  ( selrec.selr.selr_dis_file_cnt > 0 )
            THEN
                a101_DestroyGroupedTempFiles (m.mb_trns^,
                      ttfnDistinct_egg00,
                      -1, -1,
                      selrec.selr.selr_distinct_id.fileName_gg00);
            (*ENDIF*) 
            IF  ( _aux_error <> e_ok )
            THEN
                m.mb_trns^.trError_gg00 := _aux_error;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    m.mb_qual^.mr_pagecnt := 1;
    IF  ( selrec.selr.selr_write_rownum AND
        ( m.mb_trns^.trError_gg00 = e_ok) AND ( selrec.selr.selr_countresult > 0 ))
    THEN
        k74rowno_position( m, getrec, selrec );
    (*ENDIF*) 
    END
ELSE
    BEGIN
    m.mb_qual_len  := 0;
    m.mb_data_len  := 0
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74get_join_infos (
            VAR m      : tgg00_MessBlock;
            VAR getrec : tgg07_get_param);
 
VAR
      _j, _k : integer;
 
BEGIN
(* get getrec.gi_result_info *)
SAPDB_PascalMove ('VKB74 ',   2,    
      m.mb_strat_size, sizeof(getrec.gi_result_info),
      @m.mb_strat^, m.mb_st^[ m.mb_qual^.mstrat_pos +
      cgg07_ResultShiftInfo_Offset ].epos - sizeof(getrec.gi_result_info),
      @getrec.gi_result_info, 1, sizeof(getrec.gi_result_info),
      m.mb_trns^.trError_gg00);
&ifdef trace
IF  t01trace( kb ) OR t01trace( ak_join )
THEN
    BEGIN
    t01name(td_always, 'gi_result_info :  ');
    t01treeid (td_always, 'o_tree      ', getrec.gi_result_info.o_tree );
    t01p2int4 (td_always, 'n_rec_len   ', getrec.gi_result_info.n_rec_len,
          'n_key_len   ', getrec.gi_result_info.n_key_len);
    t01int4 (td_always, 'n_res_rec_le', getrec.gi_result_info.n_res_rec_len);
    t01sname(td_always, '------------');
    END;
&endif
(* get getrec.gi_copy_info *)
(*ENDIF*) 
SAPDB_PascalMove ('VKB74 ',   3,    
      m.mb_strat_size, sizeof (getrec.gi_copy_info),
      @m.mb_strat^, m.mb_st^[ m.mb_qual^.mstrat_pos +
      cgg07_ResultShiftInfo_Offset ].epos,
      @getrec.gi_copy_info, 1, m.mb_st^[ m.mb_qual^.mstrat_pos +
      cgg07_ResultShiftInfo_Offset ].elen_var,
      m.mb_trns^.trError_gg00);
&ifdef trace
IF  t01trace( kb ) OR t01trace( ak_join )
THEN
    BEGIN
    t01name(td_always, 'cols to be copied ');
    t01sname(td_always, 'gi_copy_inf:');
    t01int4 (td_always, 'n_j_cnt     ', getrec.gi_copy_info.n_j_cnt);
    FOR _j := 1 TO getrec.gi_copy_info.n_j_cnt DO
        BEGIN
        t01p2int4 (td_always, 'jfrom       ', getrec.gi_copy_info.n_j_arr[ _j ].jfrom,
              'jlen        ', getrec.gi_copy_info.n_j_arr[ _j ].jlen);
        t01int4 (td_always, 'jto         '  , getrec.gi_copy_info.n_j_arr[ _j ].jto);
        END;
    (*ENDFOR*) 
    t01sname(td_always, '------------');
    END;
&endif
(* get getrec.gi_linkrec *)
(*ENDIF*) 
SAPDB_PascalMove ('VKB74 ',   4,    
      m.mb_strat_size, sizeof (getrec.gi_linkrec),
      @m.mb_strat^, m.mb_st^[ m.mb_qual^.mstrat_pos + cgg07_JoinInfo_Offset ].epos,
      @getrec.gi_linkrec, 1, m.mb_st^[ m.mb_qual^.mstrat_pos +
      cgg07_JoinInfo_Offset ].elen_var,
      m.mb_trns^.trError_gg00);
&ifdef trace
IF  t01trace( kb ) OR t01trace( ak_join )
THEN
    BEGIN
    t01sname( td_always, 'gi_linkrec :');
    a683trace_kbjrec( td_always, getrec.gi_linkrec);
    END;
&endif
(*ENDIF*) 
IF  ( getrec.gi_linkrec.kbjr_jpath = 0 )
THEN
    BEGIN
    (* no join transition, single table strategy *)
&   ifdef trace
    t01name(kb, 'adjust kbjr_jpath ');
&   endif
    getrec.gi_linkrec.kbjr_jpath := 1;
    END;
(*ENDIF*) 
m.mb_strat_len  := m.mb_st^[ m.mb_qual^.mstrat_pos +
      cgg07_ResultShiftInfo_Offset ].epos - sizeof(getrec.gi_result_info) - 1;
(* record counter for outerjoin via vkb71 (or outerjoin) *)
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74get_new_positions (
            VAR m        : tgg00_MessBlock;
            VAR getrec   : tgg07_get_param);
 
VAR
      _i              : integer;
      _stops          : integer;
      _poscnt         : integer;
      _is_right_table : boolean;
      _pack_it        : boolean;
      _const_expr_fnd : boolean;
      _column_fnd     : boolean;
&     ifdef trace
      _ln             : tsp00_Line;
      _lnln           : integer;
&     endif
 
BEGIN
(* search columns which have to be transfered from   *)
(* i.th temporary result --> i+1.th temporary result *)
_pack_it        := NOT getrec.gi_linkrec.kbjr_left_oj;
_i              := m.mb_qual^.mqual_pos;
(* calculate last output stack entry *)
_stops          := m.mb_st^[ m.mb_qual^.mqual_pos ].epos + m.mb_qual^.mqual_pos - 1;
_is_right_table := true;
_poscnt         := 0;
getrec.gi_n_pos_s.lposcnt := 0;
getrec.gi_n_pos_s.rposcnt := 0;
&IFDEF TRACE
IF  t01trace( kb ) OR t01trace( ak_join )
THEN
    BEGIN
    t01sname(td_always, 'k74-mblock 1');
    t01qual (td_always, m.mb_qual^);
    t01sname(td_always, '------------');
    t01int4 (td_always, 'ultim stop  ', _stops);
    END;
&ENDIF
(*ENDIF*) 
REPEAT
    WHILE (m.mb_trns^.trError_gg00 = e_ok) AND (_i < _stops) DO
        BEGIN
        _const_expr_fnd := false;
        _column_fnd     := false;
        (* step to next st_join_output *)
        WHILE (_i < _stops) AND (m.mb_st^[ _i ].etype <> st_output_join) DO
            BEGIN
            (* on the way collect info *)
            IF  (m.mb_st^[ _i ].etype = st_rowno)
            THEN
                _pack_it := false
            ELSE
                IF  (m.mb_st^[ _i ].etype = st_value) AND (NOT _column_fnd)
                THEN
                    _const_expr_fnd := _is_right_table AND getrec.gi_linkrec.kbjr_left_oj
                ELSE
                    IF  (m.mb_st^[ _i ].etype IN [ st_fixkey, st_varkey,
                        st_fixcol, st_varcol, st_fixinv, st_varinv,
                        st_fixprimkey, st_varprimkey, st_varlongchar ])
                    THEN
                        BEGIN
                        _column_fnd     := true;
                        _const_expr_fnd := false;
                        END
                    ELSE
                        IF  (m.mb_st^[ _i ].etype = st_output)
                        THEN
                            BEGIN
                            _column_fnd     := false;
                            _const_expr_fnd := false;
                            END;
                        (*ENDIF*) 
                    (*ENDIF*) 
                (*ENDIF*) 
            (*ENDIF*) 
            _i := succ(_i);
            END;
        (*ENDWHILE*) 
&       ifdef trace
        t01int4 (kb, 'stop on     ', _stops);
        t01p2bool (kb, 'col found   ', _column_fnd,
              'constexp fnd', _const_expr_fnd);
&       endif
        IF  (_i < _stops)
        THEN
            BEGIN
            IF  (_poscnt = 0)
            THEN
                (* initializing run after first st_join_output found *)
                BEGIN
&               ifdef trace
                t01sname(kb, 'initialize  ');
&               endif
                _poscnt := succ (_poscnt);
                WITH getrec.gi_n_pos_s.posarr[ _poscnt ] DO
                    BEGIN
                    onfrom  := m.mb_st^[ _i ].epos;
                    onto    := m.mb_st^[ _i ].ecol_pos;
                    onlen   := m.mb_st^[ _i ].elen_var;
                    (* h.b. PTS 1104165 *)
                    IF  _const_expr_fnd
                    THEN
                        onfrom := onfrom * -1;
                    (*ENDIF*) 
                    END;
                (*ENDWITH*) 
                END
            ELSE
                BEGIN
                WITH getrec.gi_n_pos_s.posarr[ _poscnt ] DO
                    IF  _pack_it AND
                        (m.mb_st^[ _i ].eop <> op_outer_join)      AND
                        ((onfrom + onlen = m.mb_st^[ _i ].epos)    AND
                        ( onto   + onlen = m.mb_st^[ _i ].ecol_pos)   )
                    THEN
                        BEGIN
                        onlen := onlen + m.mb_st^[ _i ].elen_var
                        END
                    ELSE
                        BEGIN
                        _poscnt := succ (_poscnt);
                        WITH getrec.gi_n_pos_s.posarr[ _poscnt ] DO
                            BEGIN
                            onfrom  := m.mb_st^[ _i ].epos;
                            onto    := m.mb_st^[ _i ].ecol_pos;
                            onlen   := m.mb_st^[ _i ].elen_var;
                            IF  _const_expr_fnd (* h.b. PTS 1104484 *)
                            THEN
                                onfrom := onfrom * -1;
                            (*ENDIF*) 
                            END;
                        (*ENDWITH*) 
                        END;
                    (*ENDIF*) 
                (*ENDWITH*) 
                END;
            (*ENDIF*) 
&           IFDEF TRACE
            t01stackentry (kb, m.mb_st^[ _i ], _i);
&           ENDIF
            IF  _is_right_table
            THEN
                (* reset stack entry *)
                BEGIN
                m.mb_st^[ _i ].etype    := st_output;
                m.mb_st^[ _i ].ecol_pos := 0;
                IF  (m.mb_st^[ _i - 1 ].eop_out  = op_o_output_hold) AND
                    (m.mb_st^[ _i - 1 ].etype in [ st_output,
                    st_output_build_rec ]) AND
                    (m.mb_st^[ _i - 1 ].epos = m.mb_st^[ _i ].epos)
                THEN
                    BEGIN
                    IF  (m.mb_st^[ m.mb_qual^.mqual_pos ].etype = st_jump_output)
                    THEN
                        m.mb_st^[ m.mb_qual^.mqual_pos ].epos :=
                              m.mb_st^[ m.mb_qual^.mqual_pos ].epos - 1;
                    (*ENDIF*) 
                    ;
                    (* remove stack entry *)
                    SAPDB_PascalOverlappingMove ('VKB74 ',   5,    
                          m.mb_qual^.mst_max * STACK_ENTRY_MXGG00,
                          m.mb_qual^.mst_max * STACK_ENTRY_MXGG00,
                          @m.mb_st^, (_i - 1) * STACK_ENTRY_MXGG00 + 1,
                          @m.mb_st^, (_i - 2) * STACK_ENTRY_MXGG00 + 1,
                          (m.mb_qual^.mfirst_free - _i) * STACK_ENTRY_MXGG00,
                          m.mb_trns^.trError_gg00);
                    m.mb_qual^.mqual_cnt    := pred (m.mb_qual^.mqual_cnt);
                    m.mb_qual^.mstrat_pos   := pred (m.mb_qual^.mstrat_pos);
                    _stops        := pred(_stops);
&                   IFDEF TRACE
                    t01name(kb, 'remove stack entry');
                    t01qual(kb, m.mb_qual^);
&                   ENDIF
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        _i := succ (_i);
        END;
    (*ENDWHILE*) 
    IF  (_i >= _stops)
    THEN
        BEGIN
        IF  _is_right_table
        THEN
            BEGIN
            _pack_it        := false;
            _is_right_table := false;
            (* all columns from i.th base table found *)
            getrec.gi_n_pos_s.rposcnt := _poscnt;
            (* step over needed columns for next join step      *)
            (* colunms are from i.th temporary result           *)
            (* and have to be moved to i+1.th temporary result  *)
            _stops          := m.mb_qual^.mfirst_free;
            _i              := m.mb_qual^.mstrat_pos + 3;
&           ifdef trace
            t01int4(kb, 'new start   ', _i);
            t01int4(kb, 'new stop    ', _stops);
            t01sname(kb, 'invisible   ');
&           endif
            END
        ELSE
            getrec.gi_n_pos_s.lposcnt := _poscnt - getrec.gi_n_pos_s.rposcnt;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
UNTIL
    (_i >= _stops) OR (m.mb_trns^.trError_gg00 <> e_ok);
(*ENDREPEAT*) 
;
&IFDEF TRACE
IF  t01trace( kb ) OR t01trace( ak_join )
THEN
    BEGIN
    t01sname(td_always, 'k74-mblock 2');
    t01qual (td_always, m.mb_qual^);
    t01line_c60(td_always,
          'move from i-1. temp result -> i.temp result                 ');
    t01int4 (td_always, 'lposcnt     ', getrec.gi_n_pos_s.lposcnt);
    FOR _i := getrec.gi_n_pos_s.rposcnt + 1 TO  getrec.gi_n_pos_s.rposcnt +
          getrec.gi_n_pos_s.lposcnt DO
        BEGIN
        t01p2int4 (td_always, 'onfrom      ', getrec.gi_n_pos_s.posarr[ _i ].onfrom,
              'onlen       ', getrec.gi_n_pos_s.posarr[ _i ].onlen);
        t01int4 (td_always, 'onto        ', getrec.gi_n_pos_s.posarr[ _i ].onto);
        t01init_line( _ln, _lnln, '            ' );
        g17int4to_line( getrec.gi_n_pos_s.posarr[ _i ].onto, false, 4, _lnln+1, _ln );
        _lnln := _lnln + 5;
        g17sname_to_line('-           ', _lnln, _ln );
        g17int4to_line( getrec.gi_n_pos_s.posarr[ _i ].onto +
              getrec.gi_n_pos_s.posarr[ _i ].onlen,
              false, 4, _lnln+1, _ln );
        _lnln := _lnln + 5;
        g17sname_to_line(' filled     ', _lnln, _ln );
        t01line(td_always, _ln);
        END;
    (*ENDFOR*) 
    t01line_c60(td_always,
          'move from i. base table --> i. temp result                  ');
    t01int4 (td_always, 'rposcnt     ', getrec.gi_n_pos_s.rposcnt);
    FOR _i := 1 TO getrec.gi_n_pos_s.rposcnt DO
        BEGIN
        t01p2int4 (td_always, 'onfrom      ', getrec.gi_n_pos_s.posarr[ _i ].onfrom,
              'onlen       ', getrec.gi_n_pos_s.posarr[ _i ].onlen);
        t01int4 (td_always, 'onto        ', getrec.gi_n_pos_s.posarr[ _i ].onto);
        t01init_line( _ln, _lnln, '            ' );
        g17int4to_line( getrec.gi_n_pos_s.posarr[ _i ].onto, false, 4, _lnln+1, _ln );
        _lnln := _lnln + 5;
        g17sname_to_line('-           ', _lnln, _ln );
        g17int4to_line( getrec.gi_n_pos_s.posarr[ _i ].onto +
              getrec.gi_n_pos_s.posarr[ _i ].onlen,
              false, 4, _lnln+1, _ln );
        _lnln := _lnln + 5;
        g17sname_to_line(' filled     ', _lnln, _ln );
        t01line(td_always, _ln);
        END;
    (*ENDFOR*) 
    END;
&ENDIF
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74join_init (
            VAR m           : tgg00_MessBlock;
            VAR gg_strategy : tgg07_StrategyInfo;
            VAR selrec      : tgg07_select_param;
            VAR invindex    : integer;
            VAR invroot     : tsp00_PageNo;
            VAR invlen      : tsp00_Int4;
            VAR use_stopkey : boolean);
 
BEGIN
k720_initialize( m, selrec, gg_strategy, use_stopkey );
IF  (m.mb_trns^.trError_gg00 = e_ok) (* h.b. PTS 1104929 *)
THEN
    BEGIN
    IF  ( gg_strategy.str_strategy in a70glob_join_inv_strats )
    THEN
        BEGIN
        invroot  := gg_strategy.str_join_multfields.sjmf_invroot;
        invindex := gg_strategy.str_join_multfields.sjmf_index_no;
        invlen   := gg_strategy.str_join_multfields.sjmf_invlen;
        END;
    (*ENDIF*) 
    IF  ( ssSubquery_egg00 in m.mb_qual^.mstack_state )
    THEN
        k720_test_subquery ( m.mb_trns^, m.mb_data^, m.mb_data_size,
              m.mb_qual^.mstack_desc, selrec.selr_selectbuffer.buf_rec);
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74init_join (
            VAR m               : tgg00_MessBlock;
            VAR getrec          : tgg07_get_param;
            VAR selrec          : tgg07_select_param;
            VAR strat_maxresult : tsp00_Int4;
            VAR stenum          : tgg07_StratEnum);
 
VAR
      _strat_ptr : ^tgg07_StrategyInfo;
 
BEGIN
selrec.selr.selr_last_join := ( m.mb_type2 = mm_join_with_last_tab );
m.mb_type2            := mm_with_join;
selrec.selr.selr_l_currpos    := 0;
selrec.selr.selr_l_endpos     := 0;
selrec.selr.selr_l_defbyte_pos:= -1;
selrec.selr.selr_first_jlen   := 0;
selrec.selr.selr_file_to_drop := false;
selrec.selr.selr_join_with_func := false;
selrec.selr.selr_id_outer_join:= b01niltree_id;
m.mb_trns^.trRteCommPtr_gg00^.file_root       := NIL_PAGE_NO_GG00;
m.mb_trns^.trRteCommPtr_gg00^.file_record_cnt := 1;
(* restore getrec.gi_result_info, getrec.gi_copy_info, getrec.linkrec *)
k74get_join_infos (m, getrec);
IF  ( m.mb_trns^.trError_gg00 = e_ok )
THEN
    BEGIN
&   IFDEF TRACE
    t01bool (kb, 'l_outer_join', getrec.gi_linkrec.kbjr_left_oj);
    t01bool (kb, 'r_outer_join', getrec.gi_linkrec.kbjr_right_oj);
    t01int4 (kb, 'ecol_tab(1) ',
          ord(m.mb_st^[ m.mb_qual^.mqual_pos ].ecol_tab[ 1 ]));
&   ENDIF
    (* create getrec.gi_n_pos_s *)
    k74get_new_positions( m, getrec );
    _strat_ptr := @m.mb_strat^[ m.mb_st^[ m.mb_qual^.mstrat_pos ].epos ];
    stenum                   := _strat_ptr^.str_strategy;
    selrec.selr.selr_write_rownum := _strat_ptr^.str_use_rowno;
    strat_maxresult          := _strat_ptr^.str_rowno;
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74join_last_part (
            VAR m             : tgg00_MessBlock;
            VAR getrec        : tgg07_get_param;
            VAR selrec        : tgg07_select_param;
            strat_maxresult   : tsp00_Int4;
            destroy_into_file : boolean);
 
VAR
      _aux_error     : tgg00_BasisError;
      _set_result    : tgg00_BdSetResultRecord;
      _destroy_res   : boolean;
      _res           : tsp00_NumError;
      _left_tree_pos : tgg00_FilePos;
 
BEGIN
&IFDEF TRACE
t01int4        (kb, 'countresult ',selrec.selr.selr_countresult);
t01basis_error (kb, 'm trError  1', m.mb_trns^.trError_gg00);
t01bool (kb, 'destro into ', destroy_into_file );
&ENDIF
_destroy_res := false;
IF  ( m.mb_trns^.trError_gg00 = e_enough_resultsets )
THEN
    BEGIN
    m.mb_trns^.trError_gg00 := e_ok;
    IF  ( strat_maxresult >= cgg04_valid_rowno )
    THEN
        m.mb_trns^.trWarning_gg00 := m.mb_trns^.trWarning_gg00 +
              [ warn0_exist, warn12_rowno_used ];
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  ( m.mb_trns^.trError_gg00 in [ e_no_next_record, e_no_prev_record ] )
THEN
    m.mb_trns^.trError_gg00 := e_ok;
(*ENDIF*) 
;
IF  ( m.mb_trns^.trError_gg00 = e_ok ) AND ( m.mb_type <> m_return_result )
THEN
    BEGIN
&   ifdef trace
    t01name(kb, 'result handling   ');
&   endif
    IF  (( selrec.selr.selr_maxresult > 0 ) OR ( selrec.selr.selr_subquery ))
        (*  subquery with ! file *)
        (* i.e. not 'SELECT INTO' or cgg04_subquery_one_record *)
    THEN
        BEGIN
        m.mb_struct   := mbs_result;
        m.mb_type     := m_return_result;
        m.mb_type2    := mm_file;
        _destroy_res := ( selrec.selr.selr_countresult = 0 ) AND
              ( NOT selrec.selr.selr_UNION_ALL_append );
        selrec.selr.selr_resf_id.fileResultSite_gg00 := cgg_zero_c2;
        m.mb_qual^.mr_restree := selrec.selr.selr_resf_id;
        m.mb_qual_len         := MB_PART1_HEAD_MXGG00 + MB_PART1_RETURN_MXGG00;
        IF  ( selrec.selr.selr_UNION_ALL_append )
        THEN
            BEGIN
            selrec.selr.selr_key_cnt_offs := selrec.selr.selr_countresult;
&           ifdef TRACE
            t01int4 (kb, 'countresult4', selrec.selr.selr_countresult);
            t01int4 (kb, 'key_cnt_offs', selrec.selr.selr_key_cnt_offs);
&           endif
            s41p4int( m.mb_qual^.mr_keycnt, 2, selrec.selr.selr_key_cnt_offs, _res );
            m.mb_qual^.mr_keycnt[ 1 ] := csp_defined_byte;
            IF  ( so_INTERSECT in selrec.selr.selr_set_operator )
            THEN
                BEGIN
                IF  ( m.mb_trns^.trError_gg00 = e_ok )
                THEN
                    b01move_filecontent (m.mb_trns^,
                          selrec.selr.selr_intersect_id, selrec.selr.selr_resf_id);
                (*ENDIF*) 
                _aux_error := m.mb_trns^.trError_gg00;
                a101_DestroyGroupedTempFile (m.mb_trns^,
                      selrec.selr.selr_intersect_id);
                IF  ( _aux_error <> e_ok )
                THEN
                    m.mb_trns^.trError_gg00 := _aux_error;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  ( selrec.selr.selr_last_join )
        THEN
            m.mb_data_len  := 0
        (*ENDIF*) 
        END
    ELSE
        (* selr.selr_maxresult = 0 AND NOT selr.selr_subquery *)
        (* i.e. SELECT INTO and NOT cgg04_subquery_one_record *)
        BEGIN
        m.mb_qual_len                       := MB_PART1_HEAD_MXGG00 + MB_PART1_RETURN_MXGG00;
        m.mb_qual^.mr_restree               := selrec.selr.selr_resf_id;
        m.mb_qual^.mr_restree.fileRoot_gg00 := NIL_PAGE_NO_GG00;
        IF  ( selrec.selr.selr_one_result )
        THEN
            BEGIN
            IF  ( selrec.selr.selr_countresult = 0 )
            THEN
                BEGIN
                (*m.mb_trns^.trError_gg00 := e_no_next_record;*)
                m.mb_data_len  := 0
                END
            ELSE
                BEGIN
&               ifdef trace
                t01name( kb, 'lbuf --> mb_data  ' );
&               endif
                SAPDB_PascalMove ('VKB74 ',   6,    
                      sizeof(selrec.selr_selectbuffer.lbuf), m.mb_data_size,
                      @selrec.selr_selectbuffer.lbuf, 1, @m.mb_data^.mbp_4kbuf,
                      1, getrec.gi_result_info.n_res_rec_len,
                      m.mb_trns^.trError_gg00);
                m.mb_struct    := mbs_result;
                m.mb_type      := m_return_result;
                m.mb_type2     := mm_nil;
                m.mb_data_len  := getrec.gi_result_info.n_res_rec_len;
                END;
            (*ENDIF*) 
            END
        ELSE
            (* more than one record *)
            BEGIN
            IF  ( selrec.selr.selr_countresult > 0 )
            THEN
                BEGIN
                _left_tree_pos.tpsPno_gg00   := NIL_PAGE_NO_GG00;
                selrec.selr.selr_invkey.len       := 0;
                _set_result.bd_key_check_len := 0;
                _set_result.bd_max_rec_cnt   := 1;
                _set_result.bd_max_fill_len  := mxsp_buf;
                _set_result.bd_next          := true;
                _set_result.bd_drop_page     := false;
                ;
                b07cnext_record (m.mb_trns^, selrec.selr.selr_resf_id,
                      selrec.selr.selr_invkey, _set_result, _left_tree_pos,
                      m.mb_data^.mbp_4kbuf);
                IF  ( m.mb_trns^.trRteCommPtr_gg00^.to_cancel )
                THEN
                    m.mb_trns^.trError_gg00 := e_cancelled;
                (*ENDIF*) 
                IF  (( m.mb_trns^.trError_gg00 = e_key_not_found ) OR
                    ( m.mb_trns^.trError_gg00 = e_ok ))
                THEN
                    BEGIN
                    m.mb_struct   := mbs_result;
                    m.mb_type     := m_return_result;
                    m.mb_type2    := mm_nil;
                    m.mb_data_len := getrec.gi_result_info.n_res_rec_len;
                    selrec.selr.selr_invkey.len := m.mb_data^.mbp_keylen;
                    SAPDB_PascalMove ('VKB74 ',   7,    
                          m.mb_data_size, sizeof(selrec.selr.selr_invkey.k),
                          @m.mb_data^.mbp_4kbuf, cgg_rec_key_offset + 1,
                          @selrec.selr.selr_invkey.k, 1, selrec.selr.selr_invkey.len,
                          m.mb_trns^.trError_gg00);
                    IF  ( m.mb_trns^.trError_gg00 <> e_move_error )
                    THEN
                        BEGIN
                        b07cdel_record (m.mb_trns^, selrec.selr.selr_resf_id,
                              selrec.selr.selr_invkey);
                        m.mb_trns^.trError_gg00 := e_ok;
                        END;
                    (*ENDIF*) 
                    END
                ELSE
                    BEGIN
                    m.mb_data_len  := 0
                    END;
                (*ENDIF*) 
                END
            ELSE
                (* selr.selr_countresult = 0 *)
                BEGIN
                (*m.mb_trns^.trError_gg00 := e_no_next_record;*)
                m.mb_struct   := mbs_result;
                m.mb_type     := m_return_result;
                m.mb_type2    := mm_nil;
                m.mb_data_len := 0;
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    s41p4int( m.mb_qual^.mr_resnum, 2, selrec.selr.selr_countresult, _res );
    m.mb_qual^.mr_resnum[ 1 ] := csp_defined_byte;
    m.mb_qual^.mr_pagecnt     :=
          m.mb_trns^.trRteCommPtr_gg00^.file_record_cnt;
    m.mb_qual^.mr_res_build   := true;
    END;
(*ENDIF*) 
m.mb_qual_len := MB_PART1_HEAD_MXGG00 + MB_PART1_RETURN_MXGG00;
&IFDEF TRACE
t01int4 (kb, 'part2_len   ',m.mb_data_len );
&ENDIF
IF  ( bd998IsExtendedTempFile (m.mb_trns^, getrec.gi_result_info.o_tree)
    AND (bd998GetExtendedTempFileType (m.mb_trns^,
    getrec.gi_result_info.o_tree) = ttfnInto_egg00) )
THEN
    BEGIN (* Into file is used in case of updatable join views *)
    IF  ( destroy_into_file )
    THEN
        BEGIN
        _aux_error := m.mb_trns^.trError_gg00;
        b01empty_file (m.mb_trns^, getrec.gi_result_info.o_tree);
        m.mb_trns^.trError_gg00 := _aux_error;
        END
    (*ENDIF*) 
    END
ELSE
    BEGIN
    _aux_error := m.mb_trns^.trError_gg00;
    a101_DestroyGroupedTempFile( m.mb_trns^, getrec.gi_result_info.o_tree );
    m.mb_trns^.trError_gg00 := _aux_error
    END;
(*ENDIF*) 
IF  (( m.mb_trns^.trError_gg00 <> e_ok ) OR _destroy_res )
THEN
    BEGIN
    IF  ( m.mb_trns^.trError_gg00 <> e_ok )
    THEN
        BEGIN
        m.mb_type2 := mm_nil;
        m.mb_qual_len  := 0
        END;
    (* must not be done if mb_trns^.trError_gg00 = e_ok because         *)
    (* mb_part1 contains the result count, which is read by VAK68 *)
    (*ENDIF*) 
    m.mb_data_len  := 0;
    _aux_error     := m.mb_trns^.trError_gg00;
    IF  bd998IsExtendedTempFile (m.mb_trns^, selrec.selr.selr_resf_id)
    THEN
        IF  ( bd998GetExtendedTempFileType (m.mb_trns^, selrec.selr.selr_resf_id)
            <> ttfnInto_egg00 ) OR
            ( m.mb_trns^.trError_gg00 = e_cancelled )
        THEN
            BEGIN
            (* PTS 1113493 E.Z. *)
            IF  ( hsDropFile_egg00 in selrec.selr.selr_resf_id.fileHandling_gg00 ) OR
                (m.mb_trns^.trError_gg00 <> e_ok)
            THEN
                a101_DestroyGroupedTempFile (m.mb_trns^,
                      selrec.selr.selr_resf_id);
            (*ENDIF*) 
            END
        ELSE
            b01empty_file (m.mb_trns^, selrec.selr.selr_resf_id);
        (*ENDIF*) 
    (*ENDIF*) 
    m.mb_trns^.trError_gg00 := _aux_error;
    END
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74_join_select (VAR m : tgg00_MessBlock);
 
VAR
      _special_ot_file : boolean;
      _strat_maxresult : tsp00_Int4;
      _stenum          : tgg07_StratEnum;
      _getrec          : tgg07_get_param;
      _selrec          : tgg07_select_param;
      _aux_error       : tgg00_BasisError;
 
BEGIN
kb74init_join( m, _getrec, _selrec, _strat_maxresult, _stenum );
IF  ( m.mb_trns^.trError_gg00 = e_ok )
THEN
    BEGIN
    (* h.b. PTS 1104929 *)
    _special_ot_file :=
          _getrec.gi_linkrec.kbjr_right_oj AND
          (ord (m.mb_st^[ m.mb_qual^.mstrat_pos ].ecol_tab[ 2 ]) > 2);
    IF  (m.mb_trns^.trError_gg00 = e_ok) AND _special_ot_file
    THEN
        BEGIN
        _selrec.selr.selr_id_outer_join                  := _getrec.gi_result_info.o_tree;
        a101_GetLogicalFilename (m.mb_trns^, _selrec.selr.selr_id_outer_join);
        a101_CreateGroupedTempFile (m.mb_trns^,
              _selrec.selr.selr_id_outer_join, ttfnOuterJoin_egg00);
        END;
    (*ENDIF*) 
    IF  ( _stenum in a70glob_join_strats )
    THEN
        BEGIN
        kb74do_join (m, _getrec, _selrec );
        kb74join_last_part (m, _getrec, _selrec, _strat_maxresult,
              (_stenum <> strat_join_viewkey) OR _selrec.selr.selr_last_join);
        END
    ELSE
        BEGIN
        (* non relevant join transitions or cartesian product *)
        IF  ( m.mb_trns^.trError_gg00 = e_ok )
        THEN
            BEGIN
            k74get_last_field_pos( m, _selrec.selr.selr_l_defbyte_pos,
                  _getrec.gi_linkrec.kbjr_jpath );
            k720_select (m, _getrec, _selrec);
            ;
&           IFDEF TRACE
            t01treeid (kb, 'resf_id     ', _selrec.selr.selr_resf_id);
            t01int4 (kb, 'countresult ',_selrec.selr.selr_countresult);
            t01int4 (kb, ' distinct   ',ord(_selrec.selr.selr_distinct));
            t01int4 (kb, 'maxresult   ',_selrec.selr.selr_maxresult);
            t01int4 (kb, 'countresult ',_selrec.selr.selr_countresult);
            t01int4 (kb, 'n_rec_len   ',_getrec.gi_result_info.n_rec_len);
            t01int4 (kb, 'n_res_rec_le',_getrec.gi_result_info.n_res_rec_len);
&           ENDIF
            kb74join_last_part (m, _getrec, _selrec, _strat_maxresult, true);
&           IFDEF TRACE
            t01int4        (kb, 'n_rec_len   ', _getrec.gi_result_info.n_rec_len);
            t01int4        (kb, 'n_res_rec_le', _getrec.gi_result_info.n_res_rec_len);
            t01treeid      (kb, 'resf_id     ', _selrec.selr.selr_resf_id);
            t01basis_error (kb, 'm trError   ', m.mb_trns^.trError_gg00);
&           ENDIF
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _special_ot_file )
    THEN
        BEGIN
        _aux_error := m.mb_trns^.trError_gg00;
        a101_DestroyGroupedTempFile (m.mb_trns^,
              _selrec.selr.selr_id_outer_join);
        m.mb_trns^.trError_gg00 := _aux_error
        END;
    (*ENDIF*) 
    IF  ( m.mb_trns^.trError_gg00 = e_ok )
    THEN
        b73cmds_count (iins_sorts_rows_ins,
              _selrec.selr.selr_countresult);
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  ( m.mb_trns^.trError_gg00 <> e_ok )
THEN
    BEGIN  (* h.b. PTS 1104929 *)
    _aux_error := m.mb_trns^.trError_gg00;
    IF  bd998IsExtendedTempFile (m.mb_trns^, _getrec.gi_result_info.o_tree)
        AND (bd998GetExtendedTempFileType (m.mb_trns^,
        _getrec.gi_result_info.o_tree) = ttfnInto_egg00)
    THEN
        b01empty_file (m.mb_trns^, _getrec.gi_result_info.o_tree)
    ELSE
        a101_DestroyGroupedTempFile (m.mb_trns^,
              _getrec.gi_result_info.o_tree);
    (*ENDIF*) 
    m.mb_trns^.trError_gg00 := _aux_error;
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74finish_catalog_join (
            VAR m           : tgg00_MessBlock;
            VAR getrec      : tgg07_get_param;
            VAR selrec      : tgg07_select_context;
            strat_maxresult : tsp00_Int4;
            last_join_tab   : boolean);
 
VAR
      _selrec : tgg07_select_param;
 
BEGIN
_selrec.selr.selr_last_join := last_join_tab;
_selrec.selr := selrec;
kb74join_last_part (m, getrec, _selrec, strat_maxresult, true);
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74rowno_position (
            VAR m      : tgg00_MessBlock;
            VAR getrec : tgg07_get_param;
            VAR selrec : tgg07_select_param);
 
VAR
      _aux_mresqual_pos  : tsp00_Int2;
      _aux_mresqual_cnt  : tsp00_Int2;
      _aux_mqual_pos     : tsp00_Int2;
      _aux_mqual_cnt     : tsp00_Int2;
      _i                 : integer;
      _j                 : integer;
      _stop              : integer;
 
BEGIN
_aux_mresqual_cnt := 0;
IF  ( m.mb_qual^.mresqual_cnt > 0 )
THEN
    BEGIN
    _aux_mresqual_pos  := m.mb_qual^.mresqual_pos;
    _aux_mresqual_cnt  := m.mb_qual^.mresqual_cnt;
    _aux_mqual_pos     := m.mb_qual^.mqual_pos;
    _aux_mqual_cnt     := m.mb_qual^.mqual_cnt;
    m.mb_qual^.mqual_pos    := m.mb_qual^.mresqual_pos;
    m.mb_qual^.mqual_cnt    := m.mb_qual^.mresqual_cnt;
    m.mb_qual^.mresqual_pos := 0;
    m.mb_qual^.mresqual_cnt := 0;
    END;
(*ENDIF*) 
_i    := m.mb_qual^.mqual_pos;
_stop := m.mb_st^[ m.mb_qual^.mqual_pos ].epos + m.mb_qual^.mqual_pos - 1;
_j    := 1;
WHILE ( _i < _stop ) DO
    BEGIN
    (* step to ROWNO *)
    WHILE ( _i < _stop ) AND ( m.mb_st^[ _i ].etype <> st_rowno ) DO
        _i := succ (_i);
    (*ENDWHILE*) 
    IF  ( m.mb_st^[ _i ].etype = st_rowno )
    THEN
        BEGIN
        _i := k721out_entry( m.mb_st, _i );
        IF  ( m.mb_st^[ _i ].etype = st_output )
        THEN
            (* output of ROWNO found *)
            BEGIN
&           ifdef trace
            t01stackentry (kb, m.mb_st^[ _i ], _i);
&           endif
            WHILE ( _j <= getrec.gi_n_pos_s.rposcnt ) AND
                  ( m.mb_st^[ _i ].epos <> getrec.gi_n_pos_s.
                  posarr[ _j ].onfrom ) DO
                _j := succ (_j);
            (*ENDWHILE*) 
            IF  ( m.mb_st^[ _i ].epos = getrec.gi_n_pos_s.posarr[ _j ].onfrom )
            THEN
                BEGIN
                (* *** rowno position in resultrecord *** *)
                m.mb_st^[ _i ].epos := getrec.gi_n_pos_s.posarr[ _j ].onto;
&               ifdef trace
                t01stackentry (kb, m.mb_st^[ _i ], 0);
&               endif
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    _i := succ (_i);
    END;
(*ENDWHILE*) 
k721do_rowno (m, selrec);
IF  ( _aux_mresqual_cnt <> 0 )
THEN
    BEGIN
    m.mb_qual^.mresqual_pos     := _aux_mresqual_pos;
    m.mb_qual^.mresqual_cnt     := _aux_mresqual_cnt;
    m.mb_qual^.mqual_pos        := _aux_mqual_pos;
    m.mb_qual^.mqual_cnt        := _aux_mqual_cnt;
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74start_catalog_join (
            VAR m           : tgg00_MessBlock;
            VAR getrec      : tgg07_get_param;
            VAR selrec      : tgg07_select_context);
 
VAR
      _dummy           : tsp00_Int4;
      _stenum          : tgg07_StratEnum;
      _selrec          : tgg07_select_param;
 
BEGIN
kb74init_join (m, getrec, _selrec, _dummy, _stenum);
k74get_last_field_pos( m, _selrec.selr.selr_l_defbyte_pos,
      getrec.gi_linkrec.kbjr_jpath );
IF  ( m.mb_trns^.trError_gg00 = e_ok )
THEN
    selrec := _selrec.selr;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74_const_output_expression (
            VAR m         : tgg00_MessBlock;
            VAR selrec    : tgg07_select_param;
            VAR exp_pos   : tgg07_one_new_pos);
 
VAR
      _dummy_bool           : boolean;
      _selfields            : tgg00_SelectFieldsParam;
      _i                    : integer;
      _qual_output          : integer;
      _aux_mqual_pos        : integer;
      _aux_mqual_cnt        : integer;
      _aux_mview_cnt        : integer;
      _aux_se_jumpout       : tgg00_StackEntry;
      _aux_se_output        : tgg00_StackEntry;
      _aux_mst_optimize_pos : integer;
 
BEGIN
g04init_select_fields (_selfields, @m.mb_data^.mbp_buf, m.mb_data_size,
      m.mb_work_st, m.mb_work_st_max, m.mb_workbuf, m.mb_workbuf_size,
      m.mb_qual^.msqlmode, @m.mb_fieldlists);
_selfields.sfp_bd_mess_type    := m.mb_type;
_selfields.sfp_bd_mess2_type   := mm_first;
_selfields.sfp_result_wanted   := true;
_selfields.sfp_m_result_addr   := @selrec.selr_selectbuffer.result.buf;
_selfields.sfp_m_result_size   := sizeof (selrec.selr_selectbuffer.result.buf);
_selfields.sfp_result_length   := cgg_rec_key_offset;
_selfields.sfp_filler2         := false;
_selfields.sfp_acv_addr        := m.mb_trns^.trAcvPtr_gg00;   (* PTS 1121403 E.Z. *)
_aux_mst_optimize_pos    := m.mb_qual^.mstack_desc.mst_optimize_pos;
m.mb_qual^.mstack_desc.mst_optimize_pos := 0;
_i := m.mb_st^[ m.mb_qual^.mqual_pos ].epos - 1;
&IFDEF TRACE
t01int4 (kb, 'i           ', _i);
t01int4 (kb, 'ONFROM      ', exp_pos.onfrom);
t01int4 (kb, 'ONTO        ', exp_pos.onto);
t01int4 (kb, 'ONLEN       ', exp_pos.onlen);
&ENDIF
WHILE (_i > m.mb_qual^.mqual_pos) DO
    BEGIN
    IF  (m.mb_st^[ _i ].etype = st_output) AND
        (m.mb_st^[ _i ].epos  = - exp_pos.onfrom)
    THEN
        BEGIN
        _qual_output := _i;
        (* *** save original kbstack values *** *)
        _aux_mqual_pos       := m.mb_qual^.mqual_pos;
        _aux_mqual_cnt       := m.mb_qual^.mqual_cnt;
        _aux_mview_cnt       := m.mb_qual^.mview_cnt;
        _aux_se_output       := m.mb_st^[ _i ];
        m.mb_st^[ _i ].epos := exp_pos.onto;
&       IFDEF TRACE
        t01int4 (kb, 'output found', _i);
&       ENDIF
        _i := pred (_i);
        WHILE (_i >= m.mb_qual^.mqual_pos) DO
            BEGIN
            IF  (m.mb_st^[ _i ].etype = st_output) OR
                (_i = m.mb_qual^.mqual_pos)
            THEN
                BEGIN
                m.mb_qual^.mqual_pos      := _i;
                m.mb_qual^.mqual_cnt      := _qual_output - m.mb_qual^.mqual_pos + 1;
                m.mb_qual^.mview_cnt      := 0;
                _aux_se_jumpout := m.mb_st^[ m.mb_qual^.mqual_pos ];
                m.mb_st^[ m.mb_qual^.mqual_pos ].etype := st_jump_output;
                m.mb_st^[ m.mb_qual^.mqual_pos ].epos  := m.mb_qual^.mqual_cnt + 1;
&               IFDEF TRACE
                t01int4 (kb, 'start  found', _i);
&               ENDIF
                END;
            (*ENDIF*) 
            _i := pred (_i);
            END;
        (*ENDWHILE*) 
        END;
    (*ENDIF*) 
    _i := pred (_i);
    END;
(*ENDWHILE*) 
&IFDEF TRACE
t01messblock (ak_sem, 'k74-mblock  ', m);
&ENDIF
SAPDB_PascalFill ('VKB74 ',   8,    
      sizeof (selrec.selr_selectbuffer.rbuf),
      @selrec.selr_selectbuffer.rbuf, 1, cgg_rec_key_offset, csp_defined_byte,
      m.mb_trns^.trError_gg00);
k71col_select (m.mb_trns^, _selfields, m.mb_qual^.mstack_desc,
      selrec.selr_selectbuffer.rbuf, _dummy_bool);
m.mb_st^[ m.mb_qual^.mqual_pos ]  := _aux_se_jumpout;
m.mb_st^[ _qual_output ]          := _aux_se_output;
m.mb_qual^.mqual_pos              := _aux_mqual_pos;
m.mb_qual^.mqual_cnt              := _aux_mqual_cnt;
m.mb_qual^.mview_cnt              := _aux_mview_cnt;
m.mb_qual^.mstack_desc.mst_optimize_pos := _aux_mst_optimize_pos;
&IFDEF TRACE
t01messblock (ak_sem, 'k74-mblock  ', m);
&ENDIF
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74_join (
            VAR m           : tgg00_MessBlock;
            VAR gg_strategy : tgg07_StrategyInfo;
            invindex        : integer;
            invroot         : tsp00_PageNo;
            invlen          : tsp00_Int4;
            VAR getrec      : tgg07_get_param;
            VAR selrec      : tgg07_select_param;
            VAR sel         : tgg00_SelectFieldsParam);
 
VAR
      _i         : tsp00_Int2;
      _e         : tgg00_BasisError;
      _searchrec : t_search_rec;
 
BEGIN
_searchrec.sr_lsearchkey.len             := 0;
_searchrec.sr_prepare_for_upd            := getrec.gi_linkrec.kbjr_left_oj;
_searchrec.sr_refused_by_ophase          := false;
_searchrec.sr_res_cnt                    := 0;
_searchrec.sr_left_tree_pos.tpsPno_gg00  := NIL_PAGE_NO_GG00;
_searchrec.sr_nptr.np_ptr                := NIL;
_searchrec.sr_left_last_pno              := NIL_PAGE_NO_GG00;
_searchrec.sr_lkey_len                   := 0;
IF  (getrec.gi_linkrec.kbjr_jpath > 0 )
THEN
    BEGIN
    FOR _i := 1 TO getrec.gi_linkrec.kbjr_jpath - 1 DO
        BEGIN
        selrec.selr.selr_first_jlen := selrec.selr.selr_first_jlen +
              (* part 2 always greater or equal part 1 *)
              getrec.gi_linkrec.kbjr_jarr[ _i ].kbji_parts[ 2 ].kboj_len;
        END;
    (*ENDFOR*) 
    _searchrec.sr_lkey_len := selrec.selr.selr_first_jlen +
          getrec.gi_linkrec.kbjr_jarr[ getrec.gi_linkrec.
          kbjr_jpath ].kbji_parts[ 1 ].kboj_len;
    (* choose smaller length *)
    CASE ord(getrec.gi_linkrec.kbjr_jarr[ getrec.gi_linkrec.kbjr_jpath ].
          kbji_parts[ 2 ].kboj_op) OF
        cgg07_left_len_eq_right_len, cgg07_left_len_le_right_len :
            selrec.selr.selr_first_jlen := selrec.selr.selr_first_jlen +
                  getrec.gi_linkrec.kbjr_jarr[ getrec.gi_linkrec.kbjr_jpath ].
                  kbji_parts[ 1 ].kboj_len;
        cgg07_left_len_gt_right_len :
            selrec.selr.selr_first_jlen := selrec.selr.selr_first_jlen +
                  getrec.gi_linkrec.kbjr_jarr[ getrec.gi_linkrec.kbjr_jpath ].
                  kbji_parts[ 2 ].kboj_len;
        END;
    (*ENDCASE*) 
    END;
(*ENDIF*) 
;
&ifdef trace
t01int4 (kb, 'first_jlen  ', selrec.selr.selr_first_jlen);
&endif
selrec.selr.selr_l_currpos               := 0;
kb74get_left_leaf (m.mb_trns^, selrec, _searchrec,
      getrec.gi_result_info.o_tree, _searchrec.sr_lsearchkey, c_get_next);
CASE gg_strategy.str_strategy OF
    strat_join_all_keys_equal, strat_join_key_equal :
        kb74key_direct_search (m, getrec, selrec, sel, _searchrec);
    strat_join_key_range, strat_join_key_next :
        kb74key_next_search (m, getrec, selrec, sel, _searchrec);
    strat_join_all_inv_equal, strat_join_inv :
        BEGIN
&       ifdef TRACE
        t01int4 (kb, 'invindex    ', invindex);
&       endif
        g04index_tree_build (m.mb_qual^.mtree, selrec.selr.selr_inv_id, invindex);
        bd998IncrementIndexUsageCount(m.mb_trns^,selrec.selr.selr_inv_id.fileTabId_gg00);
        selrec.selr.selr_inv_id.fileRoot_gg00 := invroot;
        kb74inv_direct_search_parallel (m, getrec, selrec, sel, invlen, _searchrec);
        END;
    strat_join_inv_range :
        BEGIN
&       ifdef TRACE
        t01int4 (kb, 'invindex    ', invindex);
&       endif
        g04index_tree_build (m.mb_qual^.mtree, selrec.selr.selr_inv_id, invindex);
        bd998IncrementIndexUsageCount(m.mb_trns^,selrec.selr.selr_inv_id.fileTabId_gg00);
        selrec.selr.selr_inv_id.fileRoot_gg00 := invroot;
        kb74inv_next_search (m, getrec, selrec, sel, _searchrec);
        END;
    strat_join_viewkey :
        BEGIN
        IF  ( selrec.selr.selr_last_join )
        THEN
            selrec.selr.selr_maxresult := 0;
        (*ENDIF*) 
        kb74key_direct_search (m, getrec, selrec, sel, _searchrec);
        END;
    OTHERWISE
        m.mb_trns^.trError_gg00 := e_unknown_strategy;
    END;
(*ENDCASE*) 
IF  ( getrec.gi_linkrec.kbjr_left_oj )
THEN
    k74finish_l_outer_join (m, getrec, selrec);
(*ENDIF*) 
IF  ( _searchrec.sr_nptr.np_ptr <> NIL )
THEN
    BEGIN
    _e := m.mb_trns^.trError_gg00;
    b07release_result_leaf (m.mb_trns^,
          getrec.gi_result_info.o_tree, NOT c_node_changed, _searchrec.sr_nptr);
    IF  _e <> e_ok
    THEN
        m.mb_trns^.trError_gg00 := _e
    (*ENDIF*) 
    END
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74finish_l_outer_join (
            VAR m      : tgg00_MessBlock;
            VAR getrec : tgg07_get_param;
            VAR selrec : tgg07_select_param);
 
VAR
      _e         : tgg00_BasisError;
      _rec_len   : tsp_int_map_c2;
      _key_len   : tsp_int_map_c2;
      _zerokey   : tgg00_Lkey;
      _searchrec : t_search_rec;
 
BEGIN
(* for catalog joins and joins without transition we revers  *)
(* join execution!: First read records from right table and  *)
(* join this record with record from left table.             *)
(**)
(* find all records of left result, that have not been found *)
(* by the previous scan of the right table.                  *)
(* These records are marked by a record length different     *)
(* from cgg_rec_key_offset + key length + 1                  *)
IF  ( m.mb_trns^.trError_gg00 = e_ok )
THEN
    BEGIN
    _zerokey.len                    := 0;
    _searchrec.sr_left_tree_pos.tpsPno_gg00   := NIL_PAGE_NO_GG00;
    _searchrec.sr_left_tree_pos.tpsIndex_gg00 := 0;
    _searchrec.sr_nptr.np_ptr       := NIL;
    _searchrec.sr_left_last_pno               := NIL_PAGE_NO_GG00;
    _searchrec.sr_left_min_index              := 0;
    _searchrec.sr_prepare_for_upd             := false;
    _searchrec.sr_refused_by_ophase           := false;
    _searchrec.sr_res_cnt                     := 0;
    REPEAT
        BEGIN
        _searchrec.sr_left_tree_pos.tpsIndex_gg00 :=
              succ(_searchrec.sr_left_tree_pos.tpsIndex_gg00);
        IF  ( _searchrec.sr_left_tree_pos.tpsIndex_gg00 >
            _searchrec.sr_left_min_index )
        THEN
            kb74get_left_leaf (m.mb_trns^, selrec, _searchrec,
                  getrec.gi_result_info.o_tree, _zerokey, c_get_next);
        (*ENDIF*) 
        IF  ( _searchrec.sr_error_l = e_ok )
        THEN
            BEGIN
            selrec.selr.selr_l_currpos :=
                  _searchrec.sr_nptr.np_ptr^.
                  nd_pointer_list[MAX_POINTERINDEX_BD00 - _searchrec.sr_left_tree_pos.tpsIndex_gg00];
            _rec_len.map_c2[1] :=
                  _searchrec.sr_nptr.np_ptr^.nd_body[selrec.selr.selr_l_currpos  ];
            _rec_len.map_c2[2] :=
                  _searchrec.sr_nptr.np_ptr^.nd_body[selrec.selr.selr_l_currpos+1];
            _key_len.map_c2[1] :=
                  _searchrec.sr_nptr.np_ptr^.nd_body[selrec.selr.selr_l_currpos+2];
            _key_len.map_c2[2] :=
                  _searchrec.sr_nptr.np_ptr^.nd_body[selrec.selr.selr_l_currpos+3];
&           ifdef trace
            t01int4 (kb, 'rec_len     ', _rec_len.map_int);
            t01int4 (kb, 'key_len     ', _key_len.map_int);
&           endif
            IF  ( _rec_len.map_int <>
                cgg_rec_key_offset + _key_len.map_int + 1 )
            THEN
                kb74build_new_rec (m, getrec, selrec,
                      _searchrec, c_right_needed, left_outer_join);
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    UNTIL
        (_searchrec.sr_error_l <> e_ok) OR (m.mb_trns^.trError_gg00 <> e_ok);
    (*ENDREPEAT*) 
    IF  ( _searchrec.sr_error_l <> e_no_next_record ) AND
        ( m.mb_trns^.trError_gg00 = e_ok )
    THEN
        m.mb_trns^.trError_gg00 := _searchrec.sr_error_l;
    (*ENDIF*) 
    IF  ( _searchrec.sr_nptr.np_ptr <> NIL )
    THEN
        BEGIN
        _e := m.mb_trns^.trError_gg00;
        b07release_result_leaf (m.mb_trns^, getrec.gi_result_info.o_tree,
              _searchrec.sr_prepare_for_upd, _searchrec.sr_nptr);
        IF  ( _e <> e_ok )
        THEN
            m.mb_trns^.trError_gg00 := _e
        (*ENDIF*) 
        END
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74build_new_rec (
            VAR m             : tgg00_MessBlock;
            VAR getrec        : tgg07_get_param;
            VAR selrec        : tgg07_select_param;
            VAR searchrec     : t_search_rec;
            right_cols_needed : boolean;
            outer_join        : tkb07_outer_join_type);
 
VAR
      _ix                : integer;
      _l                 : integer;
      _t                 : integer;
      _f                 : integer;
      _j                 : integer;
      _frompos           : integer;
      _aux_mresqual_pos  : tsp00_Int2;
      _aux_mresqual_cnt  : tsp00_Int2;
      _aux_mqual_pos     : tsp00_Int2;
      _aux_mqual_cnt     : tsp00_Int2;
      _aux_optimize_pos  : tsp00_Int2;
      _resbuf            : tsp00_Buf;
      _sel               : tgg00_SelectFieldsParam;
      _dummy_bool        : boolean;
 
BEGIN
selrec.selr_selectbuffer.result.len    := getrec.gi_result_info.n_res_rec_len;
selrec.selr_selectbuffer.result.keylen := getrec.gi_result_info.n_key_len;
(* h.b. PTS 1104659 *)
selrec.selr_selectbuffer.result.space_var_offset := 0;
selrec.selr_selectbuffer.result.space_var_cnt    := 0;
IF  (( selrec.selr.selr_last_join )
    AND
    ( selrec.selr.selr_distinct = full_distinct )
    AND
    selrec.selr.selr_write_rownum )
THEN
    BEGIN
&   ifdef trace
    t01sname(kb, 'fill hash   ' );
&   endif
    (* initialize bytes for hash value because we have to have a defined value *)
    SAPDB_PascalFill ('VKB74 ',   9,    
          sizeof (selrec.selr_selectbuffer.result.buf),
          @selrec.selr_selectbuffer.result.buf,
          cgg_rec_key_offset + 1, HASHVAL_MXGG04, ':',
          m.mb_trns^.trError_gg00)
    END;
(*ENDIF*) 
;
&ifdef trace
t01bool (kb, 'right needed', right_cols_needed);
t01int4 (kb, 'outer join  ', ord(outer_join));
t01int4 (kb, 'n_rec_len   ', getrec.gi_result_info.n_rec_len);
t01int4 (kb, 'n_res_rec_le', getrec.gi_result_info.n_res_rec_len);
t01int4 (kb, 'n_key_len   ', getrec.gi_result_info.n_key_len);
t01int4 (kb, 'lposcnt     ', getrec.gi_n_pos_s.lposcnt);
IF  getrec.gi_n_pos_s.lposcnt > 0
THEN
    t01line_c60( kb, 'move from i-1. temp result --> i. temp result               ' );
(*ENDIF*) 
t01int4 (kb, 'rposcnt     ', getrec.gi_n_pos_s.rposcnt);
&endif
(* move from left record *)
FOR _ix := getrec.gi_n_pos_s.rposcnt + 1 TO
      getrec.gi_n_pos_s.rposcnt + getrec.gi_n_pos_s.lposcnt DO
    BEGIN
&   ifdef trace
    t01p2int4 (kb, 'onfrom      ', getrec.gi_n_pos_s.posarr[_ix].onfrom,
          'onlen       ', getrec.gi_n_pos_s.posarr[_ix].onlen);
    t01int4   (kb, 'onto        ', getrec.gi_n_pos_s.posarr[_ix].onto);
&   endif
    IF  outer_join = right_outer_join
    THEN
        BEGIN
        selrec.selr_selectbuffer.
              result.buf[getrec.gi_n_pos_s.posarr[_ix].onto] := csp_undef_byte;
        SAPDB_PascalFill ('VKB74 ',  10,    
              sizeof (selrec.selr_selectbuffer.result.buf),
              @selrec.selr_selectbuffer.result.buf,
              getrec.gi_n_pos_s.posarr[_ix].onto + 1,
              getrec.gi_n_pos_s.posarr[_ix].onlen - 1, csp_defined_byte,
              m.mb_trns^.trError_gg00)
        END
    ELSE
        BEGIN
        SAPDB_PascalMove ('VKB74 ',  11,    
              sizeof(searchrec.sr_nptr.np_ptr^),
              sizeof(selrec.selr_selectbuffer.result.buf),
              @searchrec.sr_nptr.np_ptr^ (* i.th temporary result record *),
              selrec.selr.selr_l_currpos + getrec.gi_n_pos_s.posarr[_ix].onfrom - 1,
              @selrec.selr_selectbuffer.result.buf (* i+1.th temporary result *),
              getrec.gi_n_pos_s.posarr[_ix].onto,
              getrec.gi_n_pos_s.posarr[_ix].onlen, m.mb_trns^.trError_gg00);
&       ifdef trace
        t01buf (kb, selrec.selr_selectbuffer.result.buf,
              getrec.gi_n_pos_s.posarr[_ix].onto,
              getrec.gi_n_pos_s.posarr[_ix].onto +
              getrec.gi_n_pos_s.posarr[_ix].onlen - 1);
&       endif
        END;
    (*ENDIF*) 
    END;
(*ENDFOR*) 
(* *** one_join_phase begin *** *)
IF  NOT right_cols_needed AND (m.mb_qual^.mresqual_cnt > 0)
THEN
    BEGIN
    (* *** Output list with expression (instead of two_phase)! *** *)
    right_cols_needed :=
          m.mb_st^ [ m.mb_qual^.mqual_pos ].etype = st_jump_output;
&   ifdef trace
    t01bool (kb, 'right needed', right_cols_needed);
&   endif
    END;
(* *** one_join_phase end *** *)
(*ENDIF*) 
;
IF  right_cols_needed AND (m.mb_trns^.trError_gg00 = e_ok)
THEN
    BEGIN
&   ifdef trace
    t01int4 (kb, 'rposcnt     ', getrec.gi_n_pos_s.rposcnt);
    IF  getrec.gi_n_pos_s.rposcnt > 0
    THEN
        t01line_c60( kb, 'move from i. base table  --> i. temp result                 ' );
&   endif
    (*ENDIF*) 
    FOR _ix := 1 TO getrec.gi_n_pos_s.rposcnt DO
        BEGIN
&       ifdef trace
        t01p2int4 (kb, 'onfrom      ', getrec.gi_n_pos_s.posarr[_ix].onfrom,
              'onlen       ', getrec.gi_n_pos_s.posarr[_ix].onlen);
        t01int4   (kb, 'onto        ', getrec.gi_n_pos_s.posarr[_ix].onto);
&       endif
        IF  getrec.gi_n_pos_s.posarr[_ix].onfrom > 0
        THEN
            _frompos := getrec.gi_n_pos_s.posarr[_ix].onfrom
        ELSE
            _frompos := -getrec.gi_n_pos_s.posarr[_ix].onfrom;
        (*ENDIF*) 
        IF  outer_join = left_outer_join
        THEN
            BEGIN
            IF  getrec.gi_n_pos_s.posarr[_ix].onfrom > 0
            THEN
                BEGIN
                selrec.selr_selectbuffer.
                      result.buf[getrec.gi_n_pos_s.posarr[_ix].onto] := csp_undef_byte;
                SAPDB_PascalFill ('VKB74 ',  12,    
                      sizeof (selrec.selr_selectbuffer.result.buf),
                      @selrec.selr_selectbuffer.result.buf,
                      getrec.gi_n_pos_s.posarr[_ix].onto + 1,
                      getrec.gi_n_pos_s.posarr[_ix].onlen - 1, csp_defined_byte,
                      m.mb_trns^.trError_gg00)
                END
            ELSE
                BEGIN
                (* *** constant expression in outputlist *** *)
                (* h.b. PTS 1104165 *)
                kb74_const_output_expression (m, selrec,
                      getrec.gi_n_pos_s.posarr[ _ix ]);
                END;
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            SAPDB_PascalMove ('VKB74 ',  13,    
                  sizeof(selrec.selr_selectbuffer.rbuf),
                  sizeof(selrec.selr_selectbuffer.result.buf),
                  @selrec.selr_selectbuffer.rbuf (* record from i.th base table*),
                  _frompos,
                  @selrec.selr_selectbuffer.result.buf(* i+1.th temporary result *),
                  getrec.gi_n_pos_s.posarr[_ix].onto,
                  getrec.gi_n_pos_s.posarr[_ix].onlen,
                  m.mb_trns^.trError_gg00);
&           ifdef trace
            t01buf (kb, selrec.selr_selectbuffer.result.buf,
                  getrec.gi_n_pos_s.posarr[_ix].onto,
                  getrec.gi_n_pos_s.posarr[_ix].onto +
                  getrec.gi_n_pos_s.posarr[_ix].onlen - 1);
&           endif
            END;
        (*ENDIF*) 
        END;
    (*ENDFOR*) 
    END;
(*ENDIF*) 
;
&ifdef trace
t01int4 (kb, 'n_j_cnt     ', getrec.gi_copy_info.n_j_cnt);
IF  getrec.gi_copy_info.n_j_cnt > 0
THEN
    t01line_c60( kb, 'move from i. temp result --> i. temp result                 ' );
&endif
(* move columns from earlier join step *)
(*ENDIF*) 
FOR _ix := 1 TO getrec.gi_copy_info.n_j_cnt DO
    BEGIN
&   ifdef trace
    t01p2int4 (kb, 'jfrom       ', getrec.gi_copy_info.n_j_arr[_ix].jfrom,
          'jlen        ', getrec.gi_copy_info.n_j_arr[_ix].jlen);
    t01int4   (kb, 'jto         ', getrec.gi_copy_info.n_j_arr[_ix].jto);
&   endif
    IF  getrec.gi_copy_info.n_j_arr[_ix].jfrom <= 0
    THEN
        BEGIN
        _l := getrec.gi_copy_info.n_j_arr[_ix].jlen - 1;
        _t := getrec.gi_copy_info.n_j_arr[_ix].jto;
        _f := -getrec.gi_copy_info.n_j_arr[_ix].jfrom;  (* jfrom < 0 *)
        FOR _j := 0 TO _l DO
            selrec.selr_selectbuffer.result.buf[ _t+_j ] :=
                  chr(255 - ord(selrec.selr_selectbuffer.result.buf[ _f+_j ]));
        (*ENDFOR*) 
        END
    ELSE
        BEGIN
        _t := getrec.gi_copy_info.n_j_arr[_ix].jto;
        _f := getrec.gi_copy_info.n_j_arr[_ix].jfrom;
        IF  _t <> _f
        THEN
            BEGIN
&           ifdef trace
            t01buf (kb, selrec.selr_selectbuffer.result.buf,
                  _f, _f + getrec.gi_copy_info.n_j_arr[_ix].jlen - 1);
&           endif
            SAPDB_PascalOverlappingMove ('VKB74 ',  14,    
                  sizeof(selrec.selr_selectbuffer.result.buf),
                  sizeof(selrec.selr_selectbuffer.result.buf),
                  @selrec.selr_selectbuffer.result.buf, _f,
                  @selrec.selr_selectbuffer.result.buf, _t,
                  getrec.gi_copy_info.n_j_arr[_ix].jlen,
                  m.mb_trns^.trError_gg00);
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDFOR*) 
;
(* *** one_join_phase begin *** *)
_aux_mresqual_cnt := 0;
IF  ( m.mb_qual^.mresqual_cnt > 0 ) AND ( m.mb_trns^.trError_gg00 = e_ok )
THEN
    BEGIN
&   ifdef trace
    t01name(kb, 'result qualificat ');
    t01buf (kb, selrec.selr_selectbuffer.result.buf, 1,
          1 + getrec.gi_result_info.n_rec_len - 1);
    SAPDB_PascalForcedFill( sizeof (_resbuf), @_resbuf, 1,
          getrec.gi_result_info.n_res_rec_len, ':' );
&   endif
    _aux_mresqual_pos  := m.mb_qual^.mresqual_pos;
    _aux_mresqual_cnt  := m.mb_qual^.mresqual_cnt;
    _aux_mqual_pos     := m.mb_qual^.mqual_pos;
    _aux_mqual_cnt     := m.mb_qual^.mqual_cnt;
    _aux_optimize_pos  := m.mb_qual^.mst_optimize_pos;
    m.mb_qual^.mst_optimize_pos  := 0;
    m.mb_qual^.mqual_pos         := m.mb_qual^.mresqual_pos;
    m.mb_qual^.mqual_cnt         := m.mb_qual^.mresqual_cnt;
    m.mb_qual^.mresqual_pos      := 0;
    m.mb_qual^.mresqual_cnt      := 0;
    g04init_select_fields (_sel, @m.mb_data^.mbp_buf,
          m.mb_data_size, m.mb_work_st,
          m.mb_work_st_max, m.mb_workbuf,
          m.mb_workbuf_size, m.mb_qual^.msqlmode, @m.mb_fieldlists);
    _sel.sfp_bd_mess_type    := m_select;
    _sel.sfp_result_wanted   := true;
    _sel.sfp_m_result_addr   := @_resbuf;
    _sel.sfp_m_result_size   := sizeof (_resbuf);
    _sel.sfp_first_qual      := c_first_qual;
    _sel.sfp_filler2         := false;
    _sel.sfp_acv_addr        := m.mb_trns^.trAcvPtr_gg00;   (* PTS 1121403 E.Z. *)
    _sel.sfp_result_length   := 0;
    IF  (m.mb_st^ [ m.mb_qual^.mqual_pos ].etype = st_jump_output)
    THEN
        BEGIN
        k71col_select (m.mb_trns^, _sel, m.mb_qual^.mstack_desc,
              selrec.selr_selectbuffer.result.buf, _dummy_bool);
        IF  ( m.mb_st^[ m.mb_qual^.mqual_pos ].ecol_pos = -1 )
        THEN
            (* we don't have complete output qualification of record *)
            (* ak684transfer_const_expressions() *)
            BEGIN
&           ifdef trace
            t01sname(kb, 'single moves' );
&           endif
            FOR _ix := m.mb_qual^.mqual_pos + 1
                  TO m.mb_st^ [ m.mb_qual^.mqual_pos ].epos +
                  m.mb_qual^.mqual_pos - 2 DO
                IF  ( m.mb_st^[ _ix ].etype = st_output )
                THEN
                    SAPDB_PascalMove ('VKB74 ',  15,    
                          sizeof(_resbuf),
                          sizeof(selrec.selr_selectbuffer.result.buf),
                          @_resbuf, m.mb_st^[ _ix ].epos,
                          @selrec.selr_selectbuffer.result.buf,
                          m.mb_st^[ _ix ].epos,
                          m.mb_st^[ _ix ].elen_var,
                          m.mb_trns^.trError_gg00);
                (*ENDIF*) 
            (*ENDFOR*) 
            END
        ELSE
            BEGIN
            SAPDB_PascalMove ('VKB74 ',  16,    
                  sizeof(_resbuf),
                  sizeof(selrec.selr_selectbuffer.result.buf),
                  @_resbuf, cgg_rec_key_offset+1,
                  @selrec.selr_selectbuffer.result.buf,
                  cgg_rec_key_offset+1,
                  selrec.selr_selectbuffer.result.recLen_gg00-cgg_rec_key_offset,
                  m.mb_trns^.trError_gg00);
            END;
        (*ENDIF*) 
&       ifdef trace
        t01name(kb, '_resbuf --> result');
&       endif
        END
    ELSE
        k71sel_qualification_test(m, _sel, NOT c_check_new_rec,
              selrec.selr_selectbuffer.result);
    (*ENDIF*) 
    selrec.selr_selectbuffer.result.keylen := selrec.selr.selr_res_keyl;
&   ifdef trace
    t01basis_error (kb, 'trError     ', m.mb_trns^.trError_gg00);
&   endif
    IF  ( m.mb_trns^.trError_gg00 = e_qual_violation )
    THEN
        searchrec.sr_refused_by_ophase := true;
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  ( m.mb_trns^.trError_gg00 = e_ok )
THEN
    BEGIN
&   ifdef trace
    t01sname(kb, 'add result  ');
&   endif
    searchrec.sr_res_cnt := searchrec.sr_res_cnt + 1;
    IF  ( selrec.selr.selr_join_with_func )
    THEN
        k721function_add (m, selrec, NOT c_aggr)
    ELSE
        BEGIN
        k721add_into_result (m.mb_trns^, selrec, m.mb_next_mblock);
        END;
    (*ENDIF*) 
    END
ELSE
    BEGIN
    IF  ( m.mb_trns^.trError_gg00 = e_qual_violation )
    THEN
        m.mb_trns^.trError_gg00 := e_ok;
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  ( _aux_mresqual_cnt > 0 )
THEN
    BEGIN
    m.mb_qual^.mresqual_pos     := _aux_mresqual_pos;
    m.mb_qual^.mresqual_cnt     := _aux_mresqual_cnt;
    m.mb_qual^.mqual_pos        := _aux_mqual_pos;
    m.mb_qual^.mqual_cnt        := _aux_mqual_cnt;
    m.mb_qual^.mst_optimize_pos := _aux_optimize_pos
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74check_conversions (
            VAR m              : tgg00_MessBlock;
            VAR conv_st_pos    : conv_arr;
            VAR conv_cnt       : integer;
            VAR last_field_pos : integer;
            VAR fixfieldlen    : integer;
            selr_first_jlen    : integer);
 
VAR
      _i         : integer;
      _test_pos  : integer;
      _end_found : boolean;
 
BEGIN
fixfieldlen := 0;
conv_cnt   := 0;
_i         := 1;
_end_found := false;
WHILE (NOT _end_found) DO
    BEGIN
    IF  m.mb_st^[ _i ].etype = st_fixkey
    THEN
        fixfieldlen := fixfieldlen + m.mb_st^[ _i ].elen_var
    ELSE
        IF  (m.mb_st^[ _i ].etype = st_output)
        THEN
            BEGIN
            _test_pos := pred (_i);
            IF  m.mb_st^[ _test_pos ].eop = op_none
            THEN
                _test_pos := pred (_test_pos);
            (*ENDIF*) 
            END;
        (*ENDIF*) 
    (*ENDIF*) 
    IF  ((m.mb_st^[ _i ].etype <> st_output) OR
        ((m.mb_st^[ _i ].epos + m.mb_st^[ _i ].elen_var) <
        (selr_first_jlen + cgg_rec_key_offset + 1)))
    THEN
        _i := succ (_i)
    ELSE
        _end_found := true;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
last_field_pos := m.mb_st^[ _i ].epos;
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74get_last_field_pos (
            VAR m              : tgg00_MessBlock;
            VAR last_field_pos : tsp00_Int2;
            jpath_cnt          : tsp00_Int2);
 
VAR
      _i, _stop  : tsp00_Int4;
      _j         : tsp00_Int2;
      _end_found : boolean;
 
BEGIN
last_field_pos := IS_UNDEFINED_GG07;
IF  ( m.mb_st^[ m.mb_qual^.mqual_pos ].etype = st_jump_output )
THEN
    _stop := m.mb_qual^.mqual_pos +
          m.mb_st^[ m.mb_qual^.mqual_pos ].epos - 2
ELSE
    (* avoid looping *)
    _stop := m.mb_qual^.mqual_pos;
(*ENDIF*) 
_j := 0;
_i := succ( m.mb_qual^.mqual_pos );
WHILE ( _i <= _stop ) DO
    BEGIN
    IF  ( m.mb_st^[ _i ].etype = st_output )
    THEN
        BEGIN
        _j := succ(_j);
        IF  ( _j >= jpath_cnt )
        THEN
            BEGIN
            last_field_pos := m.mb_st^[ _i ].epos;
            _i := _stop;
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    _i := succ(_i);
    END;
(*ENDWHILE*) 
&ifdef trace
t01int4( kb, 'last_field_p', last_field_pos );
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74check_inv_conversions (
            VAR m              : tgg00_MessBlock;
            VAR conv_st_pos    : tkb07_conv_arr;
            VAR conv_cnt       : tsp00_Int4;
            VAR last_field_pos : tsp00_Int2;
            VAR last_desc_field: boolean;
            jpath_cnt          : tsp00_Int2);
 
VAR
      _i, _stop  : tsp00_Int4;
      _test_pos  : tsp00_Int4;
      _j         : tsp00_Int2;
 
BEGIN
last_field_pos := IS_UNDEFINED_GG07;
IF  ( m.mb_st^[ m.mb_qual^.mqual_pos ].etype = st_jump_output )
THEN
    _stop := m.mb_qual^.mqual_pos +
          m.mb_st^[ m.mb_qual^.mqual_pos ].epos - 2
ELSE
    (* avoid looping *)
    _stop := m.mb_qual^.mqual_pos;
(*ENDIF*) 
last_desc_field := false;
conv_cnt        := 0;
_j              := 0;
_i := succ( m.mb_qual^.mqual_pos );
WHILE ( _i <= _stop ) DO
    BEGIN
    IF  ( m.mb_st^[ _i ].etype = st_output )
    THEN
        BEGIN
        _j         := succ(_j);
        _test_pos  := pred(_i);
        IF  m.mb_st^[ _test_pos ].eop = op_none
        THEN
            _test_pos := pred(_test_pos);
        (*ENDIF*) 
        CASE m.mb_st^[ _test_pos ].eop OF
            op_order_desc,
            op_unique_desc :
                BEGIN
                conv_cnt := succ (conv_cnt);
                WITH conv_st_pos[ conv_cnt ] DO
                    BEGIN
                    ct_epos    := m.mb_st^[ _i ].epos;
                    ct_elenvar := m.mb_st^[ _i ].elen_var;
                    ct_codeno  := 0;
                    ct_is_desc := true;
                    END;
                (*ENDWITH*) 
                END;
            OTHERWISE ;
            END;
        (*ENDCASE*) 
        IF  ( _j = jpath_cnt )
        THEN
            BEGIN
            last_field_pos := m.mb_st^[ _i ].epos;
            last_desc_field := ( m.mb_st^[ _test_pos ].eop in
                  [ op_order_desc, op_unique_desc ]);
            _i := _stop;
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    _i := succ(_i);
    END;
(*ENDWHILE*) 
&ifdef trace
t01int4( kb, 'last_field_p', last_field_pos );
t01bool( kb, 'last_desc_fi', last_desc_field );
FOR _i := 1 TO conv_cnt DO
    BEGIN
    t01int4( kb, ' ---------- ', _i );
    t01bool (kb, 'ct_is_desc  ', conv_st_pos[ _i ].ct_is_desc );
    t01p2int4 (kb, 'ct_epos     ', conv_st_pos[ _i ].ct_epos,
          'ct_elenvar  ', conv_st_pos[ _i ].ct_elenvar );
    CASE conv_st_pos[ _i ].ct_codeno OF
        0:
            t01int4(kb, 'ct_codeno   ', 0 );
        OTHERWISE ;
        END;
    (*ENDCASE*) 
    END;
(*ENDFOR*) 
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74compare_two_records (
            VAR m                   : tgg00_MessBlock;
            VAR selrec              : tgg07_select_param;
            VAR searchrec           : t_search_rec;
            VAR linkrec             : tgg07_KbJoinRec;
            VAR sel                 : tgg00_SelectFieldsParam;
            VAR fulfilled           : boolean;
            VAR first_fulfilled     : boolean;
            VAR end_of_range        : boolean;
            VAR basetab_rec_changed : boolean);
 
CONST
      c_escape  = true;
      c_string  = true;
 
VAR
      _op               : tgg00_StackOpType;
      _linkcnt          : integer;
      _lc_result        : tsp00_LcompResult;
      _eq_cnt           : integer;
      _lpos             : integer;
      _rpos             : integer;
      _change_pos       : integer;
      _ix               : integer;
      _compare_ok       : integer;
      _workbuf          : tkb07_buffer_description;
      _m_def_byte1      : char;
      _first            : boolean;
      _ok               : boolean;
 
      _ptr : PACKED RECORD
            CASE integer OF
                1 :
                    (node_ptr : tbd_nodeptr);
                2 :
                    (buf_ptr  : ^tsp00_Buf);
                3 :
                    (mvob_ptr : tsp00_MoveObjPtr);
                END;
            (*ENDCASE*) 
 
 
BEGIN
_linkcnt            := 1;
_eq_cnt             := _linkcnt;
fulfilled           := true;
first_fulfilled     := true;
_first              := true;
end_of_range        := false;
&IFDEF TRACE
t01int4 (kb, 'jtrans cnt  ', linkrec.kbjr_jointrans_cnt);
t01bool (kb, 'basetab chng', basetab_rec_changed);
&ENDIF
WHILE ((_linkcnt <= linkrec.kbjr_jointrans_cnt) AND fulfilled) DO
    (* compare all columns for a join transition *)
    BEGIN
    _lpos := selrec.selr.selr_l_currpos +
          linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 1 ].kboj_recpos - 1;
    _rpos := linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 2 ].kboj_recpos;
    _op   := linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 1 ].kboj_op;
&   IFDEF TRACE
    t01int4 (kb, 'selr_l_defby', selrec.selr.selr_l_defbyte_pos);
    t01buf1(kb, searchrec.sr_nptr.np_ptr^,
          _lpos, _lpos + linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 1 ].kboj_len - 1);
    t01op (kb, 'operator    ', _op);
    t01buf(kb, selrec.selr_selectbuffer.rbuf,
          _rpos, _rpos + linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[2].kboj_len - 1);
&   ENDIF
    IF  _op in [op_like, op_not_like, op_sounds, op_not_sounds]
    THEN
        BEGIN
        IF  _op in [ op_like, op_not_like ]
        THEN
            BEGIN
            IF  ( linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 1 ].
                kboj_reverse_operands )
            THEN
                BEGIN
                (* build LIKE pattern in temporary result record *)
                _ptr.node_ptr := searchrec.sr_nptr.np_ptr;
                _change_pos   := _lpos;
                _ix           := 1;
&               ifdef trace
                t01name(kb, 'patt in temp resul');
&               endif
                END
            ELSE
                BEGIN
                (* build LIKE pattern in base table record  *)
                (* necessary only one time                  *)
                IF  NOT basetab_rec_changed
                THEN
                    BEGIN
                    _ptr.buf_ptr  := @selrec.selr_selectbuffer.rbuf;
                    _change_pos   := _rpos;
                    _ix           := 2;
                    basetab_rec_changed := true;
                    END
                ELSE
                    _ptr.mvob_ptr := NIL;
                (*ENDIF*) 
&               ifdef trace
                t01name(kb, 'patt in base table');
&               endif
                END;
            (*ENDIF*) 
            IF  _ptr.mvob_ptr <> NIL
            THEN
                BEGIN
                IF  _ptr.mvob_ptr^[ _change_pos ] = csp_unicode_def_byte
                THEN
                    s49uni_build_pattern(
                          _ptr.mvob_ptr^, _change_pos + 1,
                          _change_pos +
                          linkrec.kbjr_jarr[ _linkcnt ].
                          kbji_parts[ _ix ].kboj_len,
                          csp_unicode_blank, NOT c_escape,
                          sqlm_ansi, _ok)
                ELSE
                    s49build_pattern(
                          _ptr.mvob_ptr^,
                          _change_pos + 1,
                          _change_pos +
                          linkrec.kbjr_jarr[ _linkcnt ].
                          kbji_parts[ _ix ].kboj_len,
                          bsp_c1, NOT c_escape, NOT c_string,
                          sqlm_ansi, _ok);
                (*ENDIF*) 
                IF  NOT _ok
                THEN
                    BEGIN
                    IF  m.mb_qual^.msqlmode = sqlm_ansi
                    THEN
                        m.mb_trns^.trError_gg00 := e_illegal_escape_sequence
                    ELSE
                        m.mb_trns^.trError_gg00 := e_invalid_pattern;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        _workbuf.buffer_addr := sel.sfp_workbuf_addr;
        _workbuf.buffer_size := sel.sfp_workbuf_size;
        _workbuf.buffer_len  := sel.sfp_workbuf_len;
        IF  ( linkrec.kbjr_jarr[ _linkcnt ].
            kbji_parts[ 1 ].kboj_reverse_operands )
        THEN
            k71join_comparison (sel, _op, _workbuf,
                  @selrec.selr_selectbuffer.rbuf, _rpos,
                  linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 2 ].kboj_len,
                  @searchrec.sr_nptr.np_ptr^, _lpos,
                  linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 1 ].kboj_len,
                  _compare_ok)
        ELSE
            k71join_comparison (sel, _op, _workbuf,
                  @searchrec.sr_nptr.np_ptr^, _lpos,
                  linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 1 ].kboj_len,
                  @selrec.selr_selectbuffer.rbuf, _rpos,
                  linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 2 ].kboj_len,
                  _compare_ok);
        (*ENDIF*) 
        fulfilled := (_compare_ok = cgg04_is_true);
        IF  ( _linkcnt >= linkrec.kbjr_jpath )
        THEN
            _first := false;
        (*ENDIF*) 
        END
    ELSE
        (* NOT _op in [op_like, op_not_like, op_sounds, op_not_sounds] *)
        BEGIN
&       ifdef trace
        kb74trace_luc (searchrec.sr_nptr.np_ptr^, _lpos,
              linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 1 ].kboj_len,
              @selrec.selr_selectbuffer.rbuf,
              _rpos, linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 2 ].kboj_len,
              _lc_result);
        t01comp_result (kb, 'lc_result   ', _lc_result);
&       else
        s30luc (searchrec.sr_nptr.np_ptr^, _lpos,
              linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 1 ].kboj_len,
              selrec.selr_selectbuffer.rbuf, _rpos,
              linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 2 ].kboj_len,
              _lc_result);
&       endif
        CASE _lc_result OF
            l_equal :
                BEGIN
                fulfilled :=
                      (_op <> op_ne) AND (_op <> op_lt) AND
                      (_op <> op_gt);
                (* *** R3  chars < ' ' at end of fields *** *)
                _m_def_byte1 := searchrec.sr_nptr.np_ptr^.nd_body[ _lpos ];
                IF  (selrec.selr.selr_l_defbyte_pos <> -1) AND
                    (ord (linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 2 ].kboj_op) <>
                    cgg07_left_len_eq_right_len)
                THEN
                    _m_def_byte1 := searchrec.sr_nptr.np_ptr^.nd_body
                          [selrec.selr.selr_l_currpos + selrec.selr.selr_l_defbyte_pos];
                (*ENDIF*) 
                ;
&               ifdef trace
                t01char(kb, '_m_def_byte1', _m_def_byte1 );
&               endif
                IF  _first AND
                    (_op IN [ op_lt, op_le, op_gt, op_ge ]) AND
                    (_m_def_byte1 = csp_ascii_blank)
                THEN
                    BEGIN
&                   ifdef trace
                    t01sname( kb, 'set undef   ' );
&                   endif
                    _lc_result := l_undef;
                    END;
                (*ENDIF*) 
                IF  ( _op = op_lt ) AND
                    ( _lc_result <> l_undef ) AND
                    ( _eq_cnt = _linkcnt ) AND
                    ( _linkcnt > linkrec.kbjr_jpath )
                THEN
                    end_of_range := true;
                (*ENDIF*) 
                _eq_cnt := _eq_cnt + 1
                END;
            l_less :
                BEGIN
                fulfilled :=
                      (_op <> op_eq) AND (_op <> op_gt) AND
                      (_op <> op_ge);
                (* *** R3  chars < ' ' at end of fields *** *)
                _m_def_byte1 := searchrec.sr_nptr.np_ptr^.nd_body[ _lpos ];
                IF  (selrec.selr.selr_l_defbyte_pos <> -1) AND
                    (ord (linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 2 ].kboj_op) <> cgg07_left_len_eq_right_len)
                THEN
                    _m_def_byte1 := searchrec.sr_nptr.np_ptr^.nd_body
                          [selrec.selr.selr_l_currpos + selrec.selr.selr_l_defbyte_pos];
                (*ENDIF*) 
                ;
&               ifdef trace
                t01char(kb, '_m_def_byte1', _m_def_byte1 );
&               endif
                IF  _first AND
                    (_op IN [ op_lt, op_le, op_gt, op_ge ]) AND
                    (_m_def_byte1 = csp_ascii_blank)
                THEN
                    BEGIN
                    s30cmp (searchrec.sr_nptr.np_ptr^, _lpos,
                          linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 1 ].
                          kboj_len,
                          selrec.selr_selectbuffer.rbuf, _rpos,
                          linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 2 ].
                          kboj_len,
                          _lc_result);
&                   IFDEF TRACE
                    t01comp_result (kb, 'lc_result < ', _lc_result);
&                   ENDIF
                    IF  _lc_result = l_greater
                    THEN
                        BEGIN
&                       ifdef trace
                        t01sname( kb, 'set undef   ' );
&                       endif
                        _lc_result := l_undef;
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END;
            l_greater :
                BEGIN
                fulfilled :=
                      (_op <> op_eq) AND (_op <> op_lt) AND
                      (_op <> op_le);
                (* *** R3  chars < ' ' at end of fields *** *)
                _m_def_byte1 := searchrec.sr_nptr.np_ptr^.nd_body[ _lpos ];
                IF  (selrec.selr.selr_l_defbyte_pos <> -1) AND
                    (ord (linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 2 ].kboj_op) <> cgg07_left_len_eq_right_len)
                THEN
                    _m_def_byte1 := searchrec.sr_nptr.np_ptr^.nd_body
                          [selrec.selr.selr_l_currpos + selrec.selr.selr_l_defbyte_pos];
                (*ENDIF*) 
                ;
&               ifdef trace
                t01char(kb, '_m_def_byte1', _m_def_byte1 );
&               endif
                IF  _first AND
                    (_op IN [ op_lt, op_le, op_gt, op_ge ]) AND
                    (_m_def_byte1 = csp_ascii_blank)
                THEN
                    BEGIN
                    s30cmp (searchrec.sr_nptr.np_ptr^, _lpos,
                          linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 1 ].kboj_len,
                          selrec.selr_selectbuffer.rbuf, _rpos,
                          linkrec.kbjr_jarr[ _linkcnt ].kbji_parts[ 2 ].kboj_len,
                          _lc_result);
&                   IFDEF TRACE
                    t01int4 (kb, 'lc_result > ', ord(_lc_result));
&                   ENDIF
                    IF  _lc_result = l_less
                    THEN
                        BEGIN
&                       ifdef trace
                        t01sname( kb, 'set undef   ' );
&                       endif
                        _lc_result := l_undef;
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                IF  NOT fulfilled AND
                    ( _lc_result <> l_undef ) AND
                    ( _eq_cnt = _linkcnt ) AND
                    ( _linkcnt > linkrec.kbjr_jpath )
                THEN
                    end_of_range := true
                (*ENDIF*) 
                END;
            l_undef :
                fulfilled := false
            END;
        (*ENDCASE*) 
        IF  _first
        THEN
            BEGIN
            IF  (_lc_result <> l_undef) OR linkrec.kbjr_left_oj
            THEN
                first_fulfilled := fulfilled;
            (*ENDIF*) 
            IF  ( _linkcnt >= linkrec.kbjr_jpath )
            THEN
                _first := false
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    _linkcnt := succ(_linkcnt);
    END;
(*ENDWHILE*) 
;
&ifdef trace
t01bool (kb, 'end_of_range', end_of_range );
t01p2bool (kb, 'first_fulfil', first_fulfilled,
      'fulfilled   ', fulfilled);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74join_with_left_result (
            VAR m           : tgg00_MessBlock;
            VAR getrec      : tgg07_get_param;
            VAR sel         : tgg00_SelectFieldsParam;
            VAR selrec      : tgg07_select_param);
 
VAR
      _dummy                 : boolean;
      _result_possible       : boolean;
      _e                     : tgg00_BasisError;
      _ic2                   : tsp_int_map_c2;
      _curr_rescount         : tsp00_Int4;
      _rkey_len              : tsp00_Int4;
      _searchrec             : t_search_rec;
      _i                     : tsp00_Int2;
      _compare_len           : tsp00_Int2;
      _length                : tsp00_Int4;
      _aux_countresult       : tsp00_Int4;
 
BEGIN
(* join w/o transition, result contains record from base table *)
_searchrec.sr_res_cnt := 0;
_aux_countresult      := selrec.selr.selr_countresult;
&ifdef trace
t01int4 (kb, 'result.len  ', selrec.selr_selectbuffer.result.len);
t01int4 (kb, 'result.keyle', selrec.selr_selectbuffer.result.keylen);
t01buf (kb, selrec.selr_selectbuffer.result.buf,
      1 + cgg_rec_key_offset, 1 + cgg_rec_key_offset + 50 );
t01name(kb, 'result --> rbuf   ');
&endif
SAPDB_PascalMove ('VKB74 ',  17,    
      sizeof(selrec.selr_selectbuffer.result.buf),
      sizeof(selrec.selr_selectbuffer.rbuf),
      @selrec.selr_selectbuffer.result.buf, 1,
      @selrec.selr_selectbuffer.rbuf, 1,
      selrec.selr.selr_recl,
      m.mb_trns^.trError_gg00);
(* write record length *)
_ic2.map_int                       := selrec.selr.selr_recl;
selrec.selr_selectbuffer.rbuf[ 1 ] := _ic2.map_c2[ 1 ];
selrec.selr_selectbuffer.rbuf[ 2 ] := _ic2.map_c2[ 2 ];
&ifdef trace
t01p2bool (kb, 'r_outer_join', getrec.gi_linkrec.kbjr_right_oj,
      'l_outer_join', getrec.gi_linkrec.kbjr_left_oj);
t01buf (kb, selrec.selr_selectbuffer.rbuf, 1, selrec.selr.selr_recl);
&endif
_compare_len      := 0;
_result_possible  := true;
SAPDB_PascalFill ('VKB74 ',  18,    
      sizeof(_searchrec.sr_lsearchkey.k), @_searchrec.sr_lsearchkey.k, 1,
      sizeof(_searchrec.sr_lsearchkey.k), chr(0),
      m.mb_trns^.trError_gg00);
IF  ( getrec.gi_linkrec.kbjr_jointrans_cnt = 0 )
THEN
    BEGIN
&   ifdef trace
    t01sname( kb, 'no jointrans' );
&   endif
    selrec.selr.selr_first_jlen  := 0;
    _searchrec.sr_lsearchkey.len := 0;
    END
ELSE
    BEGIN
    selrec.selr.selr_first_jlen := 0;
    FOR _i := 1 TO getrec.gi_linkrec.kbjr_jpath - 1 DO
        BEGIN
        selrec.selr.selr_first_jlen := selrec.selr.selr_first_jlen +
              (* part 2 always greather or equal part 1 *)
              getrec.gi_linkrec.kbjr_jarr[ _i ].kbji_parts[ 2 ].kboj_len;
        END;
    (*ENDFOR*) 
    _searchrec.sr_lkey_len := selrec.selr.selr_first_jlen +
          getrec.gi_linkrec.kbjr_jarr[ getrec.gi_linkrec.
          kbjr_jpath ].kbji_parts[ 1 ].kboj_len;
    _rkey_len := selrec.selr.selr_first_jlen +
          getrec.gi_linkrec.kbjr_jarr[ getrec.gi_linkrec.kbjr_jpath ].
          kbji_parts[ 2 ].kboj_len;
    (* choose smaller length *)
    CASE ord(getrec.gi_linkrec.kbjr_jarr[ getrec.gi_linkrec.kbjr_jpath ].
          kbji_parts[ 2 ].kboj_op) OF
        cgg07_left_len_eq_right_len, cgg07_left_len_le_right_len :
            selrec.selr.selr_first_jlen := selrec.selr.selr_first_jlen +
                  getrec.gi_linkrec.kbjr_jarr[ getrec.gi_linkrec.kbjr_jpath ].
                  kbji_parts[ 1 ].kboj_len;
        cgg07_left_len_gt_right_len :
            selrec.selr.selr_first_jlen := selrec.selr.selr_first_jlen +
                  getrec.gi_linkrec.kbjr_jarr[ getrec.gi_linkrec.kbjr_jpath ].
                  kbji_parts[ 2 ].kboj_len;
        END;
    (*ENDCASE*) 
&   ifdef trace
    t01int4 (kb, 'selr_first_j', selrec.selr.selr_first_jlen );
&   endif
    CASE getrec.gi_linkrec.kbjr_jarr[ getrec.gi_linkrec.kbjr_jpath ].
          kbji_parts[ 1 ].kboj_op OF
        op_le, op_lt, op_ne :
            _searchrec.sr_lsearchkey.len := 0;
        op_eq :
            BEGIN
            IF  ( ord( getrec.gi_linkrec.
                kbjr_jarr[ getrec.gi_linkrec.kbjr_jpath ].kbji_parts[ 2 ].
                kboj_op ) = cgg07_left_len_le_right_len)
            THEN
                IF  ( getrec.gi_linkrec.kbjr_jarr[ getrec.gi_linkrec.
                    kbjr_jpath ].kbji_parts[ 1 ].kboj_len <
                    getrec.gi_linkrec.kbjr_jarr[ getrec.gi_linkrec.
                    kbjr_jpath ].kbji_parts[ 2 ].kboj_len )
                THEN
                    BEGIN
                    _length := s30lnr_defbyte(
                          @selrec.selr_selectbuffer.result.buf,
                          (* define byte *)
                          selrec.selr_selectbuffer.result.buf[ cgg_rec_key_offset+1 ],
                          cgg_rec_key_offset + 1,
                          _rkey_len );
                    IF  ( _length > selrec.selr.selr_first_jlen )
                    THEN
                        _result_possible := false;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
            (*ENDIF*) 
            _compare_len  := selrec.selr.selr_first_jlen;
            _searchrec.sr_lsearchkey.len := _rkey_len;
&           ifdef trace
            t01name(kb, 'result.k -> lsearc');
&           endif
            SAPDB_PascalMove ('VKB74 ',  19,    
                  sizeof(selrec.selr_selectbuffer.result.buf),
                  sizeof(_searchrec.sr_lsearchkey.k),
                  @selrec.selr_selectbuffer.result.buf,
                  cgg_rec_key_offset + 1, @_searchrec.sr_lsearchkey.k, 1,
                  selrec.selr.selr_first_jlen, m.mb_trns^.trError_gg00);
            END;
        op_ge :
            BEGIN
            _searchrec.sr_lsearchkey.len := _rkey_len;
&           ifdef trace
            t01name(kb, 'rbuf.k   -> lsearc');
&           endif
            SAPDB_PascalMove ('VKB74 ',  20,    
                  sizeof(selrec.selr_selectbuffer.rbuf),
                  sizeof(_searchrec.sr_lsearchkey.k),
                  @selrec.selr_selectbuffer.rbuf, cgg_rec_key_offset + 1,
                  @_searchrec.sr_lsearchkey.k, 1,
                  selrec.selr.selr_first_jlen, m.mb_trns^.trError_gg00);
            _searchrec.sr_lsearchkey.len :=
                  s30lnr_defbyte(@selrec.selr_selectbuffer.rbuf,
                  selrec.selr_selectbuffer.rbuf[ cgg_rec_key_offset + 1 ],
                  cgg_rec_key_offset + 1,
                  _rkey_len );
&           ifdef trace
            t01buf (kb, selrec.selr_selectbuffer.rbuf,
                  1,4 + selrec.selr.selr_first_jlen);
            t01lkey (kb, _searchrec.sr_lsearchkey);
&           endif
            END;
        op_gt :
            BEGIN
            _searchrec.sr_lsearchkey.len := _rkey_len;
&           ifdef trace
            t01name(kb, 'rbuf.k   -> lsearc');
&           endif
            SAPDB_PascalMove ('VKB74 ',  21,    
                  sizeof(selrec.selr_selectbuffer.rbuf),
                  sizeof(_searchrec.sr_lsearchkey.k),
                  @selrec.selr_selectbuffer.rbuf, cgg_rec_key_offset + 1,
                  @_searchrec.sr_lsearchkey.k, 1,
                  selrec.selr.selr_first_jlen, m.mb_trns^.trError_gg00);
            _searchrec.sr_lsearchkey.len :=
                  s30lnr_defbyte(@selrec.selr_selectbuffer.rbuf,
                  selrec.selr_selectbuffer.rbuf[ cgg_rec_key_offset + 1 ],
                  cgg_rec_key_offset + 1, _rkey_len );
&           ifdef trace
            t01buf (kb, selrec.selr_selectbuffer.rbuf, 1,
                  cgg_rec_key_offset + selrec.selr.selr_first_jlen);
            t01lkey (kb, _searchrec.sr_lsearchkey);
&           endif
            kb74nlbuild_next_lkey (_searchrec.sr_lsearchkey,
                  selrec.selr.selr_first_jlen)
            END;
        OTHERWISE
            BEGIN
            _searchrec.sr_lsearchkey.len := 0;
            END;
        END;
    (*ENDCASE*) 
    END;
(*ENDIF*) 
_curr_rescount := _searchrec.sr_res_cnt;
_searchrec.sr_refused_by_ophase := false;
IF  ( _result_possible )
THEN
    BEGIN
    _searchrec.sr_left_tree_pos.tpsPno_gg00  := NIL_PAGE_NO_GG00;
    _searchrec.sr_nptr.np_ptr                := NIL;
    _searchrec.sr_left_last_pno              := NIL_PAGE_NO_GG00;
    _searchrec.sr_prepare_for_upd            := getrec.gi_linkrec.kbjr_left_oj;
    IF  ( m.mb_trns^.trError_gg00 = e_ok )
    THEN
        (* get first page of temporary result *)
        kb74get_left_leaf (m.mb_trns^, selrec, _searchrec,
              getrec.gi_result_info.o_tree, _searchrec.sr_lsearchkey,
              c_get_next);
    (*ENDIF*) 
    IF  ( m.mb_trns^.trRteCommPtr_gg00^.to_cancel )
    THEN
        _searchrec.sr_error_l := e_cancelled;
    (*ENDIF*) 
    IF  ( _searchrec.sr_error_l = e_ok ) AND ( m.mb_trns^.trError_gg00 = e_ok )
    THEN
        kb74join_with_left_records (m, getrec, selrec, sel, _searchrec, _dummy);
    (*ENDIF*) 
    IF  ( _searchrec.sr_nptr.np_ptr <> NIL )
    THEN
        BEGIN
        _e := m.mb_trns^.trError_gg00;
        b07release_result_leaf (m.mb_trns^, getrec.gi_result_info.o_tree,
              _searchrec.sr_prepare_for_upd, _searchrec.sr_nptr);
        IF  ( _e <> e_ok )
        THEN
            m.mb_trns^.trError_gg00 := _e
        (*ENDIF*) 
        END
    (*ENDIF*) 
    END
ELSE
    (* NOT _result_possible *)
    m.mb_trns^.trError_gg00 := e_ok;
(*ENDIF*) 
&ifdef trace
t01int4 (kb, '_curr_rescnt', _curr_rescount );
t01int4 (kb, 'sr_res_cnt  ', _searchrec.sr_res_cnt );
&endif
IF  ( _curr_rescount = _searchrec.sr_res_cnt )
    AND
    getrec.gi_linkrec.kbjr_right_oj
    AND
    NOT _searchrec.sr_refused_by_ophase
    AND
    ( m.mb_trns^.trError_gg00 = e_ok )
THEN
    BEGIN
    kb74build_new_rec (m, getrec, selrec, _searchrec,
          c_right_needed, right_outer_join);
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74nlbuild_next_lkey (
            VAR next_lkey : tgg00_Lkey;
            fieldlen : tsp00_Int2);
 
VAR
      _ix : integer;
 
BEGIN
_ix := next_lkey.len;
&IFDEF TRACE
t01lkey (kb, next_lkey);
t01int4 (kb, 'fieldlen    ',fieldlen);
&ENDIF
IF  (next_lkey.len < fieldlen)
THEN
    BEGIN
    FOR _ix  := succ (next_lkey.len) TO fieldlen DO
        next_lkey.k[ _ix ] := chr (0);
    (*ENDFOR*) 
    next_lkey.len := fieldlen;
    (* *** R3  chars < ' ' at end of fields *** *)
    IF  (next_lkey.k[ 1 ] = chr(0))
    THEN
        next_lkey.k[ next_lkey.len ] := chr (1);
    (*ENDIF*) 
    END
ELSE
    WHILE (_ix > 0) DO
        BEGIN
        IF  (next_lkey.k[ _ix ] = chr (255))
        THEN
            next_lkey.k[ _ix ] := chr (0)
        ELSE
            BEGIN
            next_lkey.k[ _ix ] := succ (next_lkey.k[ _ix ]);
            _ix      := 0;
            END;
        (*ENDIF*) 
        _ix := pred (_ix);
        END;
    (*ENDWHILE*) 
(*ENDIF*) 
&IFDEF TRACE
t01int4 (kb, 'len         ',_ix);
t01lkey (kb, next_lkey);
&ENDIF
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74convert_inv_key (
            VAR conv_st_pos    : tkb07_conv_arr;
            conv_cnt           : integer;
            VAR inv_key        : tgg00_Lkey);
 
VAR
      _ix : integer;
      _jx : integer;
 
BEGIN
FOR _ix := 1 TO conv_cnt DO
    WITH conv_st_pos[_ix] DO
        BEGIN
        IF  ct_codeno <> 0
        THEN
            s30map (g02codetables.tables[ct_codeno],
                  inv_key.k, ct_epos - cgg_rec_key_offset,
                  inv_key.k, ct_epos - cgg_rec_key_offset,
                  ct_elenvar);
        (*ENDIF*) 
        IF  ct_is_desc
        THEN
            BEGIN
            FOR _jx := (ct_epos - cgg_rec_key_offset) TO
                  (ct_epos + ct_elenvar - cgg_rec_key_offset - 1) DO
                inv_key.k[_jx] := chr(255 - ord(inv_key.k[_jx]));
            (*ENDFOR*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDWITH*) 
(*ENDFOR*) 
&ifdef trace
t01key (kb, 'conv invkey ', inv_key);
&endif
END;
 
(*------------------------------*) 
 
FUNCTION
      kb74eval_invkey_len (
            VAR m         : tgg00_MessBlock;
            VAR selrec    : tgg07_select_param;
            field_cnt     : integer;
            test_pos      : integer) : integer;
 
VAR
      _invkey : tgg00_Lkey;
 
BEGIN
IF  (test_pos > 0) AND (field_cnt = 1) AND
    (m.mb_st^[test_pos].etype in [st_fixkey, st_fixcol])
THEN
    kb74eval_invkey_len := m.mb_st^[test_pos].elen_var
ELSE
    BEGIN
    _invkey.k[1] := chr(1);
    _invkey.len  := 1;
    b03next_invkey (m.mb_trns^, selrec.selr.selr_inv_id, true, _invkey);
    IF  (m.mb_trns^.trError_gg00 = e_ok) OR
        (m.mb_trns^.trError_gg00 = e_key_not_found)
    THEN
        BEGIN
        m.mb_trns^.trError_gg00      := e_ok;
        kb74eval_invkey_len := _invkey.len
        END
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74inv_direct_search (
            VAR m         : tgg00_MessBlock;
            VAR getrec    : tgg07_get_param;
            VAR selrec    : tgg07_select_param;
            VAR sel       : tgg00_SelectFieldsParam;
            invlen        : tsp00_Int4;
            VAR searchrec : t_search_rec);
 
VAR
      _error_i            : tgg00_BasisError;
      _is_descending      : boolean;
      _skip_left          : boolean;
      _restore_left       : boolean; (* h.b. PTS 1104826 *)
      _use_stopprim       : boolean;
      _keyLen             : tsp00_IntMapC2;
      _bd_invset          : tgg00_BdInvSet;
      _conv_cnt           : integer;
      _key_pos            : integer;
      _j                  : integer;
      _inv_buf_fill_len   : integer;
      _curr_rescount      : tsp00_Int4;
      _primkeycnt         : tsp00_Int4;
      _curr_tree_pos      : tgg00_FilePos;
      _conv_st_pos        : tkb07_conv_arr;
      _last_inv_field_pos : tsp00_Int2;
 
BEGIN
_use_stopprim := sel.sfp_bd_use_stopkey;
k74check_inv_conversions (m, _conv_st_pos, _conv_cnt,
      _last_inv_field_pos, _is_descending,
      getrec.gi_linkrec.kbjr_jpath );
selrec.selr.selr_l_defbyte_pos := _last_inv_field_pos;
&IFDEF TRACE
t01bool (kb, '_is_desc    ', _is_descending);
t01int4 (kb, 'conv_cnt    ', _conv_cnt);
t01int4 (kb, 'conv_cnt    ', _conv_cnt);
t01int4 (kb, 'last_inv_fld', _last_inv_field_pos);
t01int4 (kb, 'selr_f_jlen ', selrec.selr.selr_first_jlen);
t01int4 (kb, 'invlen      ', invlen);
&ENDIF
IF  _use_stopprim
THEN
    _bd_invset := [primary_stop, incl_first]
ELSE
    _bd_invset := [incl_first];
(*ENDIF*) 
WHILE (m.mb_trns^.trError_gg00 = e_ok) AND (searchrec.sr_error_l = e_ok) DO
    BEGIN
    selrec.selr.selr_l_currpos :=
          searchrec.sr_nptr.np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -
          searchrec.sr_left_tree_pos.tpsIndex_gg00];
    selrec.selr.selr_invkey.len := s30lnr_defbyte (@searchrec.sr_nptr.np_ptr^,
          searchrec.sr_nptr.np_ptr^.nd_body
          [selrec.selr.selr_l_currpos + _last_inv_field_pos -1],
          selrec.selr.selr_l_currpos + _last_inv_field_pos,
          searchrec.sr_lkey_len -
          _last_inv_field_pos + cgg_rec_key_offset) +
          _last_inv_field_pos - cgg_rec_key_offset;
    SAPDB_PascalMove ('VKB74 ',  22,    
          sizeof(searchrec.sr_nptr.np_ptr^), sizeof(selrec.selr.selr_invkey.k),
          @searchrec.sr_nptr.np_ptr^,
          selrec.selr.selr_l_currpos + cgg_rec_key_offset,
          @selrec.selr.selr_invkey.k, 1, selrec.selr.selr_invkey.len,
          m.mb_trns^.trError_gg00);
&   ifdef trace
    t01int4 (kb, 'invkey.len  ', selrec.selr.selr_invkey.len );
    t01key (kb, 'invkey      ', selrec.selr.selr_invkey );
&   endif
    IF  selrec.selr.selr_invkey.len <= selrec.selr.selr_first_jlen
    THEN
        BEGIN
        IF  _conv_cnt > 0
        THEN
            kb74convert_inv_key( _conv_st_pos, _conv_cnt, selrec.selr.selr_invkey);
        (*ENDIF*) 
        IF  _is_descending AND (selrec.selr.selr_invkey.len < invlen)
        THEN
            BEGIN
&           ifdef trace
            t01int4( kb, 'expand ikey ', invlen - selrec.selr.selr_invkey.len );
&           endif
            IF  selrec.selr.selr_invkey.k [ _last_inv_field_pos - cgg_rec_key_offset ]
                = chr(255 - ord(csp_unicode_def_byte))
            THEN
                BEGIN
                g20unifill (sizeof(selrec.selr.selr_invkey.k),
                      @selrec.selr.selr_invkey.k, selrec.selr.selr_invkey.len+1,
                      invlen - selrec.selr.selr_invkey.len,
                      csp_unicode_blank);
                FOR _j := selrec.selr.selr_invkey.len + 1 TO invlen DO
                    selrec.selr.selr_invkey.k[ _j ] :=
                          chr(255 - ord(selrec.selr.selr_invkey.k[ _j ]));
                (*ENDFOR*) 
                END
            ELSE
                SAPDB_PascalFill ('VKB74 ',  23,    
                      sizeof (selrec.selr.selr_invkey.k), @selrec.selr.selr_invkey.k,
                      selrec.selr.selr_invkey.len + 1, invlen - selrec.selr.selr_invkey.len,
                      selrec.selr.selr_invkey.k[_last_inv_field_pos -
                      cgg_rec_key_offset], m.mb_trns^.trError_gg00);
            (*ENDIF*) 
            selrec.selr.selr_invkey.len := invlen
            END;
        (*ENDIF*) 
        searchrec.sr_rsearchkey.len := selrec.selr.selr_startkey.len;
        SAPDB_PascalMove ('VKB74 ',  24,    
              sizeof (selrec.selr.selr_startkey.k), sizeof (searchrec.sr_rsearchkey.k),
              @selrec.selr.selr_startkey.k, 1, @searchrec.sr_rsearchkey.k, 1,
              selrec.selr.selr_startkey.len, m.mb_trns^.trError_gg00);
        _error_i := e_buffer_limit
        END
    ELSE (* selrec.selr.selr_invkey.len > selrec.selr.selr_first_jlen *)
        _error_i := e_inv_list_not_found;
    (*ENDIF*) 
    _curr_rescount := searchrec.sr_res_cnt;
    _curr_tree_pos := searchrec.sr_left_tree_pos;
    _skip_left     := true;
    _restore_left  := false;  (* h.b. PTS 1104826 *)
    WHILE (_error_i = e_buffer_limit) AND
          (m.mb_trns^.trError_gg00 = e_ok) DO
        BEGIN
        b03get_inv (m.mb_trns^, selrec.selr.selr_inv_id, selrec.selr.selr_invkey,
              searchrec.sr_rsearchkey, selrec.selr.selr_stopkey,
              searchrec.sr_rsearchkey, _bd_invset,
              NOT c_count_only, lckFree_egg00, selrec.selr_selectbuffer.inv_buf.buf,
              _primkeycnt, _inv_buf_fill_len);
        _error_i           := m.mb_trns^.trError_gg00;
        m.mb_trns^.trError_gg00 := e_ok;
        IF  (_error_i = e_ok) OR (_error_i = e_buffer_limit)
        THEN
            BEGIN
            _bd_invset := _bd_invset - [incl_first];
            _key_pos   := 1;
            WHILE (_key_pos < _inv_buf_fill_len) AND
                  (m.mb_trns^.trError_gg00 = e_ok  ) DO
                BEGIN
                _keyLen.mapC2_sp00 [1]    := selrec.selr_selectbuffer.inv_buf.buf[_key_pos];
                _keyLen.mapC2_sp00 [2]    := selrec.selr_selectbuffer.inv_buf.buf[_key_pos+1];
                searchrec.sr_rsearchkey.keyLen_gg00 :=
                      _keyLen.mapInt_sp00;
                SAPDB_PascalMove ('VKB74 ',  25,    
                      sizeof (selrec.selr_selectbuffer.inv_buf.buf),
                      sizeof (searchrec.sr_rsearchkey.k), @selrec.selr_selectbuffer.inv_buf.buf,
                      _key_pos + 2, @searchrec.sr_rsearchkey.k, 1,
                      searchrec.sr_rsearchkey.len, m.mb_trns^.trError_gg00);
                IF  (m.mb_trns^.trError_gg00 = e_ok)
                THEN
                    kb74get_right_record (m, selrec,
                          mm_direct, searchrec.sr_rsearchkey, sel);
                (*ENDIF*) 
                IF  m.mb_trns^.trError_gg00 = e_ok
                THEN
                    BEGIN
                    IF  _restore_left  (* h.b. PTS 1104826 *)
                    THEN
                        kb74restore_page (m, _curr_tree_pos,
                              getrec.gi_result_info.o_tree, selrec, searchrec);
                    (*ENDIF*) 
                    IF  ( m.mb_trns^.trError_gg00 = e_ok )
                    THEN
                        BEGIN
                        _restore_left  := true; (* h.b. PTS 1104826 *)
                        _skip_left     := false;
                        kb74join_with_left_records (m,
                              getrec, selrec, sel, searchrec,
                              _skip_left)
                        END;
                    (*ENDIF*) 
                    END
                ELSE
                    BEGIN
                    IF  ( 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*) 
                    END;
                (*ENDIF*) 
                _key_pos := _key_pos + searchrec.sr_rsearchkey.len + 2
                END;
            (*ENDWHILE*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDWHILE*) 
    IF  ( m.mb_trns^.trError_gg00 = e_ok )
    THEN
        BEGIN
        IF  ( _error_i <> e_inv_list_not_found )
        THEN
            m.mb_trns^.trError_gg00 := _error_i
        ELSE
            BEGIN
            IF  (( _conv_cnt = 0 ) AND NOT getrec.gi_linkrec.kbjr_left_oj )
            THEN
                BEGIN
                (* !!! don't synchronise with conversions !!!! *)
                (* next invkey yields new position in *)
                (* left side                          *)
                b03next_invkey (m.mb_trns^, selrec.selr.selr_inv_id,
                      NOT c_inclusive, selrec.selr.selr_invkey);
                IF  ( m.mb_trns^.trError_gg00 = e_ok )
                THEN
                    BEGIN
                    _skip_left := false;
                    kb74synchronize_left_rec (m, selrec.selr.selr_invkey,
                          getrec, searchrec, selrec)
                    END
                ELSE
                    IF  ( m.mb_trns^.trError_gg00 = e_no_next_invkey ) OR
                        ( m.mb_trns^.trError_gg00 = e_inv_list_not_found )
                    THEN
                        BEGIN
                        (* end of right table, stop *)
                        searchrec.sr_error_l    := e_no_next_record;
                        m.mb_trns^.trError_gg00 := e_ok
                        END;
                    (*ENDIF*) 
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( m.mb_trns^.trError_gg00 = e_ok )
    THEN
        IF  ( getrec.gi_linkrec.kbjr_left_oj AND
            ( _curr_rescount = searchrec.sr_res_cnt ))
        THEN
            BEGIN
            IF  NOT _skip_left
            THEN
                kb74restore_page (m, _curr_tree_pos,
                      getrec.gi_result_info.o_tree, selrec, searchrec);
            (*ENDIF*) 
            searchrec.sr_rsearchkey.len := selrec.selr.selr_first_jlen;
            kb74left_scan_to_nxt_key (m, getrec, searchrec, selrec,
                  c_is_right_outer_join)
            END
        ELSE
            IF  _skip_left
            THEN
                BEGIN
                searchrec.sr_rsearchkey.len := selrec.selr.selr_first_jlen;
                kb74left_scan_to_nxt_key (m,
                      getrec, searchrec, selrec,
                      NOT c_is_right_outer_join)
                END;
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
    THEN
        searchrec.sr_error_l := e_cancelled;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
IF  ( m.mb_trns^.trError_gg00 = e_ok ) AND
    ( searchrec.sr_error_l <> e_ok ) AND
    ( searchrec.sr_error_l <> e_no_next_record )
THEN
    m.mb_trns^.trError_gg00 := searchrec.sr_error_l
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74inv_direct_search_parallel (
            VAR m         : tgg00_MessBlock;
            VAR getrec    : tgg07_get_param;
            VAR selrec    : tgg07_select_param;
            VAR sel       : tgg00_SelectFieldsParam;
            invlen        : tsp00_Int4;
            VAR searchrec : t_search_rec);
 
VAR
      _error_i            : tgg00_BasisError;
      _is_descending      : boolean;
      _skip_left          : boolean;
      _restore_left       : boolean; (* h.b. PTS 1104826 *)
      _use_stopprim       : boolean;
      _bd_invset          : tgg00_BdInvSet;
      _conv_cnt           : integer;
      _j                  : integer;
      _pIter              : tgg00_VoidPtr;
      _curr_rescount      : tsp00_Int4;
      _curr_tree_pos      : tgg00_FilePos;
      _conv_st_pos        : tkb07_conv_arr;
      _last_inv_field_pos : tsp00_Int2;
 
BEGIN
_pIter := k742CreateInvIterator (m, sel, selrec);
IF  _pIter = NIL
THEN (* no memory or parallel execution disabled, run old code *)
    kb74inv_direct_search (m, getrec, selrec, sel, invlen, searchrec)
ELSE
    BEGIN
    _use_stopprim := sel.sfp_bd_use_stopkey;
    k74check_inv_conversions (m, _conv_st_pos, _conv_cnt,
          _last_inv_field_pos, _is_descending,
          getrec.gi_linkrec.kbjr_jpath);
    selrec.selr.selr_l_defbyte_pos := _last_inv_field_pos;
&   IFDEF TRACE
    t01bool (kb, '_is_desc    ', _is_descending);
    t01int4 (kb, 'conv_cnt    ', _conv_cnt);
    t01int4 (kb, 'conv_cnt    ', _conv_cnt);
    t01int4 (kb, 'last_inv_fld', _last_inv_field_pos);
    t01int4 (kb, 'selr_f_jlen ', selrec.selr.selr_first_jlen);
    t01int4 (kb, 'invlen      ', invlen);
&   ENDIF
    IF  _use_stopprim
    THEN
        _bd_invset := [primary_stop, incl_first]
    ELSE
        _bd_invset := [incl_first];
    (*ENDIF*) 
    WHILE (m.mb_trns^.trError_gg00 = e_ok) AND (searchrec.sr_error_l = e_ok) DO
        BEGIN
        selrec.selr.selr_l_currpos :=
              searchrec.sr_nptr.np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -
              searchrec.sr_left_tree_pos.tpsIndex_gg00];
        selrec.selr.selr_invkey.len := s30lnr_defbyte (@searchrec.sr_nptr.np_ptr^,
              searchrec.sr_nptr.np_ptr^.nd_body
              [selrec.selr.selr_l_currpos + _last_inv_field_pos -1],
              selrec.selr.selr_l_currpos + _last_inv_field_pos,
              searchrec.sr_lkey_len -
              _last_inv_field_pos + cgg_rec_key_offset) +
              _last_inv_field_pos - cgg_rec_key_offset;
        SAPDB_PascalMove ('VKB74 ',  26,    
              sizeof(searchrec.sr_nptr.np_ptr^), sizeof(selrec.selr.selr_invkey.k),
              @searchrec.sr_nptr.np_ptr^,
              selrec.selr.selr_l_currpos + cgg_rec_key_offset,
              @selrec.selr.selr_invkey.k, 1, selrec.selr.selr_invkey.len,
              m.mb_trns^.trError_gg00);
&       ifdef trace
        t01int4(kb, 'invkey.len  ', selrec.selr.selr_invkey.len);
        t01key (kb, 'invkey      ', selrec.selr.selr_invkey );
&       endif
        IF  selrec.selr.selr_invkey.len <= selrec.selr.selr_first_jlen
        THEN
            BEGIN
            IF  _conv_cnt > 0
            THEN
                kb74convert_inv_key( _conv_st_pos, _conv_cnt, selrec.selr.selr_invkey);
            (*ENDIF*) 
            IF  _is_descending AND (selrec.selr.selr_invkey.len < invlen)
            THEN
                BEGIN
&               ifdef trace
                t01int4( kb, 'expand ikey ', invlen - selrec.selr.selr_invkey.len );
&               endif
                IF  selrec.selr.selr_invkey.k [ _last_inv_field_pos - cgg_rec_key_offset ]
                    = chr(255 - ord(csp_unicode_def_byte))
                THEN
                    BEGIN
                    g20unifill (sizeof(selrec.selr.selr_invkey.k),
                          @selrec.selr.selr_invkey.k, selrec.selr.selr_invkey.len+1,
                          invlen - selrec.selr.selr_invkey.len,
                          csp_unicode_blank);
                    FOR _j := selrec.selr.selr_invkey.len + 1 TO invlen DO
                        selrec.selr.selr_invkey.k[ _j ] :=
                              chr(255 - ord(selrec.selr.selr_invkey.k[ _j ]));
                    (*ENDFOR*) 
                    END
                ELSE
                    SAPDB_PascalFill ('VKB74 ',  27,    
                          sizeof (selrec.selr.selr_invkey.k), @selrec.selr.selr_invkey.k,
                          selrec.selr.selr_invkey.len + 1, invlen - selrec.selr.selr_invkey.len,
                          selrec.selr.selr_invkey.k[_last_inv_field_pos -
                          cgg_rec_key_offset], m.mb_trns^.trError_gg00);
                (*ENDIF*) 
                selrec.selr.selr_invkey.len := invlen
                END;
            (*ENDIF*) 
            searchrec.sr_rsearchkey.len := selrec.selr.selr_startkey.len;
            SAPDB_PascalMove ('VKB74 ',  28,    
                  sizeof (selrec.selr.selr_startkey.k), sizeof (searchrec.sr_rsearchkey.k),
                  @selrec.selr.selr_startkey.k, 1, @searchrec.sr_rsearchkey.k, 1,
                  selrec.selr.selr_startkey.len, m.mb_trns^.trError_gg00);
            _error_i := e_ok;
            END
        ELSE (* selrec.selr.selr_invkey.len > selrec.selr.selr_first_jlen *)
            _error_i := e_inv_list_not_found;
        (*ENDIF*) 
        IF  _error_i = e_ok
        THEN
            BEGIN
            _curr_rescount := searchrec.sr_res_cnt;
            _curr_tree_pos := searchrec.sr_left_tree_pos;
            _skip_left     := true;
            _restore_left  := false;  (* h.b. PTS 1104826 *)
            k742OpenIterator (_pIter, sel, selrec, _bd_invset);
            REPEAT
                sel.sfp_result_length   := 0;
                sel.sfp_m_result_len    := 0;
                sel.sfp_m_result_addr   := @selrec.selr_selectbuffer.rbuf;
                sel.sfp_m_result_size   := sizeof (selrec.selr_selectbuffer.rbuf);
                m.mb_trns^.trError_gg00 := k742Next (_pIter);
                IF  m.mb_trns^.trError_gg00 = e_ok
                THEN
                    BEGIN
&                   ifdef trace
                    t01buf (kb, selrec.selr_selectbuffer.rbuf, 1, sel.sfp_m_result_len);
&                   endif
                    IF  _restore_left  (* h.b. PTS 1104826 *)
                    THEN
                        kb74restore_page (m, _curr_tree_pos,
                              getrec.gi_result_info.o_tree, selrec, searchrec);
                    (*ENDIF*) 
                    IF  ( m.mb_trns^.trError_gg00 = e_ok )
                    THEN
                        BEGIN
                        _restore_left  := true; (* h.b. PTS 1104826 *)
                        _skip_left     := false;
                        kb74join_with_left_records (m,
                              getrec, selrec, sel, searchrec,
                              _skip_left)
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
            UNTIL
                m.mb_trns^.trError_gg00 <> e_ok;
            (*ENDREPEAT*) 
            k742CloseIterator(_pIter);
            IF  m.mb_trns^.trError_gg00 = e_no_next_record
            THEN
                m.mb_trns^.trError_gg00 := e_ok;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  ( m.mb_trns^.trError_gg00 = e_ok )
        THEN
            IF  ( _error_i <> e_inv_list_not_found )
            THEN
                m.mb_trns^.trError_gg00 := _error_i
            ELSE
                IF  (( _conv_cnt = 0 ) AND NOT getrec.gi_linkrec.kbjr_left_oj )
                THEN
                    BEGIN
                    (* !!! don't synchronise with conversions !!!! *)
                    (* next invkey yields new position in *)
                    (* left side                          *)
                    b03next_invkey (m.mb_trns^, selrec.selr.selr_inv_id,
                          NOT c_inclusive, selrec.selr.selr_invkey);
                    IF  ( m.mb_trns^.trError_gg00 = e_ok )
                    THEN
                        BEGIN
                        _skip_left := false;
                        kb74synchronize_left_rec (m, selrec.selr.selr_invkey,
                              getrec, searchrec, selrec)
                        END
                    ELSE
                        IF  ( m.mb_trns^.trError_gg00 = e_no_next_invkey ) OR
                            ( m.mb_trns^.trError_gg00 = e_inv_list_not_found )
                        THEN
                            BEGIN
                            (* end of right table, stop *)
                            searchrec.sr_error_l    := e_no_next_record;
                            m.mb_trns^.trError_gg00 := e_ok
                            END;
                        (*ENDIF*) 
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
            (*ENDIF*) 
        (*ENDIF*) 
        IF  ( m.mb_trns^.trError_gg00 = e_ok )
        THEN
            IF  ( getrec.gi_linkrec.kbjr_left_oj AND
                ( _curr_rescount = searchrec.sr_res_cnt ))
            THEN
                BEGIN
                IF  NOT _skip_left
                THEN
                    kb74restore_page (m, _curr_tree_pos,
                          getrec.gi_result_info.o_tree, selrec, searchrec);
                (*ENDIF*) 
                searchrec.sr_rsearchkey.len := selrec.selr.selr_first_jlen;
                kb74left_scan_to_nxt_key (m, getrec, searchrec, selrec,
                      c_is_right_outer_join)
                END
            ELSE
                IF  _skip_left
                THEN
                    BEGIN
                    searchrec.sr_rsearchkey.len := selrec.selr.selr_first_jlen;
                    kb74left_scan_to_nxt_key (m,
                          getrec, searchrec, selrec,
                          NOT c_is_right_outer_join)
                    END;
                (*ENDIF*) 
            (*ENDIF*) 
        (*ENDIF*) 
        IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
        THEN
            searchrec.sr_error_l := e_cancelled;
        (*ENDIF*) 
        END;
    (*ENDWHILE*) 
    IF  ( m.mb_trns^.trError_gg00 = e_ok ) AND
        ( searchrec.sr_error_l <> e_ok ) AND
        ( searchrec.sr_error_l <> e_no_next_record )
    THEN
        m.mb_trns^.trError_gg00 := searchrec.sr_error_l;
    (*ENDIF*) 
    k742DestroyIterator(_pIter);
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74inv_next_search (
            VAR m         : tgg00_MessBlock;
            VAR getrec    : tgg07_get_param;
            VAR selrec    : tgg07_select_param;
            VAR sel       : tgg00_SelectFieldsParam;
            VAR searchrec : t_search_rec);
 
VAR
      _error_i            : tgg00_BasisError;
      _is_descending      : boolean;
      _skip_left          : boolean;
      _use_stopprim       : boolean;
      _inclusive          : boolean;
      _restore_left       : boolean;
      _lc_result          : tsp00_LcompResult;
      _cmp_result         : tsp00_LcompResult;
      _keyLen             : tsp00_IntMapC2;
      _bd_invset          : tgg00_BdInvSet;
      _conv_cnt           : integer;
      _key_pos            : integer;
      _inv_buf_fill_len   : integer;
      _curr_rescount      : tsp00_Int4;
      _primkeycnt         : tsp00_Int4;
      _curr_tree_pos      : tgg00_FilePos;
      _conv_st_pos        : tkb07_conv_arr;
      _curr_invkey        : tgg00_Lkey;
      _last_inv_field_pos : tsp00_Int2;
 
BEGIN
_use_stopprim := sel.sfp_bd_use_stopkey;
k74check_inv_conversions (m, _conv_st_pos, _conv_cnt,
      _last_inv_field_pos, _is_descending,
      getrec.gi_linkrec.kbjr_jpath);
selrec.selr.selr_l_defbyte_pos := _last_inv_field_pos;
WHILE (m.mb_trns^.trError_gg00 = e_ok) AND (searchrec.sr_error_l = e_ok) DO
    BEGIN
    selrec.selr.selr_l_currpos :=
          searchrec.sr_nptr.np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -
          searchrec.sr_left_tree_pos.tpsIndex_gg00];
    _curr_invkey.len := selrec.selr.selr_first_jlen;
    SAPDB_PascalMove ('VKB74 ',  29,    
          sizeof(searchrec.sr_nptr.np_ptr^), sizeof(_curr_invkey.k),
          @searchrec.sr_nptr.np_ptr^,
          selrec.selr.selr_l_currpos + cgg_rec_key_offset,
          @_curr_invkey.k, 1, _curr_invkey.len, m.mb_trns^.trError_gg00);
&   ifdef trace
    t01key (kb, 'invkey      ', _curr_invkey );
&   endif
    IF  _conv_cnt > 0
    THEN
        kb74convert_inv_key( _conv_st_pos, _conv_cnt, _curr_invkey);
    (*ENDIF*) 
    selrec.selr.selr_invkey.len := _curr_invkey.len;
    SAPDB_PascalMove ('VKB74 ',  30,    
          sizeof (_curr_invkey.k), sizeof (selrec.selr.selr_invkey.k),
          @_curr_invkey.k, 1, @selrec.selr.selr_invkey.k, 1,
          selrec.selr.selr_invkey.len, m.mb_trns^.trError_gg00);
    _curr_tree_pos := searchrec.sr_left_tree_pos;
    _inclusive     := true;
    _skip_left     := true;
    _restore_left  := false;
    _curr_rescount := searchrec.sr_res_cnt;
    REPEAT
        (* execute one inv list *)
        b03next_invkey (m.mb_trns^, selrec.selr.selr_inv_id, _inclusive,
              selrec.selr.selr_invkey);
        _inclusive := false;
        IF  m.mb_trns^.trError_gg00 = e_ok
        THEN
            s30cmp2 (_curr_invkey.k, 1, selrec.selr.selr_first_jlen,
                  selrec.selr.selr_invkey.k, 1, selrec.selr.selr_first_jlen,
                  _lc_result)
        ELSE
            BEGIN
            _lc_result := l_greater;
            IF  ((m.mb_trns^.trError_gg00 = e_no_next_invkey     ) OR
                ( m.mb_trns^.trError_gg00 = e_inv_list_not_found))
                AND
                NOT getrec.gi_linkrec.kbjr_left_oj
            THEN
                BEGIN
                (* end of right table, stop *)
                _skip_left := false;
                searchrec.sr_error_l   := e_no_next_record
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  _lc_result = l_equal
        THEN
            BEGIN
            (* current inv key fulfills prefix condition *)
            (* handle corresponding inv list             *)
            IF  _use_stopprim
            THEN
                _bd_invset := [primary_stop, incl_first]
            ELSE
                _bd_invset := [incl_first];
            (*ENDIF*) 
            searchrec.sr_rsearchkey.len := selrec.selr.selr_startkey.len;
            SAPDB_PascalMove ('VKB74 ',  31,    
                  sizeof (selrec.selr.selr_startkey.k),
                  sizeof (searchrec.sr_rsearchkey.k),
                  @selrec.selr.selr_startkey.k, 1, @searchrec.sr_rsearchkey.k, 1,
                  selrec.selr.selr_startkey.len, m.mb_trns^.trError_gg00);
            REPEAT
                b03get_inv (m.mb_trns^, selrec.selr.selr_inv_id, selrec.selr.selr_invkey,
                      searchrec.sr_rsearchkey, searchrec.sr_rsearchkey,
                      selrec.selr.selr_stopkey, _bd_invset,
                      NOT c_count_only, lckFree_egg00,
                      selrec.selr_selectbuffer.inv_buf.buf,
                      _primkeycnt, _inv_buf_fill_len);
                _error_i           := m.mb_trns^.trError_gg00;
                m.mb_trns^.trError_gg00 := e_ok;
                IF  (_error_i = e_ok) OR (_error_i = e_buffer_limit)
                THEN
                    BEGIN
                    _bd_invset := _bd_invset - [incl_first];
                    _key_pos   := 1;
                    WHILE (_key_pos < _inv_buf_fill_len) AND
                          (m.mb_trns^.trError_gg00 = e_ok  ) DO
                        BEGIN
                        _keyLen.mapC2_sp00 [1]    := selrec.selr_selectbuffer.inv_buf.buf[_key_pos];
                        _keyLen.mapC2_sp00 [2]    := selrec.selr_selectbuffer.inv_buf.buf[_key_pos+1];
                        searchrec.sr_rsearchkey.keyLen_gg00 := _keyLen.mapInt_sp00;
                        SAPDB_PascalMove ('VKB74 ',  32,    
                              sizeof (selrec.selr_selectbuffer.inv_buf.buf),
                              sizeof (searchrec.sr_rsearchkey.k),
                              @selrec.selr_selectbuffer.inv_buf.buf,
                              _key_pos + 2, @searchrec.sr_rsearchkey.k, 1,
                              searchrec.sr_rsearchkey.len,
                              m.mb_trns^.trError_gg00);
                        kb74get_right_record (m, selrec,
                              mm_direct, searchrec.sr_rsearchkey, sel);
                        IF  m.mb_trns^.trError_gg00 = e_ok
                        THEN
                            BEGIN
                            IF  _restore_left
                            THEN
                                kb74restore_page (m, _curr_tree_pos,
                                      getrec.gi_result_info.o_tree, selrec,
                                      searchrec);
                            (*ENDIF*) 
                            IF  m.mb_trns^.trError_gg00 = e_ok
                            THEN
                                BEGIN
                                _restore_left := true;
                                _skip_left    := false;
                                kb74join_with_left_records (m,
                                      getrec, selrec, sel, searchrec,
                                      _skip_left)
                                END
                            (*ENDIF*) 
                            END
                        ELSE
                            IF  (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;
&                           ifdef trace
                            (*ENDIF*) 
                        (*ENDIF*) 
                        t01basis_error (kb, 'loop        ', m.mb_trns^.trError_gg00);
&                       endif
                        _key_pos := _key_pos + searchrec.sr_rsearchkey.len + 2
                        END;
                    (*ENDWHILE*) 
                    END;
                (*ENDIF*) 
            UNTIL
                (_error_i <> e_buffer_limit) OR
                (m.mb_trns^.trError_gg00 <> e_ok);
            (*ENDREPEAT*) 
            IF  m.mb_trns^.trError_gg00 = e_ok
            THEN
                IF  _error_i <> e_inv_list_not_found
                THEN
                    m.mb_trns^.trError_gg00 := _error_i;
                (*ENDIF*) 
            (*ENDIF*) 
            END
        ELSE
            IF  (_lc_result = l_less   ) AND
                (_conv_cnt  = 0        ) AND
                NOT getrec.gi_linkrec.kbjr_left_oj
            THEN
                BEGIN
                _skip_left       := false;
                selrec.selr.selr_invkey.len := selrec.selr.selr_first_jlen;
                IF  searchrec.sr_error_l = e_ok
                THEN
                    BEGIN
&                   ifdef trace
                    kb74trace_luc (searchrec.sr_nptr.np_ptr^,
                          selrec.selr.selr_l_currpos + cgg_rec_key_offset,
                          selrec.selr.selr_first_jlen, @selrec.selr.selr_invkey.k, 1,
                          selrec.selr.selr_first_jlen, _cmp_result);
&                   endif
                    s30cmp1 (selrec.selr.selr_invkey.k, 1,
                          selrec.selr.selr_first_jlen,
                          searchrec.sr_nptr.np_ptr^,
                          selrec.selr.selr_l_currpos + cgg_rec_key_offset,
                          selrec.selr.selr_first_jlen, _cmp_result);
                    IF  _cmp_result = l_greater
                    THEN (* invkey found is greater *)
                        (*  than curr left key      *)
                        kb74synchronize_left_rec (m, selrec.selr.selr_invkey,
                              getrec, searchrec, selrec)
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
        (*ENDIF*) 
        IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
        THEN
            searchrec.sr_error_l := e_cancelled;
&       ifdef trace
        (*ENDIF*) 
        t01basis_error (kb, 'm.err until ', m.mb_trns^.trError_gg00);
&       endif
    UNTIL
        (_lc_result <> l_equal     ) OR
        (m.mb_trns^.trError_gg00 <> e_ok);
    (*ENDREPEAT*) 
    (* all inversions for current left key are executed now *)
    IF  (m.mb_trns^.trError_gg00 = e_no_next_invkey) OR
        (m.mb_trns^.trError_gg00 = e_inv_list_not_found)
    THEN
        m.mb_trns^.trError_gg00 := e_ok;
    (*ENDIF*) 
    IF  m.mb_trns^.trError_gg00 = e_ok
    THEN
        IF  getrec.gi_linkrec.kbjr_left_oj AND
            (_curr_rescount = searchrec.sr_res_cnt)
        THEN
            BEGIN
            searchrec.sr_rsearchkey.len := selrec.selr.selr_first_jlen;
            IF  NOT _skip_left
            THEN
                kb74restore_page (m, _curr_tree_pos,
                      getrec.gi_result_info.o_tree, selrec, searchrec);
            (*ENDIF*) 
            kb74left_scan_to_nxt_key (m, getrec, searchrec,
                  selrec, c_is_right_outer_join)
            END
        ELSE
            IF  _skip_left
            THEN
                BEGIN
                searchrec.sr_rsearchkey.len := selrec.selr.selr_first_jlen;
                kb74left_scan_to_nxt_key (m, getrec, searchrec,
                      selrec, NOT c_is_right_outer_join)
                END;
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
IF  (m.mb_trns^.trError_gg00 =  e_ok) AND
    (searchrec.sr_error_l <> e_ok)           AND
    (searchrec.sr_error_l <> e_no_next_record)
THEN
    m.mb_trns^.trError_gg00 := searchrec.sr_error_l
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74key_direct_search (
            VAR m         : tgg00_MessBlock;
            VAR getrec    : tgg07_get_param;
            VAR selrec    : tgg07_select_param;
            VAR sel       : tgg00_SelectFieldsParam;
            VAR searchrec : t_search_rec);
 
VAR
      _end_of_range       : boolean;
      _i                  : integer;
      _last_key_field_pos : integer;
      _conv_cnt           : integer;
      _dummy_len          : integer;
      _curr_rescount      : tsp00_Int4;
      _conv_st_pos        : conv_arr;
 
BEGIN
sel.sfp_bd_use_stopkey := false;
kb74check_conversions (m, _conv_st_pos, _conv_cnt,
      _last_key_field_pos, _dummy_len, selrec.selr.selr_first_jlen);
selrec.selr.selr_l_defbyte_pos := _last_key_field_pos;
WHILE (m.mb_trns^.trError_gg00 = e_ok) AND (searchrec.sr_error_l = e_ok) DO
    BEGIN
    selrec.selr.selr_l_currpos :=
          searchrec.sr_nptr.np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -
          searchrec.sr_left_tree_pos.tpsIndex_gg00];
    searchrec.sr_rsearchkey.len := s30lnr_defbyte (@searchrec.sr_nptr.np_ptr^,
          searchrec.sr_nptr.np_ptr^.nd_body
          [selrec.selr.selr_l_currpos + _last_key_field_pos -1],
          selrec.selr.selr_l_currpos + _last_key_field_pos,
          searchrec.sr_lkey_len -
          _last_key_field_pos + cgg_rec_key_offset) +
          _last_key_field_pos - cgg_rec_key_offset;
    sel.sfp_bd_return_knf :=
          (_conv_cnt = 0) AND NOT getrec.gi_linkrec.kbjr_left_oj;
    IF  searchrec.sr_rsearchkey.len <= selrec.selr.selr_first_jlen
    THEN
        BEGIN
&       ifdef trace
        t01name(kb, 'key -> rsearchkey ');
&       endif
        SAPDB_PascalMove ('VKB74 ',  33,    
              sizeof(searchrec.sr_nptr.np_ptr^),
              sizeof(searchrec.sr_rsearchkey.k),
              @searchrec.sr_nptr.np_ptr^,
              selrec.selr.selr_l_currpos + cgg_rec_key_offset,
              @searchrec.sr_rsearchkey.k, 1, searchrec.sr_rsearchkey.len,
              m.mb_trns^.trError_gg00);
&       ifdef trace
        t01key (kb, 'rsearchkey  ', searchrec.sr_rsearchkey );
&       endif
        FOR _i := 1 TO _conv_cnt DO
            BEGIN
            s30map (g02codetables.tables[ _conv_st_pos[_i].ct_codeno ],
                  searchrec.sr_rsearchkey.k,
                  m.mb_st^[_conv_st_pos[_i].ct_st_pos].epos - cgg_rec_key_offset,
                  searchrec.sr_rsearchkey.k,
                  m.mb_st^[_conv_st_pos[_i].ct_st_pos].epos - cgg_rec_key_offset,
                  m.mb_st^[_conv_st_pos[_i].ct_st_pos].elen_var);
            END;
        (*ENDFOR*) 
        kb74get_right_record (m, selrec, mm_direct,
              searchrec.sr_rsearchkey, sel);
        searchrec.sr_error_r    := m.mb_trns^.trError_gg00;
        m.mb_trns^.trError_gg00 := e_ok
        END
    ELSE (* searchrec.sr_rsearchkey.len > selrec.selr.selr_first_jlen *)
        BEGIN
        sel.sfp_bd_return_knf := false;
        searchrec.sr_error_r               := e_key_not_found;
        END;
    (*ENDIF*) 
    _curr_rescount := searchrec.sr_res_cnt;
    IF  searchrec.sr_error_r = e_ok
    THEN
        BEGIN (* right record found *)
        kb74join_with_left_records (m, getrec, selrec,
              sel, searchrec, _end_of_range);
        IF  (searchrec.sr_error_l <> e_no_next_record) AND (* PTS 1116891 *)
            ((getrec.gi_linkrec.kbjr_left_oj AND (_curr_rescount = searchrec.sr_res_cnt) AND
            NOT searchrec.sr_refused_by_ophase)
            OR
            _end_of_range)
        THEN
            BEGIN
            searchrec.sr_rsearchkey.len := selrec.selr.selr_first_jlen;
            kb74left_scan_to_nxt_key (m, getrec, searchrec,
                  selrec, getrec.gi_linkrec.kbjr_left_oj)
            END
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        IF  (searchrec.sr_error_r <> e_key_not_found ) AND
            (searchrec.sr_error_r <> e_qual_violation) AND
            (searchrec.sr_error_r <> e_view_violation) AND
            (searchrec.sr_error_r <> e_no_next_record)
        THEN
            m.mb_trns^.trError_gg00 := searchrec.sr_error_r;
        (*ENDIF*) 
        IF  m.mb_trns^.trError_gg00 = e_ok
        THEN
            IF  sel.sfp_bd_return_knf
            THEN
                IF  (searchrec.sr_error_r = e_key_not_found ) OR
                    (searchrec.sr_error_r = e_qual_violation) OR
                    (searchrec.sr_error_r = e_view_violation)
                THEN
                    kb74synchronize_left_rec (m,
                          searchrec.sr_rsearchkey, getrec,
                          searchrec, selrec)
                ELSE
                    searchrec.sr_error_l := e_no_next_record
                (*ENDIF*) 
            ELSE
                IF  (searchrec.sr_error_l <> e_no_next_record)
                THEN
                    BEGIN
                    searchrec.sr_rsearchkey.len := selrec.selr.selr_first_jlen;
                    kb74left_scan_to_nxt_key (m, getrec, searchrec,
                          selrec, getrec.gi_linkrec.kbjr_left_oj)
                    END
                (*ENDIF*) 
            (*ENDIF*) 
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
    THEN
        searchrec.sr_error_l := e_cancelled;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
IF  (m.mb_trns^.trError_gg00 =  e_ok) AND
    (searchrec.sr_error_l <> e_ok)           AND
    (searchrec.sr_error_l <> e_no_next_record)
THEN
    m.mb_trns^.trError_gg00 := searchrec.sr_error_l
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74key_next_search (
            VAR m         : tgg00_MessBlock;
            VAR getrec    : tgg07_get_param;
            VAR selrec    : tgg07_select_param;
            VAR sel       : tgg00_SelectFieldsParam;
            VAR searchrec : t_search_rec);
 
VAR
      _skip_left          : boolean;
      _i                  : integer;
      _startpos           : integer;
      _fixfieldlen         : integer;
      _last_key_field_pos : integer;
      _curr_rescount      : tsp00_Int4;
      _conv_st_pos        : conv_arr;
      _conv_cnt           : integer;
      _curr_tree_pos      : tgg00_FilePos;
      _m2_type            : tgg00_MessType2;
 
BEGIN
kb74check_conversions (m, _conv_st_pos, _conv_cnt,
      _last_key_field_pos, _fixfieldlen, selrec.selr.selr_first_jlen);
selrec.selr.selr_l_defbyte_pos := _last_key_field_pos;
&ifdef trace
t01int4 (kb, '_fixfieldlen', _fixfieldlen);
t01int4 (kb, 'selr_first_j', selrec.selr.selr_first_jlen);
&endif
IF  (_fixfieldlen = 0) OR
    (_fixfieldlen > selrec.selr.selr_first_jlen)
THEN
    _fixfieldlen := selrec.selr.selr_first_jlen;
(*ENDIF*) 
;
(* fill selr.selr_stopkey (stopkey) trailer with 'FF' *)
SAPDB_PascalFill ('VKB74 ',  34,    
      sizeof(selrec.selr.selr_stopkey.k),
      @selrec.selr.selr_stopkey.k, _fixfieldlen + 1,
      sizeof(selrec.selr.selr_stopkey.k) - _fixfieldlen,
      chr(255), m.mb_trns^.trError_gg00);
selrec.selr.selr_stopkey.len       := sizeof(selrec.selr.selr_stopkey.k);
sel.sfp_bd_use_stopkey := true;
WHILE (m.mb_trns^.trError_gg00 = e_ok) AND (searchrec.sr_error_l = e_ok) DO
    BEGIN
    selrec.selr.selr_l_currpos    :=
          searchrec.sr_nptr.np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -
          searchrec.sr_left_tree_pos.tpsIndex_gg00];
    (* <i-1. temp. result> --> sr_rsearchkey (startkey) *)
    searchrec.sr_rsearchkey.len := selrec.selr.selr_first_jlen;
    SAPDB_PascalMove ('VKB74 ',  35,    
          sizeof(searchrec.sr_nptr.np_ptr^),
          sizeof(searchrec.sr_rsearchkey.k),
          @searchrec.sr_nptr.np_ptr^,
          selrec.selr.selr_l_currpos + cgg_rec_key_offset,
          @searchrec.sr_rsearchkey.k, 1, searchrec.sr_rsearchkey.len,
          m.mb_trns^.trError_gg00);
&   ifdef trace
    t01name(kb, 'i-1. tRes -> key  ');
&   endif
    (* adjust code conversion on sr_rsearchkey (startkey) *)
    FOR _i := 1 TO _conv_cnt DO
        WITH _conv_st_pos[_i] DO
            BEGIN
            IF  m.mb_st^[ct_st_pos].epos - cgg_rec_key_offset - 1 < _fixfieldlen
            THEN
                s30map (g02codetables.tables[ ct_codeno ],
                      searchrec.sr_rsearchkey.k,
                      m.mb_st^[ct_st_pos].epos - cgg_rec_key_offset,
                      searchrec.sr_rsearchkey.k,
                      m.mb_st^[ct_st_pos].epos - cgg_rec_key_offset,
                      m.mb_st^[ct_st_pos].elen_var)
            (*ENDIF*) 
            END;
        (*ENDWITH*) 
    (*ENDFOR*) 
    ;
    (* sr_rsearchkey (startkey) --> selr.selr_stopkey (stopkey) *)
    SAPDB_PascalMove ('VKB74 ',  36,    
          sizeof(searchrec.sr_rsearchkey.k),
          sizeof(selrec.selr.selr_stopkey.k),
          @searchrec.sr_rsearchkey.k, 1,
          @selrec.selr.selr_stopkey.k, 1, _fixfieldlen,
          m.mb_trns^.trError_gg00);
    _startpos        := selrec.selr.selr_l_currpos;
    _m2_type         := mm_first;
    _skip_left       := true;
    searchrec.sr_error_r         := e_ok;
    _curr_tree_pos   := searchrec.sr_left_tree_pos;
    _curr_rescount   := searchrec.sr_res_cnt;
    WHILE (m.mb_trns^.trError_gg00 = e_ok) AND (searchrec.sr_error_r = e_ok) DO
        BEGIN
        (*  <i. tab> record --> selrec.selr_selectbuffer.rbuf *)
        kb74get_right_record (m, selrec, _m2_type,
              searchrec.sr_rsearchkey, sel);
        searchrec.sr_error_r    := m.mb_trns^.trError_gg00;
        m.mb_trns^.trError_gg00 := e_ok;
        IF  searchrec.sr_error_r = e_ok
        THEN
            BEGIN
            _skip_left := false;
            IF  _m2_type = mm_next
            THEN
                kb74restore_page (m,
                      _curr_tree_pos, getrec.gi_result_info.o_tree, selrec,
                      searchrec);
            (*ENDIF*) 
            ;
            (* Join current right record *)
            (* with all records of left  *)
            (* result with the same key  *)
            (* prefix. As result lmaxpos *)
            (* contains the position of  *)
            (* the first record of left  *)
            (* result with               *)
            (* key <> current key prefix *)
            ;
            IF  m.mb_trns^.trError_gg00 = e_ok
            THEN
                BEGIN
                kb74join_with_left_records (m,
                      getrec, selrec, sel, searchrec, _skip_left)
                END
            (*ENDIF*) 
            END
        ELSE
            IF  (searchrec.sr_error_r <> e_qual_violation) AND
                (searchrec.sr_error_r <> e_view_violation) AND
                (searchrec.sr_error_r <> e_no_next_record )
            THEN
                m.mb_trns^.trError_gg00 := searchrec.sr_error_r;
            (*ENDIF*) 
        (*ENDIF*) 
        _m2_type := mm_next;
        END;
    (*ENDWHILE*) 
&   ifdef trace
    t01sname(kb, '- new sync -' );
&   endif
    IF  m.mb_trns^.trError_gg00 = e_ok
    THEN
        BEGIN
        IF  getrec.gi_linkrec.kbjr_left_oj AND
            (_curr_rescount = searchrec.sr_res_cnt)
        THEN
            BEGIN
            IF  NOT _skip_left
            THEN
                kb74restore_page (m,
                      _curr_tree_pos, getrec.gi_result_info.o_tree, selrec,
                      searchrec);
            (*ENDIF*) 
            searchrec.sr_rsearchkey.len  := _fixfieldlen;
            kb74left_scan_to_nxt_key (m, getrec, searchrec,
                  selrec, c_is_right_outer_join)
            END
        ELSE
            IF  _skip_left AND
                (searchrec.sr_error_l <> e_no_next_record)
            THEN
                BEGIN
                (* No record of right table with key prefix *)
                (* equal current left key prefix fulfills   *)
                (* qualification, skip all records of left  *)
                (* result with current left key             *)
                ;
                searchrec.sr_rsearchkey.len  := _fixfieldlen;
                kb74left_scan_to_nxt_key (m, getrec, searchrec,
                      selrec, NOT c_is_right_outer_join)
                END;
            (*ENDIF*) 
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
    THEN
        searchrec.sr_error_l := e_cancelled;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
IF  (m.mb_trns^.trError_gg00 = e_ok) AND
    (searchrec.sr_error_l <> e_ok)        AND
    (searchrec.sr_error_l <> e_no_next_record)
THEN
    m.mb_trns^.trError_gg00 := searchrec.sr_error_l
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74restore_page (
            VAR m                 : tgg00_MessBlock;
            VAR required_tree_pos : tgg00_FilePos;
            VAR left_tree         : tgg00_FileId;
            VAR selrec            : tgg07_select_param;
            VAR searchrec         : t_search_rec);
 
VAR
      _dummy_key : tgg00_Lkey;
 
BEGIN
IF  required_tree_pos.tpsPno_gg00 <> searchrec.sr_left_tree_pos.tpsPno_gg00
THEN
    BEGIN
    searchrec.sr_left_tree_pos := required_tree_pos;
    kb74get_left_leaf (m.mb_trns^, selrec, searchrec,
          left_tree, _dummy_key, NOT c_get_next)
    END
ELSE
    BEGIN
    searchrec.sr_left_tree_pos.tpsIndex_gg00 := required_tree_pos.tpsIndex_gg00;
    selrec.selr.selr_l_currpos :=
          searchrec.sr_nptr.np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -
          searchrec.sr_left_tree_pos.tpsIndex_gg00]
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74synchronize_left_rec (
            VAR m          : tgg00_MessBlock;
            VAR sync_key   : tgg00_Lkey;
            VAR getrec     : tgg07_get_param;
            VAR searchrec  : t_search_rec;
            VAR selrec     : tgg07_select_param);
 
VAR
      _lc_result         : tsp00_LcompResult;
      _index             : integer;
      _def_byte          : char;
      _m_def_byte        : char;
      _m_sk_def_byte     : char; (* PTS 1113064 *)
      _lpos              : integer;
 
BEGIN
selrec.selr.selr_l_currpos := searchrec.sr_nptr.np_ptr^.
      nd_pointer_list[MAX_POINTERINDEX_BD00 - searchrec.sr_left_min_index];
_lpos       := selrec.selr.selr_l_currpos + cgg_rec_key_offset;
_m_def_byte := searchrec.sr_nptr.np_ptr^.nd_body[_lpos];
_def_byte   := searchrec.sr_nptr.np_ptr^.nd_body[selrec.selr.selr_l_currpos +
      selrec.selr.selr_l_defbyte_pos-1];
IF  _def_byte = csp_undef_byte (* PTS 1114672 *)
THEN
    BEGIN
    _def_byte    := sync_key.k[selrec.selr.selr_l_defbyte_pos];
    IF  _def_byte = csp_undef_byte
    THEN
        _def_byte := csp_defined_byte;
    (*ENDIF*) 
    END;
(*ENDIF*) 
_m_sk_def_byte  := sync_key.k[1]; (* PTS 1113064 *)
sync_key.k[1]  := _def_byte;
searchrec.sr_nptr.np_ptr^.nd_body[_lpos] := _def_byte;
(* *** compare last left key in page with new right key *** *)
IF  _m_sk_def_byte = csp_undef_byte (* PTS 1113064 *)
THEN
    _lc_result := l_less
ELSE
    BEGIN
&   ifdef trace
    kb74trace_luc (searchrec.sr_nptr.np_ptr^, _lpos, searchrec.sr_lkey_len,
          @sync_key.k, 1, sync_key.len, _lc_result);
&   else
    s30luc1 (searchrec.sr_nptr.np_ptr^, _lpos, searchrec.sr_lkey_len,
          sync_key.k, 1, sync_key.len, _lc_result);
&   endif
    END;
(*ENDIF*) 
searchrec.sr_nptr.np_ptr^.nd_body[_lpos] := _m_def_byte;
CASE _lc_result OF
    l_less :
        BEGIN
        sync_key.k[1]         := _m_sk_def_byte; (* PTS 1113064 *)
        searchrec.sr_left_tree_pos.tpsPno_gg00   := NIL_PAGE_NO_GG00;
        kb74get_left_leaf (m.mb_trns^, selrec, searchrec,
              getrec.gi_result_info.o_tree, sync_key, c_get_next)
        END;
    l_equal   :
        BEGIN
        (* *** skip to next left record *** *)
        _index := searchrec.sr_left_min_index;
        REPEAT
            _index := _index - 1;
            _lpos  := searchrec.sr_nptr.np_ptr^.
                  nd_pointer_list[MAX_POINTERINDEX_BD00 - _index] +
                  cgg_rec_key_offset;
            searchrec.sr_nptr.np_ptr^.nd_body[_lpos] := _def_byte;
&           ifdef trace
            kb74trace_luc (searchrec.sr_nptr.np_ptr^, _lpos, searchrec.sr_lkey_len,
                  @sync_key.k, 1, sync_key.len, _lc_result);
&           else
            s30luc1 (searchrec.sr_nptr.np_ptr^, _lpos, searchrec.sr_lkey_len,
                  sync_key.k, 1, sync_key.len, _lc_result);
&           endif
            searchrec.sr_nptr.np_ptr^.nd_body[_lpos] := _m_def_byte;
        UNTIL
            _lc_result <> l_equal;
        (*ENDREPEAT*) 
        WITH searchrec.sr_left_tree_pos DO
            BEGIN
            tpsIndex_gg00        := _index + 1;
            selrec.selr.selr_l_currpos := searchrec.sr_nptr.np_ptr^.
                  nd_pointer_list[MAX_POINTERINDEX_BD00 - tpsIndex_gg00];
            END;
        (*ENDWITH*) 
        END;
    l_greater :
        BEGIN
        (* *** skip to next left record *** *)
&       ifdef trace
        t01int4 (kb, 'tpsIndex    ', searchrec.sr_left_tree_pos.tpsIndex_gg00);
&       endif
        REPEAT
            WITH searchrec.sr_left_tree_pos DO
                BEGIN
                tpsIndex_gg00 := tpsIndex_gg00 + 1;
                _lpos  := searchrec.sr_nptr.np_ptr^.
                      nd_pointer_list[MAX_POINTERINDEX_BD00 - tpsIndex_gg00] +
                      cgg_rec_key_offset;
                END;
            (*ENDWITH*) 
            searchrec.sr_nptr.np_ptr^.nd_body[_lpos] := _def_byte;
&           ifdef trace
            kb74trace_luc (searchrec.sr_nptr.np_ptr^, _lpos, searchrec.sr_lkey_len,
                  @sync_key.k, 1, sync_key.len, _lc_result);
&           else
            s30luc1 (searchrec.sr_nptr.np_ptr^, _lpos, searchrec.sr_lkey_len,
                  sync_key.k, 1, sync_key.len, _lc_result);
&           endif
            searchrec.sr_nptr.np_ptr^.nd_body[_lpos] := _m_def_byte;
        UNTIL
            _lc_result <> l_less;
        (*ENDREPEAT*) 
        selrec.selr.selr_l_currpos  := searchrec.sr_nptr.
              np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -
              searchrec.sr_left_tree_pos.tpsIndex_gg00];
        END;
    END;
(*ENDCASE*) 
sync_key.k[1] := _m_sk_def_byte; (* PTS 1113064 *)
&ifdef trace
IF  searchrec.sr_nptr.np_ptr <> NIL
THEN
    BEGIN
    t01int4 (kb, 'new left key', 1);
    t01buf1 (kb, searchrec.sr_nptr.np_ptr^,
          selrec.selr.selr_l_currpos + cgg_rec_key_offset,
          selrec.selr.selr_l_currpos + cgg_rec_key_offset + sync_key.len - 1)
    END;
&endif
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74get_left_leaf (
            VAR t            : tgg00_TransContext;
            VAR selrec       : tgg07_select_param;
            VAR searchrec    : t_search_rec;
            VAR left_tree_id : tgg00_FileId;
            VAR searchkey    : tgg00_Lkey;
            get_next         : boolean);
 
VAR
      _prev_tree_pos : tgg00_FilePos;
 
BEGIN
IF  (get_next) AND
    (searchrec.sr_left_tree_pos.tpsPno_gg00 = searchrec.sr_left_last_pno  ) AND
    (searchrec.sr_left_last_pno <> NIL_PAGE_NO_GG00)
THEN
    BEGIN
    IF  searchrec.sr_nptr.np_ptr <> NIL
    THEN
        b07release_result_leaf (t,
              left_tree_id, searchrec.sr_prepare_for_upd, searchrec.sr_nptr);
    (*ENDIF*) 
    IF  t.trError_gg00 = e_ok
    THEN
        searchrec.sr_error_l := e_no_next_record
    ELSE
        searchrec.sr_error_l := t.trError_gg00;
    (*ENDIF*) 
    searchrec.sr_left_tree_pos.tpsPno_gg00 := NIL_PAGE_NO_GG00;
    END
ELSE
    BEGIN
    _prev_tree_pos := searchrec.sr_left_tree_pos;
    b07get_result_leaf (t, left_tree_id, searchkey,
          get_next, searchrec.sr_prepare_for_upd,
          searchrec.sr_left_tree_pos, searchrec.sr_nptr);
    searchrec.sr_error_l := t.trError_gg00;
    IF  ( searchrec.sr_error_l = e_ok )
    THEN
        BEGIN
        IF  NOT get_next
        THEN
            searchrec.sr_left_tree_pos.tpsIndex_gg00
                  := _prev_tree_pos.tpsIndex_gg00;
        (*ENDIF*) 
        selrec.selr.selr_l_currpos := searchrec.sr_nptr.np_ptr^.
              nd_pointer_list[MAX_POINTERINDEX_BD00 -
              searchrec.sr_left_tree_pos.tpsIndex_gg00];
        searchrec.sr_left_min_index :=
              searchrec.sr_nptr.np_ptr^.nd_record_cnt - 1;
&       ifdef trace
        t01int4 (kb, 'left_min_i  ', searchrec.sr_left_min_index);
        t01int4 (kb, 'l_currpos   ', selrec.selr.selr_l_currpos);
&       endif
        END
    ELSE
        BEGIN
        IF  ( searchrec.sr_error_l = e_no_next_record )
        THEN
            BEGIN
&           ifdef trace
            t01sname(kb, 'no next rec ' );
&           endif
            t.trError_gg00   := e_ok;
            searchrec.sr_left_last_pno := _prev_tree_pos.tpsPno_gg00
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74left_scan_to_nxt_key (
            VAR m               : tgg00_MessBlock;
            VAR getrec          : tgg07_get_param;
            VAR searchrec       : t_search_rec;
            VAR selrec          : tgg07_select_param;
            is_right_outer_join : boolean);
 
VAR
      _lc_result    : tsp00_LcompResult;
 
BEGIN
(* reset right key we are looking for; was updated with kb74get_right_record() *)
SAPDB_PascalMove ('VKB74 ',  37,    
      sizeof(searchrec.sr_nptr.np_ptr^), sizeof(searchrec.sr_rsearchkey.k),
      @searchrec.sr_nptr.np_ptr^, selrec.selr.selr_l_currpos + cgg_rec_key_offset,
      @searchrec.sr_rsearchkey.k, 1, searchrec.sr_rsearchkey.len, m.mb_trns^.trError_gg00);
&IFDEF TRACE
t01lkey (kb, searchrec.sr_rsearchkey);
&ENDIF
IF  is_right_outer_join
THEN
    searchrec.sr_left_tree_pos.tpsIndex_gg00 := searchrec.sr_left_tree_pos.tpsIndex_gg00 - 1;
(*ENDIF*) 
_lc_result    := l_equal;
WHILE (_lc_result = l_equal) AND (m.mb_trns^.trError_gg00 = e_ok ) AND
      (searchrec.sr_error_l = e_ok ) DO
    BEGIN
    WITH searchrec.sr_left_tree_pos DO
        BEGIN
        tpsIndex_gg00 := tpsIndex_gg00 + 1;
        IF  tpsIndex_gg00 > searchrec.sr_left_min_index
        THEN
            kb74get_left_leaf (m.mb_trns^, selrec, searchrec,
                  getrec.gi_result_info.o_tree, searchrec.sr_lsearchkey, c_get_next)
        ELSE
            selrec.selr.selr_l_currpos :=
                  searchrec.sr_nptr.np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -tpsIndex_gg00];
        (*ENDIF*) 
&       ifdef trace
        t01int4 (kb, 'tpsIndex    ', tpsIndex_gg00);
        t01basis_error (kb, 'sr_error_l  ', searchrec.sr_error_l);
&       endif
        IF  searchrec.sr_error_l = e_ok
        THEN
            BEGIN
            s30cmp1 (searchrec.sr_rsearchkey.k, 1, searchrec.sr_rsearchkey.len,
                  searchrec.sr_nptr.np_ptr^, selrec.selr.selr_l_currpos + cgg_rec_key_offset,
                  searchrec.sr_rsearchkey.len, _lc_result);
            END;
        (*ENDIF*) 
        END;
    (*ENDWITH*) 
    END;
(*ENDWHILE*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74get_right_record (
            VAR m         : tgg00_MessBlock;
            VAR selrec    : tgg07_select_param;
            sel_type      : tgg00_MessType2;
            VAR rstartkey : tgg00_Lkey;
            VAR sel       : tgg00_SelectFieldsParam);
 
CONST
      c_ignore_vwait = true;
 
VAR
      _dummy_bool    : boolean;
      _dummy_granted : tgg00_LockReqMode;
 
BEGIN
&IFDEF TRACE
t01mess2type (kb, 'sel_type    ', sel_type);
t01key (kb, 'rstartkey   ', rstartkey);
&ENDIF
sel.sfp_act_cntresult := selrec.selr.selr_countresult + 1;
m.mb_trns^.trError_gg00 := e_ok;
sel.sfp_bd_mess2_type   := sel_type;
sel.sfp_m_result_addr   := @selrec.selr_selectbuffer.rbuf;
sel.sfp_m_result_size   := sizeof (selrec.selr_selectbuffer.rbuf);
sel.sfp_m_result_len    := 0;
m.mb_qual^.mtree.fileBdUse_gg00 := [  ];
b02kb_select_rec (m.mb_trns^, m.mb_qual^.mtree,
      rstartkey.keyVal_gg00, rstartkey.keyLen_gg00,
      selrec.selr.selr_stopkey.keyVal_gg00, selrec.selr.selr_stopkey.keyLen_gg00,
      sizeof (selrec.selr_selectbuffer.buf_rec),
      @selrec.selr_selectbuffer.buf_rec, NOT c_ignore_vwait, sel,
      m.mb_qual^.mstack_desc, _dummy_bool, _dummy_granted );
&IFDEF TRACE
t01basis_error (kb, 'm trError   ', m.mb_trns^.trError_gg00);
&ENDIF
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74join_with_left_records (
            VAR m                  : tgg00_MessBlock;
            VAR getrec             : tgg07_get_param;
            VAR selrec             : tgg07_select_param;
            VAR sel                : tgg00_SelectFieldsParam;
            VAR searchrec          : t_search_rec;
            VAR end_of_range       : boolean);
 
VAR
      _key_len              : tsp_int_map_c2;
      _curr_res_cnt         : integer;
      _new_page_req         : boolean;
      _exit_inner_loop      : boolean;
      _fulfilled            : boolean;
      _first_fulfilled      : boolean;
      _no_next_rec          : boolean;
      _unequal_join         : boolean;
      _right_needed         : boolean;
      _basetab_rec_changed  : boolean;
 
BEGIN
_no_next_rec        := false;
IF  ( getrec.gi_linkrec.kbjr_jointrans_cnt > 0 )
THEN
    _unequal_join := ( getrec.gi_linkrec.kbjr_jarr[ getrec.gi_linkrec.
          kbjr_jpath ].kbji_parts[ 1 ].kboj_op = op_ne )
ELSE
    _unequal_join := false;
(*ENDIF*) 
_right_needed       := true;
_basetab_rec_changed:= false;
end_of_range        := false;
(* loop over temporary result records *)
WHILE (NOT _no_next_rec)               AND
      (m.mb_trns^.trError_gg00 = e_ok) AND
      (searchrec.sr_error_l <> e_no_next_record) DO
    BEGIN
    _new_page_req    := false;
    _exit_inner_loop := false;
    (* loop over records of one page of temporary result *)
    REPEAT
&       ifdef trace
        t01int4 (bi, 'tpsIndex    ', searchrec.sr_left_tree_pos.tpsIndex_gg00);
&       endif
        _fulfilled            := true;
        _first_fulfilled      := true;
        (* compare temp. result record with actual base table record *)
        kb74compare_two_records (m, selrec, searchrec, getrec.gi_linkrec,
              sel, _fulfilled, _first_fulfilled, end_of_range,
              _basetab_rec_changed);
        IF  _fulfilled
        THEN
            BEGIN
            selrec.selr_selectbuffer.result.len   := 0;
            _curr_res_cnt := searchrec.sr_res_cnt;
            kb74build_new_rec (m, getrec, selrec, searchrec,
                  _right_needed, no_outer_join);
            IF  searchrec.sr_prepare_for_upd AND
                ((_curr_res_cnt < searchrec.sr_res_cnt)
                OR searchrec.sr_refused_by_ophase)
            THEN
                BEGIN
                (* mark current record as accessed *)
                (* (rec_len := 4 + keylen + 1)     *)
                _key_len.map_c2[1] :=
                      searchrec.sr_nptr.np_ptr^.nd_body[selrec.selr.selr_l_currpos+2];
                _key_len.map_c2[2] :=
                      searchrec.sr_nptr.np_ptr^.nd_body[selrec.selr.selr_l_currpos+3];
                _key_len.map_int :=
                      cgg_rec_key_offset + _key_len.map_int + 1;
&               ifdef trace
                t01name(kb, 'mark as accessed  ');
                t01int4 (kb, 'key_len     ', _key_len.map_int);
&               endif
                searchrec.sr_nptr.np_ptr^.nd_body[selrec.selr.selr_l_currpos] :=
                      _key_len.map_c2[1];
                searchrec.sr_nptr.np_ptr^.nd_body[selrec.selr.selr_l_currpos+1] :=
                      _key_len.map_c2[2];
                END;
            (*ENDIF*) 
            _right_needed := false;
            END;
        (*ENDIF*) 
        IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
        THEN
            m.mb_trns^.trError_gg00 := e_cancelled;
        (*ENDIF*) 
        IF  (_first_fulfilled OR _unequal_join) AND
            NOT end_of_range
        THEN
            BEGIN
            searchrec.sr_left_tree_pos.tpsIndex_gg00 :=
                  searchrec.sr_left_tree_pos.tpsIndex_gg00 + 1;
            IF  searchrec.sr_left_tree_pos.tpsIndex_gg00 >
                searchrec.sr_left_min_index
            THEN
                BEGIN
&               ifdef trace
                t01name(kb, 'exit loop new page');
&               endif
                _exit_inner_loop := true;
                _new_page_req    := true
                END;
            (*ENDIF*) 
            ;
            (* set to next temp. result record on page *)
&           ifdef trace
            t01name(kb, 'get next temp rec ');
&           endif
            selrec.selr.selr_l_currpos :=
                  searchrec.sr_nptr.np_ptr^.
                  nd_pointer_list[MAX_POINTERINDEX_BD00 -
                  searchrec.sr_left_tree_pos.tpsIndex_gg00]
            END
        ELSE
            _exit_inner_loop := true;
        (*ENDIF*) 
    UNTIL
        _exit_inner_loop OR
        (m.mb_trns^.trError_gg00 <> e_ok);
    (*ENDREPEAT*) 
    IF  _new_page_req               AND
        (m.mb_trns^.trError_gg00 = e_ok) AND
        (_first_fulfilled OR _unequal_join) (* h.b. PTS 1001567 *)
    THEN
        BEGIN
        kb74get_left_leaf (m.mb_trns^, selrec, searchrec,
              getrec.gi_result_info.o_tree, searchrec.sr_lsearchkey, c_get_next);
        IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
        THEN
            searchrec.sr_error_l := e_cancelled;
        (*ENDIF*) 
        _no_next_rec := searchrec.sr_error_l <> e_ok
        END
    ELSE
        _no_next_rec := true;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
END;
 
&ifdef trace
(*------------------------------*) 
 
PROCEDURE
      kb74trace_luc (
            VAR lbuf : tbd_node;
            lpos     : integer;
            llen     : integer;
            rbuf     : tsp00_BufAddr;
            rpos     : integer;
            rlen     : integer;
            VAR res  : tsp00_LcompResult);
 
VAR
      aux : tsp00_BufAddr;
 
BEGIN
aux := @lbuf;
t01buf (kb, aux^, lpos, lpos + llen - 1);
t01buf (kb, rbuf^, rpos, rpos + rlen - 1);
s30luc (lbuf, lpos, llen, rbuf^, rpos, rlen, res);
CASE res OF
    l_equal :
        t01int4 (kb, 'left = right', 1);
    l_less :
        t01int4 (kb, 'left < right', 1);
    l_greater :
        t01int4 (kb, 'left > right', 1);
    l_undef :
        t01int4 (kb, 'undefined   ', 1);
    END;
(*ENDCASE*) 
END;
 
&endif
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
.PA 
