.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$VKB741$
.tt 2 $$$
.TT 3 $ThomasA$KB_Join_Select$1999-11-18$
***********************************************************
.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_Better_Join_Select
=========
.sp
Purpose : Processing the join between two tables
.CM *-END-* purpose -------------------------------------
.sp
.cp 3
Define  :
 
        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
              k741sequential_join (
                    VAR m      : tgg_mess_block;
                    VAR getrec : tkb7_get_param;
                    VAR selrec : tkb7_select_param);
 
        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);
 
.CM *-END-* define --------------------------------------
.sp;.cp 3
Use     :
 
        FROM
              KB_get : VKB71;
 
        PROCEDURE
              k71join_comparison (
                    op       : tgg_stack_op_type;
                    VAR sel  : tgg_select_fields_param;
                    VAR buf1 : tbd_node;
                    pos1     : tsp_int4;
                    len1     : integer;
                    VAR buf2 : tsp_buf;
                    pos2     : tsp_int4;
                    len2     : integer;
                    VAR ok   : integer);
 
        PROCEDURE
              k71col_select (
                    VAR t           : tgg00_TransContext;
                    VAR sel         : tgg_select_fields_param;
                    VAR stack_desc  : tgg_stack_desc;
                    VAR rec_buf     : tgg00_Rec;
                    VAR unqualified : boolean);
 
        PROCEDURE
              k71sel_qualification_test (
                    VAR m          : tgg_mess_block;
                    VAR sel        : tgg_select_fields_param;
                    check_new_rec  : boolean;
                    VAR rec        : tgg_rec_buf);
 
      ------------------------------ 
 
        FROM
              Single_Select : VKB720;
 
        PROCEDURE
              k720_test_subquery (
                    VAR m   : tgg_mess_block;
                    VAR rec : tgg_rec_buf);
 
        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);
 
        PROCEDURE
              k720_select (
                    VAR m      : tgg_mess_block;
                    VAR getrec : tkb7_get_param;
                    VAR selrec : tkb7_select_param);
 
      ------------------------------ 
 
        FROM
              Single_Select_Part2 : VKB721;
 
        PROCEDURE
              k721add_into_result (
                    VAR t                : tgg00_TransContext;
                    VAR selrec           : tkb7_select_param;
                    VAR next_mblock      : tgg_mess_block_ptr);
 
        PROCEDURE
              k721function_add (
                    VAR m      : tgg_mess_block;
                    VAR selrec : tkb7_select_param;
                    aggr       : boolean);
 
      ------------------------------ 
 
        FROM
              KB_Join_Select : VKB74;
 
        PROCEDURE
              k74_const_output_expression (
                    VAR m         : tgg_mess_block;
                    VAR selrec    : tkb7_select_param;
                    VAR exp_pos   : tkb7_one_new_pos);
 
      ------------------------------ 
 
        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_3 : VBD03;
 
        PROCEDURE
              b03get_inv (
                    VAR t              : tgg00_TransContext;
                    VAR act_tree_id    : tgg00_FileId;
                    VAR lk             : tgg00_Lkey;
                    VAR rk             : tgg00_Lkey;
                    VAR stop_rk        : tgg00_Lkey;
                    VAR CurrentPrimKey : tgg00_Lkey;
                    VAR bd_inv_info    : tgg00_BdInvSet;
                    count_only         : boolean;
                    wanted_lock        : tgg00_LockReqMode;
                    VAR b              : tgg00_KeylistBuf;
                    VAR primkeycnt     : tsp00_Int4;
                    VAR ll             : tsp00_Int4);
 
        PROCEDURE
              b03next_invkey (
                    VAR t           : tgg00_TransContext;
                    VAR act_tree_id : tgg00_FileId;
                    incl            : boolean;
                    VAR lk          : tgg00_Lkey);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_7 : VBD07;
 
        PROCEDURE
              b07get_result_leaf (
                    VAR t           : tgg00_TransContext;
                    VAR file_id     : tgg00_FileId;
                    VAR rk          : tgg00_Lkey;
                    use_tree_pos    : boolean;
                    prepare_for_upd : boolean;
                    VAR tree_pos    : tgg00_FilePos;
                    VAR nptr        : tbd_node_ptrs);
 
        PROCEDURE
              b07release_result_leaf (
                    VAR t        : tgg00_TransContext;
                    VAR file_id  : tgg00_FileId;
                    node_changed : boolean;
                    VAR nptr     : tbd_node_ptrs);
 
      ------------------------------ 
 
        FROM
              Codetransformation_and_Coding : VGG02;
 
        VAR
              g02codetables : tgg_code_tables;
 
      ------------------------------ 
 
        FROM
              Kernel_move_and_fill : VGG10;
 
        PROCEDURE
              g10fil (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size           : tsp_int4;
                    VAR m          : tsp_key;
                    pos            : tsp_int4;
                    len            : tsp_int4;
                    fillchar       : char;
                    VAR e          : tgg_basis_error);
 
        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       : tsp_key;
                    p1             : tsp_int4;
                    VAR val2       : tsp_key;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
        PROCEDURE
              g10mv3 (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size1          : tsp_int4;
                    size2          : tsp_int4;
                    VAR val1       : tbd_node;
                    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       : tbd_node;
                    p1             : tsp_int4;
                    VAR val2       : tsp_key;
                    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_buf;
                    p1             : tsp_int4;
                    VAR val2       : tsp_buf;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
      ------------------------------ 
 
        FROM
              RTE-Extension-30 : VSP30;
 
        PROCEDURE
              s30cmp (
                    VAR buf1     : tbd_node;
                    fieldpos1    : tsp_int4;
                    fieldlength1 : tsp_int4;
                    VAR buf2     : tsp_buf;
                    fieldpos2    : tsp_int4;
                    fieldlength2 : tsp_int4;
                    VAR l_result : tsp_lcomp_result);
 
        PROCEDURE
              s30cmp1 (
                    VAR buf1     : tsp_key;
                    fieldpos1    : tsp_int4;
                    fieldlength1 : tsp_int4;
                    VAR buf2     : tbd_node;
                    fieldpos2    : tsp_int4;
                    fieldlength2 : tsp_int4;
                    VAR l_result : tsp_lcomp_result);
 
        PROCEDURE
              s30cmp2 (
                    VAR buf1     : tsp_key;
                    fieldpos1    : tsp_int4;
                    fieldlength1 : tsp_int4;
                    VAR buf2     : tsp_key;
                    fieldpos2    : tsp_int4;
                    fieldlength2 : tsp_int4;
                    VAR l_result : tsp_lcomp_result);
 
        PROCEDURE
              s30luc (
                    VAR buf1     : tbd_node;
                    fieldpos1    : tsp_int4;
                    fieldlength1 : tsp_int4;
                    VAR buf2     : tsp_buf;
                    fieldpos2    : tsp_int4;
                    fieldlength2 : tsp_int4;
                    VAR l_result : tsp_lcomp_result);
 
        PROCEDURE
              s30luc1 (
                    VAR buf1     : tbd_node;
                    fieldpos1    : tsp_int4;
                    fieldlength1 : tsp_int4;
                    VAR buf2     : tsp_key;
                    fieldpos2    : tsp_int4;
                    fieldlength2 : tsp_int4;
                    VAR l_result : tsp_lcomp_result);
 
        PROCEDURE
              s30map (
                    VAR code_t : tsp_ctable;
                    VAR source : tsp_key;
                    spos       : tsp_int4;
                    VAR dest   : tsp_key;
                    dpos       : tsp_int4;
                    length     : tsp_int4);
 
        FUNCTION
              s30lnr_defbyte (
                    str       : tsp_moveobj_ptr;
                    defbyte   : char;
                    start_pos : tsp_int4;
                    length    : tsp_int4) : tsp_int4;
&       IFDEF TRACE
 
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        PROCEDURE
              t01op (
                    debug  : tgg00_Debug;
                    nam    : tsp00_Sname;
                    op     : tgg00_StackOpType);
 
        PROCEDURE
              t01buf  (
                    level     : tgg00_Debug;
                    VAR buf   : tsp00_Buf;
                    pos_start : integer;
                    pos_end   : integer);
 
        PROCEDURE
              t01buf1  (
                    level     : tgg00_Debug;
                    VAR buf   : tbd_node;
                    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
              t01mess2type (
                    debug         : tgg00_Debug;
                    nam           : tsp00_Sname;
                    mess2_type    : tgg00_MessType2);
 
        PROCEDURE
              t01messblock (
                    debug         : tgg00_Debug;
                    nam           : tsp00_Sname;
                    VAR m         : tgg00_MessBlock);
 
      ------------------------------ 
 
        FROM
              RTE_kernel: VEN101
                    PROCEDURE
                    vdebug_break (debug_break_pos : tsp_int4);
 
&       ENDIF
      ------------------------------ 
 
        FROM
              Unicode-Utilities: VGG20;
 
        PROCEDURE
              g20unifill (
                    size      : tsp_int4;
                    m         : tsp_moveobj_ptr;
                    pos       : tsp_int4;
                    len       : tsp_int4;
                    filluchar : tsp_c2);
 
      ------------------------------ 
 
        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);
 
.CM *-END-* use -----------------------------------------
.sp;.cp 3
Synonym :
 
        PROCEDURE
              k71join_comparison;
 
              tsp_moveobj tbd_node
              tsp_moveobj tsp_buf
 
        PROCEDURE
              b03get_inv;
 
              tgg_keylist_buf tsp_buf
 
        PROCEDURE
              g10fil;
 
              tsp_moveobj tsp_key
 
        PROCEDURE
              g10fil1;
 
              tsp_moveobj tsp_buf
 
        PROCEDURE
              g10mv1;
 
              tsp_moveobj tsp_buf
              tsp_moveobj tsp_key
 
        PROCEDURE
              g10mv2;
 
              tsp_moveobj tsp_key
 
        PROCEDURE
              g10mv3;
 
              tsp_moveobj tsp_buf
              tsp_moveobj tbd_node
 
        PROCEDURE
              g10mv4;
 
              tsp_moveobj tbd_node
              tsp_moveobj tsp_key
 
        PROCEDURE
              g10mv5;
 
              tsp_moveobj tsp_buf
              tsp_moveobj tsp_buf
 
        PROCEDURE
              s30cmp;
 
              tsp_moveobj tbd_node
              tsp_moveobj tsp_buf
 
        PROCEDURE
              s30cmp1;
 
              tsp_moveobj tsp_key
              tsp_moveobj tbd_node
 
        PROCEDURE
              s30cmp2;
 
              tsp_moveobj tsp_key;
 
        PROCEDURE
              s30luc;
 
              tsp_moveobj tsp_buf
              tsp_moveobj tbd_node
 
        PROCEDURE
              s30luc1;
 
              tsp_moveobj tbd_node
              tsp_moveobj tsp_key
 
        PROCEDURE
              s30map;
 
              tsp_moveobj tsp_key
&             ifdef trace
 
        PROCEDURE
              t01buf1;
 
              tsp00_Buf tbd_node
&             endif
 
.CM *-END-* synonym -------------------------------------
.sp;.cp 3
Author  : ThomasA
.sp
.cp 3
Created : 1995-06-30
.sp
.cp 3
Version : 2002-09-17
.sp
.cp 3
Release :      Date : 1999-11-18
.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 (as of byte 89).

-  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
(e.g. SELECT..INTO only one, cf. K74_MAXRESULT_GET) 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:

        kbjr_cnt           : int2;
        kbjr_right_oj      : boolean;
        kbjr_left_oj       : boolean;
                                   ----
            kbjr_rec       : int2;    |
            kbjr_len       : int2;    > kbjr_cnt times
            kbjr_op        : int2;    |
                                   ----

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.
KBJ_POS_IN_REC indicates the position at which the join fields
begin in the two records.
(KBJ_POS_IN_REC - 4 would be the position in the key)
KBJLENGTH designates the length of the field.
KBJOP 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.

K74_MAXRESULT_GET
-----------------
The real maximum for the select is generated from the value
transferred to the STRAT_MAXCNT from the strategy information and the
Rowno value, if available in part2 of the Mess-Buffer.
.CM *-END-* specification -------------------------------
.sp 2
***********************************************************
.sp
.cp 10
.fo
.oc _/1
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_POSITION.
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.

GET_NEW_POSITION
-----------------

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.

JOIN_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.

DO_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.
JOIN_LAST_PART is called up to structure the feedback mess buffer.

ALL_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.

JOIN_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.

JOINVIEW_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 ALL_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 ALL_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.

COMPARE_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.

BUILD_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_get_next               = true;
      c_count_only             = true;
      c_inclusive              = true;
      c_is_right_outer_join    = true;
      c_right_needed           = true;
      c_left_len_eq_right_len  = 0;
      c_left_len_lt_right_len  = 1;
      c_left_len_gt_right_len  = 2;
      c_node_changed           = true;
      (* *** one_join_phase begin *** *)
      c_first_qual             = true;
      c_check_new_rec          = true;
      c_aggr                   = true (* k721function_add      *);
      (* *** one_join_phase end *** *)
 
TYPE
 
      search_rec = RECORD
            sr_lsearchkey         : tgg_lkey;
            sr_rsearchkey         : tgg_lkey;
            sr_prepare_for_upd    : boolean;
            sr_refused_by_ophase  : boolean;
            sr_res_cnt            : tsp_int4;
            sr_error_l            : tgg_basis_error;
            sr_error_r            : tgg_basis_error;
            sr_left_tree_pos      : tgg00_FilePos;
            sr_nptr               : tbd_node_ptrs;
            sr_left_min_index     : integer;
            sr_left_last_pno      : tsp_page_no;
      END;
 
 
      conv_type = RECORD
            ct_st_pos  : tsp_int2;
            ct_codeno  : tsp00_Uint1;
            ct_is_desc : boolean;
      END;
 
      conv_arr = ARRAY [ 1..MAX_JOINS_GG00 ] OF conv_type;
 
 
(*------------------------------*) 
 
PROCEDURE
      kb741all_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
&ifdef trace
t01mess2type (bi, 'sel_type    ', sel_type);
&endif
m.mb_trns^.trError_gg00       := e_ok;
sel.sfp_bd_mess2_type   := sel_type;
sel.sfp_m_result_addr   := @selrec.selr_selectbuffer.rbuf;
sel.sfp_m_result_size   := sizeof (selrec.selr_selectbuffer.rbuf);
sel.sfp_m_result_len    := 0;
m.mb_qual^.mtree.fileBdUse_gg00 := [  ];
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);
&IFDEF TRACE
t01basis_error (kb, 'm trError   ', m.mb_trns^.trError_gg00);
&ENDIF
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741build_new_rec (
            VAR m             : tgg_mess_block;
            VAR getrec        : tkb7_get_param;
            VAR selrec        : tkb7_select_param;
            VAR searchrec     : search_rec;
            right_cols_needed : boolean;
            outer_join        : tkb7_outer_join_type);
 
VAR
      _ix                : integer;
      _l                 : integer;
      _t                 : integer;
      _f                 : integer;
      _j                 : integer;
      _frompos           : integer;
      _dummy_bool        : boolean;
      _sel               : tgg_select_fields_param;
      _aux_keyl          : tsp_int2;
      _aux_mresqual_pos  : tsp_int2;
      _aux_mresqual_cnt  : tsp_int2;
      _aux_mqual_pos     : tsp_int2;
      _aux_mqual_cnt     : tsp_int2;
      _aux_optimize_pos  : tsp_int2;
 
BEGIN
selrec.selr_selectbuffer.result.len    := getrec.gi_minfo.n_rec_len;
selrec.selr_selectbuffer.result.keylen := getrec.gi_minfo.n_key_len;
(* h.b. PTS 1104659 *)
selrec.selr_selectbuffer.result.space_var_offset := 0;
selrec.selr_selectbuffer.result.space_var_cnt    := 0;
(* move from left record *)
FOR _ix := getrec.gi_n_pos_s.rposcnt + 1 TO
      getrec.gi_n_pos_s.rposcnt + getrec.gi_n_pos_s.lposcnt DO
    WITH getrec.gi_n_pos_s.posarr[_ix] DO
        IF  outer_join = left_outer_join
        THEN
            BEGIN
            selrec.selr_selectbuffer.result.buf[onto] := csp_undef_byte;
            g10fil1 ('VKB741',   1,    
                  sizeof (selrec.selr_selectbuffer.result.buf),
                  selrec.selr_selectbuffer.result.buf, onto + 1,
                  onlen - 1, csp_defined_byte,
                  m.mb_trns^.trError_gg00)
            END
        ELSE
            BEGIN
            g10mv3 ('VKB741',   2,    
                  sizeof(searchrec.sr_nptr.np_ptr^),
                  sizeof(selrec.selr_selectbuffer.result.buf),
                  searchrec.sr_nptr.np_ptr^, selrec.selr_l_currpos + onfrom - 1,
                  selrec.selr_selectbuffer.result.buf,
                  onto, onlen, m.mb_trns^.trError_gg00);
            END;
        (*ENDIF*) 
    (*ENDWITH*) 
(*ENDFOR*) 
(* *** one_join_phase begin *** *)
IF  NOT right_cols_needed AND (m.mb_qual^.mresqual_cnt > 0)
THEN
    (* *** Output list with expression (instead of two_phase)! *** *)
    right_cols_needed :=
          m.mb_st^ [ m.mb_qual^.mqual_pos ].etype = st_jump_output;
(* *** one_join_phase end *** *)
(*ENDIF*) 
;
IF  right_cols_needed AND (m.mb_trns^.trError_gg00 = e_ok)
THEN
    FOR _ix := 1 TO getrec.gi_n_pos_s.rposcnt DO
        WITH getrec.gi_n_pos_s.posarr[_ix] DO
            BEGIN
            IF  onfrom > 0
            THEN
                _frompos := onfrom
            ELSE
                _frompos := -onfrom;
            (*ENDIF*) 
            IF  outer_join = right_outer_join
            THEN
                BEGIN
                IF  onfrom > 0
                THEN
                    BEGIN
                    selrec.selr_selectbuffer.result.buf[onto] := csp_undef_byte;
                    g10fil1 ('VKB741',   3,    
                          sizeof (selrec.selr_selectbuffer.result.buf),
                          selrec.selr_selectbuffer.result.buf, onto + 1,
                          onlen - 1, csp_defined_byte,
                          m.mb_trns^.trError_gg00)
                    END
                ELSE
                    BEGIN
                    (* *** constant expression in outputlist *** *)
                    (* h.b. PTS 1104165 *)
                    k74_const_output_expression (m, selrec,
                          getrec.gi_n_pos_s.posarr[ _ix ]);
                    END;
                (*ENDIF*) 
                END
            ELSE
                g10mv5 ('VKB741',   4,    
                      sizeof(selrec.selr_selectbuffer.rbuf),
                      sizeof(selrec.selr_selectbuffer.result.buf),
                      selrec.selr_selectbuffer.rbuf,
                      selrec.selr_r_currpos + _frompos,
                      selrec.selr_selectbuffer.result.buf,
                      onto, onlen, m.mb_trns^.trError_gg00);
            (*ENDIF*) 
            END;
        (*ENDWITH*) 
    (*ENDFOR*) 
(*ENDIF*) 
;
(* move columns from earlier join step *)
FOR _ix := 1 TO getrec.gi_njrec.n_j_cnt DO
    WITH getrec.gi_njrec.n_j_arr[_ix] DO
        BEGIN
        IF  jfrom <= 0
        THEN
            BEGIN
            _l := jlen - 1;
            _t := jto;
            _f := - jfrom;  (* jfrom < 0 *)
            FOR _j := 0 TO _l DO
                selrec.selr_selectbuffer.result.buf[ _t+_j ] :=
                      chr(255 - ord(selrec.selr_selectbuffer.result.buf[ _f+_j ]));
            (*ENDFOR*) 
            END
        ELSE
            BEGIN
            _t := jto;
            _f := jfrom;
            IF  _t <> _f
            THEN
                g10mv5 ('VKB741',   5,    
                      sizeof(selrec.selr_selectbuffer.result.buf),
                      sizeof(selrec.selr_selectbuffer.result.buf),
                      selrec.selr_selectbuffer.result.buf, _f,
                      selrec.selr_selectbuffer.result.buf, _t,
                      jlen, m.mb_trns^.trError_gg00);
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDWITH*) 
(*ENDFOR*) 
;
(* *** one_join_phase begin *** *)
_aux_mresqual_cnt := 0;
IF  (m.mb_qual^.mresqual_cnt > 0) AND (m.mb_trns^.trError_gg00 = e_ok)
THEN
    BEGIN
    _aux_mresqual_pos  := m.mb_qual^.mresqual_pos;
    _aux_mresqual_cnt  := m.mb_qual^.mresqual_cnt;
    _aux_mqual_pos     := m.mb_qual^.mqual_pos;
    _aux_mqual_cnt     := m.mb_qual^.mqual_cnt;
    _aux_optimize_pos  := m.mb_qual^.mst_optimize_pos;
    m.mb_qual^.mst_optimize_pos  := 0;
    m.mb_qual^.mqual_pos         := m.mb_qual^.mresqual_pos;
    m.mb_qual^.mqual_cnt         := m.mb_qual^.mresqual_cnt;
    m.mb_qual^.mresqual_pos      := 0;
    m.mb_qual^.mresqual_cnt      := 0;
    g04init_select_fields (_sel, @m.mb_data^.mbp_buf,
          m.mb_data_size, m.mb_work_st,
          m.mb_work_st_max, m.mb_workbuf,
          m.mb_workbuf_size, m.mb_qual^.msqlmode);
    _sel.sfp_bd_mess_type    := m_select;
    _sel.sfp_result_wanted   := true;
    _sel.sfp_m_result_addr   := @selrec.selr_selectbuffer.result;
    _sel.sfp_m_result_size   := sizeof (selrec.selr_selectbuffer.result);
    _sel.sfp_first_qual      := c_first_qual;
    _sel.sfp_is_first_record := false;
    IF  (m.mb_st^ [ m.mb_qual^.mqual_pos ].etype = st_jump_output)
    THEN
        k71col_select (m.mb_trns^, _sel, m.mb_qual^.mstack_desc,
              selrec.selr_selectbuffer.result, _dummy_bool)
    ELSE
        k71sel_qualification_test(m, _sel, NOT c_check_new_rec,
              selrec.selr_selectbuffer.result);
    (*ENDIF*) 
    (* *** d_keylen (vak690)  *** *)
    selrec.selr_selectbuffer.result.keylen :=
          m.mb_st^[ m.mb_qual^.mstrat_pos + 1].ecol_pos;
&   ifdef trace
    t01basis_error (kb, 'trError     ', m.mb_trns^.trError_gg00);
&   endif
    IF  (m.mb_trns^.trError_gg00 = e_qual_violation)
    THEN
        searchrec.sr_refused_by_ophase := true;
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  (m.mb_trns^.trError_gg00 = e_ok)
THEN
    IF  selrec.selr_join_with_func
    THEN
        BEGIN
        _aux_keyl := selrec.selr_keyl;
        (* *** d_keylen (vak690)  *** *)
        selrec.selr_keyl := m.mb_st^[ m.mb_qual^.mstrat_pos + 1].ecol_pos;
        ;
        k721function_add (m, selrec, NOT c_aggr);
        selrec.selr_keyl := _aux_keyl;
        END
    ELSE
        BEGIN
        searchrec.sr_res_cnt := searchrec.sr_res_cnt + 1;
        k721add_into_result (m.mb_trns^, selrec, m.mb_next_mblock);
        END
    (*ENDIF*) 
ELSE
    IF  (m.mb_trns^.trError_gg00 = e_qual_violation)
    THEN
        m.mb_trns^.trError_gg00 := e_ok;
    (*ENDIF*) 
(*ENDIF*) 
IF  (_aux_mresqual_cnt > 0)
THEN
    BEGIN
    m.mb_qual^.mresqual_pos     := _aux_mresqual_pos;
    m.mb_qual^.mresqual_cnt     := _aux_mresqual_cnt;
    m.mb_qual^.mqual_pos        := _aux_mqual_pos;
    m.mb_qual^.mqual_cnt        := _aux_mqual_cnt;
    m.mb_qual^.mst_optimize_pos := _aux_optimize_pos
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741check_conversions (
            VAR m              : tgg_mess_block;
            VAR conv_st_pos    : conv_arr;
            VAR conv_cnt       : integer;
            VAR last_field_pos : integer;
            VAR stoplength     : integer;
            selr_first_jlen    : integer);
 
VAR
      _i         : integer;
      _test_pos  : integer;
      _end_found : boolean;
 
BEGIN
stoplength := 0;
conv_cnt   := 0;
_i         := 1;
_end_found := false;
WHILE (NOT _end_found) DO
    BEGIN
    IF  m.mb_st^[ _i ].etype = st_fixkey
    THEN
        stoplength := stoplength + m.mb_st^[ _i ].elen_var
    ELSE
        IF  (m.mb_st^[ _i ].etype = st_output)
        THEN
            BEGIN
            _test_pos := pred (_i);
            IF  m.mb_st^[ _test_pos ].eop = op_none
            THEN
                _test_pos := pred (_test_pos);
            (*ENDIF*) 
            CASE m.mb_st^[ _test_pos ].eop OF
                op_ascii :
                    BEGIN
                    conv_cnt := succ (conv_cnt);
                    WITH conv_st_pos[ conv_cnt ] DO
                        BEGIN
                        ct_st_pos := _i;
                        ct_codeno := cgg_to_ebcdic;
                        END;
                    (*ENDWITH*) 
                    END;
                op_ebcdic :
                    BEGIN
                    conv_cnt := succ (conv_cnt);
                    WITH conv_st_pos[ conv_cnt ] DO
                        BEGIN
                        ct_st_pos := _i;
                        ct_codeno := cgg_to_ascii;
                        END;
                    (*ENDWITH*) 
                    END;
                OTHERWISE ;
                END;
            (*ENDCASE*) 
            END;
        (*ENDIF*) 
    (*ENDIF*) 
    IF  ((m.mb_st^[ _i ].etype <> st_output) OR
        ((m.mb_st^[ _i ].epos + m.mb_st^[ _i ].elen_var) <
        (selr_first_jlen + cgg_rec_key_offset + 1)))
    THEN
        _i := succ (_i)
    ELSE
        _end_found := true;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
last_field_pos := m.mb_st^[ _i ].epos;
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741check_inv_conversions (
            VAR m              : tgg_mess_block;
            VAR conv_st_pos    : conv_arr;
            VAR conv_cnt       : integer;
            VAR last_field_pos : integer;
            VAR field_cnt      : integer;
            VAR field_pos      : integer;
            VAR descending     : boolean;
            first_jlen         : integer);
 
VAR
      _i         : integer;
      _test_pos  : integer;
      _end_found : boolean;
 
BEGIN
field_cnt  := 0;
field_pos  := 0;
descending := false;
conv_cnt   := 0;
_i         := 1;
_end_found := false;
WHILE (NOT _end_found) DO
    BEGIN
    IF  (m.mb_st^[ _i ].etype = st_output)
    THEN
        BEGIN
        field_cnt := succ (field_cnt);
        _test_pos  := pred (_i);
        IF  m.mb_st^[ _test_pos ].eop = op_none
        THEN
            _test_pos := pred (_test_pos);
        (*ENDIF*) 
        CASE m.mb_st^[ _test_pos ].eop OF
            op_order_desc,
            op_unique_desc :
                BEGIN
                conv_cnt := succ (conv_cnt);
                WITH conv_st_pos[ conv_cnt ] DO
                    BEGIN
                    ct_st_pos  := _i;
                    ct_codeno  := 0;
                    ct_is_desc := true;
                    END;
                (*ENDWITH*) 
                descending := true;
                IF  (field_pos = 0)
                THEN
                    field_pos := _test_pos
                ELSE
                    field_pos := -1;
                (*ENDIF*) 
                END;
            op_order_desc_ascii,
            op_unique_desc_ascii :
                BEGIN
                conv_cnt := succ (conv_cnt);
                WITH conv_st_pos[ conv_cnt ] DO
                    BEGIN
                    ct_st_pos  := _i;
                    ct_codeno  := cgg_to_ebcdic;
                    ct_is_desc := true;
                    END;
                (*ENDWITH*) 
                descending := true;
                IF  (field_pos = 0)
                THEN
                    field_pos := _test_pos
                ELSE
                    field_pos := -1;
                (*ENDIF*) 
                m.mb_st^[ _test_pos ].eop := op_ascii;
                END;
            op_order_desc_ebcdic,
            op_unique_desc_ebcdic :
                BEGIN
                conv_cnt := succ (conv_cnt);
                WITH conv_st_pos[ conv_cnt ] DO
                    BEGIN
                    ct_st_pos  := _i;
                    ct_codeno  := cgg_to_ascii;
                    ct_is_desc := true;
                    END;
                (*ENDWITH*) 
                descending := true;
                IF  (field_pos = 0)
                THEN
                    field_pos := _test_pos
                ELSE
                    field_pos := -1;
                (*ENDIF*) 
                m.mb_st^[ _test_pos ].eop := op_ebcdic;
                END;
            op_ascii :
                BEGIN
                conv_cnt := succ (conv_cnt);
                WITH conv_st_pos[ conv_cnt ] DO
                    BEGIN
                    ct_st_pos  := _i;
                    ct_codeno  := cgg_to_ebcdic;
                    ct_is_desc := false;
                    END;
                (*ENDWITH*) 
                END;
            op_ebcdic :
                BEGIN
                conv_cnt := succ (conv_cnt);
                WITH conv_st_pos[ conv_cnt ] DO
                    BEGIN
                    ct_st_pos  := _i;
                    ct_codeno  := cgg_to_ascii;
                    ct_is_desc := false;
                    END;
                (*ENDWITH*) 
                END;
            OTHERWISE ;
            END;
        (*ENDCASE*) 
        END;
    (*ENDIF*) 
    IF  ((m.mb_st^[ _i ].etype <> st_output) OR
        ((m.mb_st^[ _i ].epos + m.mb_st^[ _i ].elen_var) <
        (first_jlen + cgg_rec_key_offset+1)))
    THEN
        _i := succ (_i)
    ELSE
        _end_found := true;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
last_field_pos := m.mb_st^[ _i ].epos;
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741compare_two_records (
            VAR selrec          : tkb7_select_param;
            VAR searchrec       : search_rec;
            VAR linkrec         : tgg07_KbJoinRec;
            VAR sel             : tgg_select_fields_param;
            VAR fulfilled       : boolean;
            VAR first_fulfilled : boolean;
            VAR end_of_range    : boolean);
 
VAR
      _first            : boolean;
      _restore_def_byte : boolean;
      _op               : tgg_stack_op_type;
      _linkcnt          : integer;
      _lc_result        : tsp_lcomp_result;
      _eq_cnt           : integer;
      _lpos             : integer;
      _rpos             : integer;
      _ix               : integer;
      _compare_ok       : integer;
      _m_def_byte1      : char;
      _m_def_byte2      : char;
 
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;
end_of_range        := false;
_eq_cnt             := _linkcnt;
&IFDEF TRACE
t01int4 (kb, 'linkcnt     ', ord(_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 - 1;
        _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);
        t01buf1(kb, searchrec.sr_nptr.np_ptr^,
              _lpos, _lpos + kbji_parts[ 1 ].kboj_len - 1);
        t01op (kb, 'operator    ', _op);
        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,
                  searchrec.sr_nptr.np_ptr^, _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
                _restore_def_byte := true;
                _m_def_byte1      := searchrec.sr_nptr.np_ptr^.nd_body[_lpos];
                _m_def_byte2      := selrec.selr_selectbuffer.rbuf[_rpos];
                searchrec.sr_nptr.np_ptr^.nd_body[_lpos] := searchrec.sr_nptr.np_ptr^.nd_body
                      [selrec.selr_l_currpos + selrec.selr_l_defbyte_pos - 1];
                selrec.selr_selectbuffer.rbuf[_rpos] :=
                      selrec.selr_selectbuffer.rbuf[selrec.selr_r_currpos + selrec.selr_l_defbyte_pos]
                END
            ELSE
                _restore_def_byte := false;
            (*ENDIF*) 
&           ifdef trace
            kb741trace_luc (searchrec.sr_nptr.np_ptr^, _lpos,
                  kbji_parts[1].kboj_len,
                  @selrec.selr_selectbuffer.rbuf,
                  _rpos, kbji_parts[2].kboj_len,
                  _lc_result);
&           else
            s30luc (searchrec.sr_nptr.np_ptr^, _lpos, kbji_parts[1].kboj_len,
                  selrec.selr_selectbuffer.rbuf, _rpos,
                  kbji_parts[2].kboj_len,
                  _lc_result);
&           endif
            IF  _restore_def_byte
            THEN
                (* multiple key- or indexcolums *)
                (* with different lengths *)
                BEGIN
                searchrec.sr_nptr.np_ptr^.nd_body [_lpos] := _m_def_byte1;
                selrec.selr_selectbuffer.rbuf [_rpos] := _m_def_byte2
                END;
            (*ENDIF*) 
            CASE _lc_result OF
                l_equal :
                    BEGIN
                    fulfilled :=
                          (_op <> op_ne) AND (_op <> op_lt) AND
                          (_op <> op_gt);
                    (* *** R3  chars < ' ' at end of fields *** *)
                    _m_def_byte1 := searchrec.sr_nptr.np_ptr^.nd_body[ _lpos ];
                    IF  (selrec.selr_l_defbyte_pos <> -1) AND
                        (ord (kbji_parts[ 2 ].kboj_op) <> 0)
                    THEN
                        _m_def_byte1 := searchrec.sr_nptr.np_ptr^.nd_body
                              [selrec.selr_l_currpos + selrec.selr_l_defbyte_pos];
&                   ifdef trace
                    (*ENDIF*) 
                    t01int4 (kb, 'fulfilled   ', ord (fulfilled));
                    t01int4 (kb, 'first       ', ord (_first));
                    t01int4 (kb, 'm_def_byte1 ', ord (_m_def_byte1));
&                   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  searchrec.sr_nptr.np_ptr^.nd_body[ _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*) 
                    IF  (_op = op_lt      )     AND
                        (_lc_result <> l_undef) AND
                        (_eq_cnt = _linkcnt)     AND
                        (_linkcnt > 1     )
                    THEN
                        end_of_range := true;
                    (*ENDIF*) 
                    _eq_cnt := _eq_cnt + 1
                    END;
                l_less :
                    BEGIN
                    fulfilled :=
                          (_op <> op_eq) AND (_op <> op_gt) AND
                          (_op <> op_ge);
                    (* *** R3  chars < ' ' at end of fields *** *)
                    _m_def_byte1 := searchrec.sr_nptr.np_ptr^.nd_body[ _lpos ];
                    IF  (selrec.selr_l_defbyte_pos <> -1) AND
                        (ord (kbji_parts[ 2 ].kboj_op) <> 0)
                    THEN
                        _m_def_byte1 := searchrec.sr_nptr.np_ptr^.nd_body
                              [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 (searchrec.sr_nptr.np_ptr^, _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 := searchrec.sr_nptr.np_ptr^.nd_body[ _lpos ];
                    IF  (selrec.selr_l_defbyte_pos <> -1) AND
                        (ord (kbji_parts[ 2 ].kboj_op) <> 0)
                    THEN
                        _m_def_byte1 := searchrec.sr_nptr.np_ptr^.nd_body
                              [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 (searchrec.sr_nptr.np_ptr^, _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*) 
                    IF  NOT fulfilled          AND
                        (_lc_result <> l_undef) AND
                        (_eq_cnt = _linkcnt)     AND
                        (_linkcnt > 1     )
                    THEN
                        end_of_range := true
                    (*ENDIF*) 
                    END;
                l_undef :
                    fulfilled := false
                END;
            (*ENDCASE*) 
            IF  _first
            THEN
                BEGIN
                IF  (_lc_result = l_undef) AND
                    NOT linkrec.kbjr_right_oj
                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, 'first_fulfil', ord (first_fulfilled));
&endif
END;
 
(*------------------------------*) 
 
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);
 
VAR
      _e         : tgg_basis_error;
      _searchrec : search_rec;
 
BEGIN
kb741init (m, getrec.gi_minfo.o_tree, getrec, selrec, _searchrec);
CASE stenum OF
    strat_join_all_keys_equal, strat_join_key_equal :
        kb741key_direct_search (m, getrec, selrec, sel, _searchrec);
    strat_join_key_range, strat_join_key_next :
        kb741key_next_search (m, getrec, selrec, sel, _searchrec);
    strat_join_all_inv_equal, strat_join_inv :
        BEGIN
        kb741build_inv_treeid  (m, selrec, invindex, invroot);
        kb741inv_direct_search (m, getrec, selrec, sel, _searchrec);
        END;
    strat_join_inv_range :
        BEGIN
        kb741build_inv_treeid  (m, selrec, invindex, invroot);
        kb741inv_next_search (m, getrec, selrec, sel, _searchrec);
        END;
    OTHERWISE
        m.mb_trns^.trError_gg00 := e_unknown_strategy;
    END;
(*ENDCASE*) 
IF  getrec.gi_linkrec.kbjr_right_oj
THEN
    k741finish_r_outer_join (m, getrec, selrec);
(*ENDIF*) 
IF  _searchrec.sr_nptr.np_ptr <> NIL
THEN
    BEGIN
    _e := m.mb_trns^.trError_gg00;
    b07release_result_leaf (m.mb_trns^,
          getrec.gi_minfo.o_tree, NOT c_node_changed, _searchrec.sr_nptr);
    IF  _e <> e_ok
    THEN
        m.mb_trns^.trError_gg00 := _e
    (*ENDIF*) 
    END
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      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);
 
VAR
      _dummy                 : boolean;
      _result_possible       : boolean;
      _e                     : tgg_basis_error;
      _ic2                   : tsp_int_map_c2;
      _curr_rescount         : tsp_int4;
      _searchrec             : search_rec;
      _count                 : integer;
      _compare_len           : integer;
      _ix                    : integer;
      _aux_countresult       : integer;
 
BEGIN
&ifdef trace
t01int4 (kb, 'l_outer_join', ord (getrec.gi_linkrec.kbjr_left_oj));
t01int4 (kb, 'r_outer_join', ord (getrec.gi_linkrec.kbjr_right_oj));
&endif
_searchrec.sr_res_cnt := 0;
selrec.selr_r_currpos := 0;
selrec.selr_r_endpos  := selrec.selr_recl + selrec.selr_r_currpos;
_aux_countresult      := selrec.selr_countresult;
g10mv5 ('VKB741',   6,    
      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);
_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          := true;
g10fil ('VKB741',   7,    
      sizeof(_searchrec.sr_lsearchkey.k), _searchrec.sr_lsearchkey.k, 1,
      sizeof(_searchrec.sr_lsearchkey.k), chr(0),
      m.mb_trns^.trError_gg00);
WITH getrec.gi_linkrec.kbjr_jarr[ 1 ] DO
    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(kbji_parts[ 2 ].kboj_op) OF
            c_left_len_eq_right_len, c_left_len_lt_right_len :
                selrec.selr_first_jlen := kbji_parts[ 1 ].kboj_len;
            c_left_len_gt_right_len :
                selrec.selr_first_jlen := kbji_parts[ 2 ].kboj_len;
            END;
        (*ENDCASE*) 
        CASE kbji_parts[ 1 ].kboj_op OF
            op_le, op_lt, op_ne :
                _searchrec.sr_lsearchkey.len := 0;
            op_eq :
                BEGIN
                IF  (ord (kbji_parts[2].kboj_op) = 1)
                THEN
                    IF  kbji_parts[ 1 ].kboj_len <
                        kbji_parts[ 2 ].kboj_len
                    THEN
                        BEGIN
                        _count := s30lnr_defbyte(@selrec.selr_selectbuffer.result.buf,
                              selrec.selr_selectbuffer.result.buf[ cgg_rec_key_offset+1 ],
                              cgg_rec_key_offset+1,
                              kbji_parts[ 2 ].kboj_len);
                        IF  _count > kbji_parts[ 1 ].kboj_len
                        THEN
                            _result_possible := false;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                (*ENDIF*) 
                _compare_len       := selrec.selr_first_jlen;
                _searchrec.sr_lsearchkey.len := kbji_parts[ 2 ].kboj_len;
                g10mv1 ('VKB741',   8,    
                      sizeof(selrec.selr_selectbuffer.result.buf),
                      sizeof(_searchrec.sr_lsearchkey.k),
                      selrec.selr_selectbuffer.result.buf,
                      cgg_rec_key_offset+1, _searchrec.sr_lsearchkey.k, 1,
                      selrec.selr_first_jlen, m.mb_trns^.trError_gg00);
                END;
            op_ge :
                BEGIN
                _searchrec.sr_lsearchkey.len := kbji_parts[ 2 ].kboj_len;
                g10mv1 ('VKB741',   9,    
                      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);
                _searchrec.sr_lsearchkey.len :=
                      s30lnr_defbyte(@selrec.selr_selectbuffer.rbuf,
                      selrec.selr_selectbuffer.rbuf[ cgg_rec_key_offset+1 ],
                      cgg_rec_key_offset+1,
                      kbji_parts[ 2 ].kboj_len);
&               ifdef trace
                t01buf (kb, selrec.selr_selectbuffer.rbuf,
                      1,4 + selrec.selr_first_jlen);
                t01lkey (kb, _searchrec.sr_lsearchkey);
&               endif
                END;
            op_gt :
                BEGIN
                _searchrec.sr_lsearchkey.len := kbji_parts[ 2 ].kboj_len;
                g10mv1 ('VKB741',  10,    
                      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);
                _searchrec.sr_lsearchkey.len :=
                      s30lnr_defbyte(@selrec.selr_selectbuffer.rbuf,
                      selrec.selr_selectbuffer.rbuf[ cgg_rec_key_offset+1 ],
                      cgg_rec_key_offset+1,
                      kbji_parts[ 2 ].kboj_len);
&               ifdef trace
                t01buf (kb, selrec.selr_selectbuffer.rbuf,1,cgg_rec_key_offset + selrec.selr_first_jlen);
                t01lkey (kb, _searchrec.sr_lsearchkey);
&               endif
                kb741nlbuild_next_lkey (_searchrec.sr_lsearchkey,
                      selrec.selr_first_jlen)
                END;
            OTHERWISE
                BEGIN
                _searchrec.sr_lsearchkey.len := 0;
                END;
            END;
        (*ENDCASE*) 
        END;
    (*ENDIF*) 
(*ENDWITH*) 
_curr_rescount := _searchrec.sr_res_cnt;
IF  _result_possible
THEN
    BEGIN
    _searchrec.sr_left_tree_pos.tpsPno_gg00  := NIL_PAGE_NO_GG00;
    _searchrec.sr_nptr.np_ptr                := NIL;
    _searchrec.sr_left_last_pno              := NIL_PAGE_NO_GG00;
    _searchrec.sr_prepare_for_upd            := getrec.gi_linkrec.kbjr_right_oj;
    _searchrec.sr_refused_by_ophase          := false;
    IF  (m.mb_trns^.trError_gg00 = e_ok)
    THEN
        kb741get_left_leaf (m.mb_trns^, selrec, _searchrec,
              getrec.gi_minfo.o_tree, _searchrec.sr_lsearchkey, c_get_next);
    (*ENDIF*) 
    IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
    THEN
        _searchrec.sr_error_l := e_cancelled;
    (*ENDIF*) 
    selrec.selr_fulfilled := false;
    IF  (_searchrec.sr_error_l = e_ok) AND
        (m.mb_trns^.trError_gg00 = e_ok)
    THEN
        kb741l_join_with_left_records (m,
              getrec, selrec, sel, _searchrec, _dummy);
    (*ENDIF*) 
    IF  ((_searchrec.sr_error_l = e_ok)             OR
        ( _searchrec.sr_error_l = e_buffer_limit)     )    AND
        (m.mb_trns^.trError_gg00 = e_ok)           AND
        (_aux_countresult = selrec.selr_countresult) 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);
        t01int4 (ak_join, 'selr_l_currp', selrec.selr_l_currpos);
        t01buf1 (ak_join, _searchrec.sr_nptr.np_ptr^,
              selrec.selr_l_currpos + cgg_rec_key_offset + 1,
              selrec.selr_l_currpos + listkey.len - 1);
&       ENDIF
        listkey.len := getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 2 ].kboj_len;
        g10mv4 ('VKB741',  11,    
              sizeof(_searchrec.sr_nptr.np_ptr^), sizeof(listkey.k),
              _searchrec.sr_nptr.np_ptr^,
              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*) 
    IF  _searchrec.sr_nptr.np_ptr <> NIL
    THEN
        BEGIN
        _e := m.mb_trns^.trError_gg00;
        b07release_result_leaf (m.mb_trns^, getrec.gi_minfo.o_tree,
              _searchrec.sr_prepare_for_upd, _searchrec.sr_nptr);
        IF  _e <> e_ok
        THEN
            m.mb_trns^.trError_gg00 := _e
        (*ENDIF*) 
        END
    (*ENDIF*) 
    END
ELSE
    m.mb_trns^.trError_gg00 := e_ok;
(*ENDIF*) 
IF  (_curr_rescount = _searchrec.sr_res_cnt)
    AND
    getrec.gi_linkrec.kbjr_left_oj AND NOT _searchrec.sr_refused_by_ophase
    AND
    (m.mb_trns^.trError_gg00 = e_ok)
THEN
    BEGIN
    kb741build_new_rec (m, getrec, selrec, _searchrec,
          c_right_needed, left_outer_join);
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      k741finish_r_outer_join (
            VAR m      : tgg_mess_block;
            VAR getrec : tkb7_get_param;
            VAR selrec : tkb7_select_param);
 
VAR
      _e         : tgg_basis_error;
      _rec_len   : tsp_int_map_c2;
      _key_len   : tsp_int_map_c2;
      _zerokey   : tgg_lkey;
      _searchrec : search_rec;
 
BEGIN
(* find all records of left result, that have not been found *)
(* by the previous scan of the right table.                  *)
(* These records are marked by a record length different     *)
(* from cgg_rec_key_offset + key length + 1                  *)
IF  m.mb_trns^.trError_gg00 = e_ok
THEN
    BEGIN
    _zerokey.len                    := 0;
    _searchrec.sr_left_tree_pos.tpsPno_gg00   := NIL_PAGE_NO_GG00;
    _searchrec.sr_left_tree_pos.tpsIndex_gg00 := 0;
    _searchrec.sr_nptr.np_ptr       := NIL;
    _searchrec.sr_left_last_pno               := NIL_PAGE_NO_GG00;
    _searchrec.sr_left_min_index              := 0;
    _searchrec.sr_prepare_for_upd             := false;
    _searchrec.sr_refused_by_ophase           := false;
    _searchrec.sr_res_cnt                     := 0;
    REPEAT
        WITH _searchrec.sr_left_tree_pos DO
            BEGIN
            tpsIndex_gg00 := tpsIndex_gg00 + 1;
            IF  tpsIndex_gg00 > _searchrec.sr_left_min_index
            THEN
                kb741get_left_leaf (m.mb_trns^, selrec, _searchrec,
                      getrec.gi_minfo.o_tree, _zerokey, c_get_next);
            (*ENDIF*) 
            IF  _searchrec.sr_error_l = e_ok
            THEN
                BEGIN
                selrec.selr_l_currpos :=
                      _searchrec.sr_nptr.np_ptr^.
                      nd_pointer_list[MAX_POINTERINDEX_BD00 - tpsIndex_gg00];
                _rec_len.map_c2[1] :=
                      _searchrec.sr_nptr.np_ptr^.
                      nd_body[selrec.selr_l_currpos  ];
                _rec_len.map_c2[2] :=
                      _searchrec.sr_nptr.np_ptr^.
                      nd_body[selrec.selr_l_currpos+1];
                _key_len.map_c2[1] :=
                      _searchrec.sr_nptr.np_ptr^.
                      nd_body[selrec.selr_l_currpos+2];
                _key_len.map_c2[2] :=
                      _searchrec.sr_nptr.np_ptr^.
                      nd_body[selrec.selr_l_currpos+3];
&               ifdef trace
                t01int4 (kb, 'rec_len     ', _rec_len.map_int);
                t01int4 (kb, 'key_len     ', _key_len.map_int);
&               endif
                IF  _rec_len.map_int <>
                    cgg_rec_key_offset + _key_len.map_int + 1
                THEN
                    kb741build_new_rec (m, getrec, selrec,
                          _searchrec, c_right_needed,
                          right_outer_join)
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDWITH*) 
    UNTIL
        (_searchrec.sr_error_l <> e_ok) OR (m.mb_trns^.trError_gg00 <> e_ok);
    (*ENDREPEAT*) 
    IF  (_searchrec.sr_error_l <> e_no_next_record) AND
        (m.mb_trns^.trError_gg00 = e_ok)
    THEN
        m.mb_trns^.trError_gg00 := _searchrec.sr_error_l;
    (*ENDIF*) 
    IF  _searchrec.sr_nptr.np_ptr <> NIL
    THEN
        BEGIN
        _e := m.mb_trns^.trError_gg00;
        b07release_result_leaf (m.mb_trns^, getrec.gi_minfo.o_tree,
              _searchrec.sr_prepare_for_upd, _searchrec.sr_nptr);
        IF  _e <> e_ok
        THEN
            m.mb_trns^.trError_gg00 := _e
        (*ENDIF*) 
        END
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      k741last_defined_byte_pos (
            VAR m       : tgg_mess_block;
            VAR selrec  : tkb7_select_param;
            VAR linkrec : tgg07_KbJoinRec);
 
CONST
      c_exit_loop = csp_maxint2;
 
VAR
      _len    : integer;
      _ix     : integer;
      _maxlen : integer;
 
BEGIN
selrec.selr_l_defbyte_pos := -1;
_maxlen := linkrec.kbjr_jarr[1].kbji_parts[2].kboj_len;
_ix  := m.mb_qual^.mqual_pos;
_len := 0;
WHILE _ix < m.mb_qual^.mqual_pos + m.mb_qual^.mqual_cnt DO
    IF  m.mb_st^[_ix].etype = st_output
    THEN
        BEGIN
        _len := _len + m.mb_st^[_ix].elen_var;
        IF  _len >= _maxlen
        THEN
            BEGIN
            selrec.selr_l_defbyte_pos := m.mb_st^[_ix].epos;
            _ix := c_exit_loop
            END
        ELSE
            _ix := _ix + 1
        (*ENDIF*) 
        END
    ELSE
        _ix := _ix + 1;
    (*ENDIF*) 
(*ENDWHILE*) 
&ifdef trace
t01int4 (kb, 'l_defbyte_po', selrec.selr_l_defbyte_pos)
&     endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      k741sequential_join (
            VAR m      : tgg_mess_block;
            VAR getrec : tkb7_get_param;
            VAR selrec : tkb7_select_param);
 
BEGIN
k741last_defined_byte_pos (m, selrec, getrec.gi_linkrec);
k720_select (m, getrec, selrec);
IF  getrec.gi_linkrec.kbjr_right_oj
THEN
    k741finish_r_outer_join (m, getrec, selrec)
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741nlbuild_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
      kb741build_inv_treeid (
            VAR m           : tgg_mess_block;
            VAR selrec      : tkb7_select_param;
            invindex        : integer;
            invroot         : tsp00_PageNo);
 
BEGIN
&ifdef TRACE
t01int4 (kb, 'invindex    ', invindex);
&endif
selrec.selr_inv_id                           := m.mb_qual^.mtree;
selrec.selr_inv_id.fileName_gg00[2]          := chr(invindex);
selrec.selr_inv_id.fileTfn_gg00              := tfnMulti_egg00;
selrec.selr_inv_id.fileVersion_gg00.ci2_gg00 := cgg_dummy_file_version;
selrec.selr_inv_id.fileRoot_gg00             := invroot;
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741convert_inv_key (
            VAR m              : tgg_mess_block;
            VAR conv_st_pos    : conv_arr;
            conv_cnt           : integer;
            VAR inv_key        : tgg_lkey);
 
VAR
      _ix : integer;
      _jx : integer;
 
BEGIN
FOR _ix := 1 TO conv_cnt DO
    WITH conv_st_pos[_ix] DO
        BEGIN
        IF  ct_codeno <> 0
        THEN
            s30map (g02codetables.tables[ct_codeno],
                  inv_key.k, m.mb_st^[ct_st_pos].epos - cgg_rec_key_offset,
                  inv_key.k, m.mb_st^[ct_st_pos].epos - cgg_rec_key_offset,
                  m.mb_st^[ct_st_pos].elen_var);
        (*ENDIF*) 
        IF  ct_is_desc
        THEN
            BEGIN
            FOR _jx := (m.mb_st^[ct_st_pos].epos - cgg_rec_key_offset) TO
                  (m.mb_st^[ct_st_pos].epos +
                  m.mb_st^[ct_st_pos].elen_var - cgg_rec_key_offset - 1) DO
                inv_key.k[_jx] := chr(255 - ord(inv_key.k[_jx]));
            (*ENDFOR*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDWITH*) 
(*ENDFOR*) 
END;
 
(*------------------------------*) 
 
FUNCTION
      kb741eval_invkey_len (
            VAR m         : tgg_mess_block;
            VAR selrec    : tkb7_select_param;
            field_cnt     : integer;
            test_pos      : integer) : integer;
 
VAR
      _invkey : tgg_lkey;
 
BEGIN
IF  (test_pos > 0) AND (field_cnt = 1) AND
    (m.mb_st^[test_pos].etype in [st_fixkey, st_fixcol])
THEN
    kb741eval_invkey_len := m.mb_st^[test_pos].elen_var
ELSE
    BEGIN
    _invkey.k[1] := chr(1);
    _invkey.len  := 1;
    b03next_invkey (m.mb_trns^, selrec.selr_inv_id, true, _invkey);
    IF  (m.mb_trns^.trError_gg00 = e_ok) OR
        (m.mb_trns^.trError_gg00 = e_key_not_found)
    THEN
        BEGIN
        m.mb_trns^.trError_gg00      := e_ok;
        kb741eval_invkey_len := _invkey.len
        END
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741inv_direct_search (
            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);
 
VAR
      _error_i            : tgg_basis_error;
      _is_descending      : boolean;
      _skip_left          : boolean;
      _restore_left       : boolean; (* h.b. PTS 1104826 *)
      _use_stopprim       : boolean;
      _keyLen             : tsp00_IntMapC2;
      _bd_invset          : tgg_bd_inv_set;
      _last_inv_field_pos : integer;
      _conv_cnt           : integer;
      _inv_keylen         : integer;
      _field_cnt          : integer;
      _test_pos           : integer;
      _key_pos            : integer;
      _j                  : integer;
      _inv_buf_fill_len   : integer;
      _curr_rescount      : tsp_int4;
      _primkeycnt         : tsp_int4;
      _curr_tree_pos      : tgg00_FilePos;
      _conv_st_pos        : conv_arr;
 
BEGIN
_use_stopprim := sel.sfp_bd_use_stopkey;
kb741check_inv_conversions (m, _conv_st_pos, _conv_cnt,
      _last_inv_field_pos, _field_cnt, _test_pos, _is_descending,
      selrec.selr_first_jlen);
selrec.selr_l_defbyte_pos := _last_inv_field_pos;
IF  _is_descending
THEN
    _inv_keylen := kb741eval_invkey_len (m,
          selrec, _field_cnt, _test_pos);
&IFDEF TRACE
(*ENDIF*) 
t01messblock (kb, 'invd mblock ', m);
t01int4 (kb, 'conv_cnt    ', _conv_cnt);
t01int4 (kb, 'last_inv_fld', _last_inv_field_pos);
t01int4 (kb, 'field_cnt   ', _field_cnt);
t01int4 (kb, 'test_pos    ', _test_pos);
t01int4 (kb, 'selr_f_jlen ', selrec.selr_first_jlen);
&ENDIF
IF  _use_stopprim
THEN
    _bd_invset := [primary_stop, incl_first]
ELSE
    _bd_invset := [incl_first];
(*ENDIF*) 
WHILE (m.mb_trns^.trError_gg00 = e_ok) AND (searchrec.sr_error_l = e_ok) DO
    BEGIN
    selrec.selr_l_currpos :=
          searchrec.sr_nptr.np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -
          searchrec.sr_left_tree_pos.tpsIndex_gg00];
    selrec.selr_invkey.len := s30lnr_defbyte (@searchrec.sr_nptr.np_ptr^,
          searchrec.sr_nptr.np_ptr^.nd_body
          [selrec.selr_l_currpos + _last_inv_field_pos -1],
          selrec.selr_l_currpos + _last_inv_field_pos,
          getrec.gi_linkrec.kbjr_jarr[1].kbji_parts[1].kboj_len -
          _last_inv_field_pos + cgg_rec_key_offset) +
          _last_inv_field_pos - cgg_rec_key_offset;
    IF  selrec.selr_invkey.len <= selrec.selr_first_jlen
    THEN
        BEGIN
        g10mv4 ('VKB741',  12,    
              sizeof(searchrec.sr_nptr.np_ptr^), sizeof(selrec.selr_invkey.k),
              searchrec.sr_nptr.np_ptr^,
              selrec.selr_l_currpos + cgg_rec_key_offset,
              selrec.selr_invkey.k, 1, selrec.selr_invkey.len, m.mb_trns^.trError_gg00);
        IF  _conv_cnt > 0
        THEN
            kb741convert_inv_key (m,
                  _conv_st_pos, _conv_cnt, selrec.selr_invkey);
        (*ENDIF*) 
        IF  _is_descending AND (selrec.selr_invkey.len < _inv_keylen)
        THEN
            BEGIN
            IF  selrec.selr_invkey.k [ _last_inv_field_pos - cgg_rec_key_offset ]
                = chr(255 - ord(csp_unicode_def_byte))
            THEN
                BEGIN
                g20unifill (sizeof(selrec.selr_invkey.k),
                      @selrec.selr_invkey.k, selrec.selr_invkey.len+1,
                      _inv_keylen - selrec.selr_invkey.len,
                      csp_unicode_blank);
                FOR _j := selrec.selr_invkey.len + 1 TO _inv_keylen DO
                    selrec.selr_invkey.k[ _j ] :=
                          chr(255 - ord(selrec.selr_invkey.k[ _j ]));
                (*ENDFOR*) 
                END
            ELSE
                g10fil ('VKB741',  13,    
                      sizeof (selrec.selr_invkey.k), selrec.selr_invkey.k,
                      selrec.selr_invkey.len + 1, _inv_keylen - selrec.selr_invkey.len,
                      selrec.selr_invkey.k[_last_inv_field_pos -
                      cgg_rec_key_offset], m.mb_trns^.trError_gg00);
            (*ENDIF*) 
            selrec.selr_invkey.len := _inv_keylen
            END;
        (*ENDIF*) 
        searchrec.sr_rsearchkey.len := selrec.selr_startkey.len;
        g10mv2 ('VKB741',  14,    
              sizeof (selrec.selr_startkey.k), sizeof (searchrec.sr_rsearchkey.k),
              selrec.selr_startkey.k, 1, searchrec.sr_rsearchkey.k, 1,
              selrec.selr_startkey.len, m.mb_trns^.trError_gg00);
        _error_i := e_buffer_limit
        END
    ELSE (* selrec.selr_invkey.len > selrec.selr_first_jlen *)
        _error_i := e_inv_list_not_found;
    (*ENDIF*) 
    _curr_rescount := searchrec.sr_res_cnt;
    _curr_tree_pos := searchrec.sr_left_tree_pos;
    _skip_left     := true;
    _restore_left  := false;  (* h.b. PTS 1104826 *)
    WHILE (_error_i = e_buffer_limit) AND
          (m.mb_trns^.trError_gg00 = e_ok) DO
        BEGIN
        b03get_inv (m.mb_trns^, selrec.selr_inv_id, selrec.selr_invkey,
              searchrec.sr_rsearchkey, selrec.selr_stopkey,
              searchrec.sr_rsearchkey, _bd_invset,
              NOT c_count_only, lckFree_egg00, selrec.selr_selectbuffer.inv_buf.buf,
              _primkeycnt, _inv_buf_fill_len);
        _error_i           := m.mb_trns^.trError_gg00;
        m.mb_trns^.trError_gg00 := e_ok;
        IF  (_error_i = e_ok) OR (_error_i = e_buffer_limit)
        THEN
            BEGIN
            _bd_invset := _bd_invset - [incl_first];
            _key_pos   := 1;
            WHILE (_key_pos < _inv_buf_fill_len) AND
                  (m.mb_trns^.trError_gg00 = e_ok  ) DO
                BEGIN
                _keyLen.mapC2_sp00 [1]    := selrec.selr_selectbuffer.inv_buf.buf[_key_pos];
                _keyLen.mapC2_sp00 [2]    := selrec.selr_selectbuffer.inv_buf.buf[_key_pos+1];
                searchrec.sr_rsearchkey.keyLen_gg00 :=
                      _keyLen.mapInt_sp00;
                g10mv1 ('VKB741',  15,    
                      sizeof (selrec.selr_selectbuffer.inv_buf.buf),
                      sizeof (searchrec.sr_rsearchkey.k), selrec.selr_selectbuffer.inv_buf.buf,
                      _key_pos + 2, searchrec.sr_rsearchkey.k, 1,
                      searchrec.sr_rsearchkey.len, m.mb_trns^.trError_gg00);
                IF  (m.mb_trns^.trError_gg00 = e_ok)
                THEN
                    kb741get_right_record (m, getrec, selrec,
                          mm_direct, searchrec.sr_rsearchkey, sel);
                (*ENDIF*) 
                IF  m.mb_trns^.trError_gg00 = e_ok
                THEN
                    BEGIN
                    IF  _restore_left  (* h.b. PTS 1104826 *)
                    THEN
                        kb741restore_page (m, _curr_tree_pos,
                              getrec.gi_minfo.o_tree, selrec, searchrec);
                    (*ENDIF*) 
                    IF  m.mb_trns^.trError_gg00 = e_ok
                    THEN
                        BEGIN
                        _restore_left  := true; (* h.b. PTS 1104826 *)
                        _skip_left     := false;
                        getrec.gi_linkrec.kbjr_linkcnt    := 2;
                        kb741l_join_with_left_records (m,
                              getrec, selrec, sel, searchrec,
                              _skip_left)
                        END;
                    (*ENDIF*) 
                    END
                ELSE
                    IF  (m.mb_trns^.trError_gg00 = e_key_not_found ) OR
                        (m.mb_trns^.trError_gg00 = e_qual_violation) OR
                        (m.mb_trns^.trError_gg00 = e_view_violation)
                    THEN
                        m.mb_trns^.trError_gg00 := e_ok;
                    (*ENDIF*) 
                (*ENDIF*) 
                _key_pos := _key_pos + searchrec.sr_rsearchkey.len + 2
                END;
            (*ENDWHILE*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDWHILE*) 
    IF  m.mb_trns^.trError_gg00 = e_ok
    THEN
        IF  _error_i <> e_inv_list_not_found
        THEN
            m.mb_trns^.trError_gg00 := _error_i
        ELSE
            IF  (_conv_cnt = 0) AND NOT getrec.gi_linkrec.kbjr_right_oj
            THEN
                BEGIN
                (* next invkey yields new position in *)
                (* left side                          *)
                b03next_invkey (m.mb_trns^, selrec.selr_inv_id,
                      NOT c_inclusive, selrec.selr_invkey);
                IF  m.mb_trns^.trError_gg00 = e_ok
                THEN
                    BEGIN
                    _skip_left := false;
                    kb741synchronize_left_rec (m, selrec.selr_invkey,
                          getrec, searchrec, selrec)
                    END
                ELSE
                    IF  (m.mb_trns^.trError_gg00 = e_no_next_invkey) OR
                        (m.mb_trns^.trError_gg00 = e_inv_list_not_found)
                    THEN
                        BEGIN
                        (* end of right table, stop *)
                        searchrec.sr_error_l           := e_no_next_record;
                        m.mb_trns^.trError_gg00 := e_ok
                        END;
                    (*ENDIF*) 
                (*ENDIF*) 
                END;
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    IF  m.mb_trns^.trError_gg00 = e_ok
    THEN
        IF  getrec.gi_linkrec.kbjr_right_oj AND (_curr_rescount = searchrec.sr_res_cnt)
        THEN
            BEGIN
            IF  NOT _skip_left
            THEN
                kb741restore_page (m, _curr_tree_pos,
                      getrec.gi_minfo.o_tree, selrec, searchrec);
            (*ENDIF*) 
            searchrec.sr_rsearchkey.len := selrec.selr_first_jlen;
            kb741left_scan_to_nxt_key (m, getrec, searchrec, selrec,
                  c_is_right_outer_join)
            END
        ELSE
            IF  _skip_left
            THEN
                BEGIN
                searchrec.sr_rsearchkey.len := selrec.selr_first_jlen;
                kb741left_scan_to_nxt_key (m,
                      getrec, searchrec, selrec,
                      NOT c_is_right_outer_join)
                END;
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
    THEN
        searchrec.sr_error_l := e_cancelled;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
IF  (m.mb_trns^.trError_gg00 =  e_ok  ) AND
    (searchrec.sr_error_l <> e_ok            ) AND
    (searchrec.sr_error_l <> e_no_next_record)
THEN
    m.mb_trns^.trError_gg00 := searchrec.sr_error_l
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741inv_next_search (
            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);
 
VAR
      _error_i            : tgg_basis_error;
      _is_descending      : boolean;
      _skip_left          : boolean;
      _use_stopprim       : boolean;
      _inclusive          : boolean;
      _restore_left       : boolean;
      _lc_result          : tsp_lcomp_result;
      _cmp_result         : tsp_lcomp_result;
      _keyLen            : tsp00_IntMapC2;
      _bd_invset          : tgg_bd_inv_set;
      _last_inv_field_pos : integer;
      _conv_cnt           : integer;
      _field_cnt          : integer;
      _test_pos           : integer;
      _key_pos            : integer;
      _inv_buf_fill_len   : integer;
      _curr_rescount      : tsp_int4;
      _primkeycnt         : tsp_int4;
      _curr_tree_pos      : tgg00_FilePos;
      _conv_st_pos        : conv_arr;
      _curr_invkey        : tgg_lkey;
 
BEGIN
_use_stopprim := sel.sfp_bd_use_stopkey;
kb741check_inv_conversions (m, _conv_st_pos, _conv_cnt,
      _last_inv_field_pos, _field_cnt, _test_pos, _is_descending,
      selrec.selr_first_jlen);
selrec.selr_l_defbyte_pos := _last_inv_field_pos;
WHILE (m.mb_trns^.trError_gg00 = e_ok) AND (searchrec.sr_error_l = e_ok) DO
    BEGIN
    selrec.selr_l_currpos :=
          searchrec.sr_nptr.np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -
          searchrec.sr_left_tree_pos.tpsIndex_gg00];
    _curr_invkey.len := selrec.selr_first_jlen;
    g10mv4 ('VKB741',  16,    
          sizeof(searchrec.sr_nptr.np_ptr^), sizeof(_curr_invkey.k),
          searchrec.sr_nptr.np_ptr^,
          selrec.selr_l_currpos + cgg_rec_key_offset,
          _curr_invkey.k, 1, _curr_invkey.len, m.mb_trns^.trError_gg00);
    IF  _conv_cnt > 0
    THEN
        kb741convert_inv_key (m,
              _conv_st_pos, _conv_cnt, _curr_invkey);
    (*ENDIF*) 
    selrec.selr_invkey.len := _curr_invkey.len;
    g10mv2 ('VKB741',  17,    
          sizeof (_curr_invkey.k), sizeof (selrec.selr_invkey.k),
          _curr_invkey.k, 1, selrec.selr_invkey.k, 1,
          selrec.selr_invkey.len, m.mb_trns^.trError_gg00);
    _curr_tree_pos := searchrec.sr_left_tree_pos;
    _inclusive     := true;
    _skip_left     := true;
    _restore_left  := false;
    _curr_rescount := searchrec.sr_res_cnt;
    REPEAT
        (* execute one inv list *)
        b03next_invkey (m.mb_trns^, selrec.selr_inv_id, _inclusive,
              selrec.selr_invkey);
        _inclusive := false;
        IF  m.mb_trns^.trError_gg00 = e_ok
        THEN
            s30cmp2 (_curr_invkey.k, 1, selrec.selr_first_jlen,
                  selrec.selr_invkey.k, 1, selrec.selr_first_jlen,
                  _lc_result)
        ELSE
            BEGIN
            _lc_result := l_greater;
            IF  ((m.mb_trns^.trError_gg00 = e_no_next_invkey     ) OR
                ( m.mb_trns^.trError_gg00 = e_inv_list_not_found))
                AND
                NOT getrec.gi_linkrec.kbjr_right_oj
            THEN
                BEGIN
                (* end of right table, stop *)
                _skip_left := false;
                searchrec.sr_error_l   := e_no_next_record
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  _lc_result = l_equal
        THEN
            BEGIN
            (* current inv key fulfills prefix condition *)
            (* handle corresponding inv list             *)
            IF  _use_stopprim
            THEN
                _bd_invset := [primary_stop, incl_first]
            ELSE
                _bd_invset := [incl_first];
            (*ENDIF*) 
            searchrec.sr_rsearchkey.len := selrec.selr_startkey.len;
            g10mv2 ('VKB741',  18,    
                  sizeof (selrec.selr_startkey.k),
                  sizeof (searchrec.sr_rsearchkey.k),
                  selrec.selr_startkey.k, 1, searchrec.sr_rsearchkey.k, 1,
                  selrec.selr_startkey.len, m.mb_trns^.trError_gg00);
            REPEAT
                b03get_inv (m.mb_trns^, selrec.selr_inv_id, selrec.selr_invkey,
                      searchrec.sr_rsearchkey, searchrec.sr_rsearchkey,
                      selrec.selr_stopkey, _bd_invset,
                      NOT c_count_only, lckFree_egg00,
                      selrec.selr_selectbuffer.inv_buf.buf,
                      _primkeycnt, _inv_buf_fill_len);
                _error_i           := m.mb_trns^.trError_gg00;
                m.mb_trns^.trError_gg00 := e_ok;
                IF  (_error_i = e_ok) OR (_error_i = e_buffer_limit)
                THEN
                    BEGIN
                    _bd_invset := _bd_invset - [incl_first];
                    _key_pos   := 1;
                    WHILE (_key_pos < _inv_buf_fill_len) AND
                          (m.mb_trns^.trError_gg00 = e_ok  ) DO
                        BEGIN
                        _keyLen.mapC2_sp00 [1]    := selrec.selr_selectbuffer.inv_buf.buf[_key_pos];
                        _keyLen.mapC2_sp00 [2]    := selrec.selr_selectbuffer.inv_buf.buf[_key_pos+1];
                        searchrec.sr_rsearchkey.keyLen_gg00 := _keyLen.mapInt_sp00;
                        g10mv1 ('VKB741',  19,    
                              sizeof (selrec.selr_selectbuffer.inv_buf.buf),
                              sizeof (searchrec.sr_rsearchkey.k),
                              selrec.selr_selectbuffer.inv_buf.buf,
                              _key_pos + 2, searchrec.sr_rsearchkey.k, 1,
                              searchrec.sr_rsearchkey.len,
                              m.mb_trns^.trError_gg00);
                        kb741get_right_record (m, getrec, selrec,
                              mm_direct, searchrec.sr_rsearchkey, sel);
                        IF  m.mb_trns^.trError_gg00 = e_ok
                        THEN
                            BEGIN
                            IF  _restore_left
                            THEN
                                kb741restore_page (m, _curr_tree_pos,
                                      getrec.gi_minfo.o_tree, selrec,
                                      searchrec);
                            (*ENDIF*) 
                            IF  m.mb_trns^.trError_gg00 = e_ok
                            THEN
                                BEGIN
                                _restore_left := true;
                                _skip_left    := false;
                                getrec.gi_linkrec.kbjr_linkcnt   := 2;
                                kb741l_join_with_left_records (m,
                                      getrec, selrec, sel, searchrec,
                                      _skip_left)
                                END
                            (*ENDIF*) 
                            END
                        ELSE
                            IF  (m.mb_trns^.trError_gg00 = e_key_not_found ) OR
                                (m.mb_trns^.trError_gg00 = e_qual_violation) OR
                                (m.mb_trns^.trError_gg00 = e_view_violation)
                            THEN
                                m.mb_trns^.trError_gg00 := e_ok;
&                           ifdef trace
                            (*ENDIF*) 
                        (*ENDIF*) 
                        t01basis_error (kb, 'loop        ', m.mb_trns^.trError_gg00);
&                       endif
                        _key_pos := _key_pos + searchrec.sr_rsearchkey.len + 2
                        END;
                    (*ENDWHILE*) 
                    END;
                (*ENDIF*) 
            UNTIL
                (_error_i <> e_buffer_limit) OR
                (m.mb_trns^.trError_gg00 <> e_ok);
            (*ENDREPEAT*) 
            IF  m.mb_trns^.trError_gg00 = e_ok
            THEN
                IF  _error_i <> e_inv_list_not_found
                THEN
                    m.mb_trns^.trError_gg00 := _error_i;
                (*ENDIF*) 
            (*ENDIF*) 
            END
        ELSE
            IF  (_lc_result = l_less   ) AND
                (_conv_cnt  = 0        ) AND
                NOT getrec.gi_linkrec.kbjr_right_oj
            THEN
                BEGIN
                _skip_left       := false;
                selrec.selr_invkey.len := selrec.selr_first_jlen;
                IF  searchrec.sr_error_l = e_ok
                THEN
                    BEGIN
&                   ifdef trace
                    kb741trace_luc (searchrec.sr_nptr.np_ptr^,
                          selrec.selr_l_currpos + cgg_rec_key_offset,
                          selrec.selr_first_jlen, @selrec.selr_invkey.k, 1,
                          selrec.selr_first_jlen, _cmp_result);
&                   endif
                    s30cmp1 (selrec.selr_invkey.k, 1,
                          selrec.selr_first_jlen,
                          searchrec.sr_nptr.np_ptr^,
                          selrec.selr_l_currpos + cgg_rec_key_offset,
                          selrec.selr_first_jlen, _cmp_result);
                    IF  _cmp_result = l_greater
                    THEN (* invkey found is greater *)
                        (*  than curr left key      *)
                        kb741synchronize_left_rec (m, selrec.selr_invkey,
                              getrec, searchrec, selrec)
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
        (*ENDIF*) 
        IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
        THEN
            searchrec.sr_error_l := e_cancelled;
&       ifdef trace
        (*ENDIF*) 
        t01basis_error (kb, 'm.err until ', m.mb_trns^.trError_gg00);
&       endif
    UNTIL
        (_lc_result <> l_equal     ) OR
        (m.mb_trns^.trError_gg00 <> e_ok);
    (*ENDREPEAT*) 
    (* all inversions for current left key are executed now *)
    IF  (m.mb_trns^.trError_gg00 = e_no_next_invkey) OR
        (m.mb_trns^.trError_gg00 = e_inv_list_not_found)
    THEN
        m.mb_trns^.trError_gg00 := e_ok;
    (*ENDIF*) 
    IF  m.mb_trns^.trError_gg00 = e_ok
    THEN
        IF  getrec.gi_linkrec.kbjr_right_oj AND
            (_curr_rescount = searchrec.sr_res_cnt)
        THEN
            BEGIN
            searchrec.sr_rsearchkey.len := selrec.selr_first_jlen;
            IF  NOT _skip_left
            THEN
                kb741restore_page (m, _curr_tree_pos,
                      getrec.gi_minfo.o_tree, selrec, searchrec);
            (*ENDIF*) 
            kb741left_scan_to_nxt_key (m, getrec, searchrec,
                  selrec, c_is_right_outer_join)
            END
        ELSE
            IF  _skip_left
            THEN
                BEGIN
                searchrec.sr_rsearchkey.len := selrec.selr_first_jlen;
                kb741left_scan_to_nxt_key (m, getrec, searchrec,
                      selrec, NOT c_is_right_outer_join)
                END;
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
IF  (m.mb_trns^.trError_gg00 =  e_ok) AND
    (searchrec.sr_error_l <> e_ok)           AND
    (searchrec.sr_error_l <> e_no_next_record)
THEN
    m.mb_trns^.trError_gg00 := searchrec.sr_error_l
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741inv_intersect_search (
            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);
 
VAR
      _error_i            : tgg_basis_error;
      _is_descending      : boolean;
      _skip_left          : boolean;
      _bd_invset          : tgg_bd_inv_set;
      _keyLen             : tsp00_IntMapC2;
      _last_inv_field_pos : integer;
      _conv_cnt           : integer;
      _inv_keylen         : integer;
      _field_cnt          : integer;
      _test_pos           : integer;
      _key_pos            : integer;
      _jx                 : integer;
      _inv_buf_fill_len   : integer;
      _curr_rescount      : tsp_int4;
      _primkeycnt         : tsp_int4;
      _curr_tree_pos      : tgg00_FilePos;
      _conv_st_pos        : conv_arr;
 
BEGIN
kb741check_inv_conversions (m, _conv_st_pos, _conv_cnt,
      _last_inv_field_pos, _field_cnt, _test_pos, _is_descending,
      selrec.selr_first_jlen);
selrec.selr_l_defbyte_pos := _last_inv_field_pos;
IF  _is_descending
THEN
    _inv_keylen := kb741eval_invkey_len (m,
          selrec, _field_cnt, _test_pos);
(*ENDIF*) 
IF  sel.sfp_bd_use_stopkey
THEN
    _bd_invset := [primary_stop, incl_first]
ELSE
    _bd_invset := [incl_first];
(*ENDIF*) 
WHILE (m.mb_trns^.trError_gg00 = e_ok) AND (searchrec.sr_error_l = e_ok) DO
    BEGIN
    selrec.selr_l_currpos :=
          searchrec.sr_nptr.np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -
          searchrec.sr_left_tree_pos.tpsIndex_gg00];
    selrec.selr_invkey.len := s30lnr_defbyte (@searchrec.sr_nptr.np_ptr^,
          searchrec.sr_nptr.np_ptr^.nd_body
          [selrec.selr_l_currpos + _last_inv_field_pos -1],
          selrec.selr_l_currpos + _last_inv_field_pos,
          getrec.gi_linkrec.kbjr_jarr[1].kbji_parts[1].kboj_len -
          _last_inv_field_pos + cgg_rec_key_offset) +
          _last_inv_field_pos - cgg_rec_key_offset;
    IF  selrec.selr_invkey.len <= selrec.selr_first_jlen
    THEN
        BEGIN
        g10mv4 ('VKB741',  20,    
              sizeof(searchrec.sr_nptr.np_ptr^),
              sizeof(selrec.selr_invkey.k),
              searchrec.sr_nptr.np_ptr^,
              selrec.selr_l_currpos + cgg_rec_key_offset,
              selrec.selr_invkey.k, 1, selrec.selr_invkey.len,
              m.mb_trns^.trError_gg00);
        IF  _conv_cnt > 0
        THEN
            kb741convert_inv_key (m,
                  _conv_st_pos, _conv_cnt, selrec.selr_invkey);
        (*ENDIF*) 
        IF  _is_descending AND (selrec.selr_invkey.len < _inv_keylen)
        THEN
            BEGIN
            IF  selrec.selr_invkey.k [ _last_inv_field_pos - cgg_rec_key_offset ]
                = chr(255 - ord(csp_unicode_def_byte))
            THEN
                BEGIN
                g20unifill (sizeof(selrec.selr_invkey.k),
                      @selrec.selr_invkey.k, selrec.selr_invkey.len+1,
                      _inv_keylen - selrec.selr_invkey.len,
                      csp_unicode_blank);
                FOR _jx := selrec.selr_invkey.len + 1 TO _inv_keylen DO
                    selrec.selr_invkey.k[ _jx ] :=
                          chr(255 - ord(selrec.selr_invkey.k[ _jx ]));
                (*ENDFOR*) 
                END
            ELSE
                g10fil ('VKB741',  21,    
                      sizeof (selrec.selr_invkey.k), selrec.selr_invkey.k,
                      selrec.selr_invkey.len + 1,
                      _inv_keylen - selrec.selr_invkey.len,
                      selrec.selr_invkey.k[ _last_inv_field_pos -
                      cgg_rec_key_offset ], m.mb_trns^.trError_gg00);
            (*ENDIF*) 
            selrec.selr_invkey.len := _inv_keylen
            END;
        (*ENDIF*) 
        searchrec.sr_rsearchkey.len := selrec.selr_startkey.len;
        g10mv2 ('VKB741',  22,    
              sizeof (selrec.selr_startkey.k),
              sizeof (searchrec.sr_rsearchkey.k),
              selrec.selr_startkey.k, 1, searchrec.sr_rsearchkey.k, 1,
              selrec.selr_startkey.len, m.mb_trns^.trError_gg00);
        _error_i := e_buffer_limit
        END
    ELSE (* selrec.selr_invkey.len > selrec.selr_first_jlen *)
        _error_i := e_inv_list_not_found;
    (*ENDIF*) 
    _curr_rescount := searchrec.sr_res_cnt;
    _curr_tree_pos := searchrec.sr_left_tree_pos;
    _skip_left     := true;
    WHILE (_error_i = e_buffer_limit) AND
          (m.mb_trns^.trError_gg00 = e_ok) DO
        BEGIN
        b03get_inv (m.mb_trns^, selrec.selr_inv_id, selrec.selr_invkey,
              searchrec.sr_rsearchkey, selrec.selr_stopkey,
              searchrec.sr_rsearchkey, _bd_invset,
              NOT c_count_only, lckFree_egg00,
              selrec.selr_selectbuffer.inv_buf.buf,
              _primkeycnt, _inv_buf_fill_len);
        _error_i           := m.mb_trns^.trError_gg00;
        m.mb_trns^.trError_gg00 := e_ok;
        IF  (_error_i = e_ok) OR (_error_i = e_buffer_limit)
        THEN
            BEGIN
            _bd_invset := _bd_invset - [incl_first];
            _key_pos   := 1;
            WHILE (_key_pos < _inv_buf_fill_len) AND
                  (m.mb_trns^.trError_gg00 = e_ok  ) DO
                BEGIN
                _keyLen.mapC2_sp00 [1]    := selrec.selr_selectbuffer.inv_buf.buf[_key_pos];
                _keyLen.mapC2_sp00 [2]    := selrec.selr_selectbuffer.inv_buf.buf[_key_pos+1];
                searchrec.sr_rsearchkey.keyLen_gg00 := _keyLen.mapInt_sp00;
                g10mv1 ('VKB741',  23,    
                      sizeof (selrec.selr_selectbuffer.inv_buf.buf),
                      sizeof (searchrec.sr_rsearchkey.k),
                      selrec.selr_selectbuffer.inv_buf.buf,
                      _key_pos + 2, searchrec.sr_rsearchkey.k, 1,
                      searchrec.sr_rsearchkey.len, m.mb_trns^.trError_gg00);
                IF  (m.mb_trns^.trError_gg00 = e_ok)
                THEN
                    kb741get_right_record (m, getrec, selrec,
                          mm_direct, searchrec.sr_rsearchkey, sel);
                (*ENDIF*) 
                IF  m.mb_trns^.trError_gg00 = e_ok
                THEN
                    BEGIN
                    IF  NOT _skip_left
                    THEN
                        kb741restore_page (m, _curr_tree_pos,
                              getrec.gi_minfo.o_tree, selrec, searchrec);
                    (*ENDIF*) 
                    IF  m.mb_trns^.trError_gg00 = e_ok
                    THEN
                        BEGIN
                        _skip_left     := false;
                        getrec.gi_linkrec.kbjr_linkcnt    := 2;
                        kb741l_join_with_left_records (m,
                              getrec, selrec, sel, searchrec,
                              _skip_left)
                        END;
                    (*ENDIF*) 
                    END
                ELSE
                    IF  (m.mb_trns^.trError_gg00 = e_key_not_found ) OR
                        (m.mb_trns^.trError_gg00 = e_qual_violation) OR
                        (m.mb_trns^.trError_gg00 = e_view_violation)
                    THEN
                        m.mb_trns^.trError_gg00 := e_ok;
                    (*ENDIF*) 
                (*ENDIF*) 
                _key_pos := _key_pos + searchrec.sr_rsearchkey.len + 2
                END;
            (*ENDWHILE*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDWHILE*) 
    IF  m.mb_trns^.trError_gg00 = e_ok
    THEN
        IF  _error_i <> e_inv_list_not_found
        THEN
            m.mb_trns^.trError_gg00 := _error_i
        ELSE
            IF  (_conv_cnt = 0) AND NOT getrec.gi_linkrec.kbjr_right_oj
            THEN
                BEGIN
                (* next invkey yields new position in *)
                (* left side                          *)
                b03next_invkey (m.mb_trns^, selrec.selr_inv_id,
                      NOT c_inclusive, selrec.selr_invkey);
                IF  m.mb_trns^.trError_gg00 = e_ok
                THEN
                    BEGIN
                    _skip_left := false;
                    kb741synchronize_left_rec (m, selrec.selr_invkey,
                          getrec, searchrec, selrec)
                    END
                ELSE
                    IF  (m.mb_trns^.trError_gg00 = e_no_next_invkey) OR
                        (m.mb_trns^.trError_gg00 = e_inv_list_not_found)
                    THEN
                        BEGIN
                        (* end of right table, stop *)
                        searchrec.sr_error_l           := e_no_next_record;
                        m.mb_trns^.trError_gg00 := e_ok
                        END;
                    (*ENDIF*) 
                (*ENDIF*) 
                END;
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    IF  m.mb_trns^.trError_gg00 = e_ok
    THEN
        IF  getrec.gi_linkrec.kbjr_right_oj AND (_curr_rescount = searchrec.sr_res_cnt)
        THEN
            BEGIN
            IF  NOT _skip_left
            THEN
                kb741restore_page (m, _curr_tree_pos,
                      getrec.gi_minfo.o_tree, selrec, searchrec);
            (*ENDIF*) 
            searchrec.sr_rsearchkey.len := selrec.selr_first_jlen;
            kb741left_scan_to_nxt_key (m, getrec, searchrec, selrec,
                  c_is_right_outer_join)
            END
        ELSE
            IF  _skip_left
            THEN
                BEGIN
                searchrec.sr_rsearchkey.len := selrec.selr_first_jlen;
                kb741left_scan_to_nxt_key (m,
                      getrec, searchrec, selrec,
                      NOT c_is_right_outer_join)
                END;
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
    THEN
        searchrec.sr_error_l := e_cancelled;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
IF  (m.mb_trns^.trError_gg00 =  e_ok  ) AND
    (searchrec.sr_error_l <> e_ok            ) AND
    (searchrec.sr_error_l <> e_no_next_record)
THEN
    m.mb_trns^.trError_gg00 := searchrec.sr_error_l
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741key_direct_search (
            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);
 
VAR
      _end_of_range       : boolean;
      _i                  : integer;
      _last_key_field_pos : integer;
      _conv_cnt           : integer;
      _dummy_len          : integer;
      _curr_rescount      : tsp_int4;
      _conv_st_pos        : conv_arr;
 
BEGIN
sel.sfp_bd_use_stopkey := false;
kb741check_conversions (m, _conv_st_pos, _conv_cnt,
      _last_key_field_pos, _dummy_len, selrec.selr_first_jlen);
selrec.selr_l_defbyte_pos := _last_key_field_pos;
WHILE (m.mb_trns^.trError_gg00 = e_ok) AND (searchrec.sr_error_l = e_ok) DO
    BEGIN
    selrec.selr_l_currpos :=
          searchrec.sr_nptr.np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -
          searchrec.sr_left_tree_pos.tpsIndex_gg00];
    searchrec.sr_rsearchkey.len := s30lnr_defbyte (@searchrec.sr_nptr.np_ptr^,
          searchrec.sr_nptr.np_ptr^.nd_body
          [selrec.selr_l_currpos + _last_key_field_pos -1],
          selrec.selr_l_currpos + _last_key_field_pos,
          getrec.gi_linkrec.kbjr_jarr[1].kbji_parts[1].kboj_len -
          _last_key_field_pos + cgg_rec_key_offset) +
          _last_key_field_pos - cgg_rec_key_offset;
    sel.sfp_bd_return_knf :=
          (_conv_cnt = 0) AND NOT getrec.gi_linkrec.kbjr_right_oj;
    IF  searchrec.sr_rsearchkey.len <= selrec.selr_first_jlen
    THEN
        BEGIN
        g10mv4 ('VKB741',  24,    
              sizeof(searchrec.sr_nptr.np_ptr^),
              sizeof(searchrec.sr_rsearchkey.k),
              searchrec.sr_nptr.np_ptr^,
              selrec.selr_l_currpos + cgg_rec_key_offset,
              searchrec.sr_rsearchkey.k, 1, searchrec.sr_rsearchkey.len,
              m.mb_trns^.trError_gg00);
        FOR _i := 1 TO _conv_cnt DO
            WITH _conv_st_pos[_i] DO
                BEGIN
                s30map (g02codetables.tables[ ct_codeno ],
                      searchrec.sr_rsearchkey.k,
                      m.mb_st^[ct_st_pos].epos - cgg_rec_key_offset,
                      searchrec.sr_rsearchkey.k,
                      m.mb_st^[ct_st_pos].epos - cgg_rec_key_offset,
                      m.mb_st^[ct_st_pos].elen_var);
                END;
            (*ENDWITH*) 
        (*ENDFOR*) 
        kb741get_right_record (m, getrec, selrec, mm_direct,
              searchrec.sr_rsearchkey, sel);
        searchrec.sr_error_r           := m.mb_trns^.trError_gg00;
        m.mb_trns^.trError_gg00 := e_ok
        END
    ELSE (* searchrec.sr_rsearchkey.len > selrec.selr_first_jlen *)
        BEGIN
        sel.sfp_bd_return_knf := false;
        searchrec.sr_error_r               := e_key_not_found;
        END;
    (*ENDIF*) 
    _curr_rescount := searchrec.sr_res_cnt;
    IF  searchrec.sr_error_r = e_ok
    THEN
        BEGIN (* right record found *)
        getrec.gi_linkrec.kbjr_linkcnt := 2;
        kb741l_join_with_left_records (m, getrec, selrec,
              sel, searchrec, _end_of_range);
        IF  (searchrec.sr_error_l <> e_no_next_record) AND (* PTS 1116891 *)
            ((getrec.gi_linkrec.kbjr_right_oj AND (_curr_rescount = searchrec.sr_res_cnt) AND
            NOT searchrec.sr_refused_by_ophase)
            OR
            _end_of_range)
        THEN
            BEGIN
            searchrec.sr_rsearchkey.len := selrec.selr_first_jlen;
            kb741left_scan_to_nxt_key (m, getrec, searchrec,
                  selrec, getrec.gi_linkrec.kbjr_right_oj)
            END
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        IF  (searchrec.sr_error_r <> e_key_not_found ) AND
            (searchrec.sr_error_r <> e_qual_violation) AND
            (searchrec.sr_error_r <> e_view_violation) AND
            (searchrec.sr_error_r <> e_no_next_record)
        THEN
            m.mb_trns^.trError_gg00 := searchrec.sr_error_r;
        (*ENDIF*) 
        IF  m.mb_trns^.trError_gg00 = e_ok
        THEN
            IF  sel.sfp_bd_return_knf
            THEN
                IF  (searchrec.sr_error_r = e_key_not_found ) OR
                    (searchrec.sr_error_r = e_qual_violation) OR
                    (searchrec.sr_error_r = e_view_violation)
                THEN
                    kb741synchronize_left_rec (m,
                          searchrec.sr_rsearchkey, getrec,
                          searchrec, selrec)
                ELSE
                    searchrec.sr_error_l := e_no_next_record
                (*ENDIF*) 
            ELSE
                IF  (searchrec.sr_error_l <> e_no_next_record)
                THEN
                    BEGIN
                    searchrec.sr_rsearchkey.len := selrec.selr_first_jlen;
                    kb741left_scan_to_nxt_key (m, getrec, searchrec,
                          selrec, getrec.gi_linkrec.kbjr_right_oj)
                    END
                (*ENDIF*) 
            (*ENDIF*) 
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
    THEN
        searchrec.sr_error_l := e_cancelled;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
IF  (m.mb_trns^.trError_gg00 =  e_ok) AND
    (searchrec.sr_error_l <> e_ok)           AND
    (searchrec.sr_error_l <> e_no_next_record)
THEN
    m.mb_trns^.trError_gg00 := searchrec.sr_error_l
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741key_next_search (
            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);
 
VAR
      _skip_left          : boolean;
      _i                  : integer;
      _startpos           : integer;
      _stoplength         : integer;
      _last_key_field_pos : integer;
      _curr_rescount      : tsp_int4;
      _conv_st_pos        : conv_arr;
      _conv_cnt           : integer;
      _curr_tree_pos      : tgg00_FilePos;
      _m2_type            : tgg_message2_type;
 
BEGIN
kb741check_conversions (m, _conv_st_pos, _conv_cnt,
      _last_key_field_pos, _stoplength, selrec.selr_first_jlen);
selrec.selr_l_defbyte_pos := _last_key_field_pos;
IF  (_stoplength = 0) OR
    (_stoplength > selrec.selr_first_jlen)
THEN
    _stoplength := selrec.selr_first_jlen;
(*ENDIF*) 
g10fil ('VKB741',  25,    
      sizeof(selrec.selr_stopkey.k),
      selrec.selr_stopkey.k, _stoplength + 1,
      sizeof(selrec.selr_stopkey.k) - _stoplength,
      chr(255), m.mb_trns^.trError_gg00);
selrec.selr_stopkey.len       := sizeof(selrec.selr_stopkey.k);
sel.sfp_bd_use_stopkey := true;
WHILE (m.mb_trns^.trError_gg00 = e_ok) AND (searchrec.sr_error_l = e_ok) DO
    BEGIN
    selrec.selr_l_currpos    :=
          searchrec.sr_nptr.np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -
          searchrec.sr_left_tree_pos.tpsIndex_gg00];
    searchrec.sr_rsearchkey.len := selrec.selr_first_jlen;
    g10mv4 ('VKB741',  26,    
          sizeof(searchrec.sr_nptr.np_ptr^),
          sizeof(searchrec.sr_rsearchkey.k),
          searchrec.sr_nptr.np_ptr^,
          selrec.selr_l_currpos + cgg_rec_key_offset,
          searchrec.sr_rsearchkey.k, 1, searchrec.sr_rsearchkey.len,
          m.mb_trns^.trError_gg00);
    FOR _i := 1 TO _conv_cnt DO
        WITH _conv_st_pos[_i] DO
            BEGIN
            IF  m.mb_st^[ct_st_pos].epos - cgg_rec_key_offset - 1 < _stoplength
            THEN
                s30map (g02codetables.tables[ ct_codeno ],
                      searchrec.sr_rsearchkey.k,
                      m.mb_st^[ct_st_pos].epos - cgg_rec_key_offset,
                      searchrec.sr_rsearchkey.k,
                      m.mb_st^[ct_st_pos].epos - cgg_rec_key_offset,
                      m.mb_st^[ct_st_pos].elen_var)
            (*ENDIF*) 
            END;
        (*ENDWITH*) 
    (*ENDFOR*) 
    g10mv2 ('VKB741',  27,    
          sizeof(searchrec.sr_rsearchkey.k),
          sizeof(selrec.selr_stopkey.k),
          searchrec.sr_rsearchkey.k, 1,
          selrec.selr_stopkey.k, 1, _stoplength,
          m.mb_trns^.trError_gg00);
    _startpos        := selrec.selr_l_currpos;
    _m2_type         := mm_first;
    _skip_left       := true;
    searchrec.sr_error_r         := e_ok;
    _curr_tree_pos   := searchrec.sr_left_tree_pos;
    _curr_rescount   := searchrec.sr_res_cnt;
    WHILE (m.mb_trns^.trError_gg00 = e_ok) AND (searchrec.sr_error_r = e_ok) DO
        BEGIN
        kb741get_right_record (m, getrec, selrec, _m2_type,
              searchrec.sr_rsearchkey, sel);
        searchrec.sr_error_r         := m.mb_trns^.trError_gg00;
        m.mb_trns^.trError_gg00 := e_ok;
        IF  searchrec.sr_error_r = e_ok
        THEN
            BEGIN
            _skip_left := false;
            IF  _m2_type = mm_next
            THEN
                kb741restore_page (m,
                      _curr_tree_pos, getrec.gi_minfo.o_tree, selrec,
                      searchrec);
            (*ENDIF*) 
            ;
            (* Join current right record *)
            (* with all records of left  *)
            (* result with the same key  *)
            (* prefix. As result lmaxpos *)
            (* contains the position of  *)
            (* the first record of left  *)
            (* result with               *)
            (* key <> current key prefix *)
            ;
            IF  m.mb_trns^.trError_gg00 = e_ok
            THEN
                BEGIN
                kb741l_join_with_left_records (m,
                      getrec, selrec, sel, searchrec, _skip_left)
                END
            (*ENDIF*) 
            END
        ELSE
            IF  (searchrec.sr_error_r <> e_qual_violation) AND
                (searchrec.sr_error_r <> e_view_violation) AND
                (searchrec.sr_error_r <> e_no_next_record )
            THEN
                m.mb_trns^.trError_gg00 := searchrec.sr_error_r;
            (*ENDIF*) 
        (*ENDIF*) 
        _m2_type := mm_next;
        END;
    (*ENDWHILE*) 
    IF  m.mb_trns^.trError_gg00 = e_ok
    THEN
        BEGIN
        IF  getrec.gi_linkrec.kbjr_right_oj AND
            (_curr_rescount = searchrec.sr_res_cnt)
        THEN
            BEGIN
            IF  NOT _skip_left
            THEN
                kb741restore_page (m,
                      _curr_tree_pos, getrec.gi_minfo.o_tree, selrec,
                      searchrec);
            (*ENDIF*) 
            searchrec.sr_rsearchkey.len  := _stoplength;
            kb741left_scan_to_nxt_key (m, getrec, searchrec,
                  selrec, c_is_right_outer_join)
            END
        ELSE
            IF  _skip_left AND
                (searchrec.sr_error_l <> e_no_next_record)
            THEN
                BEGIN
                (* No record of right table with key prefix *)
                (* equal current left key prefix fulfills   *)
                (* qualification, skip all records of left  *)
                (* result with current left key             *)
                ;
                searchrec.sr_rsearchkey.len  := _stoplength;
                kb741left_scan_to_nxt_key (m, getrec, searchrec,
                      selrec, NOT c_is_right_outer_join)
                END;
            (*ENDIF*) 
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
    THEN
        searchrec.sr_error_l := e_cancelled;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
IF  (m.mb_trns^.trError_gg00 = e_ok) AND
    (searchrec.sr_error_l <> e_ok)        AND
    (searchrec.sr_error_l <> e_no_next_record)
THEN
    m.mb_trns^.trError_gg00 := searchrec.sr_error_l
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741restore_page (
            VAR m                 : tgg_mess_block;
            VAR required_tree_pos : tgg00_FilePos;
            VAR left_tree         : tgg00_FileId;
            VAR selrec            : tkb7_select_param;
            VAR searchrec         : search_rec);
 
VAR
      _dummy_key : tgg_lkey;
 
BEGIN
IF  required_tree_pos.tpsPno_gg00 <> searchrec.sr_left_tree_pos.tpsPno_gg00
THEN
    BEGIN
    searchrec.sr_left_tree_pos := required_tree_pos;
    kb741get_left_leaf (m.mb_trns^, selrec, searchrec,
          left_tree, _dummy_key, NOT c_get_next)
    END
ELSE
    BEGIN
    searchrec.sr_left_tree_pos.tpsIndex_gg00 := required_tree_pos.tpsIndex_gg00;
    selrec.selr_l_currpos :=
          searchrec.sr_nptr.np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -
          searchrec.sr_left_tree_pos.tpsIndex_gg00]
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741synchronize_left_rec (
            VAR m          : tgg_mess_block;
            VAR sync_key   : tgg_lkey;
            VAR getrec     : tkb7_get_param;
            VAR searchrec  : search_rec;
            VAR selrec     : tkb7_select_param);
 
VAR
      _lc_result         : tsp_lcomp_result;
      _l_keylen          : integer;
      _index             : integer;
      _def_byte          : char;
      _m_def_byte        : char;
      _m_sk_def_byte     : char; (* PTS 1113064 *)
      _lpos              : integer;
 
BEGIN
_l_keylen       := getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 1 ].kboj_len;
selrec.selr_l_currpos := searchrec.sr_nptr.np_ptr^.
      nd_pointer_list[MAX_POINTERINDEX_BD00 - searchrec.sr_left_min_index];
_lpos           := selrec.selr_l_currpos + cgg_rec_key_offset;
_m_def_byte     := searchrec.sr_nptr.np_ptr^.nd_body[_lpos];
_def_byte       := searchrec.sr_nptr.np_ptr^.nd_body[selrec.selr_l_currpos +
      selrec.selr_l_defbyte_pos-1];
IF  _def_byte = csp_undef_byte (* PTS 1114672 *)
THEN
    BEGIN
    _def_byte    := sync_key.k[selrec.selr_l_defbyte_pos];
    IF  _def_byte = csp_undef_byte
    THEN
        _def_byte := csp_defined_byte;
    (*ENDIF*) 
    END;
(*ENDIF*) 
_m_sk_def_byte  := sync_key.k[1]; (* PTS 1113064 *)
sync_key.k[1]  := _def_byte;
searchrec.sr_nptr.np_ptr^.nd_body[_lpos] := _def_byte;
(* *** compare last left key in page with new right key *** *)
IF  _m_sk_def_byte = csp_undef_byte (* PTS 1113064 *)
THEN
    _lc_result := l_less
ELSE
    BEGIN
&   ifdef trace
    kb741trace_luc (searchrec.sr_nptr.np_ptr^, _lpos, _l_keylen,
          @sync_key.k, 1, sync_key.len, _lc_result);
&   else
    s30luc1 (searchrec.sr_nptr.np_ptr^, _lpos, _l_keylen,
          sync_key.k, 1, sync_key.len, _lc_result);
&   endif
    END;
(*ENDIF*) 
searchrec.sr_nptr.np_ptr^.nd_body[_lpos] := _m_def_byte;
CASE _lc_result OF
    l_less :
        BEGIN
        sync_key.k[1]         := _m_sk_def_byte; (* PTS 1113064 *)
        searchrec.sr_left_tree_pos.tpsPno_gg00   := NIL_PAGE_NO_GG00;
        kb741get_left_leaf (m.mb_trns^, selrec, searchrec,
              getrec.gi_minfo.o_tree, sync_key, c_get_next)
        END;
    l_equal   :
        BEGIN
        (* *** skip to next left record *** *)
        _index := searchrec.sr_left_min_index;
        REPEAT
            _index := _index - 1;
            _lpos  := searchrec.sr_nptr.np_ptr^.
                  nd_pointer_list[MAX_POINTERINDEX_BD00 - _index] +
                  cgg_rec_key_offset;
            searchrec.sr_nptr.np_ptr^.nd_body[_lpos] := _def_byte;
&           ifdef trace
            kb741trace_luc (searchrec.sr_nptr.np_ptr^, _lpos, _l_keylen,
                  @sync_key.k, 1, sync_key.len, _lc_result);
&           else
            s30luc1 (searchrec.sr_nptr.np_ptr^, _lpos, _l_keylen,
                  sync_key.k, 1, sync_key.len, _lc_result);
&           endif
            searchrec.sr_nptr.np_ptr^.nd_body[_lpos] := _m_def_byte;
        UNTIL
            _lc_result <> l_equal;
        (*ENDREPEAT*) 
        WITH searchrec.sr_left_tree_pos DO
            BEGIN
            tpsIndex_gg00        := _index + 1;
            selrec.selr_l_currpos := searchrec.sr_nptr.np_ptr^.
                  nd_pointer_list[MAX_POINTERINDEX_BD00 - tpsIndex_gg00];
            END;
        (*ENDWITH*) 
        END;
    l_greater :
        BEGIN
        (* *** skip to next left record *** *)
&       ifdef trace
        t01int4 (kb, 'tpsIndex    ', searchrec.sr_left_tree_pos.tpsIndex_gg00);
&       endif
        REPEAT
            WITH searchrec.sr_left_tree_pos DO
                BEGIN
                tpsIndex_gg00 := tpsIndex_gg00 + 1;
                _lpos  := searchrec.sr_nptr.np_ptr^.
                      nd_pointer_list[MAX_POINTERINDEX_BD00 - tpsIndex_gg00] +
                      cgg_rec_key_offset;
                END;
            (*ENDWITH*) 
            searchrec.sr_nptr.np_ptr^.nd_body[_lpos] := _def_byte;
&           ifdef trace
            kb741trace_luc (searchrec.sr_nptr.np_ptr^, _lpos, _l_keylen,
                  @sync_key.k, 1, sync_key.len, _lc_result);
&           else
            s30luc1 (searchrec.sr_nptr.np_ptr^, _lpos, _l_keylen,
                  sync_key.k, 1, sync_key.len, _lc_result);
&           endif
            searchrec.sr_nptr.np_ptr^.nd_body[_lpos] := _m_def_byte;
        UNTIL
            _lc_result <> l_less;
        (*ENDREPEAT*) 
        selrec.selr_l_currpos  := searchrec.sr_nptr.
              np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -
              searchrec.sr_left_tree_pos.tpsIndex_gg00];
        END;
    END;
(*ENDCASE*) 
sync_key.k[1] := _m_sk_def_byte; (* PTS 1113064 *)
&ifdef trace
IF  searchrec.sr_nptr.np_ptr <> NIL
THEN
    BEGIN
    t01int4 (kb, 'new left key', 1);
    t01buf1 (kb, searchrec.sr_nptr.np_ptr^,
          selrec.selr_l_currpos + cgg_rec_key_offset,
          selrec.selr_l_currpos + cgg_rec_key_offset + sync_key.len - 1)
    END;
&endif
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741get_left_leaf (
            VAR t            : tgg00_TransContext;
            VAR selrec       : tkb7_select_param;
            VAR searchrec    : search_rec;
            VAR left_tree_id : tgg00_FileId;
            VAR searchkey    : tgg_lkey;
            get_next         : boolean);
 
VAR
      _prev_tree_pos : tgg00_FilePos;
 
BEGIN
IF  (get_next)                                          AND
    (searchrec.sr_left_tree_pos.tpsPno_gg00 = searchrec.sr_left_last_pno  ) AND
    (searchrec.sr_left_last_pno <> NIL_PAGE_NO_GG00)
THEN
    BEGIN
    IF  searchrec.sr_nptr.np_ptr <> NIL
    THEN
        b07release_result_leaf (t,
              left_tree_id, searchrec.sr_prepare_for_upd, searchrec.sr_nptr);
    (*ENDIF*) 
    IF  t.trError_gg00 = e_ok
    THEN
        searchrec.sr_error_l := e_no_next_record
    ELSE
        searchrec.sr_error_l := t.trError_gg00;
    (*ENDIF*) 
    searchrec.sr_left_tree_pos.tpsPno_gg00 := NIL_PAGE_NO_GG00;
    END
ELSE
    BEGIN
    _prev_tree_pos := searchrec.sr_left_tree_pos;
    b07get_result_leaf (t, left_tree_id, searchkey,
          get_next, searchrec.sr_prepare_for_upd,
          searchrec.sr_left_tree_pos, searchrec.sr_nptr);
    searchrec.sr_error_l := t.trError_gg00;
    IF  searchrec.sr_error_l = e_ok
    THEN
        BEGIN
        IF  NOT get_next
        THEN
            searchrec.sr_left_tree_pos.tpsIndex_gg00
                  := _prev_tree_pos.tpsIndex_gg00;
        (*ENDIF*) 
        selrec.selr_l_currpos := searchrec.sr_nptr.np_ptr^.
              nd_pointer_list[MAX_POINTERINDEX_BD00 -
              searchrec.sr_left_tree_pos.tpsIndex_gg00];
        searchrec.sr_left_min_index :=
              searchrec.sr_nptr.np_ptr^.nd_record_cnt - 1;
&       ifdef trace
        t01int4 (kb, 'left_min_i  ', searchrec.sr_left_min_index);
        t01int4 (kb, 'l_currpos   ', selrec.selr_l_currpos);
&       endif
        END
    ELSE
        IF  searchrec.sr_error_l = e_no_next_record
        THEN
            BEGIN
            t.trError_gg00   := e_ok;
            searchrec.sr_left_last_pno := _prev_tree_pos.tpsPno_gg00
            END;
        (*ENDIF*) 
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741left_scan_to_nxt_key (
            VAR m               : tgg_mess_block;
            VAR getrec          : tkb7_get_param;
            VAR searchrec       : search_rec;
            VAR selrec          : tkb7_select_param;
            is_right_outer_join : boolean);
 
VAR
      _lc_result    : tsp_lcomp_result;
      _right_needed : boolean;
 
BEGIN
g10mv4 ('VKB741',  28,    
      sizeof(searchrec.sr_nptr.np_ptr^), sizeof(searchrec.sr_rsearchkey.k),
      searchrec.sr_nptr.np_ptr^, selrec.selr_l_currpos + cgg_rec_key_offset,
      searchrec.sr_rsearchkey.k, 1, searchrec.sr_rsearchkey.len, m.mb_trns^.trError_gg00);
_lc_result := l_equal;
&IFDEF TRACE
t01lkey (kb, searchrec.sr_rsearchkey);
&ENDIF
IF  is_right_outer_join
THEN
    searchrec.sr_left_tree_pos.tpsIndex_gg00 := searchrec.sr_left_tree_pos.tpsIndex_gg00 - 1;
(*ENDIF*) 
_right_needed := true;
WHILE (_lc_result         = l_equal) AND
      (m.mb_trns^.trError_gg00 = e_ok   ) AND
      (searchrec.sr_error_l = e_ok             ) DO
    BEGIN
    WITH searchrec.sr_left_tree_pos DO
        BEGIN
        tpsIndex_gg00 := tpsIndex_gg00 + 1;
        IF  tpsIndex_gg00 > searchrec.sr_left_min_index
        THEN
            kb741get_left_leaf (m.mb_trns^, selrec, searchrec,
                  getrec.gi_minfo.o_tree, searchrec.sr_lsearchkey, c_get_next)
        ELSE
            selrec.selr_l_currpos :=
                  searchrec.sr_nptr.np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 -tpsIndex_gg00];
        (*ENDIF*) 
&       ifdef trace
        t01int4 (kb, 'tpsIndex    ', tpsIndex_gg00);
&       endif
        IF  searchrec.sr_error_l = e_ok
        THEN
            s30cmp1 (searchrec.sr_rsearchkey.k, 1, searchrec.sr_rsearchkey.len,
                  searchrec.sr_nptr.np_ptr^, selrec.selr_l_currpos + cgg_rec_key_offset,
                  searchrec.sr_rsearchkey.len, _lc_result);
        (*ENDIF*) 
        END;
    (*ENDWITH*) 
    END;
(*ENDWHILE*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741get_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;
kb741all_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
      kb741init (
            VAR m         : tgg_mess_block;
            VAR left_tree : tgg00_FileId;
            VAR getrec    : tkb7_get_param;
            VAR selrec    : tkb7_select_param;
            VAR searchrec : search_rec);
 
BEGIN
WITH getrec.gi_linkrec.kbjr_jarr[1] DO
    CASE ord(kbji_parts[2].kboj_op) OF
        c_left_len_eq_right_len, c_left_len_lt_right_len :
            selrec.selr_first_jlen := kbji_parts[1].kboj_len;
        c_left_len_gt_right_len :
            selrec.selr_first_jlen := kbji_parts[2].kboj_len;
        END;
    (*ENDCASE*) 
(*ENDWITH*) 
&ifdef trace
t01int4 (kb, 'first_jlen  ', selrec.selr_first_jlen);
&endif
searchrec.sr_lsearchkey.len             := 0;
selrec.selr_l_currpos                   := 0;
selrec.selr_r_currpos                   := 0;
searchrec.sr_prepare_for_upd            := getrec.gi_linkrec.kbjr_right_oj;
searchrec.sr_refused_by_ophase          := false;
searchrec.sr_res_cnt                    := 0;
searchrec.sr_left_tree_pos.tpsPno_gg00  := NIL_PAGE_NO_GG00;
searchrec.sr_nptr.np_ptr                := NIL;
searchrec.sr_left_last_pno              := NIL_PAGE_NO_GG00;
kb741get_left_leaf (m.mb_trns^, selrec, searchrec,
      left_tree, searchrec.sr_lsearchkey, c_get_next)
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741join_init (
            VAR m                : tgg_mess_block;
            VAR selrec           : tkb7_select_param;
            VAR invindex         : integer;
            VAR use_stopkey      : boolean;
            VAR finding_possible : boolean);
 
VAR
      _strat : tgg07_StrategyInfo;
 
BEGIN
k720_initialize (m, selrec, _strat, use_stopkey, finding_possible);
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
    invindex := _strat.str_join_inv.sji_invindex;
(*ENDIF*) 
IF  (_strat.str_use_subquery = normal_subquery)
THEN
    k720_test_subquery (m, selrec.selr_selectbuffer.buf_rec);
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      kb741l_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;
            VAR end_of_range       : boolean);
 
VAR
      _new_page_req      : boolean;
      _exit_inner_loop   : boolean;
      _first_fulfilled   : boolean;
      _no_next_rec       : boolean;
      _unequal_join      : boolean;
      _right_needed      : boolean;
      _key_len           : tsp_int_map_c2;
      _curr_res_cnt      : integer;
 
BEGIN
_no_next_rec   := false;
_unequal_join  := getrec.gi_linkrec.kbjr_jarr[ 1 ].kbji_parts[ 1 ].kboj_op = op_ne;
_right_needed  := true;
end_of_range   := false;
WHILE (NOT _no_next_rec)               AND
      (m.mb_trns^.trError_gg00 = e_ok) AND
      (searchrec.sr_error_l <> e_no_next_record) DO
    BEGIN
    _new_page_req    := false;
    _exit_inner_loop := false;
    REPEAT
&       ifdef trace
        t01int4 (bi, 'tpsIndex    ', searchrec.sr_left_tree_pos.tpsIndex_gg00);
&       endif
        selrec.selr_fulfilled  := true;
        _first_fulfilled := true;
        IF  getrec.gi_linkrec.kbjr_linkcnt <= getrec.gi_linkrec.kbjr_cnt
        THEN
            kb741compare_two_records (selrec,
                  searchrec, getrec.gi_linkrec, sel,
                  selrec.selr_fulfilled, _first_fulfilled, end_of_range);
        (*ENDIF*) 
        getrec.gi_linkrec.kbjr_linkcnt := 1;
        IF  selrec.selr_fulfilled
        THEN
            BEGIN
            selrec.selr_selectbuffer.result.len   := 0;
            _curr_res_cnt := searchrec.sr_res_cnt;
            kb741build_new_rec (m, getrec, selrec, searchrec,
                  _right_needed, no_outer_join);
            IF  searchrec.sr_prepare_for_upd AND
                ((_curr_res_cnt < searchrec.sr_res_cnt)
                OR searchrec.sr_refused_by_ophase)
            THEN
                BEGIN
                (* mark current record as accessed *)
                (* (rec_len := 4 + keylen + 1)     *)
                _key_len.map_c2[1] :=
                      searchrec.sr_nptr.np_ptr^.nd_body[selrec.selr_l_currpos+2];
                _key_len.map_c2[2] :=
                      searchrec.sr_nptr.np_ptr^.nd_body[selrec.selr_l_currpos+3];
                _key_len.map_int :=
                      cgg_rec_key_offset + _key_len.map_int + 1;
&               ifdef trace
                t01int4 (kb, 'key_len     ', _key_len.map_int);
&               endif
                searchrec.sr_nptr.np_ptr^.nd_body[selrec.selr_l_currpos] :=
                      _key_len.map_c2[1];
                searchrec.sr_nptr.np_ptr^.nd_body[selrec.selr_l_currpos+1] :=
                      _key_len.map_c2[2]
                END;
            (*ENDIF*) 
            _right_needed := false;
            END;
        (*ENDIF*) 
        IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
        THEN
            m.mb_trns^.trError_gg00 := e_cancelled;
        (*ENDIF*) 
        IF  (_first_fulfilled OR _unequal_join) AND
            NOT end_of_range
        THEN
            WITH searchrec.sr_left_tree_pos DO
                BEGIN
                tpsIndex_gg00 := tpsIndex_gg00 + 1;
                IF  tpsIndex_gg00 > searchrec.sr_left_min_index
                THEN
                    BEGIN
                    _exit_inner_loop := true;
                    _new_page_req    := true
                    END;
                (*ENDIF*) 
                selrec.selr_l_currpos :=
                      searchrec.sr_nptr.np_ptr^.nd_pointer_list[MAX_POINTERINDEX_BD00 - tpsIndex_gg00]
                END
            (*ENDWITH*) 
        ELSE
            _exit_inner_loop := true;
        (*ENDIF*) 
    UNTIL
        _exit_inner_loop OR
        (m.mb_trns^.trError_gg00 <> e_ok);
    (*ENDREPEAT*) 
    IF  _new_page_req               AND
        (m.mb_trns^.trError_gg00 = e_ok) AND
        (_first_fulfilled OR _unequal_join) (* h.b. PTS 1001567 *)
    THEN
        BEGIN
        kb741get_left_leaf (m.mb_trns^, selrec, searchrec,
              getrec.gi_minfo.o_tree, searchrec.sr_lsearchkey, c_get_next);
        IF  m.mb_trns^.trRteCommPtr_gg00^.to_cancel
        THEN
            searchrec.sr_error_l := e_cancelled;
        (*ENDIF*) 
        _no_next_rec := searchrec.sr_error_l <> e_ok
        END
    ELSE
        _no_next_rec := true;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
END;
 
&ifdef trace
(*------------------------------*) 
 
PROCEDURE
      kb741trace_luc (
            VAR lbuf : tbd_node;
            lpos     : integer;
            llen     : integer;
            rbuf     : tsp_bufaddr;
            rpos     : integer;
            rlen     : integer;
            VAR res  : tsp_lcomp_result);
 
VAR
      aux : tsp_bufaddr;
 
BEGIN
aux := @lbuf;
t01buf (kb, aux^, lpos, lpos + llen - 1);
t01buf (kb, rbuf^, rpos, rpos + rlen - 1);
s30luc (lbuf, lpos, llen, rbuf^, rpos, rlen, res);
CASE res OF
    l_equal :
        t01int4 (kb, 'left = right', 1);
    l_less :
        t01int4 (kb, 'left < right', 1);
    l_greater :
        t01int4 (kb, 'left > right', 1);
    l_undef :
        t01int4 (kb, 'undefined   ', 1);
    END;
(*ENDCASE*) 
END;
 
&endif
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
*-PRETTY-*  statements    :        937
*-PRETTY-*  lines of code :       3008        PRETTYX 3.10 
*-PRETTY-*  lines in file :       4230         1997-12-10 
.PA 
