.ad 8
.bm 3
.fm 2
.bt $Copyright by SAP AG, 2002$$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
 
 
    ========== licence begin  GPL
    Copyright (C) 2000 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
.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 : tgg_mess_block);
 
        PROCEDURE
              k74join_with_left_result (
                    VAR m           : tgg_mess_block;
                    VAR getrec      : tkb7_get_param;
                    VAR sel         : tgg_select_fields_param;
                    VAR selrec      : tkb7_select_param;
                    VAR listkey     : tgg_lkey;
                    return_next_key : boolean);
 
        PROCEDURE
              k74finish_catalog_join (
                    VAR m      : tgg_mess_block;
                    VAR getrec : tkb7_get_param;
                    VAR selrec_ctxt : tsp_buf;
                    strat_maxresult : tsp_int2;
                    j_use_rowno     : boolean;
                    last_join_tab   : boolean);
 
        PROCEDURE
              k74rowno_position (
                    VAR m      : tgg_mess_block;
                    VAR getrec : tkb7_get_param;
                    VAR selrec : tkb7_select_param);
 
        PROCEDURE
              k74start_catalog_join (
                    VAR m           : tgg_mess_block;
                    VAR getrec      : tkb7_get_param;
                    VAR selrec_ctxt : tsp_buf);
 
        PROCEDURE
              k74_const_output_expression (
                    VAR m         : tgg_mess_block;
                    VAR selrec    : tkb7_select_param;
                    VAR exp_pos   : tkb7_one_new_pos);
 
.CM *-END-* define --------------------------------------
.sp;.cp 3
Use     :
 
        FROM
              Scanner : VAK01;
 
        VAR
              a01diag_monitor_on : boolean;
              a01diag_analyze_on : boolean;
 
      ------------------------------ 
 
        FROM
              KB_get : VKB71;
 
        PROCEDURE
              k71col_select (
                    VAR t           : tgg00_TransContext;
                    VAR sel         : tgg_select_fields_param;
                    VAR stack_desc  : tgg_stack_desc;
                    VAR rec_buf     : tsp_buf;
                    VAR unqualified : boolean);
 
        PROCEDURE
              k71qualification_test (
                    VAR m           : tgg_mess_block;
                    first_qual      : boolean;
                    result_wanted   : boolean;
                    check_new_rec   : boolean;
                    VAR rec         : tgg_rec_buf;
                    result_ptr      : tsp00_MoveObjPtr;
                    result_size     : tsp00_Int4;
                    VAR result_len  : integer);
 
        PROCEDURE
              k71join_comparison (
                    op       : tgg_stack_op_type;
                    VAR sel  : tgg_select_fields_param;
                    VAR buf1 : tsp_buf;
                    pos1     : tsp_int4;
                    len1     : integer;
                    VAR buf2 : tsp_buf;
                    pos2     : tsp_int4;
                    len2     : integer;
                    VAR ok   : integer);
 
      ------------------------------ 
 
        FROM
              Single_Select : VKB720;
 
        PROCEDURE
              k720ref_statistic (
                    VAR m         : tgg_mess_block;
                    VAR arr_index : tgg_ref_info_index;
                    VAR strat     : tgg07_StrategyInfo);
 
        PROCEDURE
              k720monitor (
                    VAR trans         : tgg00_TransContext;
                    VAR sel           : tgg_select_fields_param;
                    start_sec         : tsp_int4;
                    start_microsec    : tsp_int4;
                    start_phys_ios    : tsp_int4;
                    start_suspends    : tsp_int4;
                    start_waits       : tsp_int4;
                    put_strat         : boolean;
                    arr_index         : tgg_ref_info_index;
                    strat_cnt         : boolean);
 
        PROCEDURE
              k720_test_subquery (
                    VAR m   : tgg_mess_block;
                    VAR rec : tgg_rec_buf);
 
        PROCEDURE
              k720_select (
                    VAR m      : tgg_mess_block;
                    VAR getrec : tkb7_get_param;
                    VAR selrec : tkb7_select_param);
 
        PROCEDURE
              k720_initialize (
                    VAR m                : tgg_mess_block;
                    VAR selrec           : tkb7_select_param;
                    VAR strat            : tgg07_StrategyInfo;
                    VAR use_stopkey      : boolean;
                    VAR finding_possible : boolean);
 
      ------------------------------ 
 
        FROM
              Single_Select_Part2 : VKB721;
 
        PROCEDURE
              k721call_later_output (
                    VAR m       : tgg_mess_block;
                    VAR res_buf : tsp_buf;
                    h_keylen    : integer);
 
        PROCEDURE
              k721null_result (
                    VAR m         : tgg_mess_block;
                    VAR selrec    : tkb7_select_param;
                    VAR sel       : tgg_select_fields_param;
                    act_cntresult : tsp_int4;
                    later_output  : boolean;
                    h_keylen      : integer);
 
        PROCEDURE
              k721add_into_result (
                    VAR t                : tgg00_TransContext;
                    VAR selrec           : tkb7_select_param;
                    VAR next_mblock      : tgg_mess_block_ptr);
 
        PROCEDURE
              k721do_rowno (
                    VAR m      : tgg_mess_block;
                    VAR selrec : tkb7_select_param);
 
        FUNCTION
              k721out_entry (
                    st_addr : tgg_stack_list_ptr;
                    curr : integer) : integer;
 
      ------------------------------ 
 
        FROM
              KB_Better_Join_Select : VKB741;
 
        PROCEDURE
              k741better_join (
                    VAR m      : tgg_mess_block;
                    stenum     : tgg07_StratEnum;
                    invindex   : integer;
                    invroot    : tsp00_PageNo;
                    VAR getrec : tkb7_get_param;
                    VAR selrec : tkb7_select_param;
                    VAR sel    : tgg_select_fields_param);
 
        PROCEDURE
              k741finish_r_outer_join (
                    VAR m      : tgg_mess_block;
                    VAR getrec : tkb7_get_param;
                    VAR selrec : tkb7_select_param);
 
        PROCEDURE
              k741last_defined_byte_pos (
                    VAR m       : tgg_mess_block;
                    VAR selrec  : tkb7_select_param;
                    VAR linkrec : tgg07_KbJoinRec);
 
        PROCEDURE
              k741join_with_left_result (
                    VAR m           : tgg_mess_block;
                    VAR getrec      : tkb7_get_param;
                    VAR sel         : tgg_select_fields_param;
                    VAR selrec      : tkb7_select_param;
                    VAR listkey     : tgg_lkey;
                    return_next_key : boolean);
 
        PROCEDURE
              k741sequential_join (
                    VAR m      : tgg_mess_block;
                    VAR getrec : tkb7_get_param;
                    VAR selrec : tkb7_select_param);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_1 : VBD01;
 
        PROCEDURE
              b01move_filecontent (
                    VAR t         : tgg00_TransContext;
                    VAR source_id : tgg00_FileId;
                    VAR target_id : tgg00_FileId);
 
        PROCEDURE
              b01tcreate_file (
                    VAR t           : tgg00_TransContext;
                    VAR act_tree_id : tgg00_FileId);
 
        PROCEDURE
              b01destroy_file (
                    VAR t       : tgg00_TransContext;
                    VAR current : tgg00_FileId);
 
        PROCEDURE
              b01empty_file (
                    VAR t       : tgg00_TransContext;
                    VAR current : tgg00_FileId);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_2   : VBD02;
 
        PROCEDURE
              b02select_record (
                    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;
                    VAR sel         : tgg00_SelectFieldsParam;
                    VAR stack_desc  : tgg00_StackDesc;
                    VAR unqualified : boolean);
 
      ------------------------------ 
 
        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           : tsp_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       : tgg00_Rec);
 
      ------------------------------ 
 
        FROM
              task_temp_data_cache : VBD21;
 
        PROCEDURE
              b21mp_root_put (
                    temp_cache_ptr : tgg00_TempDataCachePtr;
                    root : tsp00_PageNo);
 
      ------------------------------ 
 
        FROM
              ref_statistic : VBD73;
 
        VAR
              b73spage_ref_statistic : boolean;
 
        PROCEDURE
              b73cmds_count (
                    statement_kind : tgg00_RefInfoIndex;
                    count : tsp00_Int4);
 
      ------------------------------ 
 
        FROM
              Configuration_Parameter : VGG01;
 
        VAR
              g01code      : tgg_code_globals;
              g01localsite : tgg_serverdb_no;
 
      ------------------------------ 
 
        FROM
              Select_Help_Procedures : VGG04;
 
        PROCEDURE
              g04init_select_fields (
                    VAR sel       : tgg_select_fields_param;
                    data_addr     : tsp_moveobj_ptr;
                    data_size     : tsp_int4;
                    work_st_addr  : tgg_stack_list_ptr;
                    work_st_max   : tsp_int2;
                    work_buf_addr : tsp_moveobj_ptr;
                    work_buf_size : tsp_int4;
                    curr_sqlmode  : tsp_sqlmode);
 
      ------------------------------ 
 
        FROM
              RTE_kernel : VEN101;
 
        PROCEDURE
              vclock (
                    VAR sec      : tsp_int4;
                    VAR microsec : tsp_int4);
 
        PROCEDURE
              vmonitor (
                    pid          : tsp_process_id;
                    VAR phys_ios : tsp_int4;
                    VAR suspends : tsp_int4;
                    VAR waits    : tsp_int4);
 
      ------------------------------ 
 
        FROM
              RTE-Extension-10 : VSP10;
 
        PROCEDURE
              s10fil (
                    size     : tsp_int4;
                    VAR m    : tsp_key;
                    pos      : tsp_int4;
                    len      : tsp_int4;
                    fillchar : char);
 
      ------------------------------ 
 
        FROM
              Kernel_move_and_fill : VGG10;
 
        PROCEDURE
              g10fil1 (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size           : tsp_int4;
                    VAR m          : tsp_buf;
                    pos            : tsp_int4;
                    len            : tsp_int4;
                    fillchar       : char;
                    VAR e          : tgg_basis_error);
 
        PROCEDURE
              g10mv1 (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size1          : tsp_int4;
                    size2          : tsp_int4;
                    VAR val1       : tsp_buf;
                    p1             : tsp_int4;
                    VAR val2       : tsp_key;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
        PROCEDURE
              g10mv2 (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size1          : tsp_int4;
                    size2          : tsp_int4;
                    VAR val1       : tkb7_select_param;
                    p1             : tsp_int4;
                    VAR val2       : tsp_buf;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
        PROCEDURE
              g10mv4 (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size1          : tsp_int4;
                    size2          : tsp_int4;
                    VAR val1       : tsp_moveobj;
                    p1             : tsp_int4;
                    VAR val2       : tgg07_MInfos;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
        PROCEDURE
              g10mv5 (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size1          : tsp_int4;
                    size2          : tsp_int4;
                    VAR val1       : tsp_moveobj;
                    p1             : tsp_int4;
                    VAR val2       : tgg07_NextJoins;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
        PROCEDURE
              g10mv6 (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size1          : tsp_int4;
                    size2          : tsp_int4;
                    VAR val1       : tsp_moveobj;
                    p1             : tsp_int4;
                    VAR val2       : tgg07_KbJoinRec;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
        PROCEDURE
              g10mv7 (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size1          : tsp_int4;
                    size2          : tsp_int4;
                    VAR val1       : tsp_buf;
                    p1             : tsp_int4;
                    VAR val2       : tkb7_select_param;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
        PROCEDURE
              g10mv10 (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size1          : tsp_int4;
                    size2          : tsp_int4;
                    VAR val1       : tsp_buf;
                    p1             : tsp_int4;
                    VAR val2       : tsp_buf;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
        PROCEDURE
              g10mv11 (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size1          : tsp_int4;
                    size2          : tsp_int4;
                    VAR val1       : tsp_moveobj;
                    p1             : tsp_int4;
                    VAR val2       : tgg07_StrJoinViewkey;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
        PROCEDURE
              g10mv12 (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size1          : tsp_int4;
                    size2          : tsp_int4;
                    VAR val1       : tgg_stack_list;
                    p1             : tsp_int4;
                    VAR val2       : tgg_stack_list;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
        PROCEDURE
              g10mvb (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size1          : tsp_int4;
                    size2          : tsp_int4;
                    VAR val1       : tsp_buf;
                    p1             : tsp_int4;
                    VAR val2       : tsp_buf;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
      ------------------------------ 
 
        FROM
              RTE-Extension-20 : VSP20;
 
        PROCEDURE
              s20ch4sw (
                    val        : tsp_int4;
                    sourceswap : tsp_swap_kind;
                    VAR dest   : tsp_buf;
                    di         : tsp_int4;
                    destswap   : tsp_swap_kind);
 
        FUNCTION
              s20or4sw (
                    VAR source     : tsp_buf;
                    si             : tsp_int4;
                    sourceswap     : tsp_swap_kind;
                    destswap       : tsp_swap_kind) : tsp_int4;
 
      ------------------------------ 
 
        FROM
              RTE-Extension-30 : VSP30;
 
        PROCEDURE
              s30cmp (
                    VAR buf1     : tsp_buf;
                    fieldpos1    : tsp_int4;
                    fieldlength1 : tsp_int4;
                    VAR buf2     : tsp_buf;
                    fieldpos2    : tsp_int4;
                    fieldlength2 : tsp_int4;
                    VAR l_result : tsp_lcomp_result);
 
        PROCEDURE
              s30luc (
                    VAR buf1     : tsp_buf;
                    fieldpos1    : tsp_int4;
                    fieldlength1 : tsp_int4;
                    VAR buf2     : tsp_buf;
                    fieldpos2    : tsp_int4;
                    fieldlength2 : tsp_int4;
                    VAR l_result : tsp_lcomp_result);
 
        FUNCTION
              s30lnr_defbyte (
                    str       : tsp_moveobj_ptr;
                    defbyte   : char;
                    start_pos : tsp_int4;
                    length    : tsp_int4) : tsp_int4;
 
      ------------------------------ 
 
        FROM
              PUT-Conversions : VSP41;
 
        PROCEDURE
              s41p4int (
                    VAR buf : tsp_resnum;
                    pos     : tsp_int4;
                    source  : tsp_int4;
                    VAR res : tsp_num_error);
&       IFDEF TRACE
 
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        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
              t01strat_enum (
                    debug : tgg00_Debug;
                    nam   : tsp00_Sname;
                    strat : tgg07_StratEnum);
 
        PROCEDURE
              t01bool (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    curr_bool: boolean);
 
        PROCEDURE
              t01treeid  (
                    level    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    VAR tree : tgg00_FileId);
 
        PROCEDURE
              t01buf1  (
                    level     : tgg00_Debug;
                    VAR buf   : tsp_moveobj;
                    pos_start : integer;
                    pos_end   : integer);
 
        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
              t01lkey (
                    layer : tgg00_Debug;
                    VAR k : tgg00_Lkey);
 
        PROCEDURE
              t01char  (
                    level : tgg00_Debug;
                    nam : tsp00_Sname;
                    c   : char);
 
        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);
&       ENDIF
 
.CM *-END-* use -----------------------------------------
.sp;.cp 3
Synonym :
 
        PROCEDURE
              t01buf1;
 
              tsp00_Buf tsp_moveobj
 
        PROCEDURE
              k71col_select;
 
              tgg00_Rec tsp_buf
 
        PROCEDURE
              b07cnext_record;
 
              tsp00_MoveObj tsp_buf
 
        PROCEDURE
              k71join_comparison;
 
              tsp_moveobj tsp_buf
 
        PROCEDURE
              s10fil;
 
              tsp_moveobj tsp_key
 
        PROCEDURE
              g10fil1;
 
              tsp_moveobj tsp_buf
 
        PROCEDURE
              g10mv1;
 
              tsp_moveobj tsp_buf
              tsp_moveobj tsp_key
 
        PROCEDURE
              g10mv2;
 
              tsp_moveobj tkb7_select_param
              tsp_moveobj tsp_buf
 
        PROCEDURE
              g10mv4;
 
              tsp_moveobj tgg07_MInfos
 
        PROCEDURE
              g10mv5;
 
              tsp_moveobj tgg07_NextJoins
 
        PROCEDURE
              g10mv6;
 
              tsp_moveobj tgg07_KbJoinRec
 
        PROCEDURE
              g10mv7;
 
              tsp_moveobj tsp_buf
              tsp_moveobj tkb7_select_param
 
        PROCEDURE
              g10mv10;
 
              tsp_moveobj tsp_buf
 
        PROCEDURE
              g10mv11;
 
              tsp_moveobj tgg07_StrJoinViewkey
 
        PROCEDURE
              g10mv12;
 
              tsp_moveobj tgg_stack_list
 
        PROCEDURE
              g10mvb;
 
              tsp_page tsp_buf
 
        PROCEDURE
              s20ch4sw;
 
              tsp_moveobj tsp_buf
 
        PROCEDURE
              s20or4sw;
 
              tsp_moveobj tsp_buf
 
        PROCEDURE
              s30cmp;
 
              tsp_moveobj tsp_buf
 
        PROCEDURE
              s30luc;
 
              tsp_moveobj tsp_buf
 
        PROCEDURE
              s41p4int;
 
              tsp_moveobj tsp_resnum
 
.CM *-END-* synonym -------------------------------------
.sp;.cp 3
Author  : ElkeZ
.sp
.cp 3
Created : 1985-10-23
.sp
.cp 3
Version : 2002-09-17
.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;
            o_recl   : int2;
            o_keyl   : int2;
            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 GET_NEW_POSITIONS.
SHORT_INIT is used to rescue such data from the 1st strategy as
are required if calling up VKB72 is enough to destroy the strategy.
Depending on whether or not a straighforward join strategy can be
adopted (direct access to desired records), the procedure called up is
either DO_BETTER_JOIN (straightforward) or DO_JOIN_SELECT following
K72_SINGLE_JOIN_SELECT.
 
KB74GET_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.
SHORT_INIT
 
This procedure fetches data required for joining from the Strategy-
info (e.g. name of the 2nd intermediate result, record length and key
length of the result record) but that may also be destroyed by VKB72.
(This procedure may now be superfluous, because VKB72 no longer
destroys ??)
 
K74_MAXRESULT_GET
 
2 bytes are available in the  Strategy_info for single-table selects
and in minfo.n_maxcnt for joins. The maximum permissible number of
results derives from these two bytes in conjunction with the
Mess-Buffer.
This number could not be stated directly without an int4.
Execution would entail placing this value at the correct position in
the last join mess buffer for Rowno_statements with parameters, a
process that would be too complicated.
The 2 bytes are transferred to K74_MAXRESULT_GET as strat_maxcnt
and signify:
 
-1  the number is not restricted(largest possible value)
-2  Subquery without ALL or ANY; no more than one record may be
found
-3,-4 cannot occur
<-4 ROWNO < x was stated as a condition. The value of x is at
the position abs(strat_maxcnt) in part2 of the Mess-Buffer. Only
x-1 records need be found.
0   SELECT..INTO; no more than one record may be found
1   EXISTS; a record need only be found
2-4 cannot occur
>4 ROWNO <= x was stated as a condition. the value of x is at
the position strat_maxcnt in part2 of the Mess-Buffer
Only values of abs(strat_maxcnt) > 4 can be considered for the
Rowno data, because values appear only as of position 5 in part2 of
the mess buffer and are preceded by total length and key length, where
applicable.
Since ROWNO <= 1 is permissible, in other words the value to be
used during the search (maxresult) may be 1, the upper limit for
SELECT..INTO has to be identified by other means.
ROWNO <= x leads to an abort with an error of which the user is
not notified, if there are x results.
In the case of SELECT..INTO the first result should not lead to an
abort; instead, a check has to be run for a second result that would
lead to an error if it exists.
SELECT..INTO or the subqueries that can have only one result thus
have to be specially identified. Maxresult is, therefore, set to 0 and
suitably queried in K72_ADD_INTO_RESULT.
In a join, a strat_maxcnt <> -1 does not occur before the last
join step, because it is the number of final results that is to be
restricted, and not that of intermediate results.
 
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_BETTER_JOIN
 
JOIN_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.
 
KB74ALL_GET
 
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.
 
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.
 
KB74JOINVIEW_SEARCH
 
The procedure verifies whether a record precisely defined by its key
fulfills the join conditions along with other records taken one from
each of several other tables.
 
The initializations that are absolutely essential for KB74ALL_GET are
implemented by JOIN_INIT_SEL.
 
One record, the result of the join steps executed beforehand, is
fetched to the left buffer.
The key of the record from the current primary table is passed
from the start of part2 of the mess buffer to the right search key;
the corresponding record is fetched to the right buffer with the
possibility of a delay occasioned by lock conflicts.
Once the two records are available, they are joined by
JOIN_L_WITH_LEFT_RECORDS and the result entered in the new
intermediate-result file.
 
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.
 
All the initializations required for KB74ALL_GET are implemented by
JOIN_INIT_SEL.
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_INIT_SEL
 
The pointers and the initializations that are required by qualification
processing in VKB71 are determined.
 
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
***********************************************************
.sp
.cp 10
.nf
.oc _/1
Structure:
 
.CM *-END-* structure -----------------------------------
.sp 2
**********************************************************
.sp
.cp 10
.nf
.oc _/1
.CM -lll-
Code    :
 
 
CONST
      c_build_right_outer_join = true;
      c_first_field            = 1;
      (* *** one_join_phase begin *** *)
      c_first_qual             = true;
      c_result_wanted          = true;
      c_check_new_rec          = true;
      (* *** one_join_phase end *** *)
 
TYPE
 
      search_rec = RECORD
            sr_lsearchkey        : tgg_lkey;
            sr_rsearchkey        : tgg_lkey;
            sr_oj_lcountresult   : integer;
            sr_oj_rcountresult   : integer;
            sr_error_l           : tgg_basis_error;
            sr_error_r           : tgg_basis_error;
            sr_set_result        : tgg_bd_set_result_record;
            sr_old_left_tree_pos : tgg00_FilePos;
            sr_left_tree_pos     : tgg00_FilePos;
            sr_left_before_cnext_tree_pos : tgg00_FilePos;
            sr_seq_r_outer_join  : boolean;
            sr_j_curr_join_step  : integer;
      END;
 
 
 
(*------------------------------*) 
 
PROCEDURE
      kb74all_get (
            VAR m         : tgg_mess_block;
            VAR selrec    : tkb7_select_param;
            sel_type      : tgg_message2_type;
            VAR rstartkey : tgg_lkey;
            VAR sel       : tgg_select_fields_param);
 
VAR
      _dummy_bool : boolean;
 
BEGIN
m.mb_trns^.trError_gg00 := e_ok;
sel.sfp_bd_mess2_type   := sel_type;
m.mb_qual^.mtree.fileBdUse_gg00 := [  ];
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;
b02select_record (m.mb_trns^, m.mb_qual^.mtree,
      rstartkey.keyVal_gg00, rstartkey.keyLen_gg00,
      selrec.selr_stopkey.keyVal_gg00, selrec.selr_stopkey.keyLen_gg00,
      sizeof (selrec.selr_selectbuffer.buf_rec),
      @selrec.selr_selectbuffer.buf_rec, sel,
      m.mb_qual^.mstack_desc, _dummy_bool);
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74build_new_rec (
            VAR m         : tgg_mess_block;
            VAR getrec    : tkb7_get_param;
            VAR selrec    : tkb7_select_param;
            VAR searchrec : search_rec;
            outer_join    : tkb7_outer_join_type);
 
VAR
      _i        : integer;
      _l        : integer;
      _t        : integer;
      _f        : integer;
      _j        : integer;
      _lfirst   : boolean;
      _rfirst   : boolean;
      _dummy    : boolean;
      _ky_offs  : integer;
      _abs_mult : integer;
 
BEGIN
&IFDEF TRACE
g10fil1 ('VKB74 ',   1,    
      sizeof(selrec.selr_selectbuffer.result.buf),
      selrec.selr_selectbuffer.result.buf, 1, getrec.gi_minfo.o_recl, '@',
      m.mb_trns^.trError_gg00);
t01int4 (kb, 'o_recl      ', getrec.gi_minfo.o_recl);
t01int4 (kb, 'lbuf o_keyl ', getrec.gi_minfo.o_keyl);
t01buf (kb, selrec.selr_selectbuffer.lbuf, selrec.selr_l_currpos + 1,
      selrec.selr_l_currpos + getrec.gi_minfo.o_recl);
t01char (kb, 'buf filled w', '@');
t01int4 (kb, 'mqual_pos   ', m.mb_qual^.mqual_pos);
t01int4 (kb, 'mqual_cnt   ', m.mb_qual^.mqual_cnt);
t01int4 (kb, 'lposcnt     ', getrec.gi_n_pos_s.lposcnt);
t01int4 (kb, 'rposcnt     ', getrec.gi_n_pos_s.rposcnt);
t01int4 (kb, 'n_rec_len   ', getrec.gi_minfo.n_rec_len);
t01int4 (kb, 'n_key_len   ', getrec.gi_minfo.n_key_len);
t01stackentry (kb, m.mb_st^[ m.mb_qual^.mqual_pos ], m.mb_qual^.mqual_pos);
t01int4 (kb, 'l_currpos   ', selrec.selr_l_currpos);
t01int4 (kb, 'r_currpos   ', selrec.selr_r_currpos);
t01int4 (kb, 'l_countresul', searchrec.sr_oj_lcountresult);
&ENDIF
IF  (m.mb_trns^.trError_gg00 = e_ok)   AND
    searchrec.sr_seq_r_outer_join             AND
    (outer_join = no_outer_join) AND
    (getrec.gi_linkrec.kbjr_linkcnt > 0)
THEN
    kb74store_left_key (m.mb_trns^, getrec, selrec);
(*ENDIF*) 
IF  (m.mb_trns^.trError_gg00 = e_ok)      AND
    getrec.gi_linkrec.kbjr_left_oj                AND
    (outer_join <> left_outer_join) AND
    (searchrec.sr_j_curr_join_step > 2)
THEN
    _dummy := kb74new_outer_key (m.mb_trns^, getrec, selrec);
(*ENDIF*) 
selrec.selr_selectbuffer.result.len           := getrec.gi_minfo.n_rec_len;
selrec.selr_selectbuffer.result.keylen        := getrec.gi_minfo.n_key_len;
selrec.selr_selectbuffer.result.recVarcolOffset_gg00 := 0;
selrec.selr_selectbuffer.result.recVarcolCnt_gg00    := 0;
_lfirst        := true;
_rfirst        := true;
IF  (outer_join = left_outer_join)
THEN
    getrec.gi_lr_rec_id.l_rec_id := 0
ELSE
    BEGIN
    (* *** internal resultrecord has on last four bytes of      *)
    (*     the key an unique counter, which is used here to     *)
    (*     identify the current record (l_rec_id            *** *)
    _ky_offs := 1;
    IF  (searchrec.sr_j_curr_join_step > 2) AND
        (getrec.gi_minfo.o_keyl > mxgg_int4)
    THEN
        _ky_offs := -3;
    (*ENDIF*) 
    getrec.gi_lr_rec_id.l_rec_id :=
          s20or4sw (selrec.selr_selectbuffer.lbuf, selrec.selr_l_currpos +
          getrec.gi_minfo.o_keyl + _ky_offs, sw_normal, g01code.kernel_swap);
    END;
(*ENDIF*) 
&IFDEF TRACE
t01int4 (kb, 'outer_join  ', ord (outer_join));
t01int4 (kb, 'lr_rec_id  l', getrec.gi_lr_rec_id.l_rec_id);
t01buf (kb, selrec.selr_selectbuffer.lbuf, selrec.selr_l_currpos +
      getrec.gi_minfo.o_keyl + 1,
      selrec.selr_l_currpos + getrec.gi_minfo.o_keyl + mxgg_int4);
&ENDIF
FOR _i := getrec.gi_n_pos_s.rposcnt + 1 TO
      getrec.gi_n_pos_s.rposcnt + getrec.gi_n_pos_s.lposcnt DO
    BEGIN
&   IFDEF TRACE
    t01int4 (kb, 'onto        ', getrec.gi_n_pos_s.posarr[ _i ].onto);
    t01int4 (kb, 'onlen       ', getrec.gi_n_pos_s.posarr[ _i ].onlen);
    t01int4 (kb, 'lbuf vfill  ', 111);
    t01buf (kb, selrec.selr_selectbuffer.lbuf, selrec.selr_l_currpos +
          getrec.gi_n_pos_s.posarr[ _i ].onfrom,
          selrec.selr_l_currpos + getrec.gi_n_pos_s.posarr[ _i ].onfrom +
          getrec.gi_n_pos_s.posarr[ _i ].onlen - 1);
&   ENDIF
    IF  (outer_join = left_outer_join) AND
        getrec.gi_n_pos_s.posarr[ _i ].onouter
    THEN
        BEGIN
        IF  _lfirst
        THEN
            searchrec.sr_oj_lcountresult := succ (searchrec.sr_oj_lcountresult);
        (*ENDIF*) 
        _lfirst := false;
&       IFDEF TRACE
        t01int4 (kb, 'l_outer_join',  ord(outer_join));
        t01int4 (kb, 'r_rec_id    ', getrec.gi_lr_rec_id.r_rec_id);
&       ENDIF
        (* *** define-Byte *** *)
        selrec.selr_selectbuffer.
              result.buf[ getrec.gi_n_pos_s.posarr[ _i ].onto ] := csp_undef_byte;
        (* *** NULL VALUE *** *)
        g10fil1 ('VKB74 ',   2,    
              sizeof(selrec.selr_selectbuffer.result.buf),
              selrec.selr_selectbuffer.result.buf,
              getrec.gi_n_pos_s.posarr[ _i ].onto + 1,
              getrec.gi_n_pos_s.posarr[ _i ].onlen - 1,
              csp_defined_byte, m.mb_trns^.trError_gg00);
        END
    ELSE
        BEGIN
        g10mv10 ('VKB74 ',   3,    
              sizeof(selrec.selr_selectbuffer.lbuf),
              sizeof(selrec.selr_selectbuffer.result.buf),
              selrec.selr_selectbuffer.lbuf,
              selrec.selr_l_currpos + getrec.gi_n_pos_s.posarr[ _i ].onfrom,
              selrec.selr_selectbuffer.result.buf,
              getrec.gi_n_pos_s.posarr[ _i ].onto,
              getrec.gi_n_pos_s.posarr[ _i ].onlen, m.mb_trns^.trError_gg00);
        END;
    (*ENDIF*) 
&   IFDEF TRACE
    t01int4 (kb, 'buf nfill   ', 999);
    t01buf (kb, selrec.selr_selectbuffer.result.buf,
          getrec.gi_n_pos_s.posarr[ _i ].onto,
          getrec.gi_n_pos_s.posarr[ _i ].onto +
          getrec.gi_n_pos_s.posarr[ _i ].onlen - 1);
&   ENDIF
    END;
(*ENDFOR*) 
IF  m.mb_trns^.trError_gg00 = e_ok
THEN
    FOR _i := 1 TO getrec.gi_n_pos_s.rposcnt DO
        BEGIN
        IF  getrec.gi_n_pos_s.posarr[ _i ].onfrom > 0
        THEN
            _abs_mult := 1
        ELSE
            _abs_mult := -1;
        (*ENDIF*) 
&       IFDEF TRACE
        t01int4 (kb, 'onto        ', getrec.gi_n_pos_s.posarr[ _i ].onto);
        t01int4 (kb, 'onlen       ', getrec.gi_n_pos_s.posarr[ _i ].onlen);
        t01int4 (kb, 'rbuf vfill  ', 111);
        t01buf (kb, selrec.selr_selectbuffer.rbuf, selrec.selr_r_currpos +
              (getrec.gi_n_pos_s.posarr[ _i ].onfrom * _abs_mult),
              selrec.selr_r_currpos + getrec.gi_n_pos_s.posarr[ _i ].onfrom +
              getrec.gi_n_pos_s.posarr[ _i ].onlen - 1);
&       ENDIF
        IF  (outer_join = right_outer_join)
        THEN
            BEGIN
            IF  (getrec.gi_n_pos_s.posarr[ _i ].onfrom > 0)
            THEN
                BEGIN
                IF  _rfirst
                THEN
                    searchrec.sr_oj_rcountresult :=
                          succ (searchrec.sr_oj_rcountresult);
                (*ENDIF*) 
                _rfirst := false;
&               IFDEF TRACE
                t01int4 (kb, 'r_outer_join', ord(outer_join));
                t01int4 (kb, 'start move  ', selrec.selr_l_currpos +
                      getrec.gi_minfo.o_keyl + 1);
                t01int4 (kb, 'l_rec_id    ', getrec.gi_lr_rec_id.l_rec_id);
&               ENDIF
                (* *** define-Byte *** *)
                selrec.selr_selectbuffer.
                      result.buf[ getrec.gi_n_pos_s.posarr[ _i ].onto ] := csp_undef_byte;
                (* *** NULL VALUE *** *)
                g10fil1 ('VKB74 ',   4,    
                      sizeof(selrec.selr_selectbuffer.result.buf),
                      selrec.selr_selectbuffer.result.buf,
                      getrec.gi_n_pos_s.posarr[ _i ].onto + 1,
                      getrec.gi_n_pos_s.posarr[ _i ].onlen - 1,
                      csp_defined_byte, m.mb_trns^.trError_gg00);
                END
            ELSE
                BEGIN
                (* *** constant expression in outputlist *** *)
                k74_const_output_expression (m, selrec,
                      getrec.gi_n_pos_s.posarr[ _i ]);
                END;
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            g10mv10 ('VKB74 ',   5,    
                  sizeof(selrec.selr_selectbuffer.rbuf),
                  sizeof(selrec.selr_selectbuffer.result.buf),
                  selrec.selr_selectbuffer.rbuf, selrec.selr_r_currpos +
                  (getrec.gi_n_pos_s.posarr[ _i ].onfrom * _abs_mult),
                  selrec.selr_selectbuffer.result.buf,
                  getrec.gi_n_pos_s.posarr[ _i ].onto,
                  getrec.gi_n_pos_s.posarr[ _i ].onlen,
                  m.mb_trns^.trError_gg00)
            END;
        (*ENDIF*) 
&       IFDEF TRACE
        t01int4 (kb, 'buf nfill   ', 999);
        t01buf (kb, selrec.selr_selectbuffer.result.buf,
              getrec.gi_n_pos_s.posarr[ _i ].onto,
              getrec.gi_n_pos_s.posarr[ _i ].onto +
              getrec.gi_n_pos_s.posarr[ _i ].onlen - 1);
&       ENDIF
        END;
    (*ENDFOR*) 
&IFDEF TRACE
(*ENDIF*) 
t01buf (kb, selrec.selr_selectbuffer.result.buf, 1,
      selrec.selr_selectbuffer.result.len + 3);
t01int4 (kb, 'n_j_cnt     ', getrec.gi_njrec.n_j_cnt);
&ENDIF
FOR _i := 1 TO getrec.gi_njrec.n_j_cnt DO
    IF  getrec.gi_njrec.n_j_arr[ _i ].jfrom <= 0
    THEN
        BEGIN
        _l := getrec.gi_njrec.n_j_arr[ _i ].jlen - 1;
        _t := getrec.gi_njrec.n_j_arr[ _i ].jto;
        _f := - getrec.gi_njrec.n_j_arr[ _i ].jfrom;  (* jfrom < 0 *)
&       IFDEF TRACE
        t01int4 (ak_sem, 'last_o nklen', getrec.gi_minfo.n_key_len);
        t01int4 (ak_sem, 'last_o njcnt', getrec.gi_njrec.n_j_cnt);
        t01int4 (ak_sem, 'last_o jfrom', getrec.gi_njrec.n_j_arr[ _i ].jfrom);
        t01int4 (ak_sem, 'last_o jto  ', getrec.gi_njrec.n_j_arr[ _i ].jto);
        t01int4 (ak_sem, 'last_o jlen ', getrec.gi_njrec.n_j_arr[ _i ].jlen);
        t01int4 (ak_sem, 'last_o f    ', _f);
&       ENDIF
        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_njrec.n_j_arr[ _i ].jto;
        _f := getrec.gi_njrec.n_j_arr[ _i ].jfrom;
&       IFDEF TRACE
        t01int4 (ak_sem, 'last_o jfrom', getrec.gi_njrec.n_j_arr[ _i ].jfrom);
        t01int4 (ak_sem, 'last_o jto  ', getrec.gi_njrec.n_j_arr[ _i ].jto);
        t01int4 (ak_sem, 'last_o jlen ', getrec.gi_njrec.n_j_arr[ _i ].jlen);
        t01int4 (ak_sem, 'last_o f    ', _f);
&       ENDIF
        IF  (_t <> _f)
        THEN
            g10mv10 ('VKB74 ',   6,    
                  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_njrec.n_j_arr[ _i ].jlen, m.mb_trns^.trError_gg00);
        (*ENDIF*) 
        END;
    (*ENDIF*) 
(*ENDFOR*) 
IF  m.mb_st^[ m.mb_qual^.mqual_pos ].eop = op_outer_join
THEN (* special outerjoin via vkb71 ex: "or" *)
    BEGIN
    g10mvb ('VKB74 ',   7,    
          sizeof(selrec.selr_selectbuffer.result.buf),
          sizeof(selrec.selr_selectbuffer.result.buf),
          selrec.selr_selectbuffer.result.buf, 3,
          selrec.selr_selectbuffer.result.buf,
          3 + ckb7_oj_key_offs, selrec.selr_selectbuffer.result.len - 2,
          m.mb_trns^.trError_gg00);
    selrec.selr_selectbuffer.result.len    :=
          selrec.selr_selectbuffer.result.len + ckb7_oj_key_offs;
    selrec.selr_selectbuffer.result.keylen :=
          selrec.selr_selectbuffer.result.keylen + ckb7_oj_key_offs;
    s20ch4sw (getrec.gi_lr_rec_id.l_rec_id, g01code.kernel_swap,
          selrec.selr_selectbuffer.result.buf, cgg_rec_key_offset+1, sw_normal);
    s20ch4sw (getrec.gi_lr_rec_id.r_rec_id, g01code.kernel_swap,
          selrec.selr_selectbuffer.result.buf, cgg_rec_key_offset+1+
          sizeof(getrec.gi_lr_rec_id.r_rec_id),
          sw_normal);
    END
ELSE
    IF  getrec.gi_mto_outer_tab = left_outer_join
    THEN
        s20ch4sw (getrec.gi_lr_rec_id.r_rec_id, g01code.kernel_swap,
              selrec.selr_selectbuffer.result.buf,
              selrec.selr_selectbuffer.result.keylen - 3, sw_normal)
    ELSE
        IF  getrec.gi_mto_outer_tab = right_outer_join
        THEN
            s20ch4sw (getrec.gi_lr_rec_id.l_rec_id, g01code.kernel_swap,
                  selrec.selr_selectbuffer.result.buf,
                  selrec.selr_selectbuffer.result.keylen - 3, sw_normal);
        (*ENDIF*) 
    (*ENDIF*) 
(*ENDIF*) 
;
&IFDEF TRACE
;
t01int4 (kb, 'keylen      ', selrec.selr_selectbuffer.result.keylen);
t01int4 (kb, 'mto_outer_ta', ord (getrec.gi_mto_outer_tab));
t01int4 (kb, 'lr_rec_id  l', getrec.gi_lr_rec_id.l_rec_id);
t01int4 (kb, 'lr_rec_id  r', getrec.gi_lr_rec_id.r_rec_id);
t01buf (kb, selrec.selr_selectbuffer.result.buf, 1,
      selrec.selr_selectbuffer.result.len);
t01int4 (kb, 'N_J_COUNT   ', getrec.gi_njrec.n_j_cnt);
&ENDIF
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74nlbuild_next_lkey (
            VAR next_lkey : tgg_lkey;
            fieldlen      : tsp_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
      kb74compare_two_records (
            VAR selrec          : tkb7_select_param;
            VAR linkrec         : tgg07_KbJoinRec;
            VAR sel             : tgg_select_fields_param;
            VAR fulfilled       : boolean;
            VAR first_fulfilled : boolean);
 
VAR
      _first       : boolean;
      _op          : tgg_stack_op_type;
      _linkcnt     : integer;
      _lc_result   : tsp_lcomp_result;
      _lpos        : integer;
      _rpos        : integer;
      _compare_ok  : integer;
      _m_def_byte1 : char;
      _m_def_byte2 : char;
      _ix            : integer;
 
BEGIN
selrec.selr_l_null_val_fnd := false;
selrec.selr_r_null_val_fnd := false;
_linkcnt            := linkrec.kbjr_linkcnt;
fulfilled           := true;
first_fulfilled     := true;
_first              := _linkcnt = 1;
&IFDEF TRACE
t01int4 (kb, 'linkcnt     ', _linkcnt);
&ENDIF
WHILE ((_linkcnt <= linkrec.kbjr_cnt) AND fulfilled) DO
    WITH linkrec.kbjr_jarr[ _linkcnt ] DO
        BEGIN
        _lpos := selrec.selr_l_currpos + kbji_parts[ 1 ].kboj_recpos;
        _rpos := selrec.selr_r_currpos + kbji_parts[ 2 ].kboj_recpos;
        _op   := kbji_parts[ 1 ].kboj_op;
&       IFDEF TRACE
        t01int4 (kb, 'selr_l_def_p', selrec.selr_l_defbyte_pos);
        t01buf(kb,selrec.selr_selectbuffer.lbuf, _lpos, _lpos + kbji_parts[ 1 ].kboj_len - 1);
        CASE _op OF
            op_eq :
                t01int4 (kb, ':op:  l =  r', ord(_op));
            op_ge :
                t01int4 (kb, ':op:  l >= r', ord(_op));
            op_gt :
                t01int4 (kb, ':op:  l >  r', ord(_op));
            op_le :
                t01int4 (kb, ':op:  l <= r', ord(_op));
            op_lt :
                t01int4 (kb, ':op:  l <  r', ord(_op));
            op_ne :
                t01int4 (kb, ':op:  l <> r', ord(_op));
            OTHERWISE
                t01int4 (kb, 'UNKNOWN :op:', ord(_op));
            END;
        (*ENDCASE*) 
        t01buf(kb,selrec.selr_selectbuffer.rbuf, _rpos, _rpos + kbji_parts[ 2 ].kboj_len - 1);
&       ENDIF
        IF  _op in [ op_like, op_not_like, op_sounds, op_not_sounds ]
        THEN
            BEGIN
            k71join_comparison (_op, sel,
                  selrec.selr_selectbuffer.lbuf, _lpos, kbji_parts[ 1 ].kboj_len,
                  selrec.selr_selectbuffer.rbuf, _rpos, kbji_parts[ 2 ].kboj_len,
                  _compare_ok);
            fulfilled := (_compare_ok = cgg_is_true);
            _first     := false
            END
        ELSE
            BEGIN
            IF  (_first AND
                (selrec.selr_l_defbyte_pos <> -1) AND
                (ord (kbji_parts[ 2 ].kboj_op) <> 0))
            THEN
                (* multiple key- or indexcolums *)
                (* with different lengths *)
                BEGIN
                _m_def_byte1  := selrec.selr_selectbuffer.lbuf[ _lpos ];
                _m_def_byte2  := selrec.selr_selectbuffer.rbuf[ _rpos ];
                selrec.selr_selectbuffer.lbuf[ _lpos ] := selrec.selr_selectbuffer.lbuf
                      [ selrec.selr_l_currpos + selrec.selr_l_defbyte_pos ];
                selrec.selr_selectbuffer.rbuf[ _rpos ] := selrec.selr_selectbuffer.rbuf
                      [ selrec.selr_r_currpos + selrec.selr_l_defbyte_pos ];
                END;
            (*ENDIF*) 
            s30luc (selrec.selr_selectbuffer.lbuf, _lpos, kbji_parts[ 1 ].kboj_len,
                  selrec.selr_selectbuffer.rbuf, _rpos, kbji_parts[ 2 ].kboj_len,
                  _lc_result);
            IF  (_first AND
                (selrec.selr_l_defbyte_pos <> -1) AND
                (ord (kbji_parts[ 2 ].kboj_op) <> 0))
            THEN
                (* multiple key- or indexcolums *)
                (* with different lengths *)
                BEGIN
                selrec.selr_selectbuffer.lbuf[ _lpos ] := _m_def_byte1;
                selrec.selr_selectbuffer.rbuf[ _rpos ] := _m_def_byte2;
                END
            ELSE
                IF  (selrec.selr_l_defbyte_pos = -1)
                THEN
                    BEGIN
                    selrec.selr_r_null_val_fnd :=
                          linkrec.kbjr_right_oj     AND
                          (_linkcnt in linkrec.kbjr_rof) AND
                          (selrec.selr_selectbuffer.lbuf[ _lpos ] = csp_undef_byte);
                    selrec.selr_l_null_val_fnd :=
                          linkrec.kbjr_left_oj     AND
                          (_linkcnt in linkrec.kbjr_lof) AND
                          (selrec.selr_selectbuffer.rbuf[ _rpos ] = csp_undef_byte);
                    END;
                (*ENDIF*) 
            (*ENDIF*) 
            ;
&           IFDEF TRACE
            t01int4 (kb, 'lc_result   ', ord(_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 := selrec.selr_selectbuffer.lbuf[ _lpos ];
                    IF  (selrec.selr_l_defbyte_pos <> -1) AND
                        (ord (kbji_parts[ 2 ].kboj_op) <> 0)
                    THEN
                        _m_def_byte1 := selrec.selr_selectbuffer.lbuf
                              [ selrec.selr_l_currpos + selrec.selr_l_defbyte_pos ];
                    (*ENDIF*) 
                    IF  _first AND
                        (_op IN [ op_lt, op_le, op_gt, op_ge ]) AND
                        ((_m_def_byte1 = csp_ascii_blank)  OR
                        ( _m_def_byte1 = csp_ebcdic_blank)   )
                    THEN
                        BEGIN
                        _ix := kbji_parts[ 1 ].kboj_len - 1;
&                       IFDEF TRACE
                        t01int4 (kb, 'ix          ', _ix);
                        t01int4 (kb, 'lpos        ', _lpos);
&                       ENDIF
                        _lc_result := l_undef;
                        WHILE (_ix > 1) DO
                            IF  selrec.selr_selectbuffer.lbuf [ _lpos + _ix ] < _m_def_byte1
                            THEN
                                BEGIN
                                (* *** go on with left side *** *)
                                _lc_result := l_undef;
&                               IFDEF TRACE
                                t01int4 (kb, 'ix         .', _ix);
&                               ENDIF
                                _ix        := 0; (* exit while *)
                                END
                            ELSE
                                _ix := pred (_ix);
                            (*ENDIF*) 
                        (*ENDWHILE*) 
                        END;
                    (*ENDIF*) 
                    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 := selrec.selr_selectbuffer.lbuf[ _lpos ];
                    IF  (selrec.selr_l_defbyte_pos <> -1) AND
                        (ord (kbji_parts[ 2 ].kboj_op) <> 0)
                    THEN
                        _m_def_byte1 := selrec.selr_selectbuffer.lbuf
                              [ selrec.selr_l_currpos + selrec.selr_l_defbyte_pos ];
                    (*ENDIF*) 
                    IF  _first AND
                        (_op IN [ op_lt, op_le, op_gt, op_ge ]) AND
                        ((_m_def_byte1 = csp_ascii_blank)  OR
                        ( _m_def_byte1 = csp_ebcdic_blank)   )
                    THEN
                        BEGIN
                        s30cmp (selrec.selr_selectbuffer.lbuf, _lpos, kbji_parts[ 1 ].kboj_len,
                              selrec.selr_selectbuffer.rbuf, _rpos, kbji_parts[ 2 ].kboj_len,
                              _lc_result);
&                       IFDEF TRACE
                        t01int4 (kb, 'lc_result < ', ord(_lc_result));
&                       ENDIF
                        IF  _lc_result = l_greater
                        THEN
                            BEGIN
                            _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 := selrec.selr_selectbuffer.lbuf[ _lpos ];
                    IF  (selrec.selr_l_defbyte_pos <> -1) AND
                        (ord (kbji_parts[ 2 ].kboj_op) <> 0)
                    THEN
                        _m_def_byte1 := selrec.selr_selectbuffer.lbuf
                              [ selrec.selr_l_currpos + selrec.selr_l_defbyte_pos ];
                    (*ENDIF*) 
                    IF  _first AND
                        (_op IN [ op_lt, op_le, op_gt, op_ge ]) AND
                        ((_m_def_byte1 = csp_ascii_blank)  OR
                        ( _m_def_byte1 = csp_ebcdic_blank)   )
                    THEN
                        BEGIN
                        s30cmp (selrec.selr_selectbuffer.lbuf, _lpos, kbji_parts[ 1 ].kboj_len,
                              selrec.selr_selectbuffer.rbuf, _rpos, kbji_parts[ 2 ].kboj_len,
                              _lc_result);
&                       IFDEF TRACE
                        t01int4 (kb, 'lc_result > ', ord(_lc_result));
&                       ENDIF
                        IF  _lc_result = l_less
                        THEN
                            BEGIN
                            _lc_result := l_undef;
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    END;
                l_undef :
                    BEGIN
                    fulfilled := false;
                    selrec.selr_r_null_val_fnd :=
                          linkrec.kbjr_right_oj AND
                          (_linkcnt in linkrec.kbjr_rof) AND
                          (selrec.selr_selectbuffer.lbuf[ _lpos ] = csp_undef_byte);
                    selrec.selr_l_null_val_fnd :=
                          linkrec.kbjr_left_oj     AND
                          (_linkcnt in linkrec.kbjr_lof) AND
                          (selrec.selr_selectbuffer.rbuf[ _rpos ] = csp_undef_byte);
                    END;
                END;
            (*ENDCASE*) 
            IF  _first
            THEN
                BEGIN
                IF  _lc_result = l_undef
                THEN
                    first_fulfilled := true
                ELSE
                    first_fulfilled := fulfilled;
                (*ENDIF*) 
                _first := false
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        _linkcnt := succ(_linkcnt)
        END;
    (*ENDWITH*) 
(*ENDWHILE*) 
&IFDEF TRACE
t01int4 (kb, 'r_outer_join', ord(linkrec.kbjr_right_oj));
t01int4 (kb, 'r_nullvalfnd', ord (selrec.selr_r_null_val_fnd));
t01int4 (kb, 'l_outer_join', ord(linkrec.kbjr_left_oj));
t01int4 (kb, 'l_nullvalfnd', ord (selrec.selr_l_null_val_fnd));
&ENDIF
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74do_better_join (
            VAR m           : tgg_mess_block;
            VAR getrec      : tkb7_get_param;
            VAR selrec      : tkb7_select_param;
            stenum          : tgg07_StratEnum;
            strat_maxresult : tsp_int2;
            last_join_tab   : boolean;
            j_use_rowno     : boolean);
 
CONST
      c_put_strat = true;
      c_strat_cnt = true;
 
VAR
      _finding_possible : boolean;
      _invindex         : integer;
      _start_sec        : tsp_int4;
      _start_microsec   : tsp_int4;
      _start_phys_ios   : tsp_int4;
      _start_suspends   : tsp_int4;
      _start_waits      : tsp_int4;
      _resf_id_site     : tgg_serverdb_no;
      _invroot          : tsp00_PageNo;
      _sel              : tgg_select_fields_param;
      _strat            : tgg07_StrategyInfo;
      _arr_index        : tgg_ref_info_index;
 
BEGIN
(* PTS 1001469 E.Z. *)
IF  b73spage_ref_statistic OR a01diag_monitor_on OR a01diag_analyze_on
THEN
    BEGIN
    vclock (_start_sec, _start_microsec);
    vmonitor (m.mb_trns^.trTaskId_gg00, _start_phys_ios, _start_suspends,
          _start_waits);
    END
(* PTS 1001518 E.Z. *)
ELSE
    _start_sec := 0;
(*ENDIF*) 
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);
_sel.sfp_bd_mess_type  := m_select;
_sel.sfp_result_wanted := true;
_sel.sfp_is_first_record := NOT getrec.gi_linkrec.kbjr_right_oj;
kb74join_init (m, selrec, _invindex, _invroot, _sel.sfp_bd_use_stopkey,
      _finding_possible);
selrec.selr_use_rowno := j_use_rowno;
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
    IF  m.mb_trns^.trError_gg00 = e_ok
    THEN
        IF  (selrec.selr_resf_id.fileTfnTemp_gg00 = ttfnInto_egg00) AND
            (selrec.selr_resf_id.fileTfn_gg00     = tfnTemp_egg00 )
        THEN
            BEGIN
            IF  stenum = strat_join_viewkey
            THEN
                selrec.selr_resf_id.fileSession_gg00 := m.mb_trns^.trSessionId_gg00;
            (*ENDIF*) 
            IF  selrec.selr_resf_id.fileRoot_gg00 = NIL_PAGE_NO_GG00
            THEN
                BEGIN
                b01tcreate_file (m.mb_trns^, selrec.selr_resf_id);
                IF  m.mb_trns^.trError_gg00 = e_duplicate_filename
                THEN
                    IF  stenum = strat_join_viewkey
                    THEN
                        m.mb_trns^.trError_gg00 := e_ok
&                             ifdef NOTUSED
                    ELSE
                        BEGIN
                        _resf_id_site := selrec.selr_resf_id.fileZeroSite_gg00;
                        IF  (_resf_id_site <> g01localsite)
                        THEN
                            b01empty_file (m.mb_trns^, selrec.selr_resf_id)
                        (*ENDIF*) 
                        END
                    (*ENDIF*) 
&               endif
                (*ENDIF*) 
                END
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            IF  ((selrec.selr_resf_id.fileRoot_gg00 = NIL_PAGE_NO_GG00) AND
                ((selrec.selr_countresult = 0) OR selrec.selr_append_all)      AND
                ( hsCreateFile_egg00 in selrec.selr_resf_id.fileHandling_gg00)   )
            THEN
                BEGIN
                b01tcreate_file (m.mb_trns^, selrec.selr_resf_id);
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
    (*ENDIF*) 
    IF  m.mb_trns^.trError_gg00 = e_ok
    THEN
        BEGIN
        IF  _finding_possible
        THEN
            BEGIN
            CASE stenum OF
                strat_join_viewkey :
                    kb74joinview_search (m,
                          getrec, selrec, _sel, last_join_tab);
                OTHERWISE
                    k741better_join (m,
                          stenum, _invindex, _invroot, getrec, selrec, _sel);
                END;
            (*ENDCASE*) 
            (* PTS 1001518 E.Z. *)
            IF  _start_sec > 0
            THEN
                BEGIN
                IF  (m.mb_trns^.trBdTcachePtr_gg00 <> NIL)
                THEN
                    IF  (stenum in [strat_join_all_inv_equal,
                        strat_join_inv_range, strat_join_inv])
                        AND (selrec.selr_inv_id.fileRoot_gg00
                        <> NIL_PAGE_NO_GG00)
                        AND (selrec.selr_inv_id.fileTfn_gg00
                        = tfnMulti_egg00)
                    THEN
                        b21mp_root_put (m.mb_trns^.trBdTcachePtr_gg00,
                              selrec.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*) 
                _strat.str_strategy := stenum;
                k720ref_statistic (m, _arr_index, _strat);
                k720monitor (m.mb_trns^, _sel, _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  (m.mb_qual^.mresqual_cnt > 0)         AND
            selrec.selr_join_with_func AND
            selrec.selr_one_result            AND
            (m.mb_trns^.trError_gg00 = e_ok)
        THEN
            BEGIN
            (* *** d_keylen (vak690)  *** *)
            selrec.selr_selectbuffer.result.keylen    :=
                  m.mb_st^[ m.mb_qual^.mstrat_pos + 1 ].ecol_pos;
            selrec.selr_selectbuffer.result.len := getrec.gi_minfo.n_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_countresult := selrec.selr_group_count;
            IF  (selrec.selr_countresult > 0)
            THEN
                k721call_later_output (m, selrec.selr_selectbuffer.lbuf, selrec.selr_selectbuffer.result.keylen)
            ELSE
                IF  (((selrec.selr_distinct <> no_distinct) AND
                    (selrec.selr_selectbuffer.result.keylen =
                    mxgg_rescnt + cgg_cdistinct_bytes))
                    OR
                    (selrec.selr_selectbuffer.result.keylen = mxgg_rescnt)
                    OR
                    ((selrec.selr_resf_id.fileTfn_gg00    = tfnTemp_egg00     ) AND
                    (selrec.selr_resf_id.fileTfnTemp_gg00 = ttfnSubquery_egg00)))
                    (* an empty grouped table results in error 100 *)
                THEN
                    BEGIN
                    selrec.selr_keyl := selrec.selr_selectbuffer.result.keylen;
                    selrec.selr_recl := selrec.selr_selectbuffer.result.len;
                    k721null_result (m, selrec, _sel, selrec.selr_countresult,
                          false, selrec.selr_selectbuffer.result.keylen);
                    IF  m.mb_trns^.trError_gg00 = e_enough_resultsets
                    THEN
                        m.mb_trns^.trError_gg00 := e_ok;
                    (*ENDIF*) 
                    END
                ELSE
                    selrec.selr_one_result := false;
                (*ENDIF*) 
            (*ENDIF*) 
            IF  (selrec.selr_one_result AND (m.mb_trns^.trError_gg00 = e_ok))
            THEN
                BEGIN
                g10mv10 ('VKB74 ',   8,    
                      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);
                b07cadd_record (m.mb_trns^, selrec.selr_resf_id,
                      selrec.selr_selectbuffer.result);
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        kb74join_last_part (m, getrec, selrec, strat_maxresult,
              j_use_rowno,
              (stenum <> strat_join_viewkey) OR last_join_tab,
              last_join_tab);
        END;
    (*ENDIF*) 
    m.mb_qual^.mr_pagecnt := 1
    END
ELSE
    BEGIN
    m.mb_qual_len  := 0;
    m.mb_data_len  := 0
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74get_join_infos (
            VAR m      : tgg_mess_block;
            VAR getrec : tkb7_get_param);
 
VAR
      _i     : integer;
      _j, _k : integer;
 
BEGIN
_i := m.mb_qual^.mstrat_pos + 1;
(* get getrec.gi_minfo *)
g10mv4 ('VKB74 ',   9,    
      m.mb_strat_size, sizeof(getrec.gi_minfo),
      m.mb_strat^, m.mb_st^[ _i ].epos - mxgg_inflen,
      getrec.gi_minfo, 1, mxgg_inflen,
      m.mb_trns^.trError_gg00);
&ifdef trace
t01sname(kb, 'gi_minfo   :');
t01treeid (kb, 'o_tree      ', getrec.gi_minfo.o_tree );
t01p2int4 (kb, 'o_recl      ', getrec.gi_minfo.o_recl,
      'o_keyl      ', getrec.gi_minfo.o_keyl);
t01p2int4 (kb, 'n_rec_len   ', getrec.gi_minfo.n_rec_len,
      'n_key_len   ', getrec.gi_minfo.n_key_len);
&endif
(* get getrec.gi_njrec *)
g10mv5 ('VKB74 ',  10,    
      m.mb_strat_size, sizeof (getrec.gi_njrec),
      m.mb_strat^, m.mb_st^[ _i ].epos,
      getrec.gi_njrec, 1, m.mb_st^[ _i ].elen_var,
      m.mb_trns^.trError_gg00);
&ifdef trace
t01sname(kb, 'gi_njrec   :');
t01sname(kb, '------------');
t01int4 (kb, 'n_j_cnt     ', getrec.gi_njrec.n_j_cnt);
FOR _j := 1 TO getrec.gi_njrec.n_j_cnt DO
    BEGIN
    t01p2int4 (kb, 'jfrom       ', getrec.gi_njrec.n_j_arr[ _j ].jfrom,
          'jto         ', getrec.gi_njrec.n_j_arr[ _j ].jto);
    t01int4 (kb, 'jlen        '  , getrec.gi_njrec.n_j_arr[ _j ].jlen);
    END;
(*ENDFOR*) 
t01sname(kb, '------------');
&endif
(* get getrec.gi_linkrec *)
g10mv6 ('VKB74 ',  11,    
      m.mb_strat_size, sizeof (getrec.gi_linkrec),
      m.mb_strat^, m.mb_st^[ _i + 1 ].epos,
      getrec.gi_linkrec, 1, m.mb_st^[ _i + 1 ].elen_var,
      m.mb_trns^.trError_gg00);
&ifdef trace
t01sname(kb, 'gi_linkrec :');
t01sname(kb, '------------');
t01p2int4 (kb, 'kbjr_cnt    ', getrec.gi_linkrec.kbjr_cnt,
      'kbjr_linkcnt', getrec.gi_linkrec.kbjr_linkcnt);
t01p2bool (kb, 'kbjr_left_oj', getrec.gi_linkrec.kbjr_left_oj,
      'kbjr_right_o', getrec.gi_linkrec.kbjr_right_oj);
FOR _j := 1 TO getrec.gi_linkrec.kbjr_cnt DO
    BEGIN
    FOR _k := 1 TO 2 DO
        BEGIN
        t01int4 (kb, '~~ site ~~  '  , _k);
        t01p2int4 (kb, 'kboj_recpos ', getrec.gi_linkrec.
              kbjr_jarr[ _j ].kbji_parts[ _k ].kboj_recpos,
              'kboj_len    ', getrec.gi_linkrec.
              kbjr_jarr[ _j ].kbji_parts[ _k ].kboj_len);
        t01int4 (kb, 'kboj_op     '  ,
              ord(getrec.gi_linkrec.kbjr_jarr[ _j ].kbji_parts[ _k ].kboj_op));
        t01sname(kb, '~~~~~~~~~~~~');
        END;
    (*ENDFOR*) 
    END;
(*ENDFOR*) 
&endif
m.mb_strat_len  := m.mb_st^[ _i ].epos - mxgg_inflen - 1;
(* record counter for outerjoin via vkb71 (or outerjoin) *)
getrec.gi_lr_rec_id.l_rec_id := 0;
getrec.gi_lr_rec_id.r_rec_id := 0;
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74get_new_positions (
            VAR m        : tgg_mess_block;
            VAR getrec   : tkb7_get_param;
            is_last_join : boolean);
 
VAR
      _i              : integer;
      _stops          : integer;
      _poscnt         : integer;
      _is_right_table : boolean;
      _pack_it        : boolean;
      _const_expr_fnd : boolean;
      _column_fnd     : boolean;
      _curr_join_step : integer;
 
BEGIN
getrec.gi_mto_outer_tab  := no_outer_join;
_pack_it        := NOT getrec.gi_linkrec.kbjr_right_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;
_curr_join_step := ord (m.mb_st^[ m.mb_qual^.mqual_pos ].ecol_tab[ 2 ]);
_is_right_table := true;
_poscnt         := 0;
getrec.gi_n_pos_s.lposcnt := 0;
getrec.gi_n_pos_s.rposcnt := 0;
&IFDEF TRACE
t01sname(kb, 'k74-mblock 1');
t01qual (kb, m.mb_qual^);
t01sname(kb, '------------');
&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
            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_right_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*) 
        IF  (_i < _stops)
        THEN
            BEGIN
            IF  (_poscnt = 0)
            THEN
                (* initializing run after first st_join_output found *)
                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;
                    onouter :=
                          ((m.mb_st^[ _i ].eop = op_outer_join) AND _column_fnd) OR
                          ((m.mb_st^[ _i ].eop_out = op_o_output_outer_join) AND
                          (NOT _column_fnd));
                    (* h.b. PTS 1104165 *)
                    IF  _const_expr_fnd
                    THEN
                        onfrom := onfrom * -1;
                    (*ENDIF*) 
                    IF  NOT is_last_join  AND onouter
                    THEN
                        IF  _is_right_table
                        THEN
                            getrec.gi_mto_outer_tab := right_outer_join
                        ELSE
                            getrec.gi_mto_outer_tab := left_outer_join
                                  ;
                        (*ENDIF*) 
                    (*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;
                            onouter := m.mb_st^[ _i ].eop = op_outer_join;
                            IF  _const_expr_fnd (* h.b. PTS 1104484 *)
                            THEN
                                onfrom := onfrom * -1;
                            (*ENDIF*) 
                            IF  NOT is_last_join AND  onouter
                            THEN
                                IF  _is_right_table
                                THEN
                                    getrec.gi_mto_outer_tab := right_outer_join
                                ELSE
                                    getrec.gi_mto_outer_tab := left_outer_join;
                                (*ENDIF*) 
                            (*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 *)
                    g10mv12 ('VKB74 ',  12,    
                          m.mb_qual^.mst_max * mxgg_stack_entry,
                          m.mb_qual^.mst_max * mxgg_stack_entry,
                          m.mb_st^, (_i - 1) * mxgg_stack_entry + 1,
                          m.mb_st^, (_i - 2) * mxgg_stack_entry + 1,
                          (m.mb_qual^.mfirst_free - _i) * mxgg_stack_entry,
                          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;
            getrec.gi_n_pos_s.rposcnt := _poscnt;
            (* step over special output columns : columns needed for next join step *)
            _stops          := m.mb_qual^.mfirst_free;
            _i              := m.mb_qual^.mstrat_pos + 3;
            END
        ELSE
            getrec.gi_n_pos_s.lposcnt := _poscnt - getrec.gi_n_pos_s.rposcnt;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
UNTIL
    (_i >= _stops);
(*ENDREPEAT*) 
IF  getrec.gi_linkrec.kbjr_right_oj OR getrec.gi_linkrec.kbjr_left_oj
THEN
    getrec.gi_mto_outer_tab  := no_outer_join;
(*ENDIF*) 
;
&IFDEF TRACE
t01sname(kb, 'k74-mblock 2');
t01qual (kb, m.mb_qual^);
t01int4 (kb, 'rposcnt     ', getrec.gi_n_pos_s.rposcnt);
FOR _i := 1 TO getrec.gi_n_pos_s.rposcnt DO
    BEGIN
    t01p2int4 (kb, 'onfrom      ', getrec.gi_n_pos_s.posarr[ _i ].onfrom,
          'onto        ', getrec.gi_n_pos_s.posarr[ _i ].onto);
    t01int4 (kb, 'onlen       ', getrec.gi_n_pos_s.posarr[ _i ].onlen);
    t01bool (kb, 'onouter     ', getrec.gi_n_pos_s.posarr[ _i ].onouter);
    END;
(*ENDFOR*) 
t01int4 (kb, '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 (kb, 'onfrom      ', getrec.gi_n_pos_s.posarr[ _i ].onfrom,
          'onto        ', getrec.gi_n_pos_s.posarr[ _i ].onto);
    t01int4 (kb, 'onlen       ', getrec.gi_n_pos_s.posarr[ _i ].onlen);
    t01bool (kb, 'onouter     ', getrec.gi_n_pos_s.posarr[ _i ].onouter);
    END;
(*ENDFOR*) 
&ENDIF
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74get_right_record (
            VAR m         : tgg_mess_block;
            VAR getrec    : tkb7_get_param;
            VAR selrec    : tkb7_select_param;
            sel_type      : tgg_message2_type;
            VAR rstartkey : tgg_lkey;
            VAR sel       : tgg_select_fields_param);
 
BEGIN
&IFDEF TRACE
t01lkey (kb, rstartkey);
t01int4 (kb, 'rkeylen     ', rstartkey.len);
&ENDIF
sel.sfp_act_cntresult := selrec.selr_countresult + 1;
kb74all_get (m, selrec, sel_type, rstartkey, sel);
getrec.gi_lr_rec_id.r_rec_id := succ (getrec.gi_lr_rec_id.r_rec_id);
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74join_init (
            VAR m                : tgg_mess_block;
            VAR selrec           : tkb7_select_param;
            VAR invindex         : integer;
            VAR invroot          : tsp00_PageNo;
            VAR use_stopkey      : boolean;
            VAR finding_possible : boolean);
 
VAR
      _strat : tgg07_StrategyInfo;
 
BEGIN
k720_initialize( m, selrec, _strat, use_stopkey, finding_possible );
IF  (m.mb_trns^.trError_gg00 = e_ok) (* h.b. PTS 1104929 *)
THEN
    BEGIN
    selrec.selr_union_select :=
          selrec.selr_union_select OR selrec.selr_append_all;
    IF  (_strat.str_strategy = strat_join_inv)             OR
        (_strat.str_strategy = strat_join_all_inv_equal)   OR
        (_strat.str_strategy = strat_join_inv_range)
    THEN
        BEGIN
        invroot  := _strat.str_join_inv.sji_invroot;
        invindex := _strat.str_join_inv.sji_invindex;
        END;
    (*ENDIF*) 
    IF  (_strat.str_use_subquery = normal_subquery)
    THEN
        k720_test_subquery (m, selrec.selr_selectbuffer.buf_rec);
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74l_join_with_left_records (
            VAR m                  : tgg_mess_block;
            VAR getrec             : tkb7_get_param;
            VAR selrec             : tkb7_select_param;
            VAR sel                : tgg_select_fields_param;
            VAR searchrec          : search_rec;
            build_right_outer_join : boolean);
 
VAR
      _first_fulfilled   : boolean;
      _no_next_rec       : boolean;
      _unequal_join      : boolean;
      _build_result      : boolean;
      _mtt_tables        : boolean; (* *** more than two tables *** *)
      _lsearchkey        : tgg_lkey;
      _dummy_bool        : boolean;
      _ix                : integer;
      _result_len        : integer;
      _resbuf            : tsp_buf;
      _aux_mresqual_pos  : tsp_int2;
      _aux_mresqual_cnt  : tsp_int2;
      _aux_mqual_pos     : tsp_int2;
      _aux_mqual_cnt     : tsp_int2;
 
BEGIN
&IFDEF TRACE
IF  (searchrec.sr_error_l = e_buffer_limit)
THEN
    t01int4 (kb, 'buffer_limit', 3333);
&ENDIF
(*ENDIF*) 
_no_next_rec  := false;
_unequal_join := getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 1 ].kboj_op = op_ne;
_mtt_tables   := (searchrec.sr_j_curr_join_step > 2);
&IFDEF TRACE
t01int4 (kb, 'mtt_tables  ', ord (_mtt_tables));
t01int4 (kb, 'j_curr_joins', searchrec.sr_j_curr_join_step);
&ENDIF
WHILE (NOT _no_next_rec)          AND
      (m.mb_trns^.trError_gg00 = e_ok) AND
      (searchrec.sr_error_l <> e_no_next_record) DO
    BEGIN
    REPEAT
        selrec.selr_fulfilled  := true;
        _first_fulfilled := true;
&       IFDEF TRACE
        t01int4 (kb, 'kbjr_linkcnt', ord (getrec.gi_linkrec.kbjr_linkcnt));
&       ENDIF
        selrec.selr_l_null_val_fnd := false;
        selrec.selr_r_null_val_fnd := false;
        IF  getrec.gi_linkrec.kbjr_linkcnt <= getrec.gi_linkrec.kbjr_cnt
        THEN
            kb74compare_two_records (selrec, getrec.gi_linkrec, sel,
                  selrec.selr_fulfilled, _first_fulfilled);
        (*ENDIF*) 
        getrec.gi_linkrec.kbjr_linkcnt := 1;
&       IFDEF TRACE
        t01int4 (kb, 'fullfilled  ', ord (selrec.selr_fulfilled));
        t01int4 (kb, 'f_fullfilled', ord (_first_fulfilled));
        t01int4 (kb, 'kbjr_cnt    ', ord (getrec.gi_linkrec.kbjr_cnt));
        t01int4 (kb, 'kbjr_linkcnt', ord (getrec.gi_linkrec.kbjr_linkcnt));
        t01int4 (kb, 'r_outer_join', ord(getrec.gi_linkrec.kbjr_right_oj));
        t01int4 (kb, 'r_nullvalfnd', ord (selrec.selr_r_null_val_fnd));
        t01int4 (kb, 'l_outer_join', ord(getrec.gi_linkrec.kbjr_left_oj));
        t01int4 (kb, 'l_nullvalfnd', ord (selrec.selr_l_null_val_fnd));
&       ENDIF
        IF  selrec.selr_fulfilled
        THEN
            BEGIN
            selrec.selr_selectbuffer.result.len := 0;
            kb74build_new_rec (m, getrec, selrec, searchrec,
                  no_outer_join);
            (* *** one_join_phase begin *** *)
            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;
                IF  (m.mb_st^ [ m.mb_qual^.mqual_pos ].etype = st_jump_output)
                THEN
                    BEGIN
                    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);
                    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);
                    k71col_select (m.mb_trns^, sel,
                          m.mb_qual^.mstack_desc,
                          selrec.selr_selectbuffer.result.buf, _dummy_bool);
                    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
                            g10mv10 ('VKB74 ',  13,    
                                  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
                    k71qualification_test (m, c_first_qual,
                          NOT c_result_wanted, NOT c_check_new_rec,
                          selrec.selr_selectbuffer.result, NIL, 0, _result_len);
                (*ENDIF*) 
                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;
&               ifdef trace
                t01basis_error (kb, 'trError     ', m.mb_trns^.trError_gg00);
&               endif
                END;
            (*ENDIF*) 
            IF  (m.mb_trns^.trError_gg00 = e_ok)
            THEN
                (* *** one_join_phase end *** *)
                k721add_into_result (m.mb_trns^, selrec, m.mb_next_mblock)
                      (* *** one_join_phase begin *** *)
            ELSE
                m.mb_trns^.trError_gg00 := e_ok;
            (*ENDIF*) 
            (* *** one_join_phase end *** *)
            END
        ELSE
            IF  build_right_outer_join AND _first_fulfilled
            THEN
                BEGIN
                selrec.selr_selectbuffer.result.len := 0;
                kb74build_new_rec (m, getrec, selrec, searchrec,
                      right_outer_join);
                k721add_into_result (m.mb_trns^, selrec,
                      m.mb_next_mblock);
                END
            ELSE
                BEGIN
                IF  selrec.selr_l_null_val_fnd AND _first_fulfilled
                THEN
                    BEGIN
                    IF  _mtt_tables
                    THEN
                        _build_result := kb74new_outer_key(m.mb_trns^,
                              getrec, selrec)
                    ELSE
                        _build_result := (selrec.selr_l_defbyte_pos <> -1);
                    (*ENDIF*) 
                    selrec.selr_selectbuffer.result.len := 0;
                    IF  _build_result
                    THEN
                        BEGIN
                        kb74build_new_rec (m, getrec, selrec,
                              searchrec, left_outer_join);
                        k721add_into_result (m.mb_trns^, selrec,
                              m.mb_next_mblock);
                        END;
                    (*ENDIF*) 
                    END
                ELSE
                    IF  selrec.selr_r_null_val_fnd
                    THEN
                        BEGIN
                        IF  _mtt_tables
                        THEN
                            _build_result := kb74new_outer_key (m.mb_trns^,
                                  getrec, selrec)
                        ELSE
                            _build_result :=  (selrec.selr_l_defbyte_pos <> -1);
                        (*ENDIF*) 
                        selrec.selr_selectbuffer.result.len := 0;
                        IF  _build_result
                        THEN
                            BEGIN
                            kb74build_new_rec (m, getrec,
                                  selrec, searchrec,
                                  right_outer_join);
                            k721add_into_result (m.mb_trns^,
                                  selrec, m.mb_next_mblock);
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                (*ENDIF*) 
                END;
            (*ENDIF*) 
        (*ENDIF*) 
        IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
        THEN
            m.mb_trns^.trError_gg00 := e_cancelled;
        (*ENDIF*) 
        selrec.selr_l_currpos := selrec.selr_l_currpos + getrec.gi_minfo.o_recl;
        IF  _first_fulfilled OR _unequal_join
        THEN
            IF  selrec.selr_l_currpos > selrec.selr_lmaxpos
            THEN
                selrec.selr_lmaxpos := selrec.selr_l_currpos;
            (*ENDIF*) 
        (*ENDIF*) 
    UNTIL
        ((m.mb_trns^.trError_gg00 <> e_ok) OR
        (selrec.selr_l_currpos >= selrec.selr_l_endpos) OR
        ((NOT _first_fulfilled) AND (NOT _unequal_join)));
    (*ENDREPEAT*) 
&   IFDEF TRACE
    t01int4 (kb, 'lmaxpos whil',selrec.selr_lmaxpos);
    t01basis_error (kb, 'error_l     ',searchrec.sr_error_l);
    t01int4 (kb, 'l_currpos   ',selrec.selr_l_currpos);
    t01int4 (kb, 'l_endpos    ',selrec.selr_l_endpos);
&   ENDIF
    IF  (searchrec.sr_error_l = e_buffer_limit) AND
        (m.mb_trns^.trError_gg00 = e_ok) AND
        (_first_fulfilled OR _unequal_join) (* h.b. PTS 1001567 *)
    THEN
        BEGIN
&       IFDEF TRACE
        t01int4 (kb, 'o_keyl      ', getrec.gi_minfo.o_keyl);
        t01int4 (kb, 'tpsPno      ', searchrec.sr_left_tree_pos.tpsPno_gg00);
        t01int4 (kb, 'tpsIndex    ', searchrec.sr_left_tree_pos.tpsIndex_gg00);
&       ENDIF
        WITH searchrec.sr_set_result DO
            BEGIN
            bd_key_check_len := 0;
            bd_max_rec_cnt   := csp_maxint2;
            bd_max_fill_len  := mxsp_buf;
            bd_next          := false;
            bd_drop_page     := false;
            END;
        (*ENDWITH*) 
        searchrec.sr_left_before_cnext_tree_pos := searchrec.sr_left_tree_pos;
        b07cnext_record (m.mb_trns^, getrec.gi_minfo.o_tree, _lsearchkey,
              searchrec.sr_set_result, searchrec.sr_left_tree_pos, selrec.selr_selectbuffer.lbuf);
        IF  m.mb_trns^.trError_gg00 = e_key_not_found
        THEN
            m.mb_trns^.trError_gg00 := e_ok;
        (*ENDIF*) 
        searchrec.sr_error_l           := m.mb_trns^.trError_gg00;
        IF  (searchrec.sr_error_l = e_ok)           OR
            (searchrec.sr_error_l = e_buffer_limit) OR
            (searchrec.sr_error_l = e_no_next_record)
        THEN
            m.mb_trns^.trError_gg00 := e_ok;
        (*ENDIF*) 
        IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
        THEN
            searchrec.sr_error_l := e_cancelled;
&       IFDEF TRACE
        (*ENDIF*) 
        t01int4 (kb, 'tpsPno      ',searchrec.sr_left_tree_pos.tpsPno_gg00);
        t01int4 (kb, 'tpsIndex    ',searchrec.sr_left_tree_pos.tpsIndex_gg00);
&       ENDIF
        selrec.selr_l_endpos  := searchrec.sr_set_result.bd_fill_len;
        selrec.selr_l_currpos := 0;
        selrec.selr_lmaxpos   := 0;
        END
    ELSE
        BEGIN
        _no_next_rec    := true;
        selrec.selr_l_currpos := selrec.selr_l_currpos - getrec.gi_minfo.o_recl;
        END;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
&IFDEF TRACE
t01int4  (kb, 'endejoin_l_w', 9999);
&ENDIF
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74join_sel_init (
            VAR m               : tgg_mess_block;
            VAR getrec          : tkb7_get_param;
            VAR selrec          : tkb7_select_param;
            VAR j_use_rowno     : boolean;
            VAR strat_maxresult : tsp_int2;
            VAR stenum          : tgg07_StratEnum);
 
VAR
      _is_last_join : boolean;
 
BEGIN
_is_last_join := m.mb_type2 = mm_join_with_last_tab;
m.mb_type2   := mm_with_join;
m.mb_trns^.trRteCommPtr_gg00^.file_root       := NIL_PAGE_NO_GG00;
m.mb_trns^.trRteCommPtr_gg00^.file_record_cnt := 1;
(* restore getrec.gi_minfo, getrec.gi_njrec, getrec.linkrec *)
kb74get_join_infos (m, getrec);
IF  m.mb_trns^.trError_gg00 = e_ok
THEN
    BEGIN
    selrec.selr_cnt_outer_join := 0;
    IF  m.mb_st^[ m.mb_qual^.mqual_pos ].eop = op_outer_join
    THEN (* special outerjoin via vkb71 ex: "or" *)
        BEGIN
        getrec.gi_linkrec.kbjr_left_oj := false;
        getrec.gi_linkrec.kbjr_right_oj := false;
        CASE ord (m.mb_st^[ m.mb_qual^.mqual_pos ].ecol_tab[ 1 ]) OF
            1 :
                getrec.gi_linkrec.kbjr_left_oj := true;
            2 :
                getrec.gi_linkrec.kbjr_right_oj := true;
            3 :
                BEGIN
                getrec.gi_linkrec.kbjr_left_oj := true;
                getrec.gi_linkrec.kbjr_right_oj := true;
                END;
            OTHERWISE
            END;
        (*ENDCASE*) 
        END;
&   IFDEF TRACE
    (*ENDIF*) 
    t01bool (kb, 'r_outer_join', getrec.gi_linkrec.kbjr_right_oj);
    t01bool (kb, 'l_outer_join', getrec.gi_linkrec.kbjr_left_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 *)
    kb74get_new_positions( m, getrec, _is_last_join );
    kb74short_init( m, stenum, strat_maxresult, j_use_rowno );
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74join_last_part (
            VAR m             : tgg_mess_block;
            VAR getrec        : tkb7_get_param;
            VAR selrec        : tkb7_select_param;
            strat_maxresult   : tsp_int2;
            j_use_rowno       : boolean;
            destroy_into_file : boolean;
            last_join_tab     : boolean);
 
VAR
      _aux_error     : tgg_basis_error;
      _set_result    : tgg_bd_set_result_record;
      _destroy_res   : boolean;
      _res           : tsp_num_error;
      _left_tree_pos : tgg00_FilePos;
 
BEGIN
_destroy_res := false;
IF  m.mb_trns^.trError_gg00 = e_enough_resultsets
THEN
    BEGIN
    m.mb_trns^.trError_gg00 := e_ok;
    IF  (abs(strat_maxresult) >= cgg_valid_rowno_pos)
        (*rowno*)
    THEN
        m.mb_trns^.trWarning_gg00 := m.mb_trns^.trWarning_gg00 +
              [ warn0_exist, warn12_rowno_used ];
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  (j_use_rowno AND
    (m.mb_trns^.trError_gg00 = e_ok) AND (selrec.selr_countresult > 0))
THEN
    k74rowno_position (m, getrec, selrec);
&IFDEF TRACE
(*ENDIF*) 
WITH selrec, selr_selectbuffer, getrec.gi_minfo, m DO
    BEGIN
    t01int4        (kb, 'maxresult   ',selrec.selr_maxresult);
    t01int4        (kb, 'countresult ',selr_countresult);
    t01int4        (kb, 'n_rec_len   ',n_rec_len);
    t01basis_error (kb, 'm trError  1', m.mb_trns^.trError_gg00);
    t01treeid      (kb, 'resf_id     ', selr_resf_id);
    END;
(*ENDWITH*) 
&ENDIF
IF  (m.mb_trns^.trError_gg00 = e_ok) AND
    (* *** one_join_phase (sequential join) *** *)
    (m.mb_type <> m_return_result)
THEN
    IF  ((selrec.selr_maxresult > 0) OR
        (selrec.selr_subquery))
        (*  subquery with ! file *)
    THEN
        BEGIN
        m.mb_struct   := mbs_result;
        m.mb_type     := m_return_result;
        m.mb_type2    := mm_file;
        _destroy_res := (selrec.selr_countresult = 0) AND (NOT selrec.selr_append_all);
        s41p4int (m.mb_qual^.mr_resnum, 2, selrec.selr_countresult, _res);
        m.mb_qual^.mr_resnum[ 1 ]          := csp_defined_byte;
        m.mb_qual^.mr_res_build            := true;
        selrec.selr_resf_id.fileResultSite_gg00 := g01localsite;
        m.mb_qual^.mr_restree              := selrec.selr_resf_id;
        m.mb_qual_len                      := mxgg_mb_part1head + mxgg_mb_part1_return;
        IF  selrec.selr_union_select
        THEN
            BEGIN
            IF  selrec.selr_append_all
            THEN
                selrec.selr_key_cnt_offs := selrec.selr_countresult
            ELSE
                selrec.selr_key_cnt_offs := selrec.selr_key_cnt_offs + selrec.selr_countresult;
            (*ENDIF*) 
&           ifdef TRACE
            t01int4 (kb, 'countresult4', selrec.selr_countresult);
            t01int4 (kb, 'key_cnt_offs', selrec.selr_key_cnt_offs);
&           endif
            s41p4int (m.mb_qual^.mr_keycnt, 2, selrec.selr_key_cnt_offs, _res);
            m.mb_qual^.mr_keycnt[ 1 ] := csp_defined_byte;
            IF  selrec.selr_isintersect
            THEN
                BEGIN
                IF  (m.mb_trns^.trError_gg00 = e_ok)
                THEN
                    b01move_filecontent (m.mb_trns^,
                          selrec.selr_intersect_id, selrec.selr_resf_id);
                (*ENDIF*) 
                _aux_error := m.mb_trns^.trError_gg00;
                b01destroy_file (m.mb_trns^, selrec.selr_intersect_id);
                IF  _aux_error <> e_ok
                THEN
                    m.mb_trns^.trError_gg00 := _aux_error;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  last_join_tab
        THEN
            m.mb_data_len  := 0
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        IF  (selrec.selr_countresult > 0)
        THEN
            BEGIN
            selrec.selr_invkey.len := 0;
            WITH _set_result DO
                BEGIN
                bd_key_check_len := 0;
                bd_max_rec_cnt   := 1;
                bd_max_fill_len  := mxsp_buf;
                bd_next          := true;
                bd_drop_page     := false;
                END;
            (*ENDWITH*) 
            _left_tree_pos.tpsPno_gg00 := NIL_PAGE_NO_GG00;
            b07cnext_record (m.mb_trns^, selrec.selr_resf_id, selrec.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*) 
            m.mb_qual_len  := 0;
            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;
                m.mb_struct := mbs_result;
                m.mb_type   := m_return_result;
                m.mb_type2  := mm_nil;
                m.mb_data_len   := getrec.gi_minfo.n_rec_len;
                selrec.selr_invkey.len := m.mb_data^.mbp_keylen;
                g10mv1 ('VKB74 ',  14,    
                      m.mb_data_size, sizeof(selrec.selr_invkey.k),
                      m.mb_data^.mbp_4kbuf, cgg_rec_key_offset + 1,
                      selrec.selr_invkey.k, 1, selrec.selr_invkey.len,
                      m.mb_trns^.trError_gg00);
                IF  (m.mb_trns^.trError_gg00 = e_ok)
                THEN
                    BEGIN
                    b07cdel_record (m.mb_trns^, selrec.selr_resf_id,
                          selrec.selr_invkey);
                    m.mb_trns^.trError_gg00 := e_ok;
                    END
                (*ENDIF*) 
                END
            ELSE
                BEGIN
                m.mb_data_len  := 0
                END;
            (*ENDIF*) 
            END
        ELSE
            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*) 
(*ENDIF*) 
m.mb_qual^.mr_pagecnt := m.mb_trns^.trRteCommPtr_gg00^.file_record_cnt;
m.mb_qual_len         := mxgg_mb_part1head + mxgg_mb_part1_return;
&IFDEF TRACE
t01int4 (kb, 'part2_len   ',m.mb_data_len );
&ENDIF
IF  (getrec.gi_minfo.o_tree.fileTfnTemp_gg00 = ttfnInto_egg00) AND
    (getrec.gi_minfo.o_tree.fileTfn_gg00     = tfnTemp_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_minfo.o_tree);
        m.mb_trns^.trError_gg00 := _aux_error
        END
    (*ENDIF*) 
    END
ELSE
    BEGIN
    _aux_error := m.mb_trns^.trError_gg00;
    b01destroy_file (m.mb_trns^, getrec.gi_minfo.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  (selrec.selr_resf_id.fileTfn_gg00 = tfnTemp_egg00)
    THEN
        IF  (selrec.selr_resf_id.fileTfnTemp_gg00 <> ttfnInto_egg00) OR
            (m.mb_trns^.trError_gg00 = e_cancelled)
        THEN
            BEGIN
            (* PTS 1113493 E.Z. *)
            IF  (hsDropFile_egg00 in selrec.selr_resf_id.fileHandling_gg00) OR
                (m.mb_trns^.trError_gg00 <> e_ok)
            THEN
                b01destroy_file (m.mb_trns^, selrec.selr_resf_id);
            (*ENDIF*) 
            END
        ELSE
            b01empty_file (m.mb_trns^, selrec.selr_resf_id);
        (*ENDIF*) 
    (*ENDIF*) 
    m.mb_trns^.trError_gg00 := _aux_error;
    END
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74joinview_search (
            VAR m         : tgg_mess_block;
            VAR getrec    : tkb7_get_param;
            VAR selrec    : tkb7_select_param;
            VAR sel       : tgg_select_fields_param;
            last_join_tab : boolean);
 
VAR
      _aux_error   : tgg_basis_error;
      _jview_strat : tgg07_StrJoinViewkey;
      _searchrec   : search_rec;
 
BEGIN
g10mv11 ('VKB74 ',  15,    
      m.mb_strat_size, sizeof (_jview_strat),
      m.mb_strat^,
      m.mb_st^[ m.mb_qual^.mstrat_pos ].epos + STRATEGY_START_MXGG07,
      _jview_strat, 1, sizeof (_jview_strat),
      m.mb_trns^.trError_gg00);
_searchrec.sr_j_curr_join_step := ord (m.mb_st^[ m.mb_qual^.mstrat_pos ].ecol_tab[ 2 ]);
CASE ord(getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 2 ].kboj_op) OF
    0, 1 :
        selrec.selr_first_jlen :=
              getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 1 ].kboj_len;
    2 :
        selrec.selr_first_jlen :=
              getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 2 ].kboj_len;
    END;
(*ENDCASE*) 
getrec.gi_linkrec.kbjr_linkcnt := 2;
_searchrec.sr_lsearchkey.len      := 0;
selrec.selr_r_currpos      := 0;
selrec.selr_l_currpos      := 0;
selrec.selr_l_endpos       := selrec.selr_l_currpos + getrec.gi_minfo.o_recl;
selrec.selr_l_defbyte_pos  := cgg_rec_key_offset + 1;
_searchrec.sr_oj_lcountresult     := -1;
_searchrec.sr_oj_rcountresult     := -1;
_searchrec.sr_seq_r_outer_join    := false;
_searchrec.sr_error_l             := e_ok;
WITH _searchrec.sr_set_result DO
    BEGIN
    bd_key_check_len := 0;
    bd_max_rec_cnt   := 1;
    bd_max_fill_len  := mxsp_buf;
    bd_next          := true;
    bd_drop_page     := false;
    END;
(*ENDWITH*) 
_searchrec.sr_left_tree_pos.tpsPno_gg00 := NIL_PAGE_NO_GG00;
_searchrec.sr_left_before_cnext_tree_pos.tpsPno_gg00 := NIL_PAGE_NO_GG00;
IF  (m.mb_trns^.trError_gg00 = e_ok)
THEN
    b07cnext_record (m.mb_trns^, getrec.gi_minfo.o_tree, _searchrec.sr_lsearchkey,
          _searchrec.sr_set_result, _searchrec.sr_left_tree_pos, selrec.selr_selectbuffer.lbuf);
(*ENDIF*) 
IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
THEN
    m.mb_trns^.trError_gg00 := e_cancelled;
(*ENDIF*) 
_aux_error := m.mb_trns^.trError_gg00;
b01empty_file (m.mb_trns^, getrec.gi_minfo.o_tree);
IF  (_aux_error <> e_ok) AND
    (_aux_error <> e_key_not_found)
THEN
    m.mb_trns^.trError_gg00 := _aux_error;
(*ENDIF*) 
IF  m.mb_trns^.trError_gg00 = e_ok
THEN
    BEGIN
    _searchrec.sr_rsearchkey.len := s30lnr_defbyte (@selrec.selr_selectbuffer.lbuf,
          selrec.selr_selectbuffer.lbuf[ _jview_strat.sjv_minkeylen + cgg_rec_key_offset ],
          _jview_strat.sjv_minkeylen + cgg_rec_key_offset + 1,
          _jview_strat.sjv_lastkeylen) + _jview_strat.sjv_minkeylen;
    g10mv1 ('VKB74 ',  16,    
          sizeof(selrec.selr_selectbuffer.lbuf), sizeof(_searchrec.sr_rsearchkey.k),
          selrec.selr_selectbuffer.lbuf, cgg_rec_key_offset + 1,
          _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, getrec, selrec, mm_direct, _searchrec.sr_rsearchkey, sel);
&   IFDEF TRACE
    (*ENDIF*) 
    t01basis_error (kb, 'm trError  4', m.mb_trns^.trError_gg00);
&   ENDIF
    IF  m.mb_trns^.trError_gg00 = e_ok
    THEN
        kb74l_join_with_left_records (m, getrec, selrec, sel,
              _searchrec, NOT c_build_right_outer_join);
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  last_join_tab
THEN
    selrec.selr_maxresult := 0;
(*ENDIF*) 
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;
 
(*------------------------------*) 
 
PROCEDURE
      kb74last_r_outer_join_part (
            VAR m      : tgg_mess_block;
            VAR getrec : tkb7_get_param;
            VAR selrec : tkb7_select_param);
 
VAR
      _aux_error   : tgg_basis_error;
      _searchrec   : search_rec;
      _lc_result   : tsp_lcomp_result;
 
BEGIN
WITH _searchrec.sr_set_result DO
    BEGIN
    bd_key_check_len := 0;
    bd_max_rec_cnt   := csp_maxint2;
    bd_max_fill_len  := mxsp_buf;
    bd_next          := false;
    bd_drop_page     := true;
    END;
(*ENDWITH*) 
selrec.selr_r_currpos := 0;
selrec.selr_r_endpos  := 0;
_lc_result      := l_less;
_searchrec.sr_j_curr_join_step  :=
      ord (m.mb_st^[ m.mb_qual^.mstrat_pos ].ecol_tab[ 2 ]);
IF  (selrec.selr_cnt_outer_join > 0)
THEN
    BEGIN
    selrec.selr_id_outer_join.fileTfnTemp_gg00 := ttfnOuterJoinKeys_egg00;
    selrec.selr_oj_tree_pos.tpsPno_gg00 := NIL_PAGE_NO_GG00;
    _searchrec.sr_rsearchkey.len         := 0;
    b07cnext_record (m.mb_trns^, selrec.selr_id_outer_join,
          _searchrec.sr_rsearchkey, _searchrec.sr_set_result,
          selrec.selr_oj_tree_pos, selrec.selr_selectbuffer.rbuf);
    IF  m.mb_trns^.trError_gg00 = e_key_not_found
    THEN
        m.mb_trns^.trError_gg00 := e_ok;
    (*ENDIF*) 
    _searchrec.sr_error_r           := m.mb_trns^.trError_gg00;
    m.mb_trns^.trError_gg00 := e_ok;
    selrec.selr_r_currpos    := 0;
    selrec.selr_r_endpos     := _searchrec.sr_set_result.bd_fill_len;
&   IFDEF TRACE
    t01buf (kb, selrec.selr_selectbuffer.rbuf, 1, selrec.selr_r_endpos);
&   ENDIF
    END
ELSE
    _searchrec.sr_error_r := e_ok;
(*ENDIF*) 
IF  (m.mb_trns^.trError_gg00 = e_ok)
THEN
    BEGIN
    _searchrec.sr_oj_lcountresult                  := -1;
    _searchrec.sr_oj_rcountresult                  := -1;
    _searchrec.sr_seq_r_outer_join                 := false;
    _searchrec.sr_lsearchkey.len                   := 0;
    _searchrec.sr_left_tree_pos.tpsPno_gg00              := NIL_PAGE_NO_GG00;
    b07cnext_record (m.mb_trns^, getrec.gi_minfo.o_tree,
          _searchrec.sr_lsearchkey, _searchrec.sr_set_result,
          _searchrec.sr_left_tree_pos, selrec.selr_selectbuffer.lbuf);
    IF  m.mb_trns^.trError_gg00 = e_key_not_found
    THEN
        m.mb_trns^.trError_gg00 := e_ok;
    (*ENDIF*) 
    _searchrec.sr_error_l           := m.mb_trns^.trError_gg00;
    m.mb_trns^.trError_gg00 := e_ok;
    selrec.selr_l_currpos    := 0;
    selrec.selr_l_endpos     := _searchrec.sr_set_result.bd_fill_len;
    WHILE (m.mb_trns^.trError_gg00 = e_ok) AND
          ((_searchrec.sr_error_r = e_ok) OR (_searchrec.sr_error_r = e_buffer_limit)) AND
          ((_searchrec.sr_error_l = e_ok) OR (_searchrec.sr_error_l = e_buffer_limit)) DO
        BEGIN
        IF  (selrec.selr_r_currpos < selrec.selr_r_endpos)
        THEN
            s30luc (selrec.selr_selectbuffer.lbuf,
                  selrec.selr_l_currpos + cgg_rec_key_offset + 1,
                  getrec.gi_minfo.o_keyl,
                  selrec.selr_selectbuffer.rbuf,
                  selrec.selr_r_currpos + cgg_rec_key_offset + 1,
                  getrec.gi_minfo.o_keyl, _lc_result)
        ELSE
            _lc_result := l_less;
        (*ENDIF*) 
&       IFDEF TRACE
        t01buf(kb,selrec.selr_selectbuffer.lbuf,
              selrec.selr_l_currpos + cgg_rec_key_offset + 1,
              selrec.selr_l_currpos + getrec.gi_minfo.o_keyl +
              cgg_rec_key_offset);
        IF  (selrec.selr_r_currpos < selrec.selr_r_endpos)
        THEN
            t01buf(kb,selrec.selr_selectbuffer.rbuf,
                  selrec.selr_r_currpos + cgg_rec_key_offset + 1,
                  selrec.selr_r_currpos + getrec.gi_minfo.o_keyl +
                  cgg_rec_key_offset);
        (*ENDIF*) 
        t01int4 (kb, 'l_currpos   ', selrec.selr_l_currpos);
        t01int4 (kb, 'r_currpos   ', selrec.selr_r_currpos);
        t01int4 (kb, 'lc_result   ', ord(_lc_result));
&       ENDIF
        IF  (_lc_result <> l_equal)
        THEN
            BEGIN
            kb74build_new_rec (m, getrec, selrec,
                  _searchrec, right_outer_join);
            k721add_into_result (m.mb_trns^, selrec, m.mb_next_mblock)
            END
        ELSE
            BEGIN
            selrec.selr_r_currpos :=
                  selrec.selr_r_currpos + getrec.gi_minfo.o_keyl + mxsp_c4;
            IF  (selrec.selr_r_currpos >= selrec.selr_r_endpos) AND
                (_searchrec.sr_error_r        =  e_buffer_limit)
            THEN
                BEGIN
                b07cnext_record (m.mb_trns^, selrec.selr_id_outer_join,
                      _searchrec.sr_rsearchkey, _searchrec.sr_set_result,
                      selrec.selr_oj_tree_pos, selrec.selr_selectbuffer.rbuf);
                IF  m.mb_trns^.trError_gg00 = e_key_not_found
                THEN
                    m.mb_trns^.trError_gg00 := e_ok;
                (*ENDIF*) 
                _searchrec.sr_error_r           := m.mb_trns^.trError_gg00;
                m.mb_trns^.trError_gg00 := e_ok;
                selrec.selr_r_currpos    := 0;
                selrec.selr_r_endpos     := _searchrec.sr_set_result.bd_fill_len;
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        selrec.selr_l_currpos := selrec.selr_l_currpos + getrec.gi_minfo.o_recl;
        IF  (selrec.selr_l_currpos >= selrec.selr_l_endpos)
        THEN
            IF  (_searchrec.sr_error_l =  e_buffer_limit)
            THEN
                BEGIN
                b07cnext_record (m.mb_trns^, getrec.gi_minfo.o_tree,
                      _searchrec.sr_lsearchkey, _searchrec.sr_set_result,
                      _searchrec.sr_left_tree_pos, selrec.selr_selectbuffer.lbuf);
                IF  m.mb_trns^.trError_gg00 = e_key_not_found
                THEN
                    m.mb_trns^.trError_gg00 := e_ok;
                (*ENDIF*) 
                _searchrec.sr_error_l           := m.mb_trns^.trError_gg00;
                m.mb_trns^.trError_gg00 := e_ok;
                selrec.selr_l_currpos    := 0;
                selrec.selr_l_endpos     := _searchrec.sr_set_result.bd_fill_len;
                END
            ELSE
                _searchrec.sr_error_l := e_no_next_record;
            (*ENDIF*) 
        (*ENDIF*) 
        END;
    (*ENDWHILE*) 
    END;
(*ENDIF*) 
IF  (selrec.selr_cnt_outer_join > 0)
THEN
    BEGIN
    _aux_error := m.mb_trns^.trError_gg00;
    b01destroy_file (m.mb_trns^, selrec.selr_id_outer_join);
    m.mb_trns^.trError_gg00 := _aux_error
    END;
&IFDEF TRACE
(*ENDIF*) 
t01basis_error (kb, 'm trError   ', m.mb_trns^.trError_gg00);
&ENDIF
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74short_init (
            VAR m               : tgg_mess_block;
            VAR stenum          : tgg07_StratEnum;
            VAR strat_maxresult : tsp_int2;
            VAR j_use_rowno     : boolean);
 
VAR
      _strat_ptr : ^tgg07_StrategyInfo;
 
BEGIN
_strat_ptr := @m.mb_strat^[ m.mb_st^[ m.mb_qual^.mstrat_pos ].epos ];
stenum := _strat_ptr^.str_strategy;
IF  (stenum = strat_join_key_equal)            OR
    (stenum = strat_join_all_keys_equal) OR
    (stenum = strat_join_key_next)          OR
    (stenum = strat_join_key_range)  OR
    (stenum = strat_join_inv)              OR
    (stenum = strat_join_all_inv_equal)    OR
    (stenum = strat_join_inv_range)  OR
    (stenum = strat_join_viewkey)
THEN
    BEGIN
    j_use_rowno := _strat_ptr^.str_use_rowno;
    _strat_ptr^.str_use_rowno := false;
    END
ELSE
    j_use_rowno := false;
(*ENDIF*) 
strat_maxresult := _strat_ptr^.str_maxresults;
&ifdef trace
t01strat_enum(kb, 'stenum      ', stenum)
&     endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74store_left_key (
            VAR t         : tgg00_TransContext;
            VAR getrec    : tkb7_get_param;
            VAR selrec    : tkb7_select_param);
 
BEGIN
IF  (t.trError_gg00 = e_ok)
THEN
    BEGIN
    selrec.selr_cnt_outer_join := succ (selrec.selr_cnt_outer_join);
    IF  (selrec.selr_cnt_outer_join = 1)
    THEN
        BEGIN
        selrec.selr_id_outer_join             := selrec.selr_resf_id;
        selrec.selr_id_outer_join.fileTfnTemp_gg00 := ttfnOuterJoinKeys_egg00;
        b01tcreate_file (t, selrec.selr_id_outer_join);
        selrec.selr_oj_tree_pos.tpsPno_gg00 := NIL_PAGE_NO_GG00;
        END;
    (* *** store full left key, because record-counter is     *)
    (*     not highest sort criteria                      *** *)
    (*ENDIF*) 
    selrec.selr_selectbuffer.result.recKeyLen_gg00       :=
          getrec.gi_minfo.o_keyl;
    selrec.selr_selectbuffer.result.recLen_gg00          :=
          getrec.gi_minfo.o_keyl + cgg_rec_key_offset;
    selrec.selr_selectbuffer.result.recVarcolOffset_gg00 := 0;
    selrec.selr_selectbuffer.result.recVarcolCnt_gg00    := 0;
    g10mv10 ('VKB74 ',  17,    
          sizeof (selrec.selr_selectbuffer.lbuf),
          sizeof (selrec.selr_selectbuffer.result.buf),
          selrec.selr_selectbuffer.lbuf,
          selrec.selr_l_currpos + cgg_rec_key_offset + 1,
          selrec.selr_selectbuffer.result.buf,
          cgg_rec_key_offset + 1,
          selrec.selr_selectbuffer.result.recKeyLen_gg00,
          t.trError_gg00);
&   IFDEF TRACE
    t01int4 (kb, 'outerjoincnt', selrec.selr_cnt_outer_join);
    t01buf (kb, selrec.selr_selectbuffer.result.buf, 1, selrec.selr_selectbuffer.result.len);
&   ENDIF
    IF  (t.trError_gg00 = e_ok)
    THEN
        b07cadd_record (t, selrec.selr_id_outer_join,
              selrec.selr_selectbuffer.result);
    (*ENDIF*) 
    IF  (t.trError_gg00 = e_duplicate_key)
    THEN
        t.trError_gg00 := e_ok;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74_join_select (VAR m : tgg_mess_block);
 
VAR
      _last_join_tab   : boolean;
      _special_ot_file : boolean;
      _j_use_rowno     : boolean;
      _strat_maxresult : tsp_int2;
      _stenum          : tgg07_StratEnum;
      _getrec          : tkb7_get_param;
      _selrec          : tkb7_select_param;
      _aux_error       : tgg_basis_error;
 
BEGIN
_last_join_tab := m.mb_type2 = mm_join_with_last_tab;
kb74join_sel_init (m, _getrec, _selrec, _j_use_rowno, _strat_maxresult, _stenum);
IF  m.mb_trns^.trError_gg00 = e_ok
THEN
    BEGIN
    (* h.b. PTS 1104929 *)
    _special_ot_file :=
          _getrec.gi_linkrec.kbjr_left_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_id_outer_join                  := _getrec.gi_minfo.o_tree;
        _selrec.selr_id_outer_join.fileRoot_gg00    := NIL_PAGE_NO_GG00;
        _selrec.selr_id_outer_join.fileTfnTemp_gg00 := ttfnOuterJoin_egg00;
        b01tcreate_file (m.mb_trns^, _selrec.selr_id_outer_join);
        END;
    (*ENDIF*) 
    IF  (_stenum = strat_join_key_equal)      OR
        (_stenum = strat_join_all_keys_equal) OR
        (_stenum = strat_join_key_next)       OR
        (_stenum = strat_join_inv)            OR
        (_stenum = strat_join_viewkey)        OR
        (_stenum = strat_join_key_range)      OR
        (_stenum = strat_join_all_inv_equal)  OR
        (_stenum = strat_join_inv_range)
    THEN
        kb74do_better_join (m, _getrec, _selrec,
              _stenum, _strat_maxresult, _last_join_tab, _j_use_rowno)
    ELSE
        BEGIN
        (* non relevant join transitions or cartesian product *)
        IF  m.mb_trns^.trError_gg00 = e_ok
        THEN
            IF  (m.mb_st^[m.mb_qual^.mqual_pos].eop <> op_outer_join)
                (* *** one_join_phase begin *** *)
                OR (m.mb_qual^.mresqual_cnt > 0)
                (* *** one_join_phase end *** *)
            THEN
                BEGIN
                k741sequential_join (m, _getrec, _selrec);
&               IFDEF TRACE
                t01treeid (kb, 'resf_id     ', _selrec.selr_resf_id);
                t01int4 (kb, 'countresult ',_selrec.selr_countresult);
                t01int4 (kb, ' distinct   ',ord(_selrec.selr_distinct));
                t01int4 (kb, 'maxresult   ',_selrec.selr_maxresult);
                t01int4 (kb, 'countresult ',_selrec.selr_countresult);
                t01int4 (kb, 'n_rec_len   ',_getrec.gi_minfo.n_rec_len);
&               ENDIF
                kb74join_last_part (m, _getrec, _selrec, _strat_maxresult,
                      _j_use_rowno, true, _last_join_tab);
&               IFDEF TRACE
                t01int4        (kb, 'n_rec_len   ', _getrec.gi_minfo.n_rec_len);
                t01treeid      (kb, 'resf_id     ', _selrec.selr_resf_id);
                t01basis_error (kb, 'm trError   ', m.mb_trns^.trError_gg00);
&               ENDIF
                END
            ELSE
                BEGIN
&               IFDEF TRACE
                t01int4 (kb, 'n_rec_len   ',_getrec.gi_minfo.n_rec_len);
&               ENDIF
                k720_select (m, _getrec, _selrec);
&               IFDEF TRACE
                t01treeid (kb, 'resf_id     ', _selrec.selr_resf_id);
                t01int4 (kb, 'countresult ',_selrec.selr_countresult);
                t01int4 (kb, ' distinct   ',ord(_selrec.selr_distinct));
                t01int4 (kb, 'maxresult   ',_selrec.selr_maxresult);
                t01int4 (kb, 'countresult ',_selrec.selr_countresult);
                t01int4 (kb, 'n_rec_len   ',_getrec.gi_minfo.n_rec_len);
&               ENDIF
                IF  _getrec.gi_linkrec.kbjr_right_oj
                THEN
                    kb74last_r_outer_join_part (m, _getrec, _selrec);
                (*ENDIF*) 
                kb74join_last_part (m, _getrec, _selrec, _strat_maxresult,
                      _j_use_rowno, true, _last_join_tab);
&               IFDEF TRACE
                t01int4        (kb, 'n_rec_len   ',_getrec.gi_minfo.n_rec_len);
                t01treeid      (kb, 'resf_id     ', _selrec.selr_resf_id);
                t01basis_error (kb, 'm trError   ', m.mb_trns^.trError_gg00);
&               ENDIF
                END;
            (*ENDIF*) 
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  _special_ot_file
    THEN
        BEGIN
        _aux_error := m.mb_trns^.trError_gg00;
        b01destroy_file (m.mb_trns^, _selrec.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_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  (_getrec.gi_minfo.o_tree.fileTfnTemp_gg00 = ttfnInto_egg00) AND
        (_getrec.gi_minfo.o_tree.fileTfn_gg00     = tfnTemp_egg00 )
    THEN
        b01empty_file (m.mb_trns^, _getrec.gi_minfo.o_tree)
    ELSE
        b01destroy_file (m.mb_trns^, _getrec.gi_minfo.o_tree);
    (*ENDIF*) 
    m.mb_trns^.trError_gg00 := _aux_error;
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74finish_catalog_join (
            VAR m      : tgg_mess_block;
            VAR getrec : tkb7_get_param;
            VAR selrec_ctxt : tsp_buf;
            strat_maxresult : tsp_int2;
            j_use_rowno     : boolean;
            last_join_tab   : boolean);
 
VAR
      _selrec : tkb7_select_param;
 
BEGIN
g10mv7 ('VKB74 ',  18,    
      sizeof (selrec_ctxt), sizeof (_selrec), selrec_ctxt, 1,
      _selrec, sizeof (_selrec.selr_selectbuffer) + 1,
      sizeof (_selrec) - sizeof (_selrec.selr_selectbuffer), m.mb_trns^.trError_gg00);
IF  (m.mb_trns^.trError_gg00 = e_ok)
THEN
    IF  getrec.gi_linkrec.kbjr_right_oj
    THEN
        IF  (m.mb_st^[m.mb_qual^.mqual_pos].eop <>
            op_outer_join)
            (* *** one_join_phase begin *** *)
            OR (m.mb_qual^.mresqual_cnt > 0)
            (* *** one_join_phase end *** *)
        THEN
            k741finish_r_outer_join (m, getrec, _selrec)
        ELSE
            kb74last_r_outer_join_part (m, getrec, _selrec);
        (*ENDIF*) 
    (*ENDIF*) 
(*ENDIF*) 
kb74join_last_part (m, getrec, _selrec, strat_maxresult,
      j_use_rowno, true, last_join_tab)
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74join_with_left_result (
            VAR m           : tgg_mess_block;
            VAR getrec      : tkb7_get_param;
            VAR sel         : tgg_select_fields_param;
            VAR selrec      : tkb7_select_param;
            VAR listkey     : tgg_lkey;
            return_next_key : boolean);
 
VAR
      _error_l               : tgg_basis_error;
      _result_possible       : boolean;
      _build_left_outer_join : boolean;
      _ic2                   : tsp_int_map_c2;
      _searchrec             : search_rec;
      _count                 : integer;
      _compare_len           : integer;
      _ix                    : integer;
 
BEGIN
IF  (m.mb_st^[m.mb_qual^.mqual_pos].eop <> op_outer_join) OR
    (m.mb_qual^.mresqual_cnt > 0)
THEN
    k741join_with_left_result (m, getrec, sel, selrec,
          listkey, return_next_key)
ELSE
    BEGIN
    selrec.selr_r_currpos := 0;
    selrec.selr_r_endpos  := selrec.selr_recl + selrec.selr_r_currpos;
    selrec.selr_l_null_val_fnd := false;
    selrec.selr_r_null_val_fnd := false;
    _searchrec.sr_j_curr_join_step :=
          ord (m.mb_st^[  m.mb_qual^.mstrat_pos ].ecol_tab[ 2 ]);
    g10mv10 ('VKB74 ',  19,    
          sizeof(selrec.selr_selectbuffer.result.buf),
          sizeof(selrec.selr_selectbuffer.rbuf),
          selrec.selr_selectbuffer.result.buf, 1,
          selrec.selr_selectbuffer.rbuf, selrec.selr_r_currpos + 1,
          selrec.selr_r_endpos, m.mb_trns^.trError_gg00);
    _searchrec.sr_oj_lcountresult           := -1;
    _searchrec.sr_oj_rcountresult           := -1;
    _searchrec.sr_seq_r_outer_join          := getrec.gi_linkrec.kbjr_right_oj;
    _ic2.map_int               := selrec.selr_r_endpos;
    selrec.selr_selectbuffer.rbuf[ 1 ]                 := _ic2.map_c2[ 1 ];
    selrec.selr_selectbuffer.rbuf[ 2 ]                 := _ic2.map_c2[ 2 ];
    _compare_len               := 0;
    _result_possible           := m.mb_trns^.trError_gg00 = e_ok;
    getrec.gi_lr_rec_id.r_rec_id := succ (getrec.gi_lr_rec_id.r_rec_id);
&   IFDEF TRACE
    t01int4 (kb, 'r_rec_id    ', getrec.gi_lr_rec_id.r_rec_id);
    t01int4 (kb, 'o_keyl      ',getrec.gi_minfo.o_keyl);
    t01int4 (kb, 'keylen      ',selrec.selr_selectbuffer.result.keylen);
    t01int4 (kb, 'recl        ',selrec.selr_recl);
    t01int4 (kb, 'n_rec_len   ',getrec.gi_minfo.n_rec_len);
    t01int4 (kb, 'keyl        ',selrec.selr_keyl);
    t01int4 (kb, 'distinct    ',ord(selrec.selr_distinct));
    t01int4 (kb, 'resf_id.root', selrec.selr_resf_id.fileRoot_gg00);
    t01buf (kb, selrec.selr_selectbuffer.rbuf, 1, selrec.selr_r_endpos);
    t01int4 (kb, 'kboj_op 2   ', ord(getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 2 ].kboj_op));
    t01int4 (kb, 'kbjr_cnt    ', getrec.gi_linkrec.kbjr_cnt);
    t01int4 (kb, 'kboj_len 1  ', getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 1 ].kboj_len);
    t01int4 (kb, 'kboj_len 2  ', getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 2 ].kboj_len);
&   ENDIF
    s10fil (sizeof(_searchrec.sr_lsearchkey.k), _searchrec.sr_lsearchkey.k, 1,
          sizeof(_searchrec.sr_lsearchkey.k), chr(0));
    IF  getrec.gi_linkrec.kbjr_cnt = 0
    THEN
        BEGIN
        getrec.gi_linkrec.kbjr_linkcnt      := 1;
        selrec.selr_first_jlen := 0;
        _searchrec.sr_lsearchkey.len  := 0;
        END
    ELSE
        BEGIN
        getrec.gi_linkrec.kbjr_linkcnt := 1;
        CASE ord(getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 2 ].kboj_op) OF
            0, 1 :
                selrec.selr_first_jlen :=
                      getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 1 ].kboj_len;
            2 :
                selrec.selr_first_jlen :=
                      getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 2 ].kboj_len;
            END;
        (*ENDCASE*) 
        CASE getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 1 ].kboj_op OF
            op_le, op_lt, op_ne :
                BEGIN
                _searchrec.sr_lsearchkey.len := 0;
                END;
            op_eq :
                BEGIN
                IF  (NOT getrec.gi_linkrec.kbjr_left_oj) AND
                    (NOT getrec.gi_linkrec.kbjr_right_oj)
                THEN
                    getrec.gi_linkrec.kbjr_linkcnt := 2;
                (*ENDIF*) 
                IF  (ord (getrec.gi_linkrec.
                    kbjr_jarr[ 1 ].kbji_parts[ 2 ].kboj_op) = 1)
                THEN
                    IF  getrec.gi_linkrec.kbjr_jarr[ 1 ].
                        kbji_parts[ 1 ].kboj_len <
                        getrec.gi_linkrec.kbjr_jarr[ 1 ].
                        kbji_parts[ 2 ].kboj_len
                    THEN
                        BEGIN
                        _count := s30lnr_defbyte(@selrec.selr_selectbuffer.rbuf,
                              selrec.selr_selectbuffer.
                              rbuf[ cgg_rec_key_offset + 1 ],
                              cgg_rec_key_offset + 1,
                              getrec.gi_linkrec.kbjr_jarr[ 1 ].
                              kbji_parts[ 2 ].kboj_len);
                        IF  _count >
                            getrec.gi_linkrec.kbjr_jarr[ 1 ].
                            kbji_parts[ 1 ].kboj_len
                        THEN
                            _result_possible := false;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                (*ENDIF*) 
                _compare_len := selrec.selr_first_jlen;
                _searchrec.sr_lsearchkey.len :=
                      getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 2 ].kboj_len;
                g10mv1 ('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_first_jlen, m.mb_trns^.trError_gg00);
                END;
            op_ge :
                BEGIN
                g10mv1 ('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_first_jlen, m.mb_trns^.trError_gg00);
&               ifdef trace
                t01buf (kb, selrec.selr_selectbuffer.rbuf,1,4 + selrec.selr_first_jlen);
&               endif
                _searchrec.sr_lsearchkey.len := s30lnr_defbyte(@selrec.selr_selectbuffer.rbuf,
                      selrec.selr_selectbuffer.rbuf[ cgg_rec_key_offset + 1 ],
                      cgg_rec_key_offset + 1,
                      getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 2 ].kboj_len);
&               ifdef trace
                t01buf (kb, selrec.selr_selectbuffer.rbuf,1,4 +
                      selrec.selr_first_jlen);
&               endif
                END;
            op_gt :
                BEGIN
                g10mv1 ('VKB74 ',  22,    
                      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_first_jlen, m.mb_trns^.trError_gg00);
&               ifdef trace
                t01buf (kb, selrec.selr_selectbuffer.rbuf,1,4 + selrec.selr_first_jlen);
&               endif
                _searchrec.sr_lsearchkey.len := s30lnr_defbyte(@selrec.selr_selectbuffer.rbuf,
                      selrec.selr_selectbuffer.rbuf[ cgg_rec_key_offset + 1 ],
                      cgg_rec_key_offset + 1,
                      getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 2 ].kboj_len);
&               ifdef trace
                t01buf (kb, selrec.selr_selectbuffer.rbuf,1,4 +
                      selrec.selr_first_jlen);
&               endif
                kb74nlbuild_next_lkey (_searchrec.sr_lsearchkey,
                      selrec.selr_first_jlen);
                END;
            OTHERWISE
                BEGIN
                _searchrec.sr_lsearchkey.len := 0;
                END;
            END;
        (*ENDCASE*) 
        END;
    (*ENDIF*) 
&   IFDEF TRACE
    t01int4 (kb, 'compare_len ', _compare_len);
    t01int4 (kb, 'first_jlen  ',selrec.selr_first_jlen);
    t01buf (kb, selrec.selr_selectbuffer.rbuf,1,4 + _searchrec.sr_lsearchkey.len);
    t01treeid (kb, 'm_info.otree', getrec.gi_minfo.o_tree);
&   ENDIF
    IF  _result_possible
    THEN
        BEGIN
        WITH _searchrec.sr_set_result DO
            BEGIN
            bd_key_check_len := _compare_len;
            bd_max_rec_cnt   := csp_maxint2;
            bd_max_fill_len  := mxsp_buf;
            bd_next          := false;
            bd_drop_page     := false;
            END;
        (*ENDWITH*) 
        _error_l := e_ok;
        IF  getrec.gi_linkrec.kbjr_left_oj                     AND
            (_searchrec.sr_lsearchkey.k[ 1 ] = csp_undef_byte) AND
            (c_first_field in getrec.gi_linkrec.kbjr_lof)
        THEN
            IF  (_searchrec.sr_j_curr_join_step > 2)
            THEN
                BEGIN
                _searchrec.sr_lsearchkey.len := 0;
                _searchrec.sr_set_result.bd_key_check_len := 0;
                s10fil (sizeof(_searchrec.sr_lsearchkey.k),
                      _searchrec.sr_lsearchkey.k, 1,
                      sizeof(_searchrec.sr_lsearchkey.k), chr(0));
                END
            ELSE
                _error_l := e_no_next_record;
            (*ENDIF*) 
        (*ENDIF*) 
        IF  (_error_l = e_ok)
        THEN
            BEGIN
            _searchrec.sr_left_tree_pos.tpsPno_gg00              := NIL_PAGE_NO_GG00;
            _searchrec.sr_left_before_cnext_tree_pos.tpsPno_gg00 := NIL_PAGE_NO_GG00;
            IF  return_next_key
            THEN
                g10fil1 ('VKB74 ',  23,    
                      sizeof (selrec.selr_selectbuffer.lbuf),
                      selrec.selr_selectbuffer.lbuf, cgg_rec_key_offset + 1,
                      _compare_len + 1,
                      csp_undef_byte, m.mb_trns^.trError_gg00);
            (*ENDIF*) 
            IF  (m.mb_trns^.trError_gg00 = e_ok)
            THEN
                b07cnext_record (m.mb_trns^, getrec.gi_minfo.o_tree,
                      _searchrec.sr_lsearchkey, _searchrec.sr_set_result,
                      _searchrec.sr_left_tree_pos, selrec.selr_selectbuffer.lbuf);
            (*ENDIF*) 
            IF  m.mb_trns^.trError_gg00 = e_key_not_found
            THEN
                m.mb_trns^.trError_gg00 := e_ok;
            (*ENDIF*) 
            _error_l           := m.mb_trns^.trError_gg00;
            m.mb_trns^.trError_gg00 := e_ok;
            IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
            THEN
                _error_l := e_cancelled;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        _build_left_outer_join := getrec.gi_linkrec.kbjr_left_oj AND
              (_error_l = e_no_next_record);
&       IFDEF TRACE
        t01basis_error (kb, 'error_l     ', _error_l);
        t01int4        (kb, 'e_ok        ', ord (e_ok));
        t01int4        (kb, 'lsearchkeyln', _searchrec.sr_lsearchkey.len);
        t01int4        (kb, 'resf_id.root', selrec.selr_resf_id.fileRoot_gg00);
        t01int4        (kb, 'o_tree.root ', getrec.gi_minfo.o_tree.fileRoot_gg00);
&       ENDIF
        selrec.selr_l_currpos     := 0;
        selrec.selr_l_defbyte_pos := -1;
        selrec.selr_fulfilled     := false;
        IF  (_error_l = e_ok) OR (_error_l = e_buffer_limit)
        THEN
            BEGIN
            selrec.selr_l_endpos := _searchrec.sr_set_result.bd_fill_len;
            selrec.selr_lmaxpos  := 0;
&           IFDEF TRACE
            t01int4 (kb, 'l_endpos    ',selrec.selr_l_endpos);
            t01int4 (kb, 'l_maxpos    ',selrec.selr_lmaxpos);
            t01int4 (kb, 'l_currpos   ',selrec.selr_l_currpos);
            t01int4 (kb, 'first_jlen  ',selrec.selr_first_jlen);
            t01int4 (kb, 'l_countresul', _searchrec.sr_oj_lcountresult);
            t01int4 (kb, 'r_countresul', _searchrec.sr_oj_rcountresult);
            t01int4 (kb, 'countresult ', selrec.selr_countresult);
&           ENDIF
            _searchrec.sr_oj_rcountresult := selrec.selr_countresult;
            kb74l_join_with_left_records (m, getrec, selrec, sel,
                  _searchrec, NOT c_build_right_outer_join);
&           IFDEF TRACE
            t01int4 (kb, 'l_countresul', _searchrec.sr_oj_lcountresult);
            t01int4 (kb, 'r_countresul', _searchrec.sr_oj_rcountresult);
            t01int4 (kb, 'countresult ', selrec.selr_countresult);
            t01int4 (kb, 'lsearchkeyle', _searchrec.sr_lsearchkey.len);
            t01lkey (kb, _searchrec.sr_lsearchkey);
&           ENDIF
            IF  ((_error_l = e_ok) OR (_error_l = e_buffer_limit)) AND
                (m.mb_trns^.trError_gg00 = e_ok)
            THEN
                BEGIN
                _build_left_outer_join := getrec.gi_linkrec.kbjr_left_oj  AND
                      (_searchrec.sr_oj_rcountresult = selrec.selr_countresult) AND
                      (NOT selrec.selr_fulfilled);
                IF  (NOT selrec.selr_fulfilled) AND
                    (return_next_key)    AND
                    (selrec.selr_first_jlen > 0)
                THEN
                    BEGIN
&                   IFDEF TRACE
                    t01int4 (ak_join, 'return_nextk',ord (return_next_key));
                    t01lkey (ak_join, listkey);
&                   ENDIF
                    listkey.len := getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 2 ].kboj_len;
                    g10mv1 ('VKB74 ',  24,    
                          sizeof(selrec.selr_selectbuffer.lbuf),
                          sizeof(listkey.k),
                          selrec.selr_selectbuffer.lbuf,
                          selrec.selr_l_currpos + cgg_rec_key_offset + 1,
                          listkey.k, 1,
                          listkey.len, m.mb_trns^.trError_gg00);
&                   IFDEF TRACE
                    t01lkey (ak_join, listkey);
&                   ENDIF
                    (* *** read next inv with mbtype2 mm_next *** *)
                    _ix := listkey.len;
                    WHILE (_ix > 0) DO
                        BEGIN
                        IF  (listkey.k[ _ix ] > chr(0))
                        THEN
                            BEGIN
                            listkey.k[ _ix ] := chr (ord (listkey.k[ _ix ]) - 1);
                            _ix := 0;
                            END
                        ELSE
                            BEGIN
                            listkey.len := pred (listkey.len);
                            END;
                        (*ENDIF*) 
                        _ix := pred (_ix);
                        END;
                    (*ENDWHILE*) 
&                   IFDEF TRACE
                    t01lkey (ak_join, listkey);
&                   ENDIF
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END
        ELSE
            (* *** escape for kb74new_outer_key       *)
            (*     ==> right rec_no will be added *** *)
            selrec.selr_l_null_val_fnd := _build_left_outer_join;
        (*ENDIF*) 
&       IFDEF TRACE
        IF  (_error_l    =  e_no_next_record)
        THEN
            BEGIN
            t01int4 (ak_join, 'first_jlen  ',selrec.selr_first_jlen);
            t01int4 (ak_join, 'return_nextk',ord (return_next_key));
            IF  return_next_key
            THEN
                t01lkey (ak_join, listkey);
            (*ENDIF*) 
            t01buf (ak_join, selrec.selr_selectbuffer.lbuf, 1, 20);
            END;
&       ENDIF
        (*ENDIF*) 
        IF  (_error_l    =  e_no_next_record) AND
            (return_next_key)                AND
            (selrec.selr_first_jlen > 0)
        THEN
            BEGIN
            listkey.len :=
                  getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 2 ].kboj_len;
            g10mv1 ('VKB74 ',  25,    
                  sizeof(selrec.selr_selectbuffer.lbuf), sizeof(listkey.k),
                  selrec.selr_selectbuffer.lbuf,
                  cgg_rec_key_offset + 1, listkey.k, 1,
                  listkey.len - 1, m.mb_trns^.trError_gg00);
&           IFDEF TRACE
            t01lkey (ak_join, listkey);
&           ENDIF
            (* *** read next inv with mbtype2 mm_next *** *)
            _ix := listkey.len;
            WHILE (_ix > 0) DO
                BEGIN
                IF  (listkey.k[ _ix ] > chr(0))
                THEN
                    BEGIN
                    listkey.k[ _ix ] := chr (ord (listkey.k[ _ix ]) - 1);
                    _ix := 0;
                    END
                ELSE
                    BEGIN
                    listkey.len := pred (listkey.len);
                    END;
                (*ENDIF*) 
                _ix := pred (_ix);
                END;
            (*ENDWHILE*) 
&           IFDEF TRACE
            t01lkey (ak_join, listkey);
&           ENDIF
            END;
        (*ENDIF*) 
        IF  _build_left_outer_join AND
            (m.mb_trns^.trError_gg00 = e_ok)
        THEN
            IF  _searchrec.sr_j_curr_join_step = 2
            THEN
                BEGIN
                kb74build_new_rec (m, getrec, selrec, _searchrec,
                      left_outer_join);
                k721add_into_result (m.mb_trns^, selrec,
                      m.mb_next_mblock);
                END
            ELSE
                kb74lo_build_left_outer_join (m, getrec, selrec, _searchrec);
            (*ENDIF*) 
&       IFDEF TRACE
        (*ENDIF*) 
        t01int4        (kb, 'l_endpos    ',selrec.selr_l_endpos);
        t01int4        (kb, 'l_currpos   ',selrec.selr_l_currpos);
        t01int4        (kb, 'lmaxpos     ',selrec.selr_lmaxpos);
        t01basis_error (kb, 'm trError   ', m.mb_trns^.trError_gg00);
&       ENDIF
        IF  (m.mb_trns^.trError_gg00 = e_no_next_record)
        THEN
            m.mb_trns^.trError_gg00 := e_ok;
        (*ENDIF*) 
        END
    ELSE
        m.mb_trns^.trError_gg00 := e_ok;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74rowno_position (
            VAR m      : tgg_mess_block;
            VAR getrec : tkb7_get_param;
            VAR selrec : tkb7_select_param);
 
VAR
      _i      : integer;
      _j      : integer;
      _stop   : integer;
 
BEGIN
_i    := m.mb_qual^.mqual_pos;
_stop := m.mb_st^[ m.mb_qual^.mqual_pos ].epos + m.mb_qual^.mqual_pos - 1;
_j    := 1;
&IFDEF TRACE
t01messblock (ak_sem, 'k74-mblock  ', m);
t01int4 (kb, 'i           ', _i);
t01int4 (kb, 'stop        ', _stop);
&ENDIF
WHILE (_i < _stop) DO
    BEGIN
    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
            BEGIN
            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
                (* *** rowno position in resultrecord *** *)
                m.mb_st^[ _i ].epos := getrec.gi_n_pos_s.posarr[ _j ].onto;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    _i := succ (_i);
    END;
(*ENDWHILE*) 
&IFDEF TRACE
t01messblock (ak_sem, 'k74-mblock  ', m);
t01int4 (kb, 'i           ', _i);
t01int4 (kb, 'stop        ', _stop);
&ENDIF
k721do_rowno (m, selrec);
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74start_catalog_join (
            VAR m           : tgg_mess_block;
            VAR getrec      : tkb7_get_param;
            VAR selrec_ctxt : tsp_buf);
 
VAR
      _j_use_rowno     : boolean;
      _strat_maxresult : tsp_int2;
      _stenum          : tgg07_StratEnum;
      _selrec          : tkb7_select_param;
 
BEGIN
kb74join_sel_init (m, getrec, _selrec, _j_use_rowno, _strat_maxresult, _stenum);
IF  m.mb_trns^.trError_gg00 = e_ok
THEN
    k741last_defined_byte_pos (m, _selrec, getrec.gi_linkrec);
(*ENDIF*) 
IF  m.mb_trns^.trError_gg00 = e_ok
THEN
    g10mv2 ('VKB74 ',  26,    
          sizeof (_selrec), sizeof (selrec_ctxt),
          _selrec, sizeof (_selrec.selr_selectbuffer) + 1, selrec_ctxt, 1,
          sizeof (_selrec) - sizeof (_selrec.selr_selectbuffer), m.mb_trns^.trError_gg00)
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb74lo_build_left_outer_join (
            VAR m                  : tgg_mess_block;
            VAR getrec             : tkb7_get_param;
            VAR selrec             : tkb7_select_param;
            VAR searchrec          : search_rec);
 
VAR
      _rec_in_buf        : boolean;
      _no_next_rec       : boolean;
      _null_value_found  : boolean;
      _lsearchkey        : tgg_lkey;
      _i                 : integer;
      _aux_l_endpos      : integer;
      _aux_l_currpos     : integer;
      _aux_lmaxpos       : integer;
 
BEGIN
_null_value_found := false;
_i                := 1;
WHILE ((_i <= getrec.gi_linkrec.kbjr_cnt) AND (NOT _null_value_found)) DO
    BEGIN
    _null_value_found :=
          selrec.selr_selectbuffer.rbuf [ selrec.selr_r_currpos +
          getrec.gi_linkrec.kbjr_jarr[ _i ].kbji_parts[ 2 ].kboj_recpos ] =
          csp_undef_byte;
    _i := succ (_i)
    END;
(*ENDWHILE*) 
IF  NOT _null_value_found
THEN
    BEGIN
    _aux_l_endpos        := selrec.selr_l_endpos;
    _aux_l_currpos       := selrec.selr_l_currpos;
    _aux_lmaxpos         := selrec.selr_lmaxpos;
    selrec.selr_cnt_outer_join := 1;
    _lsearchkey.len      := 0;
    s10fil (sizeof(_lsearchkey.k), _lsearchkey.k, 1,
          sizeof(_lsearchkey.k), chr(0));
    searchrec.sr_error_l     := e_ok;
    _no_next_rec := false;
    _rec_in_buf  :=
          searchrec.sr_old_left_tree_pos.tpsPno_gg00 = searchrec.sr_left_before_cnext_tree_pos.tpsPno_gg00;
    WHILE (NOT _no_next_rec)          AND
          (m.mb_trns^.trError_gg00 = e_ok) AND
          (searchrec.sr_error_l <> e_no_next_record) DO
        BEGIN
        IF  NOT _rec_in_buf
        THEN
            BEGIN
            _rec_in_buf := false;
            WITH searchrec.sr_set_result DO
                BEGIN
                bd_key_check_len := 0;
                bd_max_rec_cnt   := csp_maxint2;
                bd_max_fill_len  := mxsp_buf;
                bd_next          := false;
                bd_drop_page     := true;
                END;
            (*ENDWITH*) 
            searchrec.sr_left_before_cnext_tree_pos := searchrec.sr_left_tree_pos;
            b07cnext_record (m.mb_trns^, getrec.gi_minfo.o_tree, _lsearchkey,
                  searchrec.sr_set_result, searchrec.sr_left_tree_pos, selrec.selr_selectbuffer.lbuf);
            IF  m.mb_trns^.trError_gg00 = e_key_not_found
            THEN
                m.mb_trns^.trError_gg00 := e_ok;
            (*ENDIF*) 
            searchrec.sr_error_l := m.mb_trns^.trError_gg00;
            IF  (searchrec.sr_error_l = e_ok)           OR
                (searchrec.sr_error_l = e_buffer_limit) OR
                (searchrec.sr_error_l = e_no_next_record)
            THEN
                m.mb_trns^.trError_gg00 := e_ok;
            (*ENDIF*) 
            IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
            THEN
                searchrec.sr_error_l := e_cancelled;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        _no_next_rec  := searchrec.sr_error_l <> e_buffer_limit;
&       IFDEF TRACE
        t01int4 (kb, 'tpsPno      ',searchrec.sr_left_tree_pos.tpsPno_gg00);
        t01int4 (kb, 'tpsIndex    ',searchrec.sr_left_tree_pos.tpsIndex_gg00);
&       ENDIF
        selrec.selr_l_endpos  := searchrec.sr_set_result.bd_fill_len;
        selrec.selr_l_currpos := 0;
        selrec.selr_lmaxpos   := 0;
        WHILE ((m.mb_trns^.trError_gg00 = e_ok) AND
              (selrec.selr_l_currpos < selrec.selr_l_endpos)) DO
            BEGIN
            selrec.selr_selectbuffer.result.len := 0;
            IF  kb74new_outer_key (m.mb_trns^, getrec, selrec)
            THEN
                BEGIN
                kb74build_new_rec (m, getrec, selrec, searchrec,
                      left_outer_join);
                k721add_into_result (m.mb_trns^, selrec,
                      m.mb_next_mblock);
                END;
            (*ENDIF*) 
            IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
            THEN
                m.mb_trns^.trError_gg00 := e_cancelled;
            (*ENDIF*) 
            selrec.selr_l_currpos := selrec.selr_l_currpos + getrec.gi_minfo.o_recl;
            END;
        (*ENDWHILE*) 
&       IFDEF TRACE
        t01int4 (kb, 'lmaxpos whil',selrec.selr_lmaxpos);
        t01basis_error (kb, 'error_l     ',searchrec.sr_error_l);
        t01int4 (kb, 'l_currpos   ',selrec.selr_l_currpos);
        t01int4 (kb, 'l_endpos    ',selrec.selr_l_endpos);
&       ENDIF
        END;
    (*ENDWHILE*) 
    selrec.selr_l_endpos     := _aux_l_endpos;
    selrec.selr_l_currpos    := _aux_l_currpos;
    selrec.selr_lmaxpos      := _aux_lmaxpos;
    searchrec.sr_old_left_tree_pos := searchrec.sr_left_before_cnext_tree_pos;
    selrec.selr_l_currpos    := selrec.selr_lmaxpos;
    END
ELSE
    BEGIN
    kb74build_new_rec (m, getrec, selrec, searchrec,
          left_outer_join);
    k721add_into_result (m.mb_trns^, selrec, m.mb_next_mblock);
    IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
    THEN
        m.mb_trns^.trError_gg00 := e_cancelled;
    (*ENDIF*) 
    selrec.selr_l_currpos := selrec.selr_l_currpos + getrec.gi_minfo.o_recl;
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
FUNCTION
      kb74new_outer_key (
            VAR t        : tgg00_TransContext;
            VAR getrec   : tkb7_get_param;
            VAR selrec   : tkb7_select_param) : boolean;
 
VAR
      _is_new   : boolean;
 
BEGIN
_is_new := true;
IF  selrec.selr_l_null_val_fnd OR
    selrec.selr_r_null_val_fnd
THEN
    BEGIN
    selrec.selr_selectbuffer.result.keylen := 2 * mxsp_c4;
    s20ch4sw (getrec.gi_lr_rec_id.r_rec_id, g01code.kernel_swap,
          selrec.selr_selectbuffer.result.buf,
          selrec.selr_selectbuffer.result.keylen - 3, sw_normal)
    END
ELSE
    selrec.selr_selectbuffer.result.keylen := mxsp_c4;
(*ENDIF*) 
selrec.selr_selectbuffer.result.len :=
      selrec.selr_selectbuffer.result.keylen + cgg_rec_key_offset;
g10mv10 ('VKB74 ',  27,    
      sizeof(selrec.selr_selectbuffer.lbuf),
      sizeof(selrec.selr_selectbuffer.result.buf),
      selrec.selr_selectbuffer.lbuf,
      selrec.selr_l_currpos + getrec.gi_minfo.o_keyl - 3,
      selrec.selr_selectbuffer.result.buf,
      selrec.selr_selectbuffer.result.keylen + 1,
      selrec.selr_selectbuffer.result.keylen, t.trError_gg00);
&IFDEF TRACE
t01treeid (kb, 'outer_joinid', selrec.selr_id_outer_join);
t01int4 (kb, 'outerjoincnt', selrec.selr_cnt_outer_join);
t01buf (kb, selrec.selr_selectbuffer.result.buf, 1,
      selrec.selr_selectbuffer.result.len);
t01buf (kb, selrec.selr_selectbuffer.lbuf,
      selrec.selr_l_currpos + getrec.gi_minfo.o_keyl + 1,
      selrec.selr_l_currpos + getrec.gi_minfo.o_keyl + mxgg_int4);
&ENDIF
selrec.selr_oj_tree_pos.tpsPno_gg00 := NIL_PAGE_NO_GG00;
IF  (t.trError_gg00 = e_ok)
THEN
    b07cadd_record (t, selrec.selr_id_outer_join,
          selrec.selr_selectbuffer.result);
(*ENDIF*) 
IF  (t.trError_gg00 = e_duplicate_key)
THEN
    BEGIN
    _is_new   := false;
    t.trError_gg00 := e_ok;
    END;
(*ENDIF*) 
kb74new_outer_key := _is_new;
END;
 
(*------------------------------*) 
 
PROCEDURE
      k74_const_output_expression (
            VAR m         : tgg_mess_block;
            VAR selrec    : tkb7_select_param;
            VAR exp_pos   : tkb7_one_new_pos);
 
VAR
      _dummy_bool           : boolean;
      _sel                  : tgg_select_fields_param;
      _i                    : integer;
      _qual_output          : integer;
      _aux_mqual_pos        : integer;
      _aux_mqual_cnt        : integer;
      _aux_mview_cnt        : integer;
      _aux_se_jumpout       : tgg_stack_entry;
      _aux_se_output        : tgg_stack_entry;
      _aux_mst_optimize_pos : integer;
 
BEGIN
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);
_sel.sfp_bd_mess_type    := m.mb_type;
_sel.sfp_bd_mess2_type   := mm_first;
_sel.sfp_replicated      := m.mb_replicated;
_sel.sfp_result_wanted   := true;
_sel.sfp_m_result_addr   := @selrec.selr_selectbuffer.result.buf;
_sel.sfp_m_result_size   := sizeof (selrec.selr_selectbuffer.result.buf);
_sel.sfp_oj_spec         := ckb7_ojoin_none;
_sel.sfp_result_length   := cgg_rec_key_offset;
_sel.sfp_is_first_record := false;
_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
k71col_select (m.mb_trns^, _sel, 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;
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
*-PRETTY-*  statements    :       1174
*-PRETTY-*  lines of code :       3247        PRETTYX 3.10 
*-PRETTY-*  lines in file :       4746         1997-12-10 
.PA 
