.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
*****************************************************
Copyright by SAP AG, 1999
SAP Database Technology
 
Release :      Date : 2000-11-22
*****************************************************
modname : VAK684
changed : 2000-11-22
module  : Join2_Select
 
Author  : ElkeZ
Created : 1985-10-16
Pretty  : 2002-08-23
*****************************************************
 
Purpose : This module completes the Join messbuffers that have
          been half-built by VAK680
 
Define  :
 
        PROCEDURE
              a684_join (
                    VAR acv                 : tak_all_command_glob;
                    VAR dmli                : tak_dml_info;
                    VAR series              : tak68_sequence;
                    VAR res_tree            : tgg00_FileId;
                    VAR parsk               : tak_parskey;
                    VAR jinfos              : tak68_joininfos;
                    VAR ak_strat_interface  : tak70_strat_rec;
                    VAR jvrec               : tak68_joinview_rec;
                    VAR cost_infos          : tak68_evaluation_records);
 
.CM *-END-* define --------------------------------------
Use     :
 
        FROM
              Scanner : VAK01;
 
        VAR
              a01sysnullkey       : tgg_sysinfokey;
 
      ------------------------------ 
 
        FROM
              AK_universal_semantic_tools : VAK06;
 
        PROCEDURE
              a06a_mblock_init (
                    VAR acv      : tak_all_command_glob;
                    mtype        : tgg_message_type;
                    m2type       : tgg_message2_type;
                    VAR tree     : tgg00_FileId);
 
      ------------------------------ 
 
        FROM
              AK_error_handling : VAK07;
 
        PROCEDURE
              a07_b_put_error (
                    VAR acv : tak_all_command_glob;
                    b_err   : tgg_basis_error;
                    err_code : tsp_int4);
 
      ------------------------------ 
 
        FROM
              Systeminfo_cache : VAK10;
 
        PROCEDURE
              a10get_sysinfo (
                    VAR acv      : tak_all_command_glob;
                    VAR syskey   : tgg_sysinfokey;
                    dstate       : tak_directory_state;
                    VAR syspoint : tak_sysbufferaddress;
                    VAR b_err    : tgg_basis_error);
 
        PROCEDURE
              a10del_sysinfo (
                    VAR acv     : tak_all_command_glob;
                    VAR syskey  : tgg_sysinfokey;
                    VAR b_err   : tgg_basis_error);
 
      ------------------------------ 
 
        FROM
              Catalog_Select_Optimizer : VAK722;
 
        PROCEDURE
              a722strategy (
                    VAR acv        : tak_all_command_glob;
                    VAR dmli       : tak_dml_info;
                    VAR eval_info  : tak70_page_eval_rec;
                    VAR gg_strategy: tgg07_StrategyInfo;
                    VAR strat_len  : tsp_int2);
 
      ------------------------------ 
 
        FROM
              Select_List : VAK61;
 
        PROCEDURE
              a61_set_jump (
                    VAR mblock : tgg_mess_block;
                    stentrynr : integer;
                    operator  : tgg_stack_entry_type);
 
        PROCEDURE
              a61_rel_old_table (
                    VAR acv  : tak_all_command_glob;
                    VAR dmli : tak_dml_info;
                    i        : integer);
 
      ------------------------------ 
 
        FROM
              Execute_Where_Part : VAK65;
 
        PROCEDURE
              a65_set_operator (
                    VAR acv  : tak_all_command_glob;
                    operator : tgg_stack_op_type);
 
      ------------------------------ 
 
        FROM
              Execute_Select_Expression : VAK660;
 
        PROCEDURE
              a660build_view_treeid (
                    VAR acv     : tak_all_command_glob;
                    VAR tableid : tgg_surrogate;
                    VAR tree    : tgg00_FileId);
 
      ------------------------------ 
 
        FROM
              Part2_Select_Expression : VAK67;
 
        PROCEDURE
              a67_explain (
                    VAR acv          : tak_all_command_glob;
                    VAR dmli         : tak_dml_info;
                    VAR strat        : tgg07_StrategyInfo;
                    VAR morestratbuf : tsp_moveobj;
                    morestratbufsize : tsp_int4;
                    morestratpos     : tsp_int4;
                    add_stackcount   : tsp_int2);
 
      ------------------------------ 
 
        FROM
              Build_Strategy : VAK70;
 
        PROCEDURE
              a70strategy (
                    VAR acv          : tak_all_command_glob;
                    VAR dmli         : tak_dml_info;
                    VAR gg_strategy  : tgg07_StrategyInfo;
                    VAR StratInfo_len: tsp_int2;
                    VAR eval_info    : tak70_page_eval_rec);
&       ifdef trace
 
      ------------------------------ 
 
        FROM
              join_trace_routines : VAK683;
 
        PROCEDURE
              a683output_joins(
                    debug       : tgg00_Debug;
                    VAR acv     : tak_all_command_glob;
                    VAR dmli    : tak_dml_info;
                    VAR joins   : tak_joinrec);
 
        PROCEDURE
              a683trace_kbjrec (
                    debug      : tgg00_Debug;
                    VAR kbjrec : tgg07_KbJoinRec);
 
        PROCEDURE
              a683joinset_trace (
                    debug        : tgg00_Debug;
                    nam          : tsp00_Sname;
                    VAR join_set : tak_joinset);
 
        PROCEDURE
              a683_output (
                    debug    : tgg00_Debug;
                    VAR dmli : tak_dml_info);
 
        PROCEDURE
              a683_one_join_entry(
                    debug    : tgg00_Debug;
                    VAR dmli : tak_dml_info;
                    index    : integer);
&       endif
 
      ------------------------------ 
 
        FROM
              Join2_Select_help_routines : VAK685;
 
        PROCEDURE
              a685next_key_length (
                    VAR dmli   : tak_dml_info;
                    VAR jinfos : tak68_joininfos);
 
        PROCEDURE
              a685last_key_len (
                    VAR acv     : tak_all_command_glob;
                    VAR jinfos  : tak68_joininfos;
                    VAR key_pos : tsp_int2);
 
        PROCEDURE
              a685olast_order_fields (
                    VAR acv     : tak_all_command_glob;
                    VAR jinfos  : tak68_joininfos;
                    VAR njrec   : tgg07_NextJoins);
 
        PROCEDURE
              a685pack_record (
                    VAR acv    : tak_all_command_glob;
                    pos        : integer;
                    VAR dmli   : tak_dml_info;
                    VAR jinfos : tak68_joininfos;
                    mj_pos     : integer);
 
        FUNCTION
              a685stentry_found_in_outplist (
                    VAR jinfos : tak68_joininfos;
                    VAR mj_pos : integer;
                    VAR dmli   : tak_dml_info;
                    VAR st_en  : tgg_stack_entry) : boolean;
 
        PROCEDURE
              a685set_st_type (
                    VAR st : tgg_stack_entry;
                    outpos : integer);
 
        PROCEDURE
              a685copy_old_output_fields (
                    VAR acv          : tak_all_command_glob;
                    VAR dmli         : tak_dml_info;
                    VAR jinfos       : tak68_joininfos;
                    outer_join_activ : boolean);
 
        PROCEDURE
              a685clast_copy_old_outp_fields (
                    VAR acv          : tak_all_command_glob;
                    VAR dmli         : tak_dml_info;
                    VAR jinfos       : tak68_joininfos;
                    VAR r_len        : tsp_int2;
                    outer_join_activ : boolean);
 
        FUNCTION
              a685evaluate_new_ecol_pos (
                    VAR dmli      : tak_dml_info;
                    VAR jinfos    : tak68_joininfos;
                    curr_st_entry : integer;
                    len_var       : integer) : integer;
 
        PROCEDURE
              a685build_next_key (
                    VAR acv    : tak_all_command_glob;
                    VAR dmli   : tak_dml_info;
                    VAR jinfos : tak68_joininfos);
 
        PROCEDURE
              a685kcopy_keyfields (
                    VAR acv          : tak_all_command_glob;
                    VAR dmli         : tak_dml_info;
                    VAR jinfos       : tak68_joininfos);
 
      ------------------------------ 
 
        FROM
              Single_Select : VKB720;
 
        PROCEDURE
              k720_maxresult_get (
                    VAR data           : tsp_moveobj;
                    strat_maxcnt       : tsp_int2;
                    VAR maxresult      : tsp_int4;
                    VAR b_err          : tgg_basis_error);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_1 : VBD01;
 
        VAR
              b01niltree_id : tgg00_FileId;
 
      ------------------------------ 
 
        FROM
              Select_Help_Procedures : VGG04;
 
        PROCEDURE
              g04build_temp_tree_id (
                    VAR temp_tree : tgg00_FileId;
                    VAR t : tgg00_TransContext);
 
      ------------------------------ 
 
        FROM
              Record_Encapsulate_Procedures : VGG09;
 
        PROCEDURE
              g09StratStackentry (
                    VAR NewStackEntry : tgg00_StackEntry;
                    inp_startpos      : tsp_int2;
                    inp_len           : tsp_int2);
 
      ------------------------------ 
 
        FROM
              Kernel_move_and_fill : VGG10;
 
        PROCEDURE
              g10mv1  (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size1          : tsp_int4;
                    size2          : tsp_int4;
                    VAR val1       : tgg_stack_list;
                    p1             : tsp_int4;
                    VAR val2       : tgg_stack_list;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
        PROCEDURE
              g10mv2  (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size1          : tsp_int4;
                    size2          : tsp_int4;
                    VAR val1       : tgg07_StrategyInfo;
                    p1             : tsp_int4;
                    VAR val2       : tsp_moveobj;
                    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       : tgg07_MInfos;
                    p1             : tsp_int4;
                    VAR val2       : tsp_moveobj;
                    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       : tgg07_NextJoins;
                    p1             : tsp_int4;
                    VAR val2       : tsp_moveobj;
                    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       : tgg07_KbJoinRec;
                    p1             : tsp_int4;
                    VAR val2       : tsp_moveobj;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
        PROCEDURE
              g10mv6  (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size1          : tsp_int4;
                    size2          : tsp_int4;
                    VAR val1       : tsp_moveobj;
                    p1             : tsp_int4;
                    VAR val2       : tsp_moveobj;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
        PROCEDURE
              g10mv7  (
                    mod_id         : tsp_c6;
                    mod_intern_num : tsp_int4;
                    size1          : tsp_int4;
                    size2          : tsp_int4;
                    VAR val1       : tsp_moveobj;
                    p1             : tsp_int4;
                    VAR val2       : tgg07_StrategyInfo;
                    p2             : tsp_int4;
                    cnt            : tsp_int4;
                    VAR e          : tgg_basis_error);
 
      ------------------------------ 
 
        FROM
              RTE-Extension-10 : VSP10;
 
        PROCEDURE
              s10mv1 (
                    size1    : tsp_int4;
                    size2    : tsp_int4;
                    VAR val1 : tak_parskey;
                    p1       : tsp_int4;
                    VAR val2 : tgg_surrogate;
                    p2       : tsp_int4;
                    cnt      : tsp_int4);
&       ifdef TRACE
 
        PROCEDURE
              s10fil1 (
                    size     : tsp_int4;
                    VAR m    : tsp_moveobj;
                    pos      : tsp_int4;
                    len      : tsp_int4;
                    fillchar : char);
 
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        PROCEDURE
              t01sname (
                    debug : tgg00_Debug;
                    nam   : tsp00_Sname);
 
        PROCEDURE
              t01p2int4 (
                    debug : tgg00_Debug;
                    nam_1 : tsp00_Sname;
                    int_1 : tsp00_Int4;
                    nam_2 : tsp00_Sname;
                    int_2 : tsp00_Int4);
 
        PROCEDURE
              t01p2bool (
                    debug : tgg00_Debug;
                    nam_1 : tsp00_Sname;
                    bool1 : boolean;
                    nam_2 : tsp00_Sname;
                    bool2 : boolean);
 
        PROCEDURE
              t01name (
                    debug : tgg00_Debug;
                    nam   : tsp00_Name);
 
        PROCEDURE
              t01qual1 (
                    debug     : tgg00_Debug;
                    nam       : tsp00_Sname;
                    VAR part1 : tgg00_QualBuf);
 
        PROCEDURE
              t01bool (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    curr_bool: boolean);
 
        PROCEDURE
              t01stackdesc (
                    debug          : tgg00_Debug;
                    nam            : tsp00_Sname;
                    stack_addr     : tgg00_StackListPtr;
                    VAR stack_desc : tgg00_StackDesc);
 
        PROCEDURE
              t01messblock (
                    debug         : tgg00_Debug;
                    nam           : tsp00_Sname;
                    VAR m         : tgg00_MessBlock);
 
        PROCEDURE
              t01qual (
                    level     : tgg00_Debug;
                    VAR q_buf : tgg00_QualBuf);
 
        PROCEDURE
              t01int4 (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    int      : tsp00_Int4);
 
        PROCEDURE
              t01stackentry (
                    layer       : tgg00_Debug;
                    VAR st      : tgg00_StackEntry;
                    entry_index : integer);
 
        FUNCTION
              t01trace (layer : tgg00_Debug) : boolean;
 
        PROCEDURE
              t01treeid (
                    layer      : tgg00_Debug;
                    nam        : tsp00_Sname;
                    VAR treeid : tgg00_FileId);
&       ENDIF
 
      ------------------------------ 
 
        FROM
              Join_Select_execution: VAK682;
 
        PROCEDURE
              a682join_parsinfo_key (
                    VAR acv      : tak_all_command_glob;
                    VAR dmli     : tak_dml_info;
                    VAR parsk    : tak_parskey;
                    VAR jv_tabid : tgg_surrogate;
                    seqno        : integer;
                    VAR ke       : tgg_sysinfokey);
 
        PROCEDURE
              a682_mbuf_to_tmpbuf (
                    VAR acv       : tak_all_command_glob;
                    VAR ke        : tgg_sysinfokey;
                    VAR b_err     : tgg_basis_error;
                    sysinfo_kind  : tak68_mbuf_to_tmpbuf_context);
 
.CM *-END-* use -----------------------------------------
Synonym :
 
        PROCEDURE
              g10mv1;
 
              tsp_moveobj tgg_stack_list
 
        PROCEDURE
              g10mv2;
 
              tsp_moveobj tgg07_StrategyInfo
 
        PROCEDURE
              g10mv3;
 
              tsp_moveobj tgg07_MInfos
 
        PROCEDURE
              g10mv4;
 
              tsp_moveobj tgg07_NextJoins
 
        PROCEDURE
              g10mv5;
 
              tsp_moveobj tgg07_KbJoinRec
 
        PROCEDURE
              g10mv7;
 
              tsp_moveobj tgg07_StrategyInfo
 
        PROCEDURE
              s10mv1;
 
              tsp_moveobj tak_parskey
              tsp_moveobj tgg_surrogate
 
.CM *-END-* synonym -------------------------------------
***********************************************************
Specification:
.sp 2;.nf
List of procedures
(No ] Name (calls)
 
(1) a684_join (2)
    (2) join_one_record (3, 5, 6, 7, 8, 9, 11, 12)
        (3) build_new_output (4, 11, 12)
            (4) one_join_column
 
        (5) transfer_output_fields
 
        (6) build_nnext_join
 
        (7) a685olast_order_fields
 
        (8) get_qualification
 
        (9) build_strat_info (10)
            (10) move_infos
.fo
 
.CM *-END-* specification -------------------------------
***********************************************************
Description:
 
A684_JOIN
 
This is the main procedure of this module. In it, the information in the
original Mess-Buffer (which contains all the output- and qualification stack
entries for all tables) and the qualification Mess-Buffer that has already been
built for the respective table (VAK68) are used to build those Join Mess-Buffers
that can then be sent to KB.
The following variables are used in this module:
 
d_inoutpos : originally specifies the length of the result record required by
the user (the length is desired by SELECT list, ORDER-BY part, FOR UPDATE). In
the course of processing, d_inoutpos is extended by the lengths of the Join
field values that are stored right at the back in the respective
intermediate-result record.
 
atkeylen : specifies the key length of a final result record.
 
ji_act_join : specifies the number of the Join step, not of the current table.
 
series : contains the processing order of the tables.
 
series[ ji_act_join ].jos_source,
 
ji_acttabno : specify the current table number.
 
ji_outpos : specifies the position of the next field in the right-hand
intermediate-result record of this Join step (first the positions of the Join
fields, then those of the normal output fields).
 
jr_keylen : specifies the key length of the right-hand intermediate-result
record of this Join step.
 
ji_outpos : specifies the length of info_part of each left-hand
intermediate-result record.
 
kbjcnt : identifies the number of Join conditions of this Join step.
 
n_j_cnt : identifies the number of Join fields of the next Join step.
 
n_j_pos : identifies the position of the next Join field of the next Join step,
i.e. the length of the key of the result record to be built in this Join step.
 
jrc_cnt : specifies the number of Join conditions described in
jrc_joinarr[ 0..jrc_cnt-1 ].
 
The necessary initializations are performed, with it being necessary, contrary
to the name, for the table number of the second table to be processed to be
entered in j_before, so that the fields necessary for the second Join step are
entered in the key of the intermediate results of the first Join step.
Accordingly, j_afterwards must start only with the third table to be processed.
j_res_fn receives the file name that has to be used for the resorting of
the right-hand table if a good strategy is not available.
In a loop, AK684JOIN_ONE_RECORD is called for each table to be processed and the
number of this table is transferred from the set of tables still to be
processed to the set of those that have already been processed.
If something has gone wrong during the creation of the Mess-Buffers, all
half- (VAK68) and fully- (VAK684) built Mess-Buffers must be deleted.
 
AK684JOIN_ONE_RECORD
 
In this procedure, the Mess-Buffer is completed for a table taking part in the
Join.
A new Mess-Buffer is initialized. mhelp.bool2 is, if necessary, set to true
if part2 of the Mess-Buffer, which is used for all Join steps, must not be
destroyed (this must not happen until in the last Join step)
jvrec.jv_maxkeyl specifies the maximum length of a participating primary
key in a Join View. This space must then be kept free.
A stack entry is kept free in which is entered later the number of output
stack entries that are to be jumped during the checking of the qualification.
See A684_JOIN for the description of the variables.
If there is at least one join condition (and it is not the cartesian
product that is to be formed), BUILD_NEW_OUTPUT, with j_before, builds output
stack entries that take the Join fields for this Join step to the key of the
right-hand intermediate-result record.
series[ ji_act_join ].jos_joinno is used to identify that Join condition in
jrc_joinarr that represents the most selective Join condition leading from an
already processed table to the current table. The associated Join field must,
therefore, come at the beginning of the key, whereas the others can be entered
in any order.
The length of the key of a right-hand result record (incl. the 4 bytes
counter that each key of a result record contains) is known.
After all Join steps, the info_part of the new intermediate result
has the appearance desired by the user for the final result. Positioned behind
it (invisible, as it were) are Join fields that were needed. The length of
the first intermediate-result record must, accordingly, be set to this length
before Join fields that are to be attached are determined.
BUILD_NEW_OUTPUT with j_afterwards determines those fields of the current
table that are needed as Join fields not in this Join step but in a later one,
i.e. those fields that must, for the time being, be appended to the end of the
intermediate-result record.
TRANSFER_OUTPUT_FIELDS transfers to the new Mess-Buffer the output
conditions that have been specified by the user. These are output stack entries
that form a right-hand intermediate-result record. Therefore, the Join fields
can be processed first. The position to which the respective field is to
be written in the intermediate result that is to be formed is described by
special mechanisms (ONE_JOIN_COLUMN).
BUILD_NNEXT_JOIN enters in the array njrec.n_j_arr which fields are
required in the key in the next Join step, and which fields must be copied at
the end of this Join step from the info part of the result record to the key,
so that they are available for the next Join step.
In the last Join step, no Join fields of the next Join step are transferred
to the key, but the fields specified by the user in ORDER BY. This is done in
LAST_ORDER_FIELDS.
The specification of DISTINCT means that, in each Join step, DISTINCT is
performed for the table that is to be resorted on the right, i.e. that there
must be space in the key for the 2 bytes necessary for this purpose (in
addition to the usual 4 bytes counter).
The number of output stack entries is known; an entry can be made in the
Jump stack entry.
The qualification that has been determined for this table in VAK68 is
transferred to the new Mess-Buffer (GET_QUALIFICATION).
By means of BUILD_STRAT_INFO, the Join strategies are built and are entered
in the Mess-Buffer.
These Join strategies and their storing in the Mess-Buffer are described in
VKB74, Specification.
The Mess-Buffer must now also be stored in 1-2 system information records of
type emessbuf (or evmessbuf for Join Views). Since VAK68 has already created a
half-filled Mess-Buffer (with the qualification), there is already a first
buffer for each table, which just needs to be extended and replaced.
 
AK684N_BUILD_NEW_OUTPUT
 
The Join condition identified by jos_joinno is the most selective one from the
already processed tables to the current one. The associated Join field must,
therefore, be entered first in the key. jos_joinno = cartesian_product indicates
that there is no Join condition from the processed tables to the current one.
Only the order in the key is important. Therefore, in_key is interrogated
only for this call of AK684N_BUILD_NEW_OUTPUT (with j_before). The order is irrelevant
as regards the call with j_afterwards, in which the Join fields go to the end
of the result set, and as regards the Join conditions not identified by
jos_joinno.
Therefore, all Join fields from Join conditions between the current table
and one of those contained in the set are processed by ONE_JOIN_COLUMN.
 
AK684ONE_JOIN_COLUMN
 
By means of this procedure, the stack entries that describe a Join field of the
current table are transferred to the Mess-Buffer. An output stack entry is built
that puts the field in the correct position in the result. If necessary, the
description of a Join condition is created for KB.
A Join field may be composed of an expression. Therefore, a Join field may
have been described by more than one stack entry. These stack entries are moved
to the new Mess-Buffer, and the Join operator, if contained, (op_eq, op_ge or
similar) is destroyed.
If the field is to be incorporated into the key of a right-hand
intermediate-result record, the output stack entry may be 'normal' in
appearance: st_output, s10fil byte specified in ecol_tab[ 1 ], ecol_tab[ 2 ]
empty.
Fields that are to be put into the key are Join fields for the current Join
step. The associated Join condition must be given to KB. This is done in
KBJ_ARR. The keys are of identical construction in the two records that are to
be compared. Therefore, KBOJ_RECPOS specifies the position of one Join field
in both records, with KBOJ_LEN specifying the length (the greater length of
the two fields is used for this purpose) and with KBOJ_OP specifying the Join
operator. This Join operator must, of course, be turned round if the table
specified on the right in the Join condition is processed first and then the
left-hand table.
In the case of fields that are required only in following Join steps, the
output stack entry for the first Join step may also be 'normal' in appearance.
It is changed in the case of the other Join steps:
ETYPE specifies that this is an output statement. Normally, this would be
identified only by st_output. The appendix in the name specifies with which
bytes a field is to be filled to the specified length.
This is normally in the form of a character in ecol_tab[ 1 ]. In the case
of Joins, however, the final position of the field in the left-hand
intermediate result is in ecol_pos (= ecol_tab[ 1..2 ]). All information
should/had to, however, go into a stack entry. Therefore, information was
grouped together that is isolated in KB when N_POS_S is built (st_output,
ecol_tab[ 1 ] = blank/'00'h, ecol_tab[ 2 ] empty).
EPOS, therefore, specifies the position in the right-hand
intermediate-result record,
which, in this Join step, is joined to an old left-hand record
to form a new left-hand record. And this new left-hand record contains the
field at position ECOL_POS in the info part (key length + start of record still
to be added).
 
AK684TRANSFER_OUTPUT_FIELDS
 
This procedure analyzes the part of the original Mess-Buffer that contains the
output stack entries.
For each output entry (etype = st_output), it is determined whether it
refers to the current table (ji_acttabno).
If the output entry refers to the current table or if the entry does not
refer to any table, but the first Join step is to be performed (which also
immediately takes care of such non-assignable outputs) or if it is the turn of
the last Join step and ROWNO was specified (it is, of course, possible for
ROWNO not to be specified until the final result is known), the stack entries
belonging to this output information are put into the new Mess-Buffer.
In the new output stack entry, epos specifies the position in the
right-hand
intermediate-result record, with ecol_pos specifying the position in the
info part of the new left-hand intermediate-result record.
d_inoutpos must be increased for order fields that are to be stored in the
rear part of the left-hand intermediate results.
Recorded in the old Mess-Buffer for Order-By fields is the position in the
intermediate result at which this field can be found. This entry is used by
A685OLAST_ORDER_FIELDS in the last Join step.
 
BUILD_NNEXT_JOIN
 
In this procedure, the array njrec.n_j_arr that is to be passed to KB is
filled. It contains information on the fields that are needed in the key in the
next Join step; more precisely: it contains the position in the info part of a
new left-hand intermediate-result record (jfrom) from which a field of which
length (jlen) is to be copied to which position in the key of the same record
(jto), in order to be available there for the following Join step.
The particularly selective Join condition, recorded in series, for the
table that is to be joined in the next Join step again needs its Join field at
the beginning of the key. All other Join fields that belong to Joins between
already processed tables (or to the current table in this Join step) and the
table current in the next Join step may be in any order in the key.
 
A685OLAST_ORDER_FIELDS
 
In the last Join step, fields that were specified in ORDER BY are handled as if
they were necessary in the key for the next Join step, i.e. information on them
is given to KB in njrec.n_j_arr.
In AK684TRANSFER_OUTPUT_FIELDS, in the original Mess-Buffer, it was entered in
ecol_pos in the output stack entries for these ORDER-BY fields at what position
in the info part of the result record they can be found. Information must now
also be built as to from where (see ecol_pos) to where they are to be copied in
the key (old epos entry minus length of the start of the record (=4)). If
sorting is to be descending (op_output_order), the field value must be
converted during copying. The need for conversion is indicated by a negative
jfrom.
 
AK684GET_QUALIFICATION
 
The Mess-Buffers created in VAK68 contain for each table only the qualifications
belonging to that table (these were already needed to determine the best table-
processing order). The Mess-Buffer belonging to the current table is fetched in
this procedure. The qualification stack entries contained in it are transferred
to the new, final Mess-Buffer for this table.
 
AK684ADD_NOT_NULL_QUALIFICATION
 
This procedure adds an 'is not null'-qualification for the
joinconditions of the current table. The procedure makes shure that
only one time an 'is not null'-qualification is added for each
joinfield of the current table.
 
AK684BUILD_STRAT_INFO
 
The Mess-Buffer contained in AK684GET_QUALIFICATION contains, in addition to the
qualification stack entries, also the best search strategy for that table
(however, for reasons of space-saving, the two file names (sourcefn and
resultfilen) are missing).
This strategy description is moved in this procedure to a corresponding
structure (strat); the source file name (primary-table name) and the name of
the possibly not required, right-hand, resorted intermediate-result table
(j_res_fn) are entered.
If there is a better possibility of access to right-hand records than the
previous resorting and entering in a right-hand intermediate-result set
(sbest_j <> sequential), the strategy description consists in any case of the
description of the primary-key bounds (keystart, keystop). For access via an
inversion, the inversion number is also recorded in invindex.
If there has been an EXPLAIN command (intern_explain), the output is
initiated.
If DISTINCT was specified by the user, it must be performed in each Join
step with the right-hand table that is to be resorted in order to remove
duplicates as early as possible.
It is possible for ROWNO not to be entered until in the last Join step
(ji_act_join = atcnt).
key_len, rec_len identify lengths of a right-hand intermediate-result
record.
 
Entered in MINFO (see VKB74) are file name, tree id, record length and key
length for the old left-hand intermediate result and for the new one that is to
be built, as well as an indication as to whether there is a restriction on the
number of result records (n_maxcnt). Information relating to the new result in
this Join step is recorded, because it reflects the old result in the next
step.
In the first Join step, there is only the first of the three strategies and
nor is there a minfo. Only the information for the second Join step needs to be
recorded.
In the last Join step, the Join fields that have in the meantime been
appended to the end of each result record are removed again (the old d_inoutpos
value is used as the record length).
By means of MOVE_INFOS, the 1 (1st Join step) or 3 strategies are
transferred to part2 of the Mess-Buffer and stack entries that refer to it
(them) are written to part1.
 
AK684MOVE_INFOS
 
This procedure shifts the strategy structures strat, minfo, njrec, kbrec to
part2 of the Mess-Buffer and creates the three strategy stack entries in part1.
For this purpose, in the first Join step, the procedure is called once
only, because, at that time, there is only strat; otherwise, the procedure is
called three times. The second time, first minfo (100 bytes long) and then
njrec are put into part2, but only one stack entry with the starting position
and length of njrec is created.
.CM *-END-* description ---------------------------------
***********************************************************
.CM -lll-
Code    :
 
 
CONST
      c_in_key           = true (* ak684n_build_new_output *);
 
 
(*------------------------------*) 
 
PROCEDURE
      ak684add_not_null_qualification (
            VAR acv    : tak_all_command_glob;
            VAR dmli   : tak_dml_info;
            VAR jinfos : tak68_joininfos;
            add_and_op : boolean);
 
VAR
      _i               : integer;
      _j               : integer;
      _k               : integer;
      _st_pos          : integer;
      _and_cnt         : integer;
      _last_st_pos     : integer;
      _field_nos       : SET OF 1..MAX_COL_PER_TAB_GG00;
      _found           : boolean;
 
BEGIN
IF  add_and_op
THEN
    _and_cnt := 0
ELSE
    _and_cnt := -1;
(*ENDIF*) 
_field_nos := [  ];
IF  acv.a_mblock.mb_data^.mbp_buf[ acv.a_mblock.mb_data_len  ] <>
    csp_undef_byte
THEN
    BEGIN
    jinfos.ji_mb_data_len    := succ (jinfos.ji_mb_data_len);
    acv.a_mblock.mb_data_len := succ (acv.a_mblock.mb_data_len );
    acv.a_mblock.mb_data^.mbp_buf[ acv.a_mblock.mb_data_len  ] :=
          csp_undef_byte;
&   IFDEF TRACE
    t01int4 (ak_join, 'ji_mb_data_l', jinfos.ji_mb_data_len);
    t01qual (ak_join, acv.a_mblock.mb_qual^);
&   ENDIF
    END;
(*ENDIF*) 
_last_st_pos  := acv.a_mblock.mb_qual^.mfirst_free;
&IFDEF TRACE
t01messblock (ak_join, 'MESSBUF     ', acv.a_mblock);
&ENDIF
FOR _i := 0 TO (dmli.d_joins.jrc_cnt - 1) DO
    IF  (acv.a_mblock.mb_qual^.mfirst_free <= acv.a_mblock.mb_st_max + 4)
    THEN
        BEGIN
        IF  (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ 2 ].jop_tableno <>
            cak68_join_value)
        THEN
            FOR _j := 1 TO 2 DO
                BEGIN
                CASE _j OF
                    1 :
                        _k := 2;
                    2 :
                        _k := 1;
                    END;
                (*ENDCASE*) 
                _found := (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].jop_fieldno in _field_nos) AND
                      (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].jop_cntstack = 1);
&               IFDEF TRACE
                t01int4 (ak_join, 'found       ', ord (_found));
                t01int4 (ak_join, 'j           ', _j);
                t01int4 (ak_join, 'i           ', _i);
&               ENDIF
                IF  (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].
                    jop_tableno = jinfos.ji_acttabno)
                    AND
                    (NOT dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].
                    jop_outer_join)
                    AND
                    (NOT _found)
                    AND
                    (NOT (jtkey in dmli.d_joins.jrc_joinarr[ _i ].
                    jo_recs[ _j ].jop_propset))
                    AND
                    (NOT (jtfirstkey in dmli.d_joins.jrc_joinarr[ _i ].
                    jo_recs[ _j ].jop_propset))
                    AND
                    (NOT (jtonlykey in dmli.d_joins.jrc_joinarr[ _i ].
                    jo_recs[ _j ].jop_propset))
                    AND
                    (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].
                    jop_cntstack = 1)
                    AND
                    (NOT (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].
                    jop_tableno in jinfos.ji_nxtjinfo.nj_left_side))
                THEN
                    BEGIN
                    _field_nos := _field_nos +
                          [ dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].jop_fieldno ];
                    IF  _and_cnt >= 0
                    THEN
                        BEGIN
                        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free ].etype := st_jump_false;
                        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free ].eop   := op_none;
                        acv.a_mblock.mb_qual^.mfirst_free := succ (acv.a_mblock.mb_qual^.mfirst_free);
                        acv.a_mblock.mb_qual^.mqual_cnt   := succ (acv.a_mblock.mb_qual^.mqual_cnt);
                        END;
                    (*ENDIF*) 
                    _st_pos := acv.a_mblock.mb_qual^.mfirst_free;
                    WITH jinfos.ji_st_addr^
                         [ dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].jop_startstack ] DO
                        BEGIN
                        IF  (eop = op_join_key)
                        THEN
                            acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free ] :=
                                  acv.a_mblock.mb_st^[ ord (ecol_tab[ 1 ]) - 1 ]
                        ELSE
                            FOR _k := 0 TO dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].jop_cntstack - 1 DO
                                BEGIN
                                acv.a_mblock.mb_st^
                                      [ acv.a_mblock.mb_qual^.mfirst_free ] :=
                                      jinfos.ji_st_addr^[ dmli.d_joins.
                                      jrc_joinarr[ _i ].jo_recs[ _j ].
                                      jop_startstack + _k ];
                                acv.a_mblock.mb_qual^.mfirst_free :=
                                      succ (acv.a_mblock.mb_qual^.mfirst_free);
                                acv.a_mblock.mb_qual^.mqual_cnt   :=
                                      succ (acv.a_mblock.mb_qual^.mqual_cnt);
                                END;
                            (*ENDFOR*) 
                        (*ENDIF*) 
                        END;
                    (*ENDWITH*) 
                    acv.a_mblock.mb_st^[ _st_pos ].eop := op_none;
                    IF  _st_pos = acv.a_mblock.mb_qual^.mfirst_free
                    THEN
                        BEGIN
                        acv.a_mblock.mb_qual^.mfirst_free :=
                              succ (acv.a_mblock.mb_qual^.mfirst_free);
                        acv.a_mblock.mb_qual^.mqual_cnt   :=
                              succ (acv.a_mblock.mb_qual^.mqual_cnt);
                        END;
&                   IFDEF TRACE
                    (*ENDIF*) 
                    t01int4 (ak_join, 'is null===>j', _j);
                    t01int4 (ak_join, 'is null===>i', _i);
&                   ENDIF
                    WITH acv.a_mblock.mb_st^
                         [ acv.a_mblock.mb_qual^.mfirst_free ] DO
                        BEGIN
                        etype         := st_value;
                        eop           := op_not_null;
                        epos          := acv.a_mblock.mb_data_len ;
                        elen_var      := 1;
                        ecol_tab[ 1 ] := chr(0);
                        ecol_tab[ 2 ] := chr(0);
                        END;
                    (*ENDWITH*) 
                    acv.a_mblock.mb_qual^.mfirst_free :=
                          succ (acv.a_mblock.mb_qual^.mfirst_free);
                    acv.a_mblock.mb_qual^.mqual_cnt   :=
                          succ (acv.a_mblock.mb_qual^.mqual_cnt);
                    _and_cnt     := succ (_and_cnt);
                    END;
                (*ENDIF*) 
                END;
            (*ENDFOR*) 
        (*ENDIF*) 
        END;
    (*ENDIF*) 
(*ENDFOR*) 
FOR _i := 1 TO _and_cnt DO
    a65_set_operator (acv, op_and);
(*ENDFOR*) 
_i := _last_st_pos;
WHILE _i < acv.a_mblock.mb_qual^.mfirst_free DO
    BEGIN
    IF  (acv.a_mblock.mb_st^[ _i ].etype = st_jump_false)
    THEN
        a61_set_jump (acv.a_mblock, _i, st_jump_false);
    (*ENDIF*) 
    _i := succ (_i);
    END;
(*ENDWHILE*) 
&IFDEF TRACE
t01qual1 (ak_join, 'add NOT NULL', acv.a_mblock.mb_qual^);
&ENDIF
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684n_build_new_output (
            VAR acv    : tak_all_command_glob;
            VAR dmli   : tak_dml_info;
            VAR jinfos : tak68_joininfos;
            VAR series : tak68_sequence;
            in_key     : boolean;
            is_outertab: boolean);
 
VAR
      _in_temp_record: boolean;
      _i             : integer;
      _j             : integer;
      _k             : integer;
      _jk_field_cnt  : integer;
      _kbj_pack      : boolean;
      _is_join_value : boolean;
 
BEGIN
(* if in_key jinfos.ji_outpos = cgg_rec_key_offset + 1 !!*)
(* if NOT in_key jinfos.ji_outpos = jinfos.ji_outpos - (cgg_rec_key_offset + 1) !!*)
IF  (series[ jinfos.ji_act_join ].jos_joinstrat = strat_join_all_keys_equal)
    OR
    (series[ jinfos.ji_act_join ].jos_joinstrat = strat_join_key_range)
    OR
    (series[ jinfos.ji_act_join ].jos_joinstrat = strat_join_all_inv_equal)
    OR
    (series[ jinfos.ji_act_join ].jos_joinstrat = strat_join_inv_range)
THEN
    _jk_field_cnt := series[ jinfos.ji_act_join ].jos_fieldcnt
ELSE
    _jk_field_cnt := 0;
(*ENDIF*) 
&IFDEF TRACE
t01int4 (ak_join, 'JOIN STEP   ', jinfos.ji_act_join);
t01bool (ak_join, 'build key   ', in_key);
t01int4 (ak_join, 'jk_field_cnt', _jk_field_cnt);
t01qual1(ak_join, 'build new  1', acv.a_mblock.mb_qual^);
&ENDIF
FOR _i := 0 TO dmli.d_joins.jrc_cnt - 1 DO
    BEGIN
    _j := 1;
    REPEAT
        (* work for left and right join side *)
        _is_join_value :=
              (* i+1.th tab = <value> *)
              (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ 1 ].jop_tableno =
              jinfos.ji_nxtjinfo.nj_nxttabno)
              AND
              (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ 2 ].jop_tableno =
              cak68_join_value)
              AND
              (
              ((jinfos.ji_act_join = 1) AND in_key)
              (* needed in 1. join step for key building *)
              OR
              ((jinfos.ji_act_join > 1) AND (NOT in_key))
              (* needed for next join steps for later usage *)
              );
        IF  (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].jop_tableno =
            jinfos.ji_acttabno)
            (* i.th tab = ??? *)
            OR
            _is_join_value
            (* i+1.th tab = <value> *)
        THEN
            BEGIN
&           ifdef trace
            t01sname( ak_join, 'entry found ' );
            a683_one_join_entry( ak_join, dmli, _i );
&           endif
            CASE _j OF
                1 :
                    _k := 2;
                2 :
                    _k := 1;
                END;
            (*ENDCASE*) 
            _in_temp_record :=
                  (* columns for join access with actual table found *)
                  (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].jop_tableno IN
                  jinfos.ji_nxtjinfo.nj_left_side)
                  (* i.th tab = i-x.th tab *)
                  OR
                  (* special cases for 1. join step *)
                  ((dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].jop_tableno =
                  jinfos.ji_nxtjinfo.nj_nxttabno) AND ( jinfos.ji_act_join = 1))
                  (* i.th tab = i+1.th tab in 1.step for key build *)
                  OR
                  (_is_join_value AND (jinfos.ji_act_join = 1)
                  (* i+1.th tab = <value> in 1.step for key build *));
&           IFDEF TRACE
            t01bool (ak_join, 'in_temp_rec ', _in_temp_record);
            t01bool (ak_join, 'is_join_valu', _is_join_value);
&           endif
            IF  (
                (in_key
                AND
                (_in_temp_record OR
                (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ 2 ].jop_tableno =
                cak68_join_value))
                (* i.th tab   = <value>  OR *)
                (* i+1.th tab = <value> for any join step *)
                )
                OR
                (* need other columns for later usage *)
                ((NOT in_key) AND
                (* any: i.th tab = ???? *)
                (NOT _in_temp_record)))
            THEN
                BEGIN
                IF  (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].jop_tableno IN
                    jinfos.ji_nxtjinfo.nj_left_side)
                THEN
                    (* i.th tab = i-x.th tab *)
                    _k := 2 (* kbjpart site *)
                ELSE
                    _k := 1;(* kbjpart site *)
                (*ENDIF*) 
                IF  _is_join_value
                THEN
                    BEGIN
                    _j := 2; (* jo_recs site with cak68_join_value *)
                    _k := 1; (* kbjpart site *)
                    END;
                (* multiple join columns *)
                (*ENDIF*) 
                _kbj_pack := _jk_field_cnt > 0;
                IF  (NOT _kbj_pack)
                    AND
                    in_key
                    AND
                    (dmli.d_joins.jrc_joinarr[ _i ].jo_op = op_eq)
                    AND
                    (series[ jinfos.ji_act_join ].jos_joinstrat = strat_key_range)
                    (* no join transition *)
                THEN
                    BEGIN
                    IF  (jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt = 0)
                    THEN (* first joinfield *)
                        _kbj_pack := true
                    ELSE
                        IF  (ord (jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jarr
                            [ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                            kbji_parts[ 2 ].kboj_op ) = 0)
                        THEN (* both have same len *)
                            _kbj_pack :=
                                  (NOT jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_right_oj)
                                  AND
                                  (NOT jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_left_oj)
                                  AND
                                  (dmli.d_oj_tables <> []);
                        (*ENDIF*) 
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                ak684one_join_column (acv, dmli, jinfos,
                      series, in_key, is_outertab, _i, _kbj_pack, _j, _k);
                _jk_field_cnt := pred (_jk_field_cnt);
                _j := 3;  (* exit repeat *)
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        _j := succ (_j);
    UNTIL
        (_j > 2);
    (*ENDREPEAT*) 
    END;
(*ENDFOR*) 
&IFDEF TRACE
t01qual1(ak_join, 'build new  2', acv.a_mblock.mb_qual^);
&ENDIF
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684build_strat_info (
            VAR acv                 : tak_all_command_glob;
            VAR dmli                : tak_dml_info;
            VAR jinfos              : tak68_joininfos;
            VAR njrec               : tgg07_NextJoins;
            VAR res_tree            : tgg00_FileId;
            VAR joinp               : tak_sysbufferaddress;
            VAR series              : tak68_sequence;
            VAR ak_strat_interface  : tak70_strat_rec;
            VAR gg_strategy         : tgg07_StrategyInfo;
            use_subquery            : boolean);
 
VAR
      _dummy_len        : tsp_int2;
      _i                : integer;
      _ilen             : integer;
      _j                : integer;
      _movelen          : integer;
      _minfo            : tgg07_MInfos;
      _bw               : tak70_page_eval_rec;
      _e                : tgg_basis_error;
 
BEGIN
gg_strategy.str_result_id := b01niltree_id;
IF  acv.a_mblock.mb_qual^.mstrat_cnt > 0
THEN
    _movelen := acv.a_mblock.mb_st^
          [ acv.a_mblock.mb_qual^.mstrat_pos ].elen_var
ELSE
    _movelen := joinp^.smessblock.mbr_mess_block.
          mb_st^[ joinp^.smessblock.mbr_mess_block.mb_qual^.mstrat_pos ].
          elen_var;
(*ENDIF*) 
_ilen := _movelen;
&ifdef TRACE
t01messblock (ak_join, 'mbr_mess_blo', joinp^.smessblock.mbr_mess_block);
IF  acv.a_mblock.mb_qual^.mstrat_cnt > 0
THEN
    t01int4 (ak_join, 'movelen  a70', _movelen)
ELSE
    t01int4 (ak_join, 'movelen  tmp', _movelen);
(*ENDIF*) 
t01int4 (ak_join, '(movelenTmp)',
      joinp^.smessblock.mbr_mess_block.
      mb_st^[ joinp^.smessblock.mbr_mess_block.mb_qual^.mstrat_pos ].
      elen_var);
&endif
IF  _movelen > sizeof (gg_strategy)
THEN
    _movelen := sizeof (gg_strategy);
(*ENDIF*) 
IF  acv.a_mblock.mb_qual^.mstrat_cnt = 0
THEN        (* *** not inv_only strategy *** *)
    BEGIN
    g10mv7 ('VAK684',   1,    
          joinp^.smessblock.mbr_mess_block.mb_strat_size,
          sizeof( gg_strategy ),
          joinp^.smessblock.mbr_mess_block.mb_strat^, 1,
          gg_strategy, 1, _movelen,
          acv.a_return_segm^.sp1r_returncode);
    (* remark stack move size for correct         *)
    (* stack positions of internal stack pointers *)
    gg_strategy.str_stack_output_offs :=
          gg_strategy.str_stack_output_offs +
          (acv.a_mblock.mb_qual^.mqual_pos + acv.a_mblock.mb_st^
          [ acv.a_mblock.mb_qual^.mqual_pos ].epos - 2);
    END;
(*ENDIF*) 
;
&ifdef TRACE
t01int4 (ak_join, 'stack_offset', gg_strategy.str_stack_output_offs);
t01int4 (ak_join, 'strat.enum  ', ord (gg_strategy.str_strategy));
t01messblock (ak_join, 'MESSBUF     ', acv.a_mblock);
&endif
IF  acv.a_return_segm^.sp1r_returncode = 0
THEN
    BEGIN
    IF  gg_strategy.str_strategy = strat_catalog
    THEN
        BEGIN
        (* strategy must be determined again due to *)
        (* changes of the message buffer            *)
        a61_rel_old_table (acv, dmli, jinfos.ji_acttabno);
        a722strategy( acv, dmli, _bw, gg_strategy, _dummy_len );
        END;
    (*ENDIF*) 
    IF  use_subquery
    THEN
        BEGIN
        gg_strategy.str_use_subquery := normal_subquery;
        gg_strategy.str_maxresults   := cgg_at_least_one_record;
        END
    ELSE
        IF  dmli.d_subquery
        THEN
            gg_strategy.str_use_subquery := query_in_subq;
        (* PTS 1112079 E.Z. *)
        (*ENDIF*) 
    (*ENDIF*) 
    gg_strategy.str_search_first := true;
    IF  dmli.d_view
    THEN
        BEGIN
        gg_strategy.str_cnt_strat := 1;
        gg_strategy.str_strategy  := strat_join_viewkey;
        _ilen := STRATEGY_START_MXGG07 + sizeof(gg_strategy.str_join_viewkey);
        END
    ELSE
        BEGIN
        IF  series[ jinfos.ji_act_join ].jos_joinstrat <> strat_key_range
        THEN
            BEGIN
            IF  ((gg_strategy.str_cnt_strat > 1) OR
                (gg_strategy.str_strategy = strat_key_equal))
            THEN
                BEGIN
                gg_strategy.str_cnt_strat := 1;
                FOR _i := 0 TO MAX_COLPOSARR_IDX_GG07 DO
                    BEGIN
                    gg_strategy.str_key_in_range.skir_keystart[ _i ] := 0;
                    gg_strategy.str_key_in_range.skir_keystop[ _i ]  := 0
                    END
                (*ENDFOR*) 
                END;
            (*ENDIF*) 
            gg_strategy.str_strategy :=
                  series[ jinfos.ji_act_join ].jos_joinstrat;
            CASE gg_strategy.str_strategy OF
                strat_join_inv :
                    BEGIN
                    _ilen := STRATEGY_START_MXGG07 +
                          sizeof(gg_strategy.str_join_inv);
                    gg_strategy.str_join_inv.sji_invindex :=
                          series[ jinfos.ji_act_join ].jos_indexno;
                    gg_strategy.str_join_inv.sji_invroot  := NIL_PAGE_NO_GG00;
                    gg_strategy.str_join_inv.sji_jfiller  := 0
                    END;
                strat_join_all_inv_equal,
                strat_join_inv_range :
                    BEGIN
                    gg_strategy.str_join_multfields.sjmf_cntfields :=
                          series[ jinfos.ji_act_join ].jos_fieldcnt;
                    gg_strategy.str_join_multfields.sjmf_index_no  :=
                          series[ jinfos.ji_act_join ].jos_indexno;
                    gg_strategy.str_join_multfields.sjmf_invroot   :=
                          NIL_PAGE_NO_GG00;
                    _ilen := STRATEGY_START_MXGG07 +
                          sizeof(gg_strategy.str_join_multfields);
                    END;
                strat_join_all_keys_equal,
                strat_join_key_range :
                    BEGIN
                    gg_strategy.str_join_multfields.sjmf_cntfields :=
                          series[ jinfos.ji_act_join ].jos_fieldcnt;
                    gg_strategy.str_join_multfields.sjmf_index_no  := 1;
                    gg_strategy.str_join_multfields.sjmf_invroot   :=
                          NIL_PAGE_NO_GG00;
                    _ilen := STRATEGY_START_MXGG07 +
                          sizeof(gg_strategy.str_join_multfields);
                    END;
                OTHERWISE
                    _ilen := STRATEGY_START_MXGG07 +
                          sizeof(gg_strategy.str_key_in_range);
                END;
            (*ENDCASE*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  acv.a_intern_explain
    THEN
        BEGIN
        a61_rel_old_table (acv, dmli, jinfos.ji_acttabno);
        _i := acv.a_mblock.mb_qual^.mqual_pos;
        a67_explain (acv, dmli,
              gg_strategy, joinp^.smessblock.mbr_mess_block.mb_strat^,
              joinp^.smessblock.mbr_mess_block.mb_strat_size, 1,
              gg_strategy.str_stack_output_offs);
        END;
    (*ENDIF*) 
    IF  jinfos.ji_act_join = dmli.d_cntfromtab
    THEN
        BEGIN
        gg_strategy.str_use_rowno := ak_strat_interface.sr_use_rowno;
        gg_strategy.str_distinc   := dmli.d_distinct;
        gg_strategy.str_ordering  := ak_strat_interface.sr_distinct_bytes;
        END
    ELSE
        BEGIN
        gg_strategy.str_use_rowno := false;
        gg_strategy.str_distinc   := no_distinct;
        gg_strategy.str_ordering  := false;
        END;
    (*ENDIF*) 
    gg_strategy.str_key_len := jinfos.ji_keylen;
    gg_strategy.str_rec_len := jinfos.ji_outpos - 1;
    IF  jinfos.ji_act_join = dmli.d_cntfromtab
    THEN
        IF  dmli.d_single AND NOT dmli.d_view
        THEN
            IF  acv.a_sqlmode = sqlm_oracle
            THEN
                gg_strategy.str_maxresults := cgg_one_record_at_most_oracle
            ELSE
                BEGIN
                IF  ( abs(dmli.d_rowno) >= cgg_valid_rowno_pos )
                THEN
                    BEGIN
                    _e := e_ok;
                    k720_maxresult_get( acv.a_mblock.mb_data^.mbp_buf,
                          dmli.d_rowno, _j, _e );
                    IF  ( _e = e_ok ) AND ( _j = 1 )
                    THEN
                        gg_strategy.str_maxresults := cgg_one_record_at_most_oracle
                    ELSE
                        gg_strategy.str_maxresults := cgg_one_record_at_most_internal;
                    (*ENDIF*) 
                    END
                ELSE
                    gg_strategy.str_maxresults := cgg_one_record_at_most_internal;
                (*ENDIF*) 
                END
            (*ENDIF*) 
        ELSE
            gg_strategy.str_maxresults := dmli.d_rowno
        (*ENDIF*) 
    ELSE
        gg_strategy.str_maxresults := cgg_no_rowno_predicate;
    (*ENDIF*) 
    IF  jinfos.ji_act_join < dmli.d_cntfromtab
    THEN
        BEGIN
        g04build_temp_tree_id ( gg_strategy.str_result_id,
              acv.a_transinf.tri_trans);
        gg_strategy.str_result_id.fileTfnTemp_gg00  := ttfnJoinResult_egg00;
        gg_strategy.str_result_id.fileTempCnt_gg00  := jinfos.ji_act_join;
        IF  (ftsShared_egg00 in
            dmli.d_tabarr[ series[ jinfos.ji_act_join ].jos_source ].
            otreeid.fileType_gg00)
        THEN
            gg_strategy.str_result_id.fileType_gg00 :=
                  gg_strategy.str_result_id.fileType_gg00 + [ ftsShared_egg00 ];
        (*ENDIF*) 
        IF  (jinfos.ji_stack_desc.mresqual_cnt = 0) AND
            (NOT acv.a_outer_join)
        THEN
            gg_strategy.str_result_id.fileHandling_gg00 := gg_strategy.str_result_id.fileHandling_gg00 +
                  [ hsDropFile_egg00 ];
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        gg_strategy.str_result_id := res_tree;
        gg_strategy.str_result_id.fileHandling_gg00 := gg_strategy.str_result_id.fileHandling_gg00 +
              [ hsDropFile_egg00 ];
        IF  dmli.d_single
        THEN
            gg_strategy.str_result_id := acv.a_into_tree;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
&   IFDEF TRACE
    t01treeid (ak_join, 'join_res_id ', gg_strategy.str_result_id);
    t01treeid (ak_join, 'otree       ',
          dmli.d_tabarr[ series[ jinfos.ji_act_join ].jos_source ].otreeid);
&   ENDIF
    IF  jinfos.ji_act_join > 1
    THEN
        BEGIN
        _minfo.o_tree    := jinfos.ji_old_tree;
        _minfo.o_recl    := jinfos.ji_old_recl;
        _minfo.o_keyl    := jinfos.ji_old_keyl;
        jinfos.ji_old_keyl := jinfos.ji_nxtjinfo.nj_nk_len;
        (* *** one_join_phase begin *** *)
        IF  (jinfos.ji_act_join = dmli.d_cntfromtab)          AND
            (* *** OR all tabs with or in use *** *)
            (jinfos.ji_stack_desc.mresqual_cnt > 0)
        THEN
            BEGIN
            jinfos.ji_old_recl := dmli.d_reclen - 1;
            END
        ELSE
            (* *** one_join_phase end *** *)
            BEGIN
            jinfos.ji_old_recl := jinfos.ji_nxtjinfo.nj_r_len;
            END;
        (*ENDIF*) 
        _minfo.n_key_len := jinfos.ji_old_keyl;
        _minfo.n_rec_len := jinfos.ji_old_recl;
        ;
&       IFDEF TRACE
        t01int4 (ak_join, 'o_keyl      ', _minfo.o_keyl);
        t01int4 (ak_join, 'n_rec_len kb', _minfo.n_rec_len);
        t01int4 (ak_join, 'n_key_len kb', _minfo.n_key_len);
        t01int4 (ak_join, 'nk_len    kb', jinfos.ji_nxtjinfo.nj_nk_len);
&       ENDIF
        END
    ELSE
        BEGIN
        jinfos.ji_old_keyl := gg_strategy.str_key_len;
        jinfos.ji_old_recl := gg_strategy.str_rec_len;
        END;
    (*ENDIF*) 
    jinfos.ji_old_tree := gg_strategy.str_result_id
    END;
(*ENDIF*) 
IF  acv.a_return_segm^.sp1r_returncode = 0
THEN
    BEGIN
    (* *** 8-byte alignement of tgg_strategy *** *)
    IF  (jinfos.ji_mb_data_len MOD ALIGNMENT_GG00) > 0
    THEN
        acv.a_mblock.mb_data_len := jinfos.ji_mb_data_len + ALIGNMENT_GG00
              - (jinfos.ji_mb_data_len MOD ALIGNMENT_GG00)
    ELSE
        acv.a_mblock.mb_data_len := jinfos.ji_mb_data_len;
    (*ENDIF*) 
&   IFDEF TRACE
    t01int4 (ak_join, 'mb_data_len ', acv.a_mblock.mb_data_len);
    t01int4 (ak_join, 'ji_mb_data_l', jinfos.ji_mb_data_len);
&   ENDIF
    IF  jinfos.ji_act_join = 1
    THEN
        _j := 1
    ELSE
        BEGIN
        _j := 3;
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mstrat_pos ].ecol_tab[ 2 ] :=
              chr (jinfos.ji_act_join);
        END;
    (*ENDIF*) 
    FOR _i := 1 TO _j DO
        ak684move_infos (acv, gg_strategy, joinp,
              njrec, jinfos.ji_nxtjinfo.nj_kbjrec, _minfo, _i, _ilen, jinfos.ji_act_join);
    (*ENDFOR*) 
    IF  (jinfos.ji_act_join > 1)
    THEN
        BEGIN
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mstrat_pos ].
              ecol_tab[ 2 ] := chr (jinfos.ji_act_join);
        (* *** one_join_phase *** *)
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mstrat_pos + 1 ].
              ecol_pos := dmli.d_keylen;
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684get_qualification (
            VAR acv      : tak_all_command_glob;
            VAR dmli     : tak_dml_info;
            VAR jinfos   : tak68_joininfos;
            VAR joinp    : tak_sysbufferaddress;
            add_notnull  : boolean);
 
VAR
      _e     : tgg_basis_error;
      _jmbp  : tgg_mess_block_ptr;
      _jqbp  : tgg_qual_buf_ptr;
 
BEGIN
_jmbp      := @joinp^.smessblock.mbr_mess_block;
_jqbp      := _jmbp^.mb_qual;
acv.a_mblock.mb_qual^.msubquery := _jqbp^.msubquery;
IF  acv.a_mblock.mb_qual^.mfirst_free + _jqbp^.mqual_cnt > acv.a_mblock.mb_st_max
THEN
    a07_b_put_error (acv, e_too_many_mb_stackentries, 1)
ELSE
    BEGIN
    g10mv1 ('VAK684',   2,    
          _jmbp^.mb_st_size, acv.a_mblock.mb_st_size,
          _jmbp^.mb_st^, 1,
          acv.a_mblock.mb_st^, (acv.a_mblock.mb_qual^.mfirst_free - 1) * mxgg_stack_entry + 1,
          _jqbp^.mqual_cnt * mxgg_stack_entry,
          acv.a_return_segm^.sp1r_returncode);
&   IFDEF TRACE
    t01qual1 (ak_join, 'get_qualif 1', acv.a_mblock.mb_qual^);
&   ENDIF
    acv.a_mblock.mb_qual^.mqual_cnt    :=
          acv.a_mblock.mb_qual^.mqual_cnt + _jqbp^.mqual_cnt;
    acv.a_mblock.mb_qual^.mfirst_free  :=
          acv.a_mblock.mb_qual^.mfirst_free + _jqbp^.mqual_cnt;
&   IFDEF TRACE
    t01qual1 (ak_join, 'get_qualif 2', acv.a_mblock.mb_qual^);
&   ENDIF
    IF  (jinfos.ji_act_join < dmli.d_cntfromtab)
        AND
        (dmli.d_joins.jrc_cnt > 0)
        AND
        (acv.a_mblock.mb_qual^.mfirst_free <= acv.a_mblock.mb_st_max + 4)
        AND
        NOT (dmli.d_view AND dmli.d_checkview)
        AND
        add_notnull
    THEN
        ak684add_not_null_qualification (acv, dmli, jinfos, _jqbp^.mqual_cnt > 0);
    (*ENDIF*) 
    END
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684join_one_record (
            VAR acv                 : tak_all_command_glob;
            VAR dmli                : tak_dml_info;
            VAR jinfos              : tak68_joininfos;
            VAR series              : tak68_sequence;
            VAR res_tree            : tgg00_FileId;
            VAR session_cmd_id      : tak_parskey;
            VAR ak_strat_interface  : tak70_strat_rec;
            VAR jvrec               : tak68_joinview_rec;
            VAR cost_infos          : tak68_evaluation_records);
 
VAR
      _e                  : tgg_basis_error;
      _m_type             : tgg_message_type;
      _m2_type            : tgg_message2_type;
      _i                  : integer;
      _stree              : tgg00_FileId;
      _njrec              : tgg07_NextJoins;
      _ke                 : tgg_sysinfokey;
      _joinp              : tak_sysbufferaddress;
      _add_distinct_bytes : boolean;
      _use_subquery       : boolean;
      _aux_addr           : tgg_stack_list_ptr;
      _plus_ot_id_size    : integer;
      _page_eval_info     : tak70_page_eval_rec;
      _op_outer           : boolean;
      _outer_gt2          : boolean;
      _is_corr_outer_tab  : boolean;
      _add_notnull        : boolean;
      _StratInfo_len      : tsp_int2;
      _gg_strategy        : tgg07_StrategyInfo;
      _ix                 : integer;
      _istop              : integer;
      _key_pos            : tsp_int2;
 
BEGIN
_plus_ot_id_size   := 0;
_op_outer          := false;
_is_corr_outer_tab := false;
_use_subquery      := false;
jinfos.ji_acttabno := series[ jinfos.ji_act_join ].jos_source;
IF  dmli.d_tabarr[ jinfos.ji_acttabno ].ocomplex_view
THEN
    a660build_view_treeid (acv,
          dmli.d_tabarr[ jinfos.ji_acttabno ].ofromtableid, _stree)
ELSE
    _stree := dmli.d_tabarr[ jinfos.ji_acttabno ].otreeid;
(*ENDIF*) 
;
(* set KB order type *)
IF  oisshowview in dmli.d_tabarr[ jinfos.ji_acttabno ].ospecialname
THEN
    _m_type := m_show
ELSE
    _m_type := m_select;
(*ENDIF*) 
;
(* set KB order subtype *)
IF  jinfos.ji_act_join = 1
THEN
    _m2_type := mm_first_join_select
ELSE
    _m2_type := mm_with_join;
(*ENDIF*) 
;
_aux_addr := acv.a_mblock.mb_st;
a06a_mblock_init (acv, _m_type, _m2_type, _stree);
acv.a_mblock.mb_st := _aux_addr;
IF  acv.a_mblock.mb_qual^.mtree.fileTfn_gg00 <> tfnTemp_egg00
THEN
    acv.a_mblock.mb_qual^.mtree.fileHandling_gg00 := dmli.d_globstate;
(*ENDIF*) 
IF  acv.a_isolation_info = temp_lock_rec_get
THEN
    IF  hsPermLock_egg00 in acv.a_mblock.mb_qual^.mtree.fileHandling_gg00
    THEN
        IF  hsIntentExcl_egg00 in acv.a_mblock.mb_qual^.mtree.fileHandling_gg00
        THEN
            acv.a_mblock.mb_qual^.mtree.fileHandling_gg00 :=
                  acv.a_mblock.mb_qual^.mtree.fileHandling_gg00 -
                  [ hsPermLock_egg00 ]
        ELSE
            acv.a_mblock.mb_qual^.mtree.fileHandling_gg00 :=
                  (acv.a_mblock.mb_qual^.mtree.fileHandling_gg00 + [ hsWithoutLock_egg00 ])
                  - [ hsPermLock_egg00 ]
        (*ENDIF*) 
    ELSE
        acv.a_mblock.mb_qual^.mtree.fileHandling_gg00 :=
              acv.a_mblock.mb_qual^.mtree.fileHandling_gg00 - [ hsTempLock_egg00 ];
    (*ENDIF*) 
(*ENDIF*) 
;
(* stamp st_dummy stack entry - will be st_jump_output *)
acv.a_mblock.mb_data_len          := jinfos.ji_mb_data_len;
acv.a_mblock.mb_data^.mbp_keylen  := jvrec.jv_maxkeyl;
acv.a_mblock.mb_qual^.mqual_pos   := acv.a_mblock.mb_qual^.mfirst_free;
acv.a_mblock.mb_qual^.mqual_cnt   := succ (acv.a_mblock.mb_qual^.mqual_cnt);
acv.a_mblock.mb_qual^.mfirst_free := succ (acv.a_mblock.mb_qual^.mfirst_free);
acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mqual_pos ].etype     := st_dummy;
acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mqual_pos ].epos      := 0;
acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mqual_pos ].eval4_var := 0;
;
jinfos.ji_outpos                      := cgg_rec_key_offset + 1;
(* set common values for cartesian product *)
jinfos.ji_nxtjinfo.nj_nk_len          := mxgg_rescnt;
jinfos.ji_nxtjinfo.nj_r_len           := cgg_rec_key_offset + jinfos.ji_nxtjinfo.nj_nk_len;
jinfos.ji_nxtjinfo.nj_nxt_klen_filled := mxgg_rescnt;
jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt      := 0;
jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_lof      := []; (* *** left  outer join fields *** *)
jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_rof      := []; (* *** right outer join fields *** *)
jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_linkcnt  := 1;
jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_right_oj := 
      acv.a_outer_join           AND
      (jinfos.ji_acttabno in dmli.d_oj_tables);
(* %-( ?????? *)
jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_left_oj  :=
      acv.a_outer_join           AND
      (dmli.d_cntfromtab = 2)    AND
      (jinfos.ji_act_join   = 2) AND
      ((jinfos.ji_nxtjinfo.nj_left_side - dmli.d_oj_tables)
      <> jinfos.ji_nxtjinfo.nj_left_side);
_njrec.n_j_cnt  := 0;
_key_pos        := 1;
_outer_gt2      :=
      acv.a_outer_join                           AND
      (jinfos.ji_act_join   > 1)                 AND
      (jinfos.ji_act_join   < dmli.d_cntfromtab) AND
      (dmli.d_cntfromtab > 2);
IF  _outer_gt2
THEN
    BEGIN
    _op_outer          := (jinfos.ji_acttabno in dmli.d_oj_tables);
    _is_corr_outer_tab :=
          ak684_is_corresponding_outer_join_table(dmli, jinfos.ji_acttabno);
    IF  ak684_add_ot_id_size (dmli, jinfos, series)
    THEN
        _plus_ot_id_size := mxsp_c4;
    (*ENDIF*) 
    END;
(*ENDIF*) 
_add_distinct_bytes :=
      (jinfos.ji_act_join = dmli.d_cntfromtab)
      AND
      (
      ((dmli.d_distinct <> no_distinct) AND ak_strat_interface.sr_distinct_bytes)
      OR dmli.d_union
      OR ((res_tree.fileTfn_gg00     = tfnTemp_egg00) AND
      (    res_tree.fileTfnTemp_gg00 = ttfnSubquery_egg00))
      );
&IFDEF TRACE
t01p2int4 (ak_join, 'ji_act_join ', jinfos.ji_act_join,
      'ji_acttabno ', jinfos.ji_acttabno);
t01int4 (ak_join, 'd_inoutpos  ', dmli.d_inoutpos);
a683joinset_trace (ak_join, 'left side   ',  jinfos.ji_nxtjinfo.nj_left_side);
a683joinset_trace (ak_join, 'd_oj_tables ', dmli.d_oj_tables);
t01int4 (ak_join, 'plus_ot_id_s', _plus_ot_id_size);
t01p2bool (ak_join, 'is_outertab ', _op_outer,
      'add_distinct', _add_distinct_bytes);
&ENDIF
IF  (dmli.d_joins.jrc_cnt > 0)
THEN
    (* there is a real join *)
    BEGIN
&   IFDEF TRACE
    a683trace_kbjrec (ak_join, jinfos.ji_nxtjinfo.nj_kbjrec);
    t01int4 (ak_join, 'nxt_klen_fil', jinfos.ji_nxtjinfo.nj_nxt_klen_filled);
&   ENDIF
    IF  ((jinfos.ji_act_join > 1) AND (jinfos.ji_act_join < dmli.d_cntfromtab))
    THEN
        a685next_key_length (dmli, jinfos);
    (*ENDIF*) 
    jinfos.ji_nxtjinfo.nj_r_len := cgg_rec_key_offset + jinfos.ji_nxtjinfo.nj_nk_len
          + _plus_ot_id_size;
    IF  _add_distinct_bytes
    THEN
        (* ??? add distinct bytes to record length and not to key lenght ??? *)
        jinfos.ji_nxtjinfo.nj_r_len := jinfos.ji_nxtjinfo.nj_r_len + cgg_cdistinct_bytes;
&   IFDEF TRACE
    (*ENDIF*) 
    t01int4 (ak_join, 'nk_len      ', jinfos.ji_nxtjinfo.nj_nk_len);
    t01int4 (ak_join, 'r_len       ', jinfos.ji_nxtjinfo.nj_r_len);
&   ENDIF
    (* get join columns for next join step, these build key columns *)
    ak684n_build_new_output (acv, dmli, jinfos, series, c_in_key, _op_outer);
&   IFDEF TRACE
    a683trace_kbjrec(ak_join, jinfos.ji_nxtjinfo.nj_kbjrec);
&   ENDIF
    END;
(*ENDIF*) 
jinfos.ji_outpos := jinfos.ji_outpos + _plus_ot_id_size;
jinfos.ji_keylen := jinfos.ji_outpos - 1 - cgg_rec_key_offset + mxgg_rescnt;
IF  (jinfos.ji_keylen > mxsp_key)
THEN
    a07_b_put_error (acv, e_join_fields_too_long, 1);
(*ENDIF*) 
IF  (jinfos.ji_act_join = 1)
THEN
    (* first temporary result is built, therefore it exists a result counter *)
    jinfos.ji_outpos := jinfos.ji_outpos + mxgg_rescnt;
(*ENDIF*) 
IF  ((dmli.d_joins.jrc_cnt > 0) AND (acv.a_return_segm^.sp1r_returncode = 0))
THEN
    BEGIN
    (* get join columns for further join step, these build non key columns *)
    ak684n_build_new_output (acv, dmli, jinfos, series, NOT c_in_key, _op_outer);
&   IFDEF TRACE
    a683trace_kbjrec (ak_join, jinfos.ji_nxtjinfo.nj_kbjrec);
    t01int4 (ak_join, 'ji_act_join ', jinfos.ji_act_join);
    t01int4 (ak_join, 'ji_acttabno ', jinfos.ji_acttabno);
&   ENDIF
    END;
(*ENDIF*) 
IF  (acv.a_return_segm^.sp1r_returncode = 0)
THEN
    (* get output fields for actual table *)
    ak684transfer_output_fields (acv, dmli, jinfos);
(*ENDIF*) 
;
&IFDEF TRACE
t01int4 (ak_join, 'ji_outpos   ', jinfos.ji_outpos);
t01int4 (ak_join, 'ji_keylen   ', jinfos.ji_keylen);
t01int4 (ak_join, 'nj_nk_len   ', jinfos.ji_nxtjinfo.nj_nk_len);
t01int4 (ak_join, 'nj_r_len    ', jinfos.ji_nxtjinfo.nj_r_len);
&ENDIF
IF  (jinfos.ji_act_join = dmli.d_cntfromtab)
THEN
    a685last_key_len (acv, jinfos, _key_pos);
(*ENDIF*) 
_key_pos := _key_pos + cgg_rec_key_offset + _plus_ot_id_size;
IF  _add_distinct_bytes
THEN
    _key_pos := _key_pos + cgg_cdistinct_bytes;
(*ENDIF*) 
IF  _key_pos > mxsp_key
THEN
    a07_b_put_error (acv, e_join_fields_too_long, 1);
(*ENDIF*) 
jinfos.ji_nxtjinfo.nj_nk_len := _key_pos +
      jinfos.ji_nxtjinfo.nj_nk_len - cgg_rec_key_offset - 1;
(* overwrite st_dummy stack entry *)
a61_set_jump (acv.a_mblock, acv.a_mblock.mb_qual^.mqual_pos, st_jump_output);
acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mqual_pos ].epos :=
      succ (acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mqual_pos ].epos);
IF  acv.a_outer_join
THEN
    BEGIN
    IF  (jinfos.ji_act_join = 1)
    THEN
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mqual_pos ].eop := op_outer_join;
    (*ENDIF*) 
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mqual_pos ].ecol_tab[ 1 ] :=
          chr (0);
    END;
(*ENDIF*) 
IF  (acv.a_return_segm^.sp1r_returncode = 0)
THEN
    BEGIN
    _add_notnull := (jinfos.ji_act_join < dmli.d_cntfromtab) AND
          (* NOT index only access *)
          ( NOT cost_infos[ jinfos.ji_acttabno ].ev_inv_only );
    (* get seperated messblock for one table *)
    a682join_parsinfo_key (acv, dmli, session_cmd_id, jvrec.jv_tabid,
          jinfos.ji_acttabno, _ke);
    a10get_sysinfo (acv, _ke, d_release, _joinp, _e);
    IF  _e <> e_ok
    THEN
        a07_b_put_error (acv, _e, 1)
    ELSE
        ak684get_qualification (acv, dmli, jinfos, _joinp, _add_notnull);
    (*ENDIF*) 
    END;
(*ENDIF*) 
acv.a_mblock.mb_qual^.mstrat_pos := acv.a_mblock.mb_qual^.mfirst_free;
IF  (acv.a_return_segm^.sp1r_returncode = 0) AND
    (jinfos.ji_act_join  = 1) AND
    (NOT (acv.a_outer_join OR dmli.d_outer_join))
THEN
    ak684_exists_subquery (acv, jinfos, _use_subquery);
(*ENDIF*) 
acv.a_mblock.mb_qual^.mstrat_cnt := 0;
IF  cost_infos[ jinfos.ji_acttabno ].ev_inv_only
THEN
    BEGIN
    IF  acv.a_mblock.mb_data_len MOD ALIGNMENT_GG00 <> 0
    THEN
        acv.a_mblock.mb_data_len := acv.a_mblock.mb_data_len -
              (acv.a_mblock.mb_data_len MOD ALIGNMENT_GG00) +
              ALIGNMENT_GG00;
    (*ENDIF*) 
    _StratInfo_len   := 0;
    IF  (series[ jinfos.ji_act_join ].jos_joinstrat = strat_key_range)
    THEN
        dmli.d_index_strat_poss := ind_init
    ELSE
        dmli.d_index_strat_poss := ind_no_inv;
    (*ENDIF*) 
    _gg_strategy.str_result_id    := b01niltree_id;
    _gg_strategy.str_build_result := true;
    _gg_strategy.str_ordering     := ( dmli.d_distinct <> no_distinct );
    _gg_strategy.str_distinc      := dmli.d_distinct;
    IF  ( ak_strat_interface.sr_use_subquery OR
        acv.a_mblock.mb_qual^.msubquery )
    THEN
        _gg_strategy.str_use_subquery := normal_subquery
    ELSE
        IF  dmli.d_subquery
        THEN
            _gg_strategy.str_use_subquery := query_in_subq
        ELSE
            _gg_strategy.str_use_subquery := no_subquery;
        (*ENDIF*) 
    (*ENDIF*) 
    _gg_strategy.str_rec_len      := jinfos.ji_outpos - 1;
    _gg_strategy.str_use_rowno    := false;
    _gg_strategy.str_corr_single  := false;
    _gg_strategy.str_union_kind   := 0;
    _gg_strategy.str_res_possible := true;
    _gg_strategy.str_use_order    := false;
    _gg_strategy.str_qual_kind    := primary_only;
    _gg_strategy.str_out_keyseqlen:= NOT_SEQUENCED_GG07;
    _gg_strategy.str_cnt_strat    := 1;
    _gg_strategy.str_maxresults   := cgg_no_rowno_predicate;
    _gg_strategy.str_foundresults := 0;
    (*  str_stack_output_offs used as stackoffset vkb720  *)
    _gg_strategy.str_stack_output_offs  := 0;
    _gg_strategy.str_search_first       := true;
    _gg_strategy.str_all_files := acv.a_recursive_state = rs_last_select;
    FOR _i := 0 TO MAX_COLPOSARR_IDX_GG07 DO
        BEGIN
        _gg_strategy.str_key_in_range.skir_keystart[ _i ] := 0;
        _gg_strategy.str_key_in_range.skir_keystop[ _i ]  := 0
        END;
    (*ENDFOR*) 
    _gg_strategy.str_strategy := strat_undecided;
    _m2_type     := mm_with_join;
    IF  dmli.d_acttabindex <> jinfos.ji_acttabno
    THEN
        a61_rel_old_table (acv, dmli, jinfos.ji_acttabno);
    (*ENDIF*) 
    a70strategy( acv, dmli, _gg_strategy, _StratInfo_len, _page_eval_info );
    ;
    cost_infos[ jinfos.ji_acttabno ].
          ev_result_pages  := _page_eval_info.pev_result_pages;
    cost_infos[ jinfos.ji_acttabno ].
          ev_cost_pages  := _page_eval_info.pev_cost_pages;
    cost_infos[ jinfos.ji_acttabno ].
          ev_strat_value := 1;
    ;
    g09StratStackentry( acv.a_mblock.mb_qual^.
        mst_addr^[ acv.a_mblock.mb_qual^.mfirst_free ], 1, _StratInfo_len);
    acv.a_mblock.mb_qual^.mstrat_cnt    := 1;
    acv.a_mblock.mb_qual^.mstrat_pos    := acv.a_mblock.mb_qual^.mfirst_free;
    IF  jinfos.ji_act_join = 1
    THEN
        _m2_type := mm_first_join_select;
    (*ENDIF*) 
    dmli.d_join := true;
    END;
(*ENDIF*) 
IF  ((jinfos.ji_act_join > 1) AND (acv.a_return_segm^.sp1r_returncode = 0))
THEN
    BEGIN
    IF  (jinfos.ji_act_join <> dmli.d_cntfromtab)
    THEN
        BEGIN
        (* reserve space for strategies *)
        acv.a_mblock.mb_qual^.mfirst_free :=
              acv.a_mblock.mb_qual^.mfirst_free + 3;
        a685copy_old_output_fields (acv, dmli, jinfos,
              jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_left_oj OR
              (_plus_ot_id_size > 0));
        IF  (jinfos.ji_nxtjinfo.nj_nxt_klen_filled < jinfos.ji_nxtjinfo.nj_nk_len)
        THEN
            a685build_next_key (acv, dmli, jinfos);
        (*ENDIF*) 
        IF  (jinfos.ji_nxtjinfo.nj_not_copied_keyfields_cnt > 0)
        THEN
            a685kcopy_keyfields (acv, dmli, jinfos);
        (*ENDIF*) 
        END
    ELSE
        (* last join step *)
        BEGIN
        IF  (acv.a_outer_join OR dmli.d_outer_join)
        THEN
            ak684_exists_subquery (acv, jinfos, _use_subquery);
        (*ENDIF*) 
        ;
        (* reserve space for strategies *)
        acv.a_mblock.mb_qual^.mfirst_free :=
              acv.a_mblock.mb_qual^.mfirst_free + 3;
        a685clast_copy_old_outp_fields (acv, dmli, jinfos, 
              jinfos.ji_nxtjinfo.nj_r_len,
              jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_left_oj);
        _njrec.n_j_cnt := 0;
        a685olast_order_fields (acv, jinfos, _njrec);
        END;
    (*ENDIF*) 
    END
ELSE
    acv.a_mblock.mb_qual^.mfirst_free :=
          succ (acv.a_mblock.mb_qual^.mfirst_free);
(*ENDIF*) 
;
(* *** one_join_phase begin *** *)
IF  (acv.a_return_segm^.sp1r_returncode = 0) AND
    (* *** OR all tabs with or in use *** *)
    (jinfos.ji_stack_desc.mresqual_cnt > 0) AND
    (jinfos.ji_act_join = dmli.d_cntfromtab)
THEN
    WITH acv.a_mblock.mb_qual^ DO
        IF  (mfirst_free + jinfos.ji_stack_desc.mresqual_cnt) <= 
            acv.a_mblock.mb_st_max
        THEN
            BEGIN
            (* *** or joins with qualificationtest before writing *** *)
            g10mv1 ('VAK684',   3,    
                  (jinfos.ji_stack_desc.mst_max * mxgg_stack_entry),
                  acv.a_mblock.mb_st_size, jinfos.ji_st_addr^,
                  (jinfos.ji_stack_desc.mresqual_pos - 1) * mxgg_stack_entry + 1,
                  acv.a_mblock.mb_st^, (mfirst_free - 1) * mxgg_stack_entry + 1,
                  jinfos.ji_stack_desc.mresqual_cnt * mxgg_stack_entry,
                  acv.a_return_segm^.sp1r_returncode);
            IF  (acv.a_mblock.mb_st^ [ mfirst_free ].etype = st_jump_output)
            THEN
                acv.a_mblock.mb_st^ [ mfirst_free ].elen_var := dmli.d_keylen;
            (*ENDIF*) 
            mresqual_cnt := jinfos.ji_stack_desc.mresqual_cnt;
            mresqual_pos := mfirst_free;
            mfirst_free  := mfirst_free + jinfos.ji_stack_desc.mresqual_cnt;
            _i            := mresqual_pos;
            msubquery    := _use_subquery OR msubquery;
            WHILE (_i < mresqual_pos + mresqual_cnt) AND
                  NOT _use_subquery DO
                BEGIN
                _use_subquery := (acv.a_mblock.mb_st^[ _i ].etype = st_subquery)     AND
                      (acv.a_mblock.mb_st^[ _i ].ecol_tab[ 1 ] = chr (1)) AND
                      (acv.a_mblock.mb_st^[ _i ].ecol_tab[ 2 ] = chr (1));
                msubquery    := (acv.a_mblock.mb_st^[ _i ].etype = st_subquery) OR msubquery;
                _i := succ (_i);
                END;
            (*ENDWHILE*) 
            END
        ELSE
            a07_b_put_error (acv, e_too_many_mb_stackentries, 1);
        (*ENDIF*) 
    (*ENDWITH*) 
(*ENDIF*) 
IF  (acv.a_return_segm^.sp1r_returncode = 0) AND
    (jinfos.ji_acttabno in dmli.d_oj_tables)    AND
    (jinfos.ji_act_join = dmli.d_cntfromtab)
THEN
    ak684ctransfer_const_expressions (acv, dmli, jinfos);
(* *** one_join_phase end *** *)
(*ENDIF*) 
IF  (acv.a_return_segm^.sp1r_returncode = 0)
THEN
    ak684build_strat_info (acv, dmli, jinfos, _njrec, res_tree,
          _joinp, series, ak_strat_interface, _gg_strategy, _use_subquery);
(*ENDIF*) 
;
IF  (cost_infos[ jinfos.ji_acttabno ].ev_inv_only) AND
    (jinfos.ji_act_join > 1)                AND
    (series[ jinfos.ji_act_join ].jos_indexno <> 0)
THEN
    BEGIN
    _ix    := acv.a_mblock.mb_qual^.mqual_pos;
    _istop := acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mqual_pos ].epos + 
        acv.a_mblock.mb_qual^.mqual_pos - 1;
    WHILE (_ix < _istop) DO
        BEGIN
        IF  ( acv.a_mblock.mb_st^[ _ix ].etype    = st_fixinv) AND
            ( acv.a_mblock.mb_st^[ _ix ].epos     = 1)         AND
            ((acv.a_mblock.mb_st^[ _ix + 1].etype = st_output) OR
            ( acv.a_mblock.mb_st^[ _ix + 1].etype = st_output_join))
        THEN
            BEGIN
            acv.a_mblock.
                mb_st^[ acv.a_mblock.mb_qual^.mstrat_pos + 1 ].ecol_tab[ 2 ] := 
                    chr (1);
            _ix            := _istop;
            END
        ELSE
            IF  ((acv.a_mblock.mb_st^[ _ix ].etype = st_output) OR
                ( acv.a_mblock.mb_st^[ _ix ].etype = st_output_join))
            THEN
                _ix := _istop;
            (*ENDIF*) 
        (*ENDIF*) 
        _ix := succ (_ix);
        END;
    (*ENDWHILE*) 
    END;
&IFDEF TRACE
(*ENDIF*) 
a683_output (ak_join, dmli);
a683trace_kbjrec (ak_join, jinfos.ji_nxtjinfo.nj_kbjrec);
&ENDIF
IF  acv.a_return_segm^.sp1r_returncode = 0
THEN
    BEGIN
    _ke := _joinp^.syskey;
    a682_mbuf_to_tmpbuf (acv, _ke, _e, mtc_join_one_record);
    END;
(*ENDIF*) 
IF  _outer_gt2 AND
    (jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_right_oj OR
    (((jinfos.ji_nxtjinfo.nj_left_side - dmli.d_oj_tables) <>
    jinfos.ji_nxtjinfo.nj_left_side)
    AND
    _is_corr_outer_tab))
THEN
    dmli.d_oj_tables := [ ];
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684move_infos (
            VAR acv        : tak_all_command_glob;
            VAR strat      : tgg07_StrategyInfo;
            VAR joinp      : tak_sysbufferaddress;
            VAR njrec      : tgg07_NextJoins;
            VAR kbjrec     : tgg07_KbJoinRec;
            VAR minfo      : tgg07_MInfos;
            inf_numb       : integer;
            i_len          : integer;
            curr_join      : integer);
 
VAR
      _ilen : integer;
      _jmbp : tgg_mess_block_ptr;
 
BEGIN
WITH acv.a_mblock.mb_qual^, acv.a_mblock.mb_data^, kbjrec DO
    BEGIN
    CASE inf_numb OF
        1 :
            _ilen := i_len;
        2 :
            _ilen := sizeof(minfo)                           +
                  (sizeof(njrec) - sizeof(njrec.n_j_arr)) +
                  (sizeof(njrec.n_j_arr[1]) * njrec.n_j_cnt);
        3 :
            _ilen := sizeof (kbjr_cnt) + sizeof (kbjr_linkcnt) +
                  sizeof (kbjr_left_oj) + sizeof (kbjr_right_oj) +
                  sizeof (kbjr_lof) + sizeof (kbjr_rof) +
                  (kbjr_cnt * sizeof (tgg07_KbJoinInfo));
        END;
    (*ENDCASE*) 
&   ifdef trace
    t01int4 (ak_join, 'ilen        ', _ilen);
    IF  inf_numb = 1
    THEN
        s10fil1 (acv.a_mblock.mb_data_size, acv.a_mblock.mb_data^.mbp_buf, acv.a_mblock.mb_data_len + 1,
              acv.a_mblock.mb_data_size - acv.a_mblock.mb_data_len , chr (253));
&   endif
    (*ENDIF*) 
    IF  mfirst_free > acv.a_mblock.mb_st_max
    THEN
        a07_b_put_error (acv, e_too_many_mb_stackentries, 1)
    ELSE
        IF  acv.a_mblock.mb_strat_len + 1 + _ilen > acv.a_mblock.mb_strat_size
        THEN
            a07_b_put_error (acv, e_too_many_mb_strat, 1);
        (*ENDIF*) 
    (*ENDIF*) 
    IF  acv.a_return_segm^.sp1r_returncode = 0
    THEN
        BEGIN
        CASE inf_numb OF
            1 :
                BEGIN
                IF  (acv.a_mblock.mb_qual^.mstrat_cnt > 0) OR
                    (NOT (strat.str_strategy in [ strat_more_than_one, strat_undecided]))
                THEN
                    BEGIN
                    g10mv2 ('VAK684',   4,    
                          sizeof( strat ), acv.a_mblock.mb_strat_size, strat, 1,
                          acv.a_mblock.mb_strat^, acv.a_mblock.mb_strat_len + 1, _ilen,
                          acv.a_return_segm^.sp1r_returncode)
                    END
                ELSE
                    BEGIN
                    IF  ((acv.a_mblock.mb_strat_len + _ilen) > acv.a_mblock.mb_strat_size)
                    THEN
                        a07_b_put_error (acv, e_too_many_mb_strat, 1)
                    ELSE
                        BEGIN
                        g10mv2 ('VAK684',   5,    
                              sizeof( strat ), acv.a_mblock.mb_strat_size, strat, 1,
                              acv.a_mblock.mb_strat^, acv.a_mblock.mb_strat_len + 1,
                              STRATEGY_START_MXGG07,
                              acv.a_return_segm^.sp1r_returncode);
                        _jmbp := @joinp^.smessblock.mbr_mess_block;
                        g10mv6 ('VAK684',   6,    
                              _jmbp^.mb_strat_size, acv.a_mblock.mb_strat_size,
                              _jmbp^.mb_strat^, STRATEGY_START_MXGG07 + 1,
                              acv.a_mblock.mb_strat^,
                              acv.a_mblock.mb_strat_len + 1 + STRATEGY_START_MXGG07,
                              _ilen - STRATEGY_START_MXGG07,
                              acv.a_return_segm^.sp1r_returncode);
                        END
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                acv.a_mblock.mb_qual^.mstrat_cnt := 0;
                END;
            2 :
                BEGIN
                g10mv3 ('VAK684',   7,    
                      sizeof(minfo), acv.a_mblock.mb_strat_size, minfo, 1,
                      acv.a_mblock.mb_strat^, acv.a_mblock.mb_strat_len + 1, mxgg_inflen,
                      acv.a_return_segm^.sp1r_returncode);
                _ilen         := _ilen - mxgg_inflen;
                acv.a_mblock.mb_strat_len  := acv.a_mblock.mb_strat_len  + mxgg_inflen;
                g10mv4 ('VAK684',   8,    
                      sizeof (njrec), acv.a_mblock.mb_strat_size, njrec, 1,
                      acv.a_mblock.mb_strat^, acv.a_mblock.mb_strat_len + 1, _ilen,
                      acv.a_return_segm^.sp1r_returncode);
                END;
            3 :
                g10mv5 ('VAK684',   9,    
                      sizeof (kbjrec), acv.a_mblock.mb_strat_size, kbjrec, 1,
                      acv.a_mblock.mb_strat^, acv.a_mblock.mb_strat_len + 1, _ilen,
                      acv.a_return_segm^.sp1r_returncode);
            END;
        (*ENDCASE*) 
        WITH acv.a_mblock.mb_st^[ mstrat_pos + mstrat_cnt ] DO
            BEGIN
            etype         := st_strat;
            eop           := op_none;
            epos          := succ (acv.a_mblock.mb_strat_len);
            elen_var      := _ilen;
            ecol_tab[ 1 ] := chr(0);
            ecol_tab[ 2 ] := chr(0);
            IF  (inf_numb = 1) AND (curr_join > 1)
            THEN
                ecol_tab[ 2 ] := chr (curr_join)
            ELSE
                ecol_tab[ 2 ] := chr(0);
            (*ENDIF*) 
            END;
        (*ENDWITH*) 
        mstrat_cnt   := succ (mstrat_cnt);
        acv.a_mblock.mb_strat_len  := acv.a_mblock.mb_strat_len + _ilen;
        END
    (*ENDIF*) 
    END
(*ENDWITH*) 
;
&IFDEF TRACE
t01messblock (ak_join, '684move end ', acv.a_mblock);
&ENDIF
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684one_join_column (
            VAR acv     : tak_all_command_glob;
            VAR dmli    : tak_dml_info;
            VAR jinfos  : tak68_joininfos;
            VAR series  : tak68_sequence;
            in_key      : boolean;
            is_outertab : boolean;
            currj       : integer;
            is_multiple : boolean;
            partj       : integer;
            kbpartj     : integer);
 
TYPE
 
      op_htype = PACKED RECORD
            CASE boolean OF
                TRUE :
                    (c : char);
                FALSE :
                    (op : tgg_stack_op_type);
                END;
            (*ENDCASE*) 
 
 
VAR
      _i                     : integer;
      _j                     : integer;
      _pos                   : integer;
      _hop                   : op_htype;
      _found                 : boolean;
      _field_len             : integer;
 
BEGIN
(* for constant local join predicate (cak68_join_value) partj = 2 !! *)
(* otherwise partj is side with ji_acttabno (i.th tab = ...) *)
IF  acv.a_mblock.mb_qual^.mfirst_free +
    dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].jop_cntstack
    >
    acv.a_mblock.mb_st_max
THEN
    a07_b_put_error (acv, e_too_many_mb_stackentries, 1)
ELSE
    BEGIN
    (* move join condition from original messbuf *)
    g10mv1 ('VAK684',  10,    
          (jinfos.ji_stack_desc.mst_max * mxgg_stack_entry),
          acv.a_mblock.mb_st_size,
          jinfos.ji_st_addr^,
          (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].
          jop_startstack - 1) * mxgg_stack_entry + 1,
          acv.a_mblock.mb_st^,
          (acv.a_mblock.mb_qual^.mfirst_free - 1) * mxgg_stack_entry + 1,
          (* count *)
          dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].jop_cntstack * mxgg_stack_entry,
          acv.a_return_segm^.sp1r_returncode);
&   ifdef trace
    t01sname( ak_join, 'get stack  :' );
    FOR _i := 0 TO dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].
        jop_cntstack - 1 DO
        BEGIN
        t01stackentry (ak_join, 
            jinfos.ji_st_addr^[ dmli.d_joins.jrc_joinarr[ currj ].
            jo_recs[ partj ].jop_startstack + _i ], 
            dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].jop_startstack + _i);
        END;
    (*ENDFOR*) 
&   endif
    (* mark new stack entry *)
    _pos := acv.a_mblock.mb_qual^.mfirst_free;
    (* update mqual_cnt, mfirst_free, save space for st_output *)
    acv.a_mblock.mb_qual^.mqual_cnt   := acv.a_mblock.mb_qual^.mqual_cnt +
          dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].jop_cntstack + 1;
    acv.a_mblock.mb_qual^.mfirst_free := acv.a_mblock.mb_qual^.mfirst_free +
          dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].jop_cntstack + 1;
    IF  acv.a_return_segm^.sp1r_returncode = 0
    THEN
        IF  (acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 2 ].eop in
            [ op_eq, op_ge, op_gt, op_le, op_lt,
            op_ne, op_like, op_not_like, op_sounds, op_not_sounds,
            op_join_key])
        THEN
            (* delete join condition *)
            (* preserve function calls *)
            acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 2 ].eop :=  op_none;
        (*ENDIF*) 
    (*ENDIF*) 
    IF  in_key
    THEN
        BEGIN
        (* write into empty stack entry, update kbjrec *)
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
              etype    := st_output;
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
              ecol_pos := 0;
        IF  (jinfos.ji_act_join > 1)
        THEN
            (* collect join infos for KB handling *)
            BEGIN
            CASE kbpartj OF
                1 :
                    _i := 2;
                2 :
                    _i := 1;
                END;
            (*ENDCASE*) 
            CASE partj OF
                1 :
                    _j := 2;
                2 :
                    _j := 1;
                END;
            (*ENDCASE*) 
            ;
            jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_right_oj :=
                  jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_right_oj
                  OR dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].
                  jop_outer_join;
            IF  dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].jop_outer_join
                OR
                (acv.a_outer_join AND
                (jinfos.ji_act_join > 1) AND
                (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].
                jop_tableno = cak68_join_value) AND
                ak684_is_corresponding_outer_join_table(dmli,
                dmli.d_joins.jrc_joinarr[ currj ].jo_recs [ _j ].
                jop_tableno))
            THEN
                jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_rof :=
                      jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_rof +
                      [ succ (jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt) ];
            (*ENDIF*) 
            dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].
                  jop_outer_join := false;
            jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_left_oj :=
                  jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_left_oj
                  OR dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ _j ].
                  jop_outer_join;
            IF  dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ _j ].
                jop_outer_join
                OR
                (acv.a_outer_join AND
                (jinfos.ji_act_join > 1) AND
                (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ _j ].
                jop_tableno = cak68_join_value) AND
                ak684_is_corresponding_outer_join_table(dmli,
                dmli.d_joins.jrc_joinarr[ currj ].jo_recs [ partj ].
                jop_tableno))
            THEN
                jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_lof :=
                      jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_lof +
                      [ succ (jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt) ];
            (*ENDIF*) 
            dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ _j ].
                  jop_outer_join := false;
            ;
            IF  ((jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt = 0) OR
                (NOT is_multiple))
            THEN
                BEGIN
                jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt :=
                      succ (jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt);
                IF  (jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt > 1)
                THEN
                    BEGIN
                    jinfos.ji_nxtjinfo.nj_kbjrec.
                          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                          kbji_parts[ 1 ].kboj_recpos :=
                          jinfos.ji_nxtjinfo.nj_kbjrec.
                          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt - 1 ].
                          kbji_parts[ 1 ].kboj_recpos +
                          jinfos.ji_nxtjinfo.nj_kbjrec.
                          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt - 1 ].
                          kbji_parts[ 1 ].kboj_len;
                    jinfos.ji_nxtjinfo.nj_kbjrec.
                          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                          kbji_parts[ 2 ].kboj_recpos :=
                          jinfos.ji_nxtjinfo.nj_kbjrec.
                          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt - 1 ].
                          kbji_parts[ 2 ].kboj_recpos +
                          jinfos.ji_nxtjinfo.nj_kbjrec.
                          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt - 1 ].
                          kbji_parts[ 2 ].kboj_len;
                    END
                ELSE
                    BEGIN
                    (* initialize *)
                    jinfos.ji_nxtjinfo.nj_kbjrec.
                          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                          kbji_parts[ kbpartj ].kboj_recpos := cgg_rec_key_offset + 1;
                    jinfos.ji_nxtjinfo.nj_kbjrec.
                          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                          kbji_parts[ _i ].kboj_recpos := cgg_rec_key_offset + 1;
                    END;
                (*ENDIF*) 
                jinfos.ji_nxtjinfo.nj_kbjrec.
                      kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                      kbji_parts[ kbpartj ].kboj_len := dmli.d_joins.
                      jrc_joinarr[ currj ].jo_recs[ partj ].jop_inoutlen;
                jinfos.ji_nxtjinfo.nj_kbjrec.
                      kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                      kbji_parts[ _i ].kboj_len := dmli.d_joins.
                      jrc_joinarr[ currj ].jo_recs[ _j ].jop_inoutlen;
                IF  (partj = 1)
                THEN
                    (* reverse join operation if necessary *)
                    CASE dmli.d_joins.jrc_joinarr[ currj ].jo_op OF
                        op_lt :
                            jinfos.ji_nxtjinfo.nj_kbjrec.
                                  kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                                  kbji_parts[ 1 ].kboj_op := op_gt;
                        op_le :
                            jinfos.ji_nxtjinfo.nj_kbjrec.
                                  kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                                  kbji_parts[ 1 ].kboj_op := op_ge;
                        op_gt :
                            jinfos.ji_nxtjinfo.nj_kbjrec.
                                  kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                                  kbji_parts[ 1 ].kboj_op := op_lt;
                        op_ge :
                            jinfos.ji_nxtjinfo.nj_kbjrec.
                                  kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                                  kbji_parts[ 1 ].kboj_op := op_le;
                        op_eq :
                            jinfos.ji_nxtjinfo.nj_kbjrec.
                                  kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                                  kbji_parts[ 1 ].kboj_op := op_eq;
                        op_ne :
                            jinfos.ji_nxtjinfo.nj_kbjrec.
                                  kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                                  kbji_parts[ 1 ].kboj_op := op_ne;
                        op_like :
                            jinfos.ji_nxtjinfo.nj_kbjrec.
                                  kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                                  kbji_parts[ 1 ].
                                  kboj_op := op_like;
                        op_not_like :
                            jinfos.ji_nxtjinfo.nj_kbjrec.
                                  kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ]
                                  .kbji_parts[ 1 ].kboj_op := op_not_like;
                        op_sounds :
                            jinfos.ji_nxtjinfo.nj_kbjrec.
                                  kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                                  kbji_parts[ 1 ].kboj_op := op_sounds;
                        op_not_sounds :
                            jinfos.ji_nxtjinfo.nj_kbjrec.
                                  kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                                  kbji_parts[ 1 ].kboj_op := op_not_sounds;
                        END
                    (*ENDCASE*) 
                ELSE
                    jinfos.ji_nxtjinfo.nj_kbjrec.
                          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                          kbji_parts[ 1 ].kboj_op := dmli.d_joins.
                          jrc_joinarr[ currj ].jo_op;
                (*ENDIF*) 
                END
            ELSE
                (* jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt > 0 AND is_multiple *)
                BEGIN
                IF  (jinfos.ji_nxtjinfo.nj_kbjrec.
                    kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                    kbji_parts[ kbpartj ].kboj_len +
                    dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].
                    jop_inoutlen) < mxsp_key
                THEN
                    jinfos.ji_nxtjinfo.nj_kbjrec.
                          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                          kbji_parts[ kbpartj ].kboj_len :=
                          jinfos.ji_nxtjinfo.nj_kbjrec.
                          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                          kbji_parts[ kbpartj ].kboj_len + dmli.d_joins.
                          jrc_joinarr[ currj ].jo_recs[ partj ].jop_inoutlen;
                (*ENDIF*) 
                IF  (jinfos.ji_nxtjinfo.nj_kbjrec.
                    kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                    kbji_parts[ _i ].kboj_len +
                    dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ _j ].
                    jop_inoutlen) < mxsp_key
                THEN
                    jinfos.ji_nxtjinfo.nj_kbjrec.
                          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                          kbji_parts[ _i ].kboj_len :=
                          jinfos.ji_nxtjinfo.nj_kbjrec.
                          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                          kbji_parts[ _i ].kboj_len +
                          dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ _j ].
                          jop_inoutlen;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            IF  (jinfos.ji_nxtjinfo.nj_kbjrec.
                kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                kbji_parts[ 1 ].kboj_len =
                jinfos.ji_nxtjinfo.nj_kbjrec.
                kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                kbji_parts[ 2 ].kboj_len)
            THEN
                (* same length *)
                _hop.c := chr (0)
            ELSE
                IF  (jinfos.ji_nxtjinfo.nj_kbjrec.
                    kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                    kbji_parts[ 1 ].kboj_len >
                    jinfos.ji_nxtjinfo.nj_kbjrec.
                    kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                    kbji_parts[ 2 ].kboj_len)
                THEN
                    _hop.c := chr (2)
                ELSE
                    _hop.c := chr (1);
                (*ENDIF*) 
            (*ENDIF*) 
            jinfos.ji_nxtjinfo.nj_kbjrec.
                  kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_cnt ].
                  kbji_parts[ 2 ].kboj_op := _hop.op;
            END
        (*ENDIF*) 
        END
    ELSE
        (* not in key *)
        BEGIN
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
              etype         := st_output;
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
              ecol_tab[ 1 ] := chr (0);
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
              ecol_tab[ 2 ] := chr (jinfos.ji_acttabno);
        dmli.d_inoutpos := dmli.d_inoutpos + dmli.d_joins.
              jrc_joinarr[ currj ].jo_recs[ partj ].jop_inoutlen;
        IF  dmli.d_inoutpos > mxgg_record + 1
        THEN
            a07_b_put_error (acv, e_join_fields_too_long, 1)
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
          epos     := jinfos.ji_outpos;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
          elen_var := dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].
          jop_inoutlen;
    jinfos.ji_outpos := jinfos.ji_outpos + dmli.d_joins.jrc_joinarr[ currj ].
          jo_recs[ partj ].jop_inoutlen;
    IF  is_outertab
    THEN
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
              eop_out := op_o_output_outer_join
    ELSE
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
              eop_out := op_o_none;
    (*ENDIF*) 
&   IFDEF TRACE
    t01qual1(ak_join, 'results in  ', acv.a_mblock.mb_qual^);
    t01int4 (ak_join, 'ji_outpos   ', jinfos.ji_outpos );
    t01int4 (ak_join, 'jop_inoutlen', dmli.d_joins.jrc_joinarr[ currj ].
          jo_recs[ partj ].jop_inoutlen);
&   ENDIF
    _field_len := dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].
          jop_inoutlen;
    _i := 0;
    IF  (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].jop_tableno = cak68_join_value)
        AND
        (jinfos.ji_act_join > 1) AND (jinfos.ji_act_join < dmli.d_cntfromtab)
    THEN
        (* overwrite st_column with st_output_join *)
        a685set_st_type (acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ],
              (* calculate position in i+1.th temporary result record *)
              a685evaluate_new_ecol_pos (dmli, jinfos,
              dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].jop_startstack,
              acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
              elen_var))
    ELSE
        (* i.th tab = any tab *)
        BEGIN
        _found := (jinfos.ji_act_join < dmli.d_cntfromtab)
              AND
              (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].jop_cntstack = 1)
              AND
              (NOT is_outertab)
              AND
              ((NOT (acv.a_out_packet^.sp1_header.sp1h_mess_code in
              [ csp_unicode_swap, csp_unicode ])) OR
              (NOT (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].
              jop_datatyp in [ dcha, dche, dvarchara, dvarchare ])))
              AND
              (NOT (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].
              jop_datatyp in [ ddate, dtime, dtimestamp ]))
              AND
              (acv.a_mblock.mb_st^[ _pos - 1 ].elen_var =
              acv.a_mblock.mb_st^[ _pos ].elen_var)
              AND
              a685stentry_found_in_outplist (jinfos, _i,
              dmli, acv.a_mblock.mb_st^[ _pos ]);
&       IFDEF TRACE
        t01bool (ak_join, 'found       ', _found);
        t01int4 (ak_join, 'field_len   ', _field_len);
&       ENDIF
        IF  (_found AND
            (_field_len = jinfos.ji_stack_desc.mst_addr^[ _i + 1 ].elen_var))
        THEN
            a685pack_record (acv, _pos, dmli, jinfos, _i)
        ELSE
            BEGIN
            CASE partj OF
                1 :
                    _j := 2;
                2 :
                    _j := 1;
                END;
            (*ENDCASE*) 
            IF  ((NOT(dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ _j ].jop_tableno
                in jinfos.ji_nxtjinfo.nj_left_side))
                (* NOT i.th tab = i-x.th tab *)
                AND
                (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ _j ].jop_tableno <>
                cak68_join_value)
                (* NOT i.th tab = <value> *)
                AND
                (
                ((dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ _j ].
                jop_tableno <> jinfos.ji_nxtjinfo.nj_nxttabno) AND (jinfos.ji_act_join = 1))
                (* i.th tab = i+1.th tab and 1.step *)
                OR (jinfos.ji_act_join > 1))
                (* i.th tab = any tab for any other step *)
                )
            THEN
                BEGIN
                jinfos.ji_nxtjinfo.nj_not_copied_keyfields_cnt :=
                      succ (jinfos.ji_nxtjinfo.nj_not_copied_keyfields_cnt);
                (* update original stack entries *)
                jinfos.ji_st_addr^[ dmli.d_joins.jrc_joinarr[ currj ].
                      jo_recs[ partj ].jop_startstack ].etype := st_fixcol;
                jinfos.ji_st_addr^[ dmli.d_joins.jrc_joinarr[ currj ].
                      jo_recs[ partj ].jop_startstack ].eop   := op_join_key;
                jinfos.ji_st_addr^[ dmli.d_joins.jrc_joinarr[ currj ].
                      jo_recs[ partj ].jop_startstack ].epos  :=
                      acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].epos;
                jinfos.ji_st_addr^[ dmli.d_joins.jrc_joinarr[ currj ].
                      jo_recs[ partj ].jop_startstack ].elen_var :=
                      acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].elen_var;
                jinfos.ji_st_addr^[ dmli.d_joins.jrc_joinarr[ currj ].
                      jo_recs[ partj ].jop_startstack ].ecol_tab[ 1 ] :=
                      chr (pred (acv.a_mblock.mb_qual^.mfirst_free));
                jinfos.ji_st_addr^[ dmli.d_joins.jrc_joinarr[ currj ].
                      jo_recs[ partj ].jop_startstack ].ecol_tab[ 2 ] :=
                      chr (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ partj ].
                      jop_tableno);
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684transfer_output_fields (
            VAR acv    : tak_all_command_glob;
            VAR dmli   : tak_dml_info;
            VAR jinfos : tak68_joininfos);
 
VAR
      _is_acttabno : boolean;
      _col_found : boolean;
      _starts    : integer;
      _stops     : integer;
      _startd    : integer;
      _i         : integer;
      _j         : integer;
      _scnt      : integer;
 
BEGIN
IF  jinfos.ji_st_addr^[ jinfos.ji_stack_desc.mqual_pos ].etype = st_jump_output
THEN
    _stops := jinfos.ji_stack_desc.mqual_pos +
          jinfos.ji_st_addr^[ jinfos.ji_stack_desc.mqual_pos ].epos - 2
ELSE
    _stops := jinfos.ji_stack_desc.mmult_pos;
(*ENDIF*) 
_i      := succ (jinfos.ji_stack_desc.mmult_pos);
_starts := _i;
_startd := pred (acv.a_mblock.mb_qual^.mfirst_free);
WHILE _i <= _stops DO
    (* loop over output columns of orig. mblock *)
    BEGIN
    _is_acttabno := false;
    _col_found   := false;
    (* step to next output column *)
    WHILE ((_i <= _stops) AND
          (NOT (jinfos.ji_st_addr^[ _i ].etype in
          [ st_output, st_output_join ]))) DO
        BEGIN
        IF  (jinfos.ji_st_addr^[ _i ].etype IN [ st_fixkey, st_varkey,
            st_fixcol, st_varcol, st_varlongchar ])
        THEN
            (* column found *)
            BEGIN
            _col_found := true;
            _is_acttabno := (ord(jinfos.ji_st_addr^[ _i ].ecol_tab[ 2 ]) =
                  jinfos.ji_acttabno)
                  OR
                  (ord(jinfos.ji_st_addr^[ _i ].ecol_tab[ 2 ]) =
                  jinfos.ji_acttabno + 100);
            END;
        (*ENDIF*) 
        _i := succ (_i);
        END;
    (*ENDWHILE*) 
    IF  ((_i <= _stops)
        (* output column found *)
        AND
        (* output columns for i.th tab *)
        (_is_acttabno  OR
        (* for last join step grab remaining output *)
        ((jinfos.ji_act_join = dmli.d_cntfromtab) AND (NOT _col_found))))
    THEN
        BEGIN
        _scnt := _i - _starts + 1;
&       ifdef trace
        t01name(ak_join, 'get stack entries:');
        FOR _j := _starts TO _starts + _scnt - 1 DO
            t01stackentry( ak_join, jinfos.ji_st_addr^[ _j ], _j );
        (*ENDFOR*) 
&       endif
        (* get colunms until output column *)
        g10mv1 ('VAK684',  11,    
              (jinfos.ji_stack_desc.mst_max * mxgg_stack_entry),
              acv.a_mblock.mb_st_size,
              (* source *)
              jinfos.ji_st_addr^, (_starts - 1) * mxgg_stack_entry + 1,
              (* destination *)
              acv.a_mblock.mb_st^, _startd * mxgg_stack_entry + 1,
              _scnt * mxgg_stack_entry,
              acv.a_return_segm^.sp1r_returncode);
        _startd := _startd + _scnt;
        _j      := _i; (* mark actual output stack entry *)
        IF  acv.a_return_segm^.sp1r_returncode = 0
        THEN
            BEGIN
            (* update a_mblock *)
            acv.a_mblock.mb_qual^.mqual_cnt   :=
                  acv.a_mblock.mb_qual^.mqual_cnt + _scnt;
            acv.a_mblock.mb_qual^.mfirst_free :=
                  acv.a_mblock.mb_qual^.mfirst_free + _scnt;
            IF  ((acv.a_mblock.mb_st^[ _startd ].eop_out in
                [ op_o_none, op_o_output_hold ]) AND
                (acv.a_mblock.mb_st^[ _startd ].etype in [ st_output, st_output_join ]) )
                OR
                (( acv.a_mblock.mb_st^[ _startd ].eop_out = op_o_output_oflw ) AND
                (   jinfos.ji_st_addr^[ _i - 1 ].etype <> st_output ))
            THEN
                BEGIN
                IF  acv.a_mblock.mb_st^[ _startd ].eop_out = op_o_output_hold
                THEN
                    BEGIN
                    (* look one stack entry below in original stack entries *)
                    _i := succ(_i);
                    IF  (jinfos.ji_st_addr^[ _i ].eop_out
                        in [ op_o_output, op_o_output_order,
                        op_o_output_no_oflw, op_o_output_oflw ])
                        AND (jinfos.ji_st_addr^[ _i ].etype in
                        [ st_output,st_output_join ])
                    THEN
                        (* st_output -> st_output_join in original mblock *)
                        a685set_st_type (jinfos.ji_st_addr^[ _i ],
                              (* set epos from orig. stackentry above *)
                              jinfos.ji_st_addr^[ _j ].epos);
                    (*ENDIF*) 
                    CASE jinfos.ji_st_addr^[ _i ].eop_out OF
                        op_o_output_oflw,
                        op_o_output_no_oflw :
                            acv.a_mblock.mb_st^[ _startd ].eop_out :=
                                  (* set eop_out from orig. stackentry below *)
                                  jinfos.ji_st_addr^[ _i ].eop_out;
                        OTHERWISE
                            acv.a_mblock.mb_st^[ _startd ].eop_out :=
                                  op_o_none;
                        END
                    (*ENDCASE*) 
                    END
                (*ENDIF*) 
                END
            ELSE
                BEGIN
                (* ** eop in [ op_output, op_output_order,    *)
                (*             op_output_no_oflw ]         ** *)
                dmli.d_inoutpos :=
                      dmli.d_inoutpos + acv.a_mblock.mb_st^[ _startd ].elen_var;
                IF  (dmli.d_inoutpos > mxgg_record + 1)
                THEN
                    a07_b_put_error (acv, e_join_fields_too_long, 1);
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            IF  (jinfos.ji_act_join > 1)
            THEN
                BEGIN
                IF  (jinfos.ji_act_join = dmli.d_cntfromtab)
                THEN
                    BEGIN
                    (* st_output st_output_join *)
                    a685set_st_type (acv.a_mblock.mb_st^[ _startd ],
                          (* set epos from last orig. output stack entry *)
                          jinfos.ji_st_addr^[ _j ].epos);
                    IF  (jinfos.ji_nxtjinfo.nj_r_len <
                        (acv.a_mblock.mb_st^[ _startd ].ecol_pos +
                        acv.a_mblock.mb_st^[ _startd ].elen_var))
                    THEN
                        jinfos.ji_nxtjinfo.nj_r_len :=
                              acv.a_mblock.mb_st^[ _startd ].ecol_pos +
                              acv.a_mblock.mb_st^[ _startd ].elen_var - 1;
                    (*ENDIF*) 
                    END
                ELSE
                    (* st_output -> st_output_join *)
                    a685set_st_type (acv.a_mblock.mb_st^[ _startd ],
                          a685evaluate_new_ecol_pos (dmli, jinfos,
                          _starts, jinfos.ji_st_addr^[ _i ].elen_var));
                (*ENDIF*) 
                ;
                (* st_output -> st_output_join in original mblock *)
                a685set_st_type (jinfos.ji_st_addr^[ _j ],
                      (* set ecol_pos from copied stack entry *)
                      acv.a_mblock.mb_st^[ _startd ].ecol_pos);
&               IFDEF TRACE
                t01int4 (ak_join, 'r_len     = ', jinfos.ji_nxtjinfo.nj_r_len);
                t01int4 (ak_join, 'starts    = ', _starts);
&               ENDIF
                END
            ELSE
                (* jinfos.ji_act_join = 1 *)
                (* stamp st_output_join in original mblock *)
                a685set_st_type (jinfos.ji_st_addr^[ _j ], jinfos.ji_outpos);
            (*ENDIF*) 
            acv.a_mblock.mb_st^[ _startd ].epos := jinfos.ji_outpos;
            jinfos.ji_outpos := jinfos.ji_outpos +
                  acv.a_mblock.mb_st^[ _startd ].elen_var;
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  (jinfos.ji_st_addr^[ _i ].eop_out = op_o_output_hold) AND
        (jinfos.ji_st_addr^[ _i ].etype in [ st_output, st_output_join ])
    THEN
        _i := _i + 2
    ELSE
        _i := succ(_i);
    (*ENDIF*) 
    _starts := _i;
    END;
(*ENDWHILE*) 
IF  (jinfos.ji_act_join = 1)
THEN
    jinfos.ji_nxtjinfo.nj_r_len := jinfos.ji_outpos;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a684_join (
            VAR acv                 : tak_all_command_glob;
            VAR dmli                : tak_dml_info;
            VAR series              : tak68_sequence;
            VAR res_tree            : tgg00_FileId;
            VAR parsk               : tak_parskey; (* session command ID *)
            VAR jinfos              : tak68_joininfos;
            VAR ak_strat_interface  : tak70_strat_rec;
            VAR jvrec               : tak68_joinview_rec;
            VAR cost_infos          : tak68_evaluation_records);
 
VAR
      _e             : tgg_basis_error;
      _xi            : integer;
      _stops         : integer;
      _old_return    : integer;
      _ke            : tgg_sysinfokey;
 
BEGIN
&IFDEF TRACE
t01messblock (ak_join, 'NEW MESSBUF ', acv.a_mblock);
a683output_joins( ak_join, acv, dmli, dmli.d_joins );
a683_output( ak_join, dmli );
&ENDIF
_old_return := acv.a_return_segm^.sp1r_returncode;
(* initialize jinfos *)
jinfos.ji_act_join                         := 1;
jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_right_oj := false;
jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_left_oj  := false;
jinfos.ji_nxtjinfo.nj_left_side := [ series[ 1 ].jos_source ];
jinfos.ji_nxtjinfo.nj_not_copied_keyfields_cnt := 0;
(* save original mqual_pos *)
jinfos.ji_stack_desc.mmult_pos := jinfos.ji_stack_desc.mqual_pos;
(* loop for each join step *)
WHILE ((jinfos.ji_act_join <= dmli.d_cntfromtab) AND
      (acv.a_return_segm^.sp1r_returncode = 0)) DO
    BEGIN
    (* set ji_nxtjinfo.nj_nxttabno *)
    IF  (jinfos.ji_act_join < dmli.d_cntfromtab)
    THEN
        jinfos.ji_nxtjinfo.nj_nxttabno := series[ jinfos.ji_act_join + 1 ].jos_source
    ELSE
        jinfos.ji_nxtjinfo.nj_nxttabno := jinfos.ji_acttabno;
    (*ENDIF*) 
&   IFDEF TRACE
    a683joinset_trace (ak_join, 'left side   ', jinfos.ji_nxtjinfo.nj_left_side);
&   ENDIF
    ak684join_one_record (acv, dmli, jinfos, series, res_tree, parsk,
          ak_strat_interface, jvrec, cost_infos);
    IF  (jinfos.ji_act_join < dmli.d_cntfromtab)
    THEN
        BEGIN
        IF  jinfos.ji_st_addr^[ jinfos.ji_stack_desc.mqual_pos ].etype =
            st_jump_output
        THEN
            _stops := jinfos.ji_stack_desc.mqual_pos +
                  jinfos.ji_st_addr^[ jinfos.ji_stack_desc.mqual_pos ].epos - 2
        ELSE
            _stops := jinfos.ji_stack_desc.mmult_pos;
        (*ENDIF*) 
        (* *** reset copied join output stackentries *** *)
        FOR _xi := jinfos.ji_stack_desc.mqual_pos TO _stops DO
            IF  jinfos.ji_st_addr^[ _xi ].etype = st_outp_cp_join
            THEN
                jinfos.ji_st_addr^[ _xi ].etype := st_output_join;
            (*ENDIF*) 
        (*ENDFOR*) 
        END;
&   IFDEF TRACE
    (*ENDIF*) 
    t01qual1 (ak_join, 'NEW MESSBUF ', acv.a_mblock.mb_qual^);
&   ENDIF
    ;
    (* mark table as processed *)
    jinfos.ji_nxtjinfo.nj_left_side := jinfos.ji_nxtjinfo.nj_left_side +
          [ series[ jinfos.ji_act_join ].jos_source ];
    jinfos.ji_act_join := succ (jinfos.ji_act_join);
    END;
(*ENDWHILE*) 
IF  ((_old_return = 0) AND (acv.a_return_segm^.sp1r_returncode <> 0))
THEN
    (* error handling - remove all build messblocks *)
    BEGIN
    _ke := a01sysnullkey;
    IF  dmli.d_view
    THEN
        BEGIN
        _ke.stableid  := jvrec.jv_tabid;
        _ke.sentrytyp := cak_epermmessblock;
        END
    ELSE
        BEGIN
        IF  acv.a_ex_kind = only_parsing
        THEN
            BEGIN
            _ke.sauthid[ 1 ] := cak_tempinfo_byte;
            s10mv1 (sizeof(parsk), sizeof(_ke.sauthid), parsk, 1,
                  _ke.sauthid, 2, mxak_parskey);
            END
        ELSE
            _ke.stempid := acv.a_curr_res_id;
        (*ENDIF*) 
        _ke.sentrytyp := cak_emessblock;
        END;
    (*ENDIF*) 
    _old_return := acv.a_return_segm^.sp1r_returncode;
    acv.a_return_segm^.sp1r_returncode := 0;
    FOR _xi := 1 TO dmli.d_cntfromtab DO
        BEGIN
        _ke.slinkage[ 2 ] := chr(_xi);
        a10del_sysinfo (acv, _ke, _e);
        _ke.slinkage[ 2 ] := chr(_xi + cak_maxsources);
        a10del_sysinfo (acv, _ke, _e)
        END;
    (*ENDFOR*) 
    acv.a_return_segm^.sp1r_returncode := _old_return
    END;
(*ENDIF*) 
dmli.d_inoutpos := succ (jinfos.ji_nxtjinfo.nj_r_len);
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684_exists_subquery (
            VAR acv          : tak_all_command_glob;
            VAR jinfos       : tak68_joininfos;
            VAR use_subquery : boolean);
 
VAR
      _i            : integer;
      _stopi        : integer;
      _op_not_found : boolean;
 
BEGIN
_i     := jinfos.ji_stack_desc.mqual_pos +
      jinfos.ji_st_addr^[ jinfos.ji_stack_desc.mqual_pos ].epos - 1;
_stopi := jinfos.ji_stack_desc.mqual_pos + jinfos.ji_stack_desc.mqual_cnt;
WHILE (_i < _stopi) DO
    BEGIN
    (* loop over original stack entries *)
    (* *** subquery with exists [ NOT ] *** *)
    IF  (jinfos.ji_st_addr^[ _i ].etype = st_subquery)     AND
        (jinfos.ji_st_addr^[ _i ].ecol_tab[ 1 ] = chr (1)) AND
        (jinfos.ji_st_addr^[ _i ].ecol_tab[ 2 ] = chr (1))
    THEN
        BEGIN
        use_subquery  := true;
        acv.a_mblock.mb_qual^.msubquery := true;
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free ] :=
              jinfos.ji_st_addr^[ _i ];
        _i := succ (_i);
        IF  (_i <= jinfos.ji_stack_desc.mqual_cnt)
        THEN
            _op_not_found := (jinfos.ji_st_addr^[ _i ].eop = op_not)
        ELSE
            _op_not_found := false;
        (*ENDIF*) 
        IF  _op_not_found
        THEN
            BEGIN
            acv.a_mblock.mb_st^[acv.a_mblock.mb_qual^.mfirst_free + 1 ] :=
                  jinfos.ji_st_addr^[ _i ];
            acv.a_mblock.mb_qual^.mfirst_free :=
                  acv.a_mblock.mb_qual^.mfirst_free + 2;
            acv.a_mblock.mb_qual^.mqual_cnt   :=
                  acv.a_mblock.mb_qual^.mqual_cnt + 2;
            acv.a_mblock.mb_qual^.mstrat_pos  :=
                  acv.a_mblock.mb_qual^.mstrat_pos + 2;
            END
        ELSE
            BEGIN
            acv.a_mblock.mb_qual^.mfirst_free :=
                  acv.a_mblock.mb_qual^.mfirst_free + 1;
            acv.a_mblock.mb_qual^.mqual_cnt   :=
                  acv.a_mblock.mb_qual^.mqual_cnt + 1;
            acv.a_mblock.mb_qual^.mstrat_pos  :=
                  acv.a_mblock.mb_qual^.mstrat_pos + 1;
            END;
        (*ENDIF*) 
        _i := jinfos.ji_stack_desc.mqual_cnt;
        END;
    (*ENDIF*) 
    _i := succ (_i);
    END;
(*ENDWHILE*) 
END;
 
(*------------------------------*) 
 
FUNCTION
      ak684_add_ot_id_size (
            VAR dmli     : tak_dml_info;
            VAR jinfos   : tak68_joininfos;
            VAR series   : tak68_sequence) : boolean;
 
VAR
      _i              : integer;
      _j              : integer;
      _k              : integer;
      _l              : integer;
      _m              : integer;
      _found_tab      : boolean;
      _found_otab     : boolean;
      _found_ctab     : boolean;
      _add_ot_id_size : boolean;
 
BEGIN
(* find out if we are between a outer join ? *)
_found_tab      := false;
_found_otab     := false;
_found_ctab     := false;
_add_ot_id_size := false;
_i              := 0;
WHILE (_i < dmli.d_joins.jrc_cnt) AND (NOT _found_tab) DO
    WITH dmli.d_joins.jrc_joinarr[ _i ] DO
        BEGIN
        _j := 1;
        _k := 2;
        REPEAT
            IF  jo_recs[ _j ].jop_outer_join
            THEN
                BEGIN
                _found_tab := true;
                IF  jinfos.ji_act_join < dmli.d_cntfromtab
                THEN
                    _m := jinfos.ji_act_join
                ELSE
                    _m := jinfos.ji_act_join - 1;
                (*ENDIF*) 
                FOR _l := 1 TO _m DO
                    BEGIN
                    IF  (series[ _l ].jos_source = jo_recs[ _j ].jop_tableno)
                    THEN
                        _found_otab := true;
                    (*ENDIF*) 
                    IF  (series[ _l ].jos_source = jo_recs[ _k ].jop_tableno)
                    THEN
                        _found_ctab := true;
                    (*ENDIF*) 
                    END;
                (*ENDFOR*) 
                END;
            (*ENDIF*) 
            _k := pred (_k);
            _j := succ (_j);
        UNTIL
            (_j > 2) OR _found_tab;
        (*ENDREPEAT*) 
        _i := succ (_i);
        END;
    (*ENDWITH*) 
(*ENDWHILE*) 
ak684_add_ot_id_size :=
      (_found_otab AND (NOT _found_ctab)) OR
      (_found_ctab AND (NOT _found_otab));
END;
 
(*------------------------------*) 
 
FUNCTION
      ak684_is_corresponding_outer_join_table (
            VAR dmli : tak_dml_info;
            curr_tab : integer) : boolean;
 
VAR
      _i         : integer;
      _j         : integer;
      _k         : integer;
      _found_tab : boolean;
 
BEGIN
_found_tab := false;
_i         := 0;
WHILE (_i < dmli.d_joins.jrc_cnt) AND (NOT _found_tab) DO
    BEGIN
    _j := 1;
    _k := 2;
    REPEAT
        IF  dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].jop_outer_join
        THEN
            _found_tab :=
                  (dmli.d_joins.jrc_joinarr[ _i ].jo_recs [ _k ].jop_tableno =
                  curr_tab);
        (*ENDIF*) 
        _k := pred (_k);
        _j := succ (_j);
    UNTIL
        (_j > 2) OR _found_tab;
    (*ENDREPEAT*) 
    _i := succ (_i);
    END;
(*ENDWHILE*) 
ak684_is_corresponding_outer_join_table := _found_tab;
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684ctransfer_const_expressions (
            VAR acv    : tak_all_command_glob;
            VAR dmli   : tak_dml_info;
            VAR jinfos : tak68_joininfos);
 
VAR
      _found           : boolean;
      _col_found       : boolean;
      _starts          : integer;
      _stops           : integer;
      _startd          : integer;
      _i               : integer;
      _j               : integer;
      _scnt            : integer;
      _aux_resqual_cnt : integer;
 
BEGIN
_aux_resqual_cnt := acv.a_mblock.mb_qual^.mresqual_cnt;
WITH jinfos.ji_stack_desc DO
    BEGIN
    IF  jinfos.ji_st_addr^[ mqual_pos ].etype = st_jump_output
    THEN
        _stops := mqual_pos + jinfos.ji_st_addr^[ mqual_pos ].epos - 2
    ELSE
        _stops := mmult_pos;
    (*ENDIF*) 
    _i := succ (mmult_pos);
    END;
(*ENDWITH*) 
_starts := _i;
_startd := pred (acv.a_mblock.mb_qual^.mfirst_free);
&IFDEF TRACE
t01int4 (ak_join, 'ji_act_join=', jinfos.ji_act_join);
t01int4 (ak_join, 'd_inoutpos= ', dmli.d_inoutpos);
t01int4 (ak_join, 'startd    = ', _startd);
t01int4 (ak_join, 'i         = ', _i);
t01int4 (ak_join, 'stops     = ', _stops);
t01stackdesc (ak_join, 'ji_stack_des', jinfos.ji_st_addr, jinfos.ji_stack_desc);
&ENDIF
WITH jinfos.ji_stack_desc DO
    WHILE _i <= _stops DO
        BEGIN
        _found     := false;
        _col_found := false;
&       IFDEF TRACE
        t01qual (ak_join, acv.a_mblock.mb_qual^);
        t01int4 (ak_join, 'i           ', _i);
        t01stackentry (ak_join, jinfos.ji_st_addr^[ _i ], _i);
&       ENDIF
        WHILE ((_i <= _stops) AND
              (NOT (jinfos.ji_st_addr^[ _i ].etype in
              [ st_output, st_output_join ]))) DO
            BEGIN
            IF  (jinfos.ji_st_addr^[ _i ].etype IN [ st_fixkey, st_varkey,
                st_fixcol, st_varcol, st_varlongchar ])
            THEN
                BEGIN
                _col_found := true;
                _found := (ord(jinfos.ji_st_addr^[ _i ].ecol_tab[ 2 ]) =
                      jinfos.ji_acttabno)
                      OR
                      (ord(jinfos.ji_st_addr^[ _i ].ecol_tab[ 2 ]) =
                      jinfos.ji_acttabno + 100);
                END;
            (*ENDIF*) 
            _i := succ (_i);
            END;
        (*ENDWHILE*) 
&       IFDEF TRACE
        t01int4 (ak_join, 'i      while', _i);
        t01stackentry (ak_join, jinfos.ji_st_addr^[ _i ], _i);
&       ENDIF
        _scnt := _i - _starts + 1;
        IF  ((_i <= _stops)   AND
            (NOT _col_found) AND
            (_scnt > 1))
        THEN
            BEGIN
            WITH acv.a_mblock.mb_qual^ DO
                BEGIN
                IF  mresqual_pos = 0
                THEN
                    BEGIN
                    mresqual_pos := mfirst_free;
                    mfirst_free  := succ (mfirst_free);
                    _startd       := succ (_startd);
                    mresqual_cnt := succ (mresqual_cnt);
                    END;
                (*ENDIF*) 
                g10mv1 ('VAK684',  12,    
                      (mst_max * mxgg_stack_entry),
                      acv.a_mblock.mb_st_size,
                      jinfos.ji_st_addr^, (_starts - 1) * mxgg_stack_entry + 1,
                      acv.a_mblock.mb_st^,
                      _startd * mxgg_stack_entry + 1,
                      (_i - _starts + 1) * mxgg_stack_entry,
                      acv.a_return_segm^.sp1r_returncode);
                _startd := _startd + _scnt;
                _j      := _i;
                IF  acv.a_return_segm^.sp1r_returncode = 0
                THEN
                    WITH acv.a_mblock.mb_st^[ _startd ] DO
                        BEGIN
                        mresqual_cnt  := mresqual_cnt + _scnt;
                        mfirst_free   := mfirst_free + _scnt;
                        epos          := jinfos.ji_st_addr^[ _j ].epos;
                        etype         := st_output;
                        ecol_tab[ 1 ] := chr(0);
                        ecol_tab[ 2 ] := chr(0);
&                       IFDEF TRACE
                        t01stackentry (ak_join, jinfos.ji_st_addr^[ _j ], _j);
                        t01stackentry (ak_join, acv.a_mblock.mb_st^[ _startd ], _startd);
                        t01int4 (ak_join, 'starts    = ', _starts);
                        t01int4 (ak_join, 'startd    = ', _startd);
                        t01int4 (ak_join, 'i         = ', _i);
                        t01int4 (ak_join, 'j         = ', _j);
                        t01int4 (ak_join, 'd_inoutpos= ', dmli.d_inoutpos);
                        t01int4 (ak_join, 'jr_outpos = ', jinfos.ji_outpos);
&                       ENDIF
                        END;
                    (*ENDWITH*) 
                (*ENDIF*) 
                END;
            (*ENDWITH*) 
            END;
        (*ENDIF*) 
        _i      := succ(_i);
        _starts := _i;
        END;
    (*ENDWHILE*) 
(*ENDWITH*) 
IF  (_aux_resqual_cnt < acv.a_mblock.mb_qual^.mresqual_cnt) AND
    (acv.a_mblock.mb_qual^.mresqual_pos    > 0)
THEN
    WITH acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ] DO
        BEGIN
        etype         := st_jump_output;
        eop           := op_none;
        epos          := 
            acv.a_mblock.mb_qual^.mfirst_free - 
            acv.a_mblock.mb_qual^.mresqual_pos + 1;
        elen_var      := 0;
        ecol_tab[ 1 ] := chr(0);
        ecol_tab[ 2 ] := chr(0);
        END;
    (*ENDWITH*) 
&IFDEF TRACE
(*ENDIF*) 
t01qual (ak_join, acv.a_mblock.mb_qual^);
t01stackdesc (ak_join, 'ji_stack_des', jinfos.ji_st_addr, jinfos.ji_stack_desc);
&ENDIF
END;
 
.CM *-END-* code---------------
.SP 2 
***********************************************************
*-PRETTY-*  statements    :        849
*-PRETTY-*  lines of code :       2577        PRETTYX 3.10 
*-PRETTY-*  lines in file :       3511         1997-12-10 
.PA 
