.nf
 
 .nf
 
    ========== licence begin  GPL
    Copyright (c) 1999-2005 SAP AG
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end
.fo
 
 
.fo
*****************************************************
Copyright (c) 1999-2005 SAP AG
SAP Database Technology
 
Release :      Date : 2000-11-22
*****************************************************
modname : VAK684
changed : 2000-11-22
module  : Join2_Select
 
Author  : ElkeZ
Created : 1985-10-16
*****************************************************
 
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 jinfos              : tak68_joininfos;
                    VAR ak_strat_interface  : tak71_strat_rec;
                    VAR jvrec               : tak68_joinview_rec;
                    VAR table_stats         : tak68_table_stats);
 
        PROCEDURE
              a684get_relation_info(
                    VAR acv         : tak_all_command_glob;
                    VAR tabledesc   : tak_one_table;
                    dstate          : tak_directory_state;
                    VAR pbasep      : tak_sysbufferaddress);
 
        PROCEDURE
              a684move_infos_strategy (
                    VAR acv             : tak_all_command_glob;
                    VAR strat           : tgg07_StrategyInfo;
                    VAR joinp           : tak_sysbufferaddress;
                    StratInfo_len       : tsp00_Int2;
                    new_strat_created   : boolean);
 
        PROCEDURE
              a684move_infos_onetabstrat (
                    VAR acv             : tak_all_command_glob;
                    VAR strat           : tgg07_StrategyInfo;
                    VAR joinp           : tak_sysbufferaddress;
                    StratInfo_len       : tsp00_Int2;
                    new_strat_created   : boolean);
 
        PROCEDURE
              a684set_filehandling(
                    VAR acv    : tak_all_command_glob;
                    VAR dmli   : tak_dml_info);
 
        FUNCTION
              a684get_used_invlen(
                    VAR acv    : tak_all_command_glob;
                    VAR tabid  : tgg00_Surrogate;
                    index_no   : tsp00_Int4;
                    used_cols  : tsp00_Int2) : tsp00_Int4;
 
        PROCEDURE
              a684update_strategy(
                    VAR strat   : tgg07_StrategyInfo );
 
.CM *-END-* define --------------------------------------
Use     :
 
        FROM
              Scanner : VAK01;
 
        VAR
              a01_il_b_identifier    : tsp00_KnlIdentifier;
              a01_i_temp             : tsp00_KnlIdentifier;
              a01_into_res_name      : tsp00_KnlIdentifier;
              a01use_join_hashtable  : boolean;
              a01join_hash_min_ratio : tsp00_Int4;
              a01join_parall_minsize : tsp00_Int4;
 
      ------------------------------ 
 
        FROM
              AK_universal_semantic_tools : VAK06;
 
        PROCEDURE
              a06a_mblock_init (
                    VAR acv      : tak_all_command_glob;
                    mtype        : tgg00_MessType;
                    m2type       : tgg00_MessType2;
                    VAR tree     : tgg00_FileId);
 
        PROCEDURE
              a06_systable_get (
                    VAR acv      : tak_all_command_glob;
                    dstate       : tak_directory_state;
                    VAR tableid  : tgg00_Surrogate;
                    VAR base_ptr : tak_sysbufferaddress;
                    get_all      : boolean;
                    VAR ok       : boolean);
 
      ------------------------------ 
 
        FROM
              AK_error_handling : VAK07;
 
        PROCEDURE
              a07_b_put_error (
                    VAR acv : tak_all_command_glob;
                    b_err   : tgg00_BasisError;
                    err_code : tsp00_Int4);
 
        PROCEDURE
              a07ak_system_error (
                    VAR acv  : tak_all_command_glob;
                    modul_no : integer;
                    id       : integer);
 
        PROCEDURE
              a07_tb_put_error (
                    VAR acv     : tak_all_command_glob;
                    b_err       : tgg00_BasisError;
                    err_code    : tsp00_Int4;
                    VAR tab_id  : tgg00_Surrogate);
 
      ------------------------------ 
 
        FROM
              Systeminfo_cache : VAK10;
 
        PROCEDURE
              a10get_sysinfo (
                    VAR acv      : tak_all_command_glob;
                    VAR syskey   : tgg00_SysInfoKey;
                    dstate       : tak_directory_state;
                    VAR syspoint : tak_sysbufferaddress;
                    VAR b_err    : tgg00_BasisError);
 
      ------------------------------ 
 
        FROM
              SQLManager : VAK101;
 
        FUNCTION
              a101_GetMaxJoinHashTableSize : tsp00_Int4;
 
      ------------------------------ 
 
        FROM
              AK_Index : VAK24;
 
        PROCEDURE
              a24fnd_indexno (
                    VAR acv            : tak_all_command_glob;
                    VAR tabid          : tgg00_Surrogate;
                    indexno            : integer;
                    VAR index_scan_rec : tak_index_scan_record);
 
      ------------------------------ 
 
        FROM
              Build_Strategy_2 : VAK71;
 
        PROCEDURE
              a71default_strat (VAR gg_strategy : tgg07_StrategyInfo);
 
        PROCEDURE
              a71prepare_qual_on_index (
                    VAR acv       : tak_all_command_glob;
                    VAR qual_kind : tgg00_QualKind);
 
      ------------------------------ 
 
        FROM
              Catalog_Select_Optimizer : VAK722;
 
        PROCEDURE
              a722strategy (
                    VAR acv        : tak_all_command_glob;
                    VAR dmli       : tak_dml_info;
                    VAR eval_info  : tak71_page_eval_rec;
                    VAR gg_strategy: tgg07_StrategyInfo;
                    VAR strat_len  : tsp00_Int2);
&       ifdef trace
 
      ------------------------------ 
 
        FROM
              Trace_Strategy_1 : VAK725;
 
        PROCEDURE
              a725output_gg_strat (
                    debug         : tgg00_Debug;
                    nam           : tsp00_Sname;
                    VAR gg_strat  : tgg07_StrategyInfo);
&       endif
 
      ------------------------------ 
 
        FROM
              AK_universal_show_tools : VAK40;
 
        PROCEDURE
              a40add_explain_record (
                    VAR acv  : tak_all_command_glob;
                    VAR expl : tak71_explain_rec);
 
      ------------------------------ 
 
        FROM
              Select_List : VAK61;
 
        PROCEDURE
              a61_set_jump (
                    VAR mblock : tgg00_MessBlock;
                    stentrynr : integer;
                    operator  : tgg00_StackEntryType);
 
        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 : tgg00_StackOpType);
 
      ------------------------------ 
 
        FROM
              Execute_Select_Expression : VAK660;
 
        PROCEDURE
              a660build_view_treeid (
                    VAR acv     : tak_all_command_glob;
                    VAR tableid : tgg00_Surrogate;
                    VAR tree    : tgg00_FileId);
 
      ------------------------------ 
 
        FROM
              Subquery_handling : VAK661;
 
        PROCEDURE
              a661_get_from_select_table (
                    VAR acv     : tak_all_command_glob;
                    VAR tableid : tgg00_Surrogate;
                    VAR pbasep  : tak_sysbufferaddress;
                    dstate      : tak_directory_state;
                    all         : boolean;
                    VAR f_ok    : boolean);
 
        FUNCTION
              a661_is_fromsel_table (
                    VAR acv     : tak_all_command_glob;
                    VAR ftreeid : tgg00_FileId) : boolean;
 
      ------------------------------ 
 
        FROM
              Resultname_handling : VAK663;
 
        PROCEDURE
              a663get_result_records (
                    VAR acv    : tak_all_command_glob;
                    dstate     : tak_directory_state;
                    VAR resid  : tsp00_Int4;
                    VAR pbasep : tak_sysbufferaddress;
                    VAR ok     : boolean);
 
        PROCEDURE
              a663_get_result_info (
                    VAR acv          : tak_all_command_glob;
                    VAR resname      : tsp00_KnlIdentifier;
                    VAR modul_name   : tsp00_KnlIdentifier;
                    VAR resname_addr : tak_sysbufferaddress;
                    make_new_res     : boolean;
                    ftemptype        : tgg00_TfnTemp;
                    dstate           : tak_directory_state;
                    VAR f_ok         : boolean);
 
        PROCEDURE
              a663recurs_result_records (
                    VAR acv    : tak_all_command_glob;
                    dstate     : tak_directory_state;
                    VAR surr   : tgg00_Surrogate;
                    VAR pbasep : tak_sysbufferaddress;
                    VAR ok     : boolean);
 
      ------------------------------ 
 
        FROM
              Build_Strategy : VAK70;
 
        VAR
              a70glob_join_key_strats   : tgg07_StratEnumSet;
              a70glob_inv_strats        : tgg07_StratEnumSet;
              a70glob_key_strats        : tgg07_StratEnumSet;
              a70glob_join_strats       : tgg07_StratEnumSet;
 
        PROCEDURE
              a70strategy (
                    VAR acv          : tak_all_command_glob;
                    VAR dmli         : tak_dml_info;
                    VAR gg_strategy  : tgg07_StrategyInfo;
                    VAR StratInfo_len: tsp00_Int2;
                    VAR eval_info    : tak71_page_eval_rec;
                    config           : tak00_access_configuration);
 
      ------------------------------ 
 
        FROM
              Strategy_Explain : VAK728;
 
        PROCEDURE
              a728_explain (
                    VAR acv          : tak_all_command_glob;
                    VAR dmli         : tak_dml_info;
                    VAR strat        : tgg07_StrategyInfo;
                    joininfo_ptr     : tak68_join_ptr;
                    VAR morestratbuf : tsp00_MoveObj;
                    morestratbufsize : tsp00_Int4;
                    morestratpos     : tsp00_Int4);
 
      ------------------------------ 
 
        FROM
              Hint_Handling : VAK80;
 
        PROCEDURE
              a80get_access_for_join_hint(
                    VAR acv         : tak_all_command_glob;
                    parskey         : tak_parskey;
                    tableno         : tsp00_Int2;
                    VAR access_hint : tak00_access_configuration);
&       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 dmli     : tak_dml_info;
                    VAR join_set : tak_joinset);
 
        PROCEDURE
              a683_output (
                    debug    : tgg00_Debug;
                    VAR dmli : tak_dml_info);
 
        PROCEDURE
              a683_one_join_entry_ex(
                    debug    : tgg00_Debug;
                    VAR dmli : tak_dml_info;
                    index    : integer;
                    trace_all: boolean);
&       endif
 
      ------------------------------ 
 
        FROM
              Join_Select  : VAK680;
 
        PROCEDURE
              a680rollback_temp_jinfo(
                    VAR acv      : tak_all_command_glob;
                    VAR dmli     : tak_dml_info;
                    VAR parsk    : tak_parskey;
                    VAR jv_tabid : tgg00_Surrogate;
                    info_cnt     : tsp00_Int2);
 
      ------------------------------ 
 
        FROM
              Join2_Select_help_routines : VAK685;
 
        PROCEDURE
              a685next_key_length (
                    VAR dmli   : tak_dml_info;
                    VAR jinfos : tak68_joininfos);
 
        PROCEDURE
              a685olast_order_fields (
                    VAR jinfos  : tak68_joininfos;
                    VAR njrec   : tgg07_JoinColCopyInfo);
 
        PROCEDURE
              a685pack_record (
                    VAR acv    : tak_all_command_glob;
                    pos        : tsp00_Int2;
                    VAR dmli   : tak_dml_info;
                    VAR jinfos : tak68_joininfos;
                    mj_pos     : tsp00_Int2);
 
        FUNCTION
              a685stentry_found_in_outplist (
                    VAR jinfos : tak68_joininfos;
                    VAR mj_pos : tsp00_Int2;
                    VAR st_en  : tgg00_StackEntry) : boolean;
 
        PROCEDURE
              a685set_output_join (
                    VAR st : tgg00_StackEntry;
                    outpos : tsp00_Int4);
 
        PROCEDURE
              a685output_columns_shift (
                    VAR acv          : tak_all_command_glob;
                    VAR dmli         : tak_dml_info;
                    VAR jinfos       : tak68_joininfos;
                    outer_join_activ : boolean);
 
        FUNCTION
              a685evaluate_new_ecol_pos (
                    VAR dmli      : tak_dml_info;
                    VAR jinfos    : tak68_joininfos;
                    curr_st_entry : tsp00_Int2;
                    len_var       : tsp00_Int4) : tsp00_Int4;
 
        PROCEDURE
              a685join_columns_last_shift (
                    VAR acv    : tak_all_command_glob;
                    VAR dmli   : tak_dml_info;
                    VAR jinfos : tak68_joininfos);
 
        PROCEDURE
              a685join_columns_shift (
                    VAR acv          : tak_all_command_glob;
                    VAR dmli         : tak_dml_info;
                    VAR jinfos       : tak68_joininfos);
 
      ------------------------------ 
 
        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      : tsp00_Int2;
                    inp_len           : tsp00_Int2);
 
      ------------------------------ 
 
        FROM
              RTE-Extension-20 : VSP20;
 
        FUNCTION
              s20or4b (
                    VAR source : tsp00_MoveObj;
                    source_pos : tsp00_Int4) : tsp00_Int4;
 
      ------------------------------ 
 
        FROM
              Kernel_move_and_fill : VGG101;
 
        PROCEDURE
              SAPDB_PascalMove   (
                    mod_id         : tsp00_C6;
                    mod_intern_num : tsp00_Int4;
                    size1          : tsp00_Int4;
                    size2          : tsp00_Int4;
                    val1           : tsp00_MoveObjPtr;
                    p1             : tsp00_Int4;
                    val2           : tsp00_MoveObjPtr;
                    p2             : tsp00_Int4;
                    cnt            : tsp00_Int4;
                    VAR e          : tgg00_BasisError);
 
        PROCEDURE
              SAPDB_PascalForcedMove (
                    size1    : tsp00_Int4;
                    size2    : tsp00_Int4;
                    val1     : tsp00_MoveObjPtr;
                    p1       : tsp00_Int4;
                    val2     : tsp00_MoveObjPtr;
                    p2       : tsp00_Int4;
                    cnt      : tsp00_Int4);
 
        PROCEDURE
              SAPDB_PascalOverlappingMove (
                    mod_id      : tsp00_C6;
                    mod_num     : tsp00_Int4;
                    source_upb  : tsp00_Int4;
                    dest_upb    : tsp00_Int4;
                    source      : tsp00_MoveObjPtr;
                    src_pos     : tsp00_Int4;
                    destin      : tsp00_MoveObjPtr;
                    dest_pos    : tsp00_Int4;
                    length      : tsp00_Int4;
                    VAR e       : tgg00_BasisError);
&       ifdef TRACE
 
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        PROCEDURE
              t01treeid  (
                    level    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    VAR tree : tgg00_FileId);
 
        FUNCTION
              t01trace (debug : tgg00_Debug) : boolean;
 
        PROCEDURE
              t01op (
                    debug  : tgg00_Debug;
                    nam    : tsp00_Sname;
                    op     : tgg00_StackOpType);
 
        PROCEDURE
              t01Int4 (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Name;
                    int4     : tsp00_Int4);
 
        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
              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
              t01int4 (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    int      : tsp00_Int4);
 
        PROCEDURE
              t01stackentry (
                    layer       : tgg00_Debug;
                    VAR st      : tgg00_StackEntry;
                    entry_index : integer);
&       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 : tgg00_Surrogate;
                    seqno        : tsp00_Int2;
                    VAR ke       : tgg00_SysInfoKey);
 
        PROCEDURE
              a682_mbuf_to_tmpbuf (
                    VAR acv       : tak_all_command_glob;
                    VAR ke        : tgg00_SysInfoKey;
                    VAR b_err     : tgg00_BasisError;
                    sysinfo_kind  : tak68_mbuf_to_tmpbuf_context);
 
.CM *-END-* use -----------------------------------------
Synonym :
 
.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, AK684GENERATE_JOIN_INFO 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.
 
AK684GENERATE_JOIN_INFO
 
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.
 
AK684JOIN_COLUMNS_STACK
 
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 AK684JOIN_COLUMNS_STACK. The order is irrelevant
as regards the call with NOT in_key, 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, SAPDB_PascalForcedFill 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).
 
AK684OUTPUT_COLUMNS_STACK
 
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 AK684OUTPUT_COLUMNS_STACK, 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.
 
AK684QUALIFICATION_STACK
 
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.
 
AK684WRITE_STRAT_INFO
 
The Mess-Buffer contained in AK684QUALIFICATION_STACK 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 (* ak684join_columns_stack *);
 
 
(*------------------------------*) 
 
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, _j, _k       : tsp00_Int2;
      _st_pos          : tsp00_Int2;
      _and_cnt         : tsp00_Int2;
      _last_st_pos     : tsp00_Int2;
      _field_nos       : SET OF 1..MAX_COL_PER_TAB_GG00;
      _handled         : boolean;
 
BEGIN
(* add NOT NULL qualification for <i.th tab> = <i+x.th tab> *)
(* because such NULL values can't satisfy join condition    *)
IF  add_and_op
THEN
    _and_cnt := 0
ELSE
    _and_cnt := -1;
(*ENDIF*) 
_field_nos := [];
_last_st_pos := acv.a_mblock.mb_qual^.mfirst_free;
FOR _i := 0 TO (dmli.d_joins.jrc_cnt - 1) DO
    BEGIN
    (* loop through join array *)
    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
            BEGIN
            FOR _j := 1 TO 2 DO
                BEGIN
                CASE _j OF
                    1 :
                        _k := 2;
                    2 :
                        _k := 1;
                    END;
                (*ENDCASE*) 
                _handled :=
                      (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].
                      jop_fieldno in _field_nos) AND
                      (* ??? superfluous with next condition ??? *)
                      (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].
                      jop_cntstack = 1);
&               ifdef trace
                t01bool (ak_join, '_handled ?  ', _handled);
&               endif
                IF  (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].
                    jop_tableno = jinfos.ji_acttabno)
                    (* <i.th tab> = <???> *)
                    AND
                    (NOT dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].
                    jop_outer_join)
                    AND
                    (NOT _handled)
                    AND
                    (NOT (jtkey in dmli.d_joins.jrc_joinarr[ _i ].
                    jo_recs[ _j ].jop_propset))
                    (* NOT NULL for keys guaranteed *)
                    AND
                    (NOT (jtfirstkey in dmli.d_joins.jrc_joinarr[ _i ].
                    jo_recs[ _j ].jop_propset))
                    (* NOT NULL for keys guaranteed *)
                    AND
                    (NOT (jtonlykey in dmli.d_joins.jrc_joinarr[ _i ].
                    jo_recs[ _j ].jop_propset))
                    (* NOT NULL for keys guaranteed *)
                    AND
                    (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].
                    jop_cntstack = 1)
                    (* don't allow expression *)
                    AND
                    (NOT (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].
                    jop_tableno in jinfos.ji_nxtjinfo.nj_left_side))
                    (* NOT  <i.th tab> = <i-x.th tab> *)
                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*) 
                    ;
                    (* mark last stack entry *)
                    _st_pos := acv.a_mblock.mb_qual^.mfirst_free;
                    IF  (jinfos.ji_st_addr^[ dmli.d_joins.jrc_joinarr[ _i ].
                        jo_recs[ _j ].jop_startstack ].eop = op_join_key)
                    THEN
                        BEGIN
                        (* column marked by ak684one_join_column()      *)
                        (* for <i.th tab> = <i+x.th tab>                *)
                        (* REMARK:                                      *)
                        (* code from ak684one_join_column():            *)
                        (* jinfos.ji_st_addr^[ dmli.d_joins.            *)
                        (* jrc_joinarr[ currj ].jo_recs[ partj ].       *)
                        (* jop_startstack ].ecol_tab[ 1 ] :=            *)
                        (* chr (acv.a_mblock.mb_qual^.mfirst_free - 1); *)
                        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free ] :=
                              acv.a_mblock.mb_st^[
                              ord (jinfos.ji_st_addr^[ dmli.d_joins.
                              jrc_joinarr[ _i ].jo_recs[ _j ].
                              jop_startstack ].ecol_tab[ 1 ]) - 1 ];
                        (* copy join column from new messblock because  *)
                        (* original stack entry was changed to st_fixcol*)
                        END
                    ELSE
                        (* a685pack_record() called ?? *)
                        BEGIN
                        (* get column from original messblock *)
                        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 ];
                        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*) 
                    acv.a_mblock.mb_st^[ _st_pos ].eop := op_none;
                    IF  _st_pos = acv.a_mblock.mb_qual^.mfirst_free
                    THEN
                        BEGIN
                        (* copied from new messblock *)
                        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*) 
                    WITH acv.a_mblock.mb_st^
                         [ acv.a_mblock.mb_qual^.mfirst_free ] DO
                        BEGIN
                        etype         := st_value;
                        eop           := op_not_null;
                        (* a680search_sequence() asures NULL value at mb_data_len *)
                        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*) 
            END;
        (*ENDIF*) 
        END
    ELSE
        (* no matter if we deliver NULL values with fieldwise comparison *)
    (*ENDIF*) 
    END;
(*ENDFOR*) 
IF  ( acv.a_returncode = 0 )
THEN
    BEGIN
    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*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684join_columns_stack (
            VAR acv             : tak_all_command_glob;
            VAR dmli            : tak_dml_info;
            VAR jinfos          : tak68_joininfos;
            VAR series          : tak68_sequence;
            cols_for_next_join  : boolean;
            is_outertab         : boolean);
 
VAR
      _needed_from_base : boolean; (* needed from base for i.th join *)
      _i                : tsp00_Int2;
      _jarr_side        : tsp00_Int2; (* side with act. tabno, i.e. act. destination*)
      _jarr_oside       : tsp00_Int2;
      _kb_side          : tsp00_Int2;
      _jk_field_cnt     : tsp00_Int2;
      _further_cols     : boolean;
      _needed_value     : boolean;
&     ifdef trace
      _colstack         : boolean;
&     endif
 
BEGIN
(* if     cols_for_next_join --> jinfos.ji_outpos = cgg_rec_key_offset + 1   *)
(* if NOT cols_for_next_join --> jinfos.ji_outpos = jinfos.ji_outpos -       *)
(* (cgg_rec_key_offset + 1) + RESCNT_MXGG04                                    *)
(**)
(* cols_for_next_join:                                  *)
(* prepare stack for actually join, these columns       *)
(* build key columns of <i.th tab> record               *)
(* actually join is <i-1.th temp result> with <i.th tab>*)
(**)
(* NOT cols_for_next_join:                              *)
(* prepare stack for further joins, these columns       *)
(* are non key of <i.th tab> record                     *)
IF  (series[ jinfos.ji_act_join ].jos_joinstrat in
    [ strat_join_all_keys_equal, strat_join_key_range,
    strat_join_all_inv_equal, strat_join_inv_range ])
THEN
    _jk_field_cnt := series[ jinfos.ji_act_join ].jos_fieldcnt
ELSE
    (* strat_join_key_equal, strat_join_key_next,   *)
    (* strat_join_viewkey, strat_join_inv           *)
    (* no join transition                           *)
    _jk_field_cnt := 0;
(*ENDIF*) 
&IFDEF TRACE
t01p2int4 (ak_join, 'JOIN STEP   ', jinfos.ji_act_join,
      'i.th tab    ', jinfos.ji_acttabno);
t01bool (ak_join, 'build key   ', cols_for_next_join);
t01int4 (ak_join, 'next tabno  ', jinfos.ji_nxtjinfo.nj_nxttabno);
t01int4 (ak_join, 'join fields ', _jk_field_cnt);
t01int4 (ak_join, 'jrc_cnt     ', dmli.d_joins.jrc_cnt );
_colstack := false;
&ENDIF
FOR _i := 0 TO dmli.d_joins.jrc_cnt - 1 DO
    BEGIN
    _jarr_side := 1;
    (* look in left and right join side *)
    REPEAT
        _needed_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)
              (* !!allow constant expression!!
              AND
              (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ 2 ].jop_cntstack = 1)
              *)
              AND
              (dmli.d_joins.jrc_joinarr[ _i ].jo_op = op_eq)
              AND
              (
              ((jinfos.ji_act_join = 1) AND cols_for_next_join)
              (* needed in 1. join step for key building *)
              (* <1st tab> = <value> *)
              OR
              ((jinfos.ji_act_join > 1) AND (NOT cols_for_next_join))
              (* needed for next join steps for later usage *)
              (* <i+1.th tab> = <value> for i>=2 *)
              );
&       ifdef trace
        t01int4 (ak_join, '_i          ', _i );
        t01bool (ak_join, 'needed value', _needed_value);
        a683_one_join_entry_ex( ak_join, dmli, _i, false );
&       endif
        IF  (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _jarr_side ].jop_tableno =
            jinfos.ji_acttabno)
            (* <i.th tab> = <???> *)
            OR
            _needed_value
            (* <i+1.th tab> = <value> *)
        THEN
            BEGIN
            CASE _jarr_side OF
                1 :
                    _jarr_oside := 2;
                2 :
                    _jarr_oside := 1;
                END;
            (*ENDCASE*) 
            _needed_from_base :=
                  (* columns for join access with actual table found *)
                  (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _jarr_oside ].jop_tableno IN
                  jinfos.ji_nxtjinfo.nj_left_side)
                  (* we need this columns for actual join *)
                  (* <i.th tab> = <i-x.th tab> *)
                  OR
                  ((dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _jarr_oside ].jop_tableno =
                  jinfos.ji_nxtjinfo.nj_nxttabno) AND ( jinfos.ji_act_join = 1))
                  (* special cases for 1. join step *)
                  (* <1st tab> = <2nd tab> *)
                  OR
                  (_needed_value AND (jinfos.ji_act_join = 1)
                  (* <2nd tab> = <value> *));
            IF  ((
                (* needed columns for next join transition *)
                cols_for_next_join AND
                (
                _needed_from_base
                (* cols_for_next_join and                                           *)
                (* ( <i.th tab> = <i-x.th tab> or <1st tab> = <2nd tab> *)
                (* or <2nd tab> = <value> )                             *)
                OR
                ((dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ 2 ].jop_tableno =
                cak68_join_value) AND
                (dmli.d_joins.jrc_joinarr[ _i ].jo_op = op_eq))
                (* cols_for_next_join and                               *)
                (* ( <i.th tab> = <value> or <i+1.th tab> = <value> )   *)
                (* remember: we need this column from <i.th tab> because*)
                (* <value> exits in <i-1.th temp result> as constant column *)
                (* and we use <value> as join transition                *)
                )
                )
                OR
                (* need other columns for later usage *)
                (
                (NOT cols_for_next_join) AND
                (NOT _needed_from_base (* i.e. needed from base for later join steps *)
                )
                (* non key and ( <i.th tab> = <i+x.th tab> ) for i >= 2 *)
                ))
            THEN
                BEGIN
&               ifdef trace
                IF  ( _needed_from_base )
                THEN
                    t01name(ak_join, 'col for i. join   ')
                ELSE
                    t01name(ak_join, 'col for i+x. join ');
                (*ENDIF*) 
                t01sname( ak_join, 'found       ' );
                t01bool (ak_join, 'needed value', _needed_value);
                a683_one_join_entry_ex( ak_join, dmli, _i, false );
                _colstack := true;
&               endif
                IF  (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _jarr_oside ].jop_tableno IN
                    jinfos.ji_nxtjinfo.nj_left_side)
                THEN
                    (* <i.th tab> = <i-x.th tab> *)
                    _kb_side := 2
                ELSE
                    _kb_side := 1;
                (*ENDIF*) 
                IF  _needed_value
                THEN
                    BEGIN
                    _jarr_side   := 2; (* jo_recs site with cak68_join_value *)
                    _kb_side := 1; (* part for temporary result *)
                    END;
                (*ENDIF*) 
                ;
                (* multiple join columns *)
                _further_cols := (_jk_field_cnt > 0);
                (* create stack entry for base table access *)
                ak684one_join_column (acv, dmli, jinfos,
                      cols_for_next_join, is_outertab, _i,
                      _further_cols, _jarr_side, _kb_side);
                _jk_field_cnt := pred (_jk_field_cnt);
                _jarr_side := 3;  (* loop to next join array index *)
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        _jarr_side := succ (_jarr_side);
    UNTIL
        (_jarr_side > 2);
    (*ENDREPEAT*) 
    END;
(*ENDFOR*) 
&ifdef trace
IF  (_colstack)
THEN
    BEGIN
    t01stackdesc (ak_join, 'orig mblock ', jinfos.ji_st_addr,
          jinfos.ji_stack_desc);
    t01stackdesc (ak_join, 'i.th mblock ', acv.a_mblock.mb_st,
          acv.a_mblock.mb_qual^.mstack_desc);
    END
ELSE
    t01name(ak_join, 'no needed cols fnd');
(*ENDIF*) 
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684one_join_column (
            VAR acv             : tak_all_command_glob;
            VAR dmli            : tak_dml_info;
            VAR jinfos          : tak68_joininfos;
            cols_for_next_join  : boolean;
            is_outertab         : boolean;
            currj               : tsp00_Int4;
            further_cols        : boolean;
            jarr_side           : tsp00_Int4;
            kb_side             : tsp00_Int4);
 
VAR
      _i            : tsp00_Int2;
      _jarr_oside   : tsp00_Int2;
      _jcol_pos     : tsp00_Int2;
      _dstpos       : tsp00_Int2;
 
BEGIN
(* precondition for this function call:                                     *)
(* key handling and                                                         *)
(* ( <i.th tab> = <i-x.th tab> or <1st tab> = <2nd tab> or <2nd tab> = <value> ) *)
(* or                                                                       *)
(* key handling and ( <i.th tab> = <value> or <i+1.th tab> = <value> )      *)
(* or                                                                       *)
(* non key handling and ( <i.th tab> = <i+x.th tab> ) for i >= 2            *)
(*                                                                          *)
(* for constant local join predicate (cak68_join_value) jarr_side = 2 !!    *)
(* otherwise jarr_side is side with ji_acttabno (i.th tab = ...)            *)
(* i.e.                                                                     *)
(* dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ jarr_side ].jop_tableno =     *)
(* <i.th tab>                                                               *)
(* or                                                                       *)
(* dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ jarr_side = 2 ].jop_tableno = *)
(* <value>                                                                  *)
&ifdef trace
t01p2int4 (ak_join, 'JOIN STEP   ', jinfos.ji_act_join,
      'i.th tab    ', jinfos.ji_acttabno);
&endif
IF  acv.a_mblock.mb_qual^.mfirst_free +
    dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ jarr_side ].jop_cntstack
    > acv.a_mblock.mb_st_max
THEN
    a07_b_put_error (acv, e_too_many_mb_stackentries, 1)
ELSE
    BEGIN
    _dstpos := (acv.a_mblock.mb_qual^.mfirst_free - 1);
    (* move join condition from original messbuf *)
    SAPDB_PascalMove ('VAK684',   1,    
          (jinfos.ji_stack_desc.mst_max * STACK_ENTRY_MXGG00),
          acv.a_mblock.mb_st_size,
          (* source *)
          @jinfos.ji_st_addr^,
          (* source pos *)
          (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ jarr_side ].
          jop_startstack - 1) * STACK_ENTRY_MXGG00 + 1,
          @acv.a_mblock.mb_st^, _dstpos * STACK_ENTRY_MXGG00 + 1,
          (* count *)
          dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ jarr_side ].jop_cntstack *
          STACK_ENTRY_MXGG00,
          acv.a_returncode);
&   ifdef trace
    t01bool (ak_join, 'further cols', further_cols);
    t01p2int4 (ak_join, 'jarr_side   ', jarr_side,
          'kb_side     ', kb_side);
    t01name(ak_join, 'orig jcol-> new mb');
    FOR _i := 0 TO dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ jarr_side ].
          jop_cntstack - 1 DO
        BEGIN
        t01stackentry (ak_join,
              jinfos.ji_st_addr^[ dmli.d_joins.jrc_joinarr[ currj ].
              jo_recs[ jarr_side ].jop_startstack + _i ],
              dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ jarr_side ].jop_startstack + _i);
        END;
    (*ENDFOR*) 
&   endif
    (* mark new join column stack entry *)
    _jcol_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[ jarr_side ].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[ jarr_side ].jop_cntstack + 1;
    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 *)
        BEGIN
        acv.a_mblock.
              mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 2 ].eop :=  op_none;
        IF  (acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 2 ].
            etype = st_op )
        THEN
            BEGIN
            (* detect stackcode like:
                  [x  ]   VALUE
                  [x+1]   VALUE
                  [   ]   +
                  [x+2]   =
                  *)
            acv.a_mblock.
                  mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 2 ].etype :=  st_dummy;
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    ;
    (* write on st_output stack entry *)
    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 ].
          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[ jarr_side ].
          jop_inoutlen;
    jinfos.ji_outpos := jinfos.ji_outpos + dmli.d_joins.jrc_joinarr[ currj ].
          jo_recs[ jarr_side ].jop_inoutlen;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
          eop_out := op_o_none;
    IF  NOT cols_for_next_join
    THEN
        BEGIN
        (* write into st_output stack entry of ith. messblock *)
        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[ jarr_side ].jop_inoutlen;
&       ifdef trace
        t01stackentry (ak_join, acv.a_mblock.
              mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ],
              acv.a_mblock.mb_qual^.mfirst_free - 1);
&       endif
        IF  dmli.d_inoutpos > MAX_RECLEN_GG00 + 1
        THEN
            a07_b_put_error (acv, e_join_fields_too_long, 1)
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        (* write into st_output stack entry of ith. messblock *)
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
              ecol_pos := 0;
&       ifdef trace
        t01stackentry (ak_join, acv.a_mblock.
              mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ],
              acv.a_mblock.mb_qual^.mfirst_free - 1);
&       endif
        IF  (jinfos.ji_act_join > 1)
        THEN
            (* update kbjrec, i.e. collect join infos for KB handling *)
            ak684update_kbjoininfo(dmli, jinfos,
                  currj, further_cols, jarr_side, kb_side);
        (*ENDIF*) 
        END;
    (*ENDIF*) 
&   ifdef trace
    t01int4 (ak_join, 'd_inoutpos  ', dmli.d_inoutpos );
    t01p2int4 (ak_join, 'ji_outpos   ', jinfos.ji_outpos,
          'jop_inoutlen', dmli.d_joins.jrc_joinarr[ currj ].
          jo_recs[ jarr_side ].jop_inoutlen);
&   endif
    IF  (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ jarr_side ].jop_tableno =
        cak68_join_value)
        AND
        (jinfos.ji_act_join > 1) AND (jinfos.ji_act_join < dmli.d_cntfromtab)
        (* <i.th tab> = <value> or <i+1.th tab> = <value> for i>=2 *)
    THEN
        BEGIN
        (* mark for copying to from i.th messblock to <i.th temp result> *)
&       ifdef trace
        t01Int4(ak_join, 'mark on i.th mbloc', acv.a_mblock.mb_qual^.mfirst_free - 1);
&       endif
        a685set_output_join (acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ],
              (* calculate position in <i.th temp result> record *)
              a685evaluate_new_ecol_pos (dmli, jinfos,
              dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ jarr_side ].jop_startstack,
              acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
              elen_var));
        IF  ( jinfos.ji_acttabno in dmli.d_oj_tables (* is table with (+)*)
            ) AND
            ( NOT ( jinfos.ji_use_operator_join = jopu_none ))
        THEN
            BEGIN
            (* write output filter if constant expression in part of *)
            (* table which is filled with NULL values (OUTER JOIN)   *)
            (* so that constant expression survive OUTER JOIN        *)
            jinfos.ji_set_output_filter := true;
            END;
        (*ENDIF*) 
        END
    ELSE
        (* key handling and                                         *)
        (* ( <i.th tab> = <i-x.th tab> or <1st tab> = <2nd tab> or  *)
        (* <1st tab> = <value> or <2nd tab> = <value> )             *)
        (* or *)
        (* non key handling and ( <i.th tab> = <i+x.th tab> ) for i >= 2 *)
        BEGIN
        _i       := 0; (* search through whole output columns *)
&       IFDEF TRACE
        a683joinset_trace (ak_join, 'left side   ', dmli, jinfos.ji_nxtjinfo.nj_left_side);
        t01int4 (ak_join, 'i.th tableno', dmli.d_joins.jrc_joinarr[ currj ].
              jo_recs[ jarr_side ].jop_tableno);
        t01bool (ak_join, 'is_outertab ', is_outertab);
        t01int4 (ak_join, 'stackcnt    ', dmli.d_joins.jrc_joinarr[ currj ].
              jo_recs[jarr_side].jop_cntstack);
        t01bool (ak_join, 'elen_var    ', (acv.a_mblock.mb_st^[ _jcol_pos  ].elen_var =
              acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].elen_var));
&       ENDIF
        IF  (jinfos.ji_act_join < dmli.d_cntfromtab)
            AND
            (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ jarr_side ].
            jop_cntstack = 1)
            AND
            (NOT is_outertab)
            AND
            (* bar all columns which output representation could be changed *)
            ((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[ jarr_side ].
            jop_datatyp in [ dcha, dvarchara ])))
            AND
            (NOT (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ jarr_side ].
            jop_datatyp in [ ddate, dtime, dtimestamp ]))
            AND
            (* we have to convert LIKE pattern into internal representation *)
            (* therefore we can't subsumize output column and join column   *)
            ( NOT ( dmli.d_joins.jrc_joinarr[ currj ].jo_op = op_like ))
            AND
            (* if column has same length as output column                  *)
            (* UNION of char(5) with char(10) therfore output lenght is 10 *)
            (acv.a_mblock.mb_st^[ _jcol_pos  ].elen_var =
            acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].elen_var)
            AND
            a685stentry_found_in_outplist (jinfos, _i, acv.a_mblock.mb_st^[ _jcol_pos ])
        THEN
            a685pack_record (acv, _jcol_pos, dmli, jinfos, _i)
        ELSE
            BEGIN
            CASE jarr_side OF
                1 :
                    _jarr_oside := 2;
                2 :
                    _jarr_oside := 1;
                END;
            (*ENDCASE*) 
            IF  ((NOT(dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ _jarr_oside ].jop_tableno
                in jinfos.ji_nxtjinfo.nj_left_side))
                (* NOT (<i.th tab> = <i-x.th tab>)                      *)
                (* remark: for 1. join step nj_left_side = [ <1st tab> ]*)
                AND
                (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ _jarr_oside ].jop_tableno <>
                cak68_join_value)
                (* NOT (<1st or 2nd tab> = <value>) *)
                AND
                (
                ((dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ _jarr_oside ].
                jop_tableno <> jinfos.ji_nxtjinfo.nj_nxttabno) AND
                (jinfos.ji_act_join = 1))
                (* NOT (<1st tab>  = <2nd tab>) *)
                OR (jinfos.ji_act_join > 1))
                (* <i.th tab> = <i+x.th tab> for i>=2 *)
                )
            THEN
                BEGIN
                (* remaining conditions: *)
                (* key handling and ( <i.th tab> = <value> or   *)
                (* <i+1.th tab> = <value> )                     *)
                (* or                                           *)
                (* non key handling and                         *)
                (* ( <i.th tab> = <i+x.th tab> ) for i >= 2     *)
                jinfos.ji_nxtjinfo.nj_joincols_to_be_shifted :=
                      succ (jinfos.ji_nxtjinfo.nj_joincols_to_be_shifted);
&               ifdef trace
                t01name( ak_join, 'mark as tab for   ' );
                t01name( ak_join, 'i+x.th join       ' );
                t01int4 (ak_join, 'not_copied_k', jinfos.ji_nxtjinfo.nj_joincols_to_be_shifted);
&               endif
                (* update/mark original stack entries for           *)
                (* a685join_columns_shift() and a685join_columns_last_shift()   *)
                jinfos.ji_st_addr^[ dmli.d_joins.jrc_joinarr[ currj ].
                      jo_recs[ jarr_side ].jop_startstack ].etype := st_fixcol;
                jinfos.ji_st_addr^[ dmli.d_joins.jrc_joinarr[ currj ].
                      jo_recs[ jarr_side ].jop_startstack ].eop   := op_join_key;
                (* save column position  from <i.th tab> *)
                (* into original messblock               *)
                jinfos.ji_st_addr^[ dmli.d_joins.jrc_joinarr[ currj ].
                      jo_recs[ jarr_side ].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[ jarr_side ].jop_startstack ].elen_var :=
                      acv.a_mblock.mb_st^
                      [ acv.a_mblock.mb_qual^.mfirst_free - 1 ].elen_var;
                (* save output column stack entry position *)
                (* in original messblock in ecol_tab[ 1 ]  *)
                jinfos.ji_st_addr^[ dmli.d_joins.jrc_joinarr[ currj ].
                      jo_recs[ jarr_side ].jop_startstack ].ecol_tab[ 1 ] :=
                      chr (acv.a_mblock.mb_qual^.mfirst_free - 1);
                jinfos.ji_st_addr^[ dmli.d_joins.jrc_joinarr[ currj ].
                      jo_recs[ jarr_side ].jop_startstack ].ecol_tab[ 2 ] :=
                      chr (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ jarr_side ].
                      jop_tableno);
                IF  ( acv.a_mblock.mb_qual^.mfirst_free - 1 > MAX_UINT1_SP00 )
                THEN
                    a07ak_system_error( acv, 684, 3 );
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684write_strat_info (
            VAR acv                 : tak_all_command_glob;
            VAR dmli                : tak_dml_info;
            VAR jinfos              : tak68_joininfos;
            VAR colcopy_inf         : tgg07_JoinColCopyInfo;
            VAR res_tree            : tgg00_FileId;
            VAR joinp               : tak_sysbufferaddress;
            VAR series              : tak68_sequence;
            VAR ak_strat_interface  : tak71_strat_rec;
            get_new_strat           : boolean);
 
VAR
      _strat_len            : tsp00_Int2;
      _strat_pos            : tsp00_Int2;
      _strat_num            : tsp00_Int2;
      _i                    : tsp00_Int2;
      _movelen              : tsp00_Int2;
      _expl                 : tak71_explain_rec;
      _result_inf           : tgg07_JoinResInfo;
      _bw                   : tak71_page_eval_rec;
      _onetab_strat         : tgg07_StrategyInfo;
      _gg_strategy          : tgg07_StrategyInfo;
      _page_eval_info       : tak71_page_eval_rec;
      _config               : tak00_access_configuration;
      _StratInfo_len        : tsp00_Int2;
      _onetab_StratInfo_len : tsp00_Int2;
 
      _str            : RECORD
            CASE boolean OF
                true  :
                    (strat_char : tsp00_C1);
                false :
                    (strat_enum : tgg07_StratEnum);
                END;
            (*ENDCASE*) 
 
 
BEGIN
&ifdef trace
t01p2int4 (ak_join, 'JOIN STEP   ', jinfos.ji_act_join,
      'i.th tab    ', jinfos.ji_acttabno);
&endif
IF  ( get_new_strat )
THEN
    (* we need new strategy information because of  *)
    (* the stack code wasn't updated for index only *)
    BEGIN
    _StratInfo_len   := 0;
    IF  NOT ( series[ jinfos.ji_act_join ].jos_joinstrat in a70glob_join_strats )
    THEN
        dmli.d_index_strat_poss := ind_init
    ELSE
        dmli.d_index_strat_poss := ind_no_inv;
    (*ENDIF*) 
    a71default_strat( _gg_strategy );
    _gg_strategy.str_ordering  := ( dmli.d_distinct <> no_distinct );
    _gg_strategy.str_rec_len   := jinfos.ji_outpos - 1;
    _gg_strategy.str_all_files := ( acv.a_recursive_state = rs_last_select );
    _gg_strategy.str_strategy  := strat_undecided;
    IF  dmli.d_acttabindex <> jinfos.ji_acttabno
    THEN
        a61_rel_old_table (acv, dmli, jinfos.ji_acttabno);
    (*ENDIF*) 
    a80get_access_for_join_hint( acv, jinfos.ji_parskey,
          jinfos.ji_acttabno, _config );
    IF  ( jinfos.ji_use_operator_join in [ jopu_op_legacy, jopu_op_improved ] )
    THEN
        BEGIN
        _gg_strategy.str_build_result := false;
        _config.cfg_switches := _config.cfg_switches - [ cs_build_result ];
        _config.cfg_switches := _config.cfg_switches + [ cs_operator_join ];
        a70strategy( acv, dmli, _gg_strategy, _StratInfo_len,
              _page_eval_info, _config );
        END
    ELSE
        a70strategy( acv, dmli, _gg_strategy, _StratInfo_len,
              _page_eval_info, _config );
    (*ENDIF*) 
    ;
    g09StratStackentry( acv.a_mblock.mb_qual^.
          mst_addr^[ acv.a_mblock.mb_qual^.mstrat_pos ], 1, _StratInfo_len);
    _movelen := _StratInfo_len;
    IF  ( _gg_strategy.str_strategy = strat_more_than_one )
    THEN
        (* strat_more_than_one *)
        _movelen := STRATEGY_START_MXGG07;
    (*ENDIF*) 
    ;
    (* for strat_more_than_one data was written into strat part *)
    (* but mb_strat_len isn't up to date                        *)
    ;
    _onetab_strat         := _gg_strategy;
    _onetab_StratInfo_len := _StratInfo_len;
    END
ELSE
    BEGIN
    (* get strategy length from seperated messblock (ak680prepare_join())*)
    _StratInfo_len := joinp^.smessblock.mbr_mess_block.
          mb_st^[ joinp^.smessblock.mbr_mess_block.mb_qual^.mstrat_pos ].
          elen_var;
    _movelen := _StratInfo_len;
    IF  ( _movelen > sizeof (_gg_strategy) )
    THEN
        (* strat_more_than_one but no sufficient condition *)
        _movelen := STRATEGY_START_MXGG07;
    (*ENDIF*) 
    ;
&   ifdef trace
    t01int4 (ak_join, '_StratInfo_l', _StratInfo_len );
    t01int4 (ak_join, '_movelen    ', _movelen );
&   endif
    ;
    (* get strategy from seperated messblock *)
    SAPDB_PascalMove ('VAK684',   2,    
          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_returncode);
    ;
    (* remember 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);
    IF  ( _gg_strategy.str_strategy = strat_more_than_one )
    THEN
        BEGIN (* PTS 1122378 *)
        _strat_num := 1;
        _strat_pos := 1 + STRATEGY_START_MXGG07;
&       ifdef trace
        SAPDB_PascalMove ('VAK684',   3,    
              sizeof(_gg_strategy), sizeof(_onetab_strat),
              @_gg_strategy, 1, @_onetab_strat, 1,
              STRATEGY_START_MXGG07, acv.a_returncode);
&       endif
        WHILE ( _strat_num <= _gg_strategy.str_cnt_strat )  DO
            BEGIN
            _str.strat_char[ 1 ] := joinp^.smessblock.mbr_mess_block.mb_strat^[ _strat_pos ];
            _strat_len           :=
                  s20or4b( joinp^.smessblock.mbr_mess_block.mb_strat^,
                  _strat_pos + 4 );
            SAPDB_PascalMove ('VAK684',   4,    
                  joinp^.smessblock.mbr_mess_block.mb_strat_size,
                  sizeof( _onetab_strat ),
                  @joinp^.smessblock.mbr_mess_block.mb_strat^,
                  _strat_pos + cgg07_stratpos_offs,
                  @_onetab_strat, STRATEGY_START_MXGG07 + 1,
                  _strat_len, acv.a_returncode);
            _onetab_strat.str_strategy          := _str.strat_enum;
            _onetab_strat.str_stack_output_offs := _gg_strategy.str_stack_output_offs;
            a684update_strategy( _onetab_strat );
            SAPDB_PascalMove ('VAK684',   5,    
                  sizeof(_onetab_strat),
                  joinp^.smessblock.mbr_mess_block.mb_strat_size,
                  @_onetab_strat, STRATEGY_START_MXGG07 + 1,
                  @joinp^.smessblock.mbr_mess_block.mb_strat^,
                  _strat_pos + cgg07_stratpos_offs,
                  _strat_len, acv.a_returncode);
            _strat_num := succ(_strat_num);
            _strat_pos := _strat_pos + _strat_len + cgg07_stratpos_offs;
            END;
        (*ENDWHILE*) 
        END
    ELSE
        a684update_strategy( _gg_strategy );
    (*ENDIF*) 
    _onetab_strat         := _gg_strategy;
    _onetab_StratInfo_len := _StratInfo_len;
    END;
(*ENDIF*) 
;
(* PTS 1127791 M.Ki. *)
(* check if strategy and table sizes of this and previous table would *)
(* allow hashing of table                                             *)
IF  a01use_join_hashtable
    AND (jinfos.ji_act_join > 1)
    AND
    (series[ jinfos.ji_act_join ].jos_joinstrat in a70glob_join_key_strats)
    AND
    (NOT jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_right_oj)
    AND
    (series[ jinfos.ji_act_join ].jos_expected_table_rec_reads <
    (a101_GetMaxJoinHashTableSize / _gg_strategy.str_rec_len))
    AND
    (series[ jinfos.ji_act_join ].jos_expected_table_rec_reads <> 0)
    AND
    (series[ jinfos.ji_act_join-1 ].jos_expected_table_rec_reads
    / (series[ jinfos.ji_act_join ].jos_expected_table_rec_reads)
    > a01join_hash_min_ratio)
    AND
    ( NOT ( jinfos.ji_use_operator_join = jopu_none ))
    AND
    NOT ( strmod_sorted in series[ jinfos.ji_act_join ].jos_access_mod )
THEN
    BEGIN
&   ifdef trace
    t01name(ak_join, 'hash join enabled ');
    t01int4 (ak_join, 'exp size    ',
          series[ jinfos.ji_act_join ].jos_expected_table_rec_reads
          * _gg_strategy.str_rec_len);
&   endif
    series[ jinfos.ji_act_join ].jos_access_mod :=
          series[ jinfos.ji_act_join ].jos_access_mod + [ strmod_hash ];
    END;
(*ENDIF*) 
IF  ( series[ jinfos.ji_act_join ].jos_parallel_server > 0 )
    AND
    (series[ jinfos.ji_act_join ].jos_joinstrat in
    [ strat_join_inv, strat_join_all_inv_equal ])
    AND
    (series[ jinfos.ji_act_join ].jos_expected_table_rec_reads
    > a01join_parall_minsize)
THEN
    BEGIN
&   ifdef trace
    t01name(ak_join, 'parallel inv acc. ');
&   endif
    series[ jinfos.ji_act_join ].jos_access_mod :=
          series[ jinfos.ji_act_join ].jos_access_mod + [ strmod_parallel ];
    END;
(*ENDIF*) 
;
IF  ( acv.a_returncode = 0 )
THEN
    BEGIN
    _gg_strategy.str_access_mod :=
          series[ jinfos.ji_act_join ].jos_access_mod; (* PTS 1127791 M.Ki. *)
    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, _StratInfo_len );
        END;
    (*ENDIF*) 
    IF  ( acv.a_mblock.mb_qual^.msubquery )
    THEN
        _gg_strategy.str_rowno := cgg04_at_least_one_record;
    (*ENDIF*) 
    ;
    (* PTS 1112079 E.Z. *)
    _gg_strategy.str_search_first := true;
    IF  ( dmli.d_view )
    THEN
        BEGIN
        _gg_strategy.str_access_mod := [];
        _gg_strategy.str_cnt_strat  := 1;
        IF  ( jinfos.ji_act_join = 1 )
        THEN
            _gg_strategy.str_strategy := strat_viewkey
        ELSE
            _gg_strategy.str_strategy := strat_join_viewkey;
        (*ENDIF*) 
        _StratInfo_len := STRATEGY_START_MXGG07 +
              sizeof(_gg_strategy.str_key_in_range);
        END
    ELSE
        BEGIN
        IF  ( series[ jinfos.ji_act_join ].jos_joinstrat in a70glob_join_strats )
        THEN
            (* we have a join strategy *)
            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
                    _StratInfo_len := STRATEGY_START_MXGG07 +
                          sizeof(_gg_strategy.str_join_multfields);
                    _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;
                    _gg_strategy.str_join_multfields.sjmf_cntfields := 1;
                    _gg_strategy.str_join_multfields.sjmf_invlen    :=
                          a684get_used_invlen( acv,
                          dmli.d_tabarr[ series[ jinfos.ji_act_join ].jos_source ].
                          otreeid.fileTabId_gg00,
                          series[ jinfos.ji_act_join ].jos_indexno,
                          series[ jinfos.ji_act_join ].jos_fieldcnt );
                    series[ jinfos.ji_act_join ].jos_invlen :=
                          _gg_strategy.str_join_multfields.sjmf_invlen;
                    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;
                    _gg_strategy.str_join_multfields.sjmf_invlen    :=
                          a684get_used_invlen( acv,
                          dmli.d_tabarr[ series[ jinfos.ji_act_join ].jos_source ].
                          otreeid.fileTabId_gg00,
                          series[ jinfos.ji_act_join ].jos_indexno,
                          series[ jinfos.ji_act_join ].jos_fieldcnt );
                    series[ jinfos.ji_act_join ].jos_invlen :=
                          _gg_strategy.str_join_multfields.sjmf_invlen;
                    _StratInfo_len := STRATEGY_START_MXGG07 +
                          sizeof(_gg_strategy.str_join_multfields);
                    END;
                strat_join_all_keys_equal,
                strat_join_key_range,
                strat_join_key_equal,
                strat_join_key_next :
                    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;
                    _gg_strategy.str_join_multfields.sjmf_invlen    :=
                          IS_UNDEFINED_GG07;
                    _StratInfo_len := STRATEGY_START_MXGG07 +
                          sizeof(_gg_strategy.str_join_multfields);
                    END;
                OTHERWISE
                    BEGIN
                    _StratInfo_len := STRATEGY_START_MXGG07 +
                          sizeof(_gg_strategy.str_join_multfields)
                    END;
                END;
            (*ENDCASE*) 
            END
        ELSE
            BEGIN
            series[ jinfos.ji_act_join ].jos_joinstrat := _gg_strategy.str_strategy;
            END;
        (*ENDIF*) 
        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
        BEGIN
        IF  ( dmli.d_single AND NOT dmli.d_view )
        THEN
            _gg_strategy.str_selinto := true;
        (*ENDIF*) 
        _gg_strategy.str_rowno := dmli.d_rowno;
        END
    ELSE
        _gg_strategy.str_rowno := cgg04_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  (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
        (* last join step *)
        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*) 
    ;
    IF  ( series[ jinfos.ji_act_join ].jos_predefined_buf )
    THEN
        BEGIN
        IF  ( series[ jinfos.ji_act_join ].jos_table_buffer = 0 )
        THEN
            BEGIN
            (* write length of record demanded from table    *)
            (* reminder: length contains cgg_rec_key_offset  *)
            (* we use this offset as failure tolerance       *)
            series[ jinfos.ji_act_join ].jos_table_buffer :=
                  _gg_strategy.str_rec_len;
            END
        ELSE
            ; (* buffer size via hint *)
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        series[ jinfos.ji_act_join ].jos_table_buffer :=
              _gg_strategy.str_rec_len;
        END;
    (*ENDIF*) 
    IF  ( jinfos.ji_act_join > 1 )
    THEN
        BEGIN
        _result_inf.o_tree := jinfos.ji_old_tree;
        (* these length informations will be modified in *)
        (* case of UNION with a503build_union_buffer()   *)
        _result_inf.n_key_len := jinfos.ji_nxtjinfo.nj_nk_len;
        _result_inf.n_rec_len := jinfos.ji_nxtjinfo.nj_r_len;
        IF  ( jinfos.ji_act_join = dmli.d_cntfromtab )
        THEN
            BEGIN
            IF  ( jinfos.ji_stack_desc.mresqual_cnt > 0 )
            THEN
                BEGIN
                (* real output length is greater but we need some columns        *)
                (* for result qualifying, these columns doesn't appear in result *)
&               ifdef trace
                t01sname( ak_join, 'get d_reclen' );
&               endif
                _result_inf.n_res_rec_len := dmli.d_reclen;
                END
            ELSE
                _result_inf.n_res_rec_len := _result_inf.n_rec_len;
            (*ENDIF*) 
            END
        ELSE
            _result_inf.n_res_rec_len := _result_inf.n_rec_len;
        (*ENDIF*) 
        ;
&       ifdef trace
        t01int4 (ak_join, 'nj_r_len    ', jinfos.ji_nxtjinfo.nj_r_len);
        t01int4 (ak_join, 'nj_nk_len   ', jinfos.ji_nxtjinfo.nj_nk_len);
        t01int4 (ak_join, 'n_rec_len kb', _result_inf.n_rec_len);
        t01int4 (ak_join, 'n_res_rec kb', _result_inf.n_res_rec_len);
        t01int4 (ak_join, 'n_key_len kb', _result_inf.n_key_len);
&       endif
        END
    ELSE
        BEGIN
        IF  (( _gg_strategy.str_strategy in a70glob_key_strats ) AND
            ( ksp_exact_match in
            _gg_strategy.str_key_in_range.skir_strat_props ))
            OR
            (( _gg_strategy.str_strategy in a70glob_inv_strats ) AND
            ( isp_exact_match in
            _gg_strategy.str_inv_in_range.siir_strat_props ) AND
            ( isp_unique_idx in
            _gg_strategy.str_inv_in_range.siir_strat_props ))
        THEN
            series[ 1 ].jos_predefined_buf := true;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    jinfos.ji_old_tree := _gg_strategy.str_result_id
    END;
(*ENDIF*) 
IF  ( acv.a_returncode = 0 )
THEN
    BEGIN
    (*                                                         *)
    (* +- 4. strat entry                                       *)
    (* |        +- 1. strat entry                              *)
    (* |        |                   +- 2. strat entry          *)
    (* |        |                   |       +- 3. strat entry  *)
    (* V        V                   V       V                  *)
    (* +--------+----------------------------------+           *)
    (* | one tab| strategy | result | shift | join |           *)
    (* | strat  |   info   |  info  | info  | info |           *)
    (* +--------+----------+--------+-------+------+           *)
    (*                                                         *)
    IF  ( jinfos.ji_act_join > 1 )
    THEN
        BEGIN
        a684move_infos_onetabstrat( acv, _onetab_strat, joinp,
              _onetab_StratInfo_len, get_new_strat );
        END;
    (*ENDIF*) 
    a684move_infos_strategy( acv, _gg_strategy, joinp,
          _StratInfo_len, get_new_strat );
    IF  ( jinfos.ji_act_join > 1 )
    THEN
        BEGIN
        ak684move_infos_result_shift( acv, colcopy_inf, _result_inf );
        ak684move_infos_join( acv, jinfos.ji_nxtjinfo.nj_kbjrec );
        ;
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mstrat_pos ].
              ecol_tab[ 2 ] := chr (jinfos.ji_act_join);
        IF  (( series[ jinfos.ji_act_join ].jos_joinstrat in
            a70glob_join_strats ) AND
            ( jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt = 0 ))
        THEN
            a07ak_system_error( acv, 684, 4 );
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  ( acv.a_returncode = 0 )
THEN
    BEGIN
    IF  ( _gg_strategy.str_strategy in a70glob_inv_strats ) AND
        ( _gg_strategy.str_qual_kind <> inv_only ) AND
        (( jinfos.ji_act_join = 1 ) OR
        ( jinfos.ji_use_operator_join in [ jopu_op_legacy, jopu_op_improved ]) )
    THEN
        a71prepare_qual_on_index( acv, _gg_strategy.str_qual_kind );
    (*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;
        a728_explain (acv, dmli,
              _gg_strategy, NIL,
              joinp^.smessblock.mbr_mess_block.mb_strat^,
              joinp^.smessblock.mbr_mess_block.mb_strat_size, 1);
        IF  (( dmli.d_cntfromtab = jinfos.ji_act_join ) AND
            ( jinfos.ji_use_operator_join in
            [ jopu_op_legacy, jopu_op_improved ]))
        THEN
            BEGIN
            (* add row if new join execution in used *)
            _expl.exp_user         := a01_il_b_identifier;
            _expl.exp_column       := a01_il_b_identifier;
            _expl.exp_table        := a01_il_b_identifier;
            _expl.exp_flags        := [];
            _expl.exp_pagecount    := -1; (* don't display a number *)
            _expl.exp_strat        := '     NO TEMPORARY RESULTS CREATED       ';
            IF  ( NOT acv.a_pars_explain )
            THEN
                a40add_explain_record( acv, _expl );
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684qualification_stack (
            VAR acv      : tak_all_command_glob;
            VAR dmli     : tak_dml_info;
            VAR jinfos   : tak68_joininfos;
            VAR joinp    : tak_sysbufferaddress);
 
VAR
      _jmbp  : tgg00_MessBlockPtr;
      _jqbp  : tgg00_QualBufPtr;
 
BEGIN
&ifdef trace
t01p2int4 (ak_join, 'JOIN STEP   ', jinfos.ji_act_join,
      'i.th tab    ', jinfos.ji_acttabno);
&endif
_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
    (* get qualification from i.th messblock *)
    SAPDB_PascalMove ('VAK684',   6,    
          _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) * STACK_ENTRY_MXGG00 + 1,
          _jqbp^.mqual_cnt * STACK_ENTRY_MXGG00,
          acv.a_returncode);
    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;
    IF  (acv.a_returncode = 0) AND
        (jinfos.ji_act_join < dmli.d_cntfromtab) AND
        (dmli.d_joins.jrc_cnt > 0) AND
        NOT (dmli.d_view AND dmli.d_checkview)
    THEN
        ak684add_not_null_qualification (acv, dmli, jinfos,
              (* add AND op ? *)
              (_jqbp^.mqual_cnt > 0));
    (*ENDIF*) 
    END;
(*ENDIF*) 
&ifdef trace
t01stackdesc (ak_join, 'i.th mblock ', acv.a_mblock.mb_st,
      acv.a_mblock.mb_qual^.mstack_desc);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684generate_join_info (
            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 ak_strat_interface  : tak71_strat_rec;
            VAR jvrec               : tak68_joinview_rec;
            VAR table_stats         : tak68_table_stats);
 
VAR
      _e                  : tgg00_BasisError;
      _m_type             : tgg00_MessType;
      _m2_type            : tgg00_MessType2;
      _stree              : tgg00_FileId;
      _colcopy_inf        : tgg07_JoinColCopyInfo;
      _ke                 : tgg00_SysInfoKey;
      _joinp              : tak_sysbufferaddress;
      _aux_addr           : tgg00_StackListPtr;
      _i                  : tsp00_Int2;
      _ix                 : tsp00_Int4;
      _istop              : tsp00_Int4;
      _stack_pos          : tsp00_Int4;
      _op_outer           : boolean;
      _const_expr_fnd     : boolean;
      _column_fnd         : boolean;
      _gg_strategy        : tgg07_StrategyInfo;
 
BEGIN
_op_outer          := 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*) 
IF  ( dmli.d_view )
THEN
    (* delete from <tab> create new root entry                   *)
    (* therefor a59check_join_view() fails because of wrog  root *)
    _stree.fileRoot_gg00 := NIL_PAGE_NO_GG00;
(*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;
a684set_filehandling( acv, dmli );
;
(* 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_set_output_filter := false;
jinfos.ji_outpos            := cgg_rec_key_offset + 1;
(* set common values for cartesian product *)
IF  ( jinfos.ji_act_join = dmli.d_cntfromtab )
THEN
    BEGIN
    IF  ( jinfos.ji_stack_desc.mresqual_cnt > 0 )
    THEN
        jinfos.ji_nxtjinfo.nj_nk_len      := RESCNT_MXGG04
    ELSE
        jinfos.ji_nxtjinfo.nj_nk_len      := dmli.d_keylen;
    (*ENDIF*) 
    END
ELSE
    jinfos.ji_nxtjinfo.nj_nk_len      := RESCNT_MXGG04;
(*ENDIF*) 
jinfos.ji_nxtjinfo.nj_r_len           := cgg_rec_key_offset +
      jinfos.ji_nxtjinfo.nj_nk_len;
jinfos.ji_nxtjinfo.nj_nxt_klen_filled := RESCNT_MXGG04;
jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt := 0;
jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jpath  := 0;
jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_filler := 0;
jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_left_oj :=
      acv.a_outer_join           AND
      (jinfos.ji_acttabno in dmli.d_oj_tables);
(* !! this is true only for a special case !! *)
jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_right_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);
_colcopy_inf.n_j_cnt := 0;
dmli.d_inoutpos := jinfos.ji_outpos;
_op_outer       := (jinfos.ji_acttabno in dmli.d_oj_tables);
&IFDEF TRACE
t01p2int4 (ak_join, 'JOIN STEP   ', jinfos.ji_act_join,
      'i.th tab    ', jinfos.ji_acttabno);
t01int4 (ak_join, 'd_inoutpos  ', dmli.d_inoutpos);
a683joinset_trace (ak_join, 'left side   ', dmli, jinfos.ji_nxtjinfo.nj_left_side);
a683joinset_trace (ak_join, 'd_oj_tables ', dmli, dmli.d_oj_tables);
t01bool (ak_join, 'is_outertab ', _op_outer);
&ENDIF
IF  (dmli.d_joins.jrc_cnt > 0)
THEN
    (* there is a real join *)
    BEGIN
    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;
    (* prepare stack for actually join, these columns       *)
    (* build key columns of <i.th tab> record               *)
    (* actually join is <i-1.th temp result> with <i.th tab>*)
    ak684join_columns_stack (acv, dmli, jinfos, series, c_in_key, _op_outer);
    END;
(*ENDIF*) 
jinfos.ji_keylen := jinfos.ji_outpos - (cgg_rec_key_offset + 1) + RESCNT_MXGG04;
IF  (jinfos.ji_keylen > mxsp_key)
THEN
    a07_b_put_error (acv, e_join_fields_too_long, 1);
(*ENDIF*) 
IF  ( acv.a_returncode = 0 )
THEN
    BEGIN
    (* get seperated messblock for one table *)
    a682join_parsinfo_key( acv, dmli, jinfos.ji_parskey, 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 )
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  (acv.a_returncode = 0)
THEN
    SAPDB_PascalMove ('VAK684',   7,    
          _joinp^.smessblock.mbr_mess_block.mb_strat_size,
          sizeof( _gg_strategy ),
          @_joinp^.smessblock.mbr_mess_block.mb_strat^, 1,
          @_gg_strategy, 1, STRATEGY_START_MXGG07,
          acv.a_returncode);
(*ENDIF*) 
IF  (acv.a_returncode = 0) AND
    ((jinfos.ji_act_join = 1)
    OR
    ((jinfos.ji_use_operator_join = jopu_op_legacy) AND
    (_gg_strategy.str_strategy = strat_more_than_one)))
THEN
    (* first temporary result is built, therefore it exists a result counter *)
    jinfos.ji_outpos := jinfos.ji_outpos + RESCNT_MXGG04;
&ifdef trace
(*ENDIF*) 
t01int4 (ak_join, 'ji_outpos   ', jinfos.ji_outpos);
t01int4 (ak_join, 'ji_keylen   ', jinfos.ji_keylen);
&endif
IF  ((dmli.d_joins.jrc_cnt > 0) AND ( jinfos.ji_act_join < dmli.d_cntfromtab ) AND
    (acv.a_returncode = 0))
THEN
    BEGIN
    (* prepare stack for further joins, these columns *)
    (* are non key of <i.th tab> record               *)
    ak684join_columns_stack (acv, dmli, jinfos, series, NOT c_in_key, _op_outer);
    END;
(*ENDIF*) 
;
(* get output fields for actual table <i.th tab> *)
ak684output_columns_stack (acv, dmli, jinfos);
IF  (( jinfos.ji_use_operator_join in [ jopu_op_legacy, jopu_op_improved ] ) AND
    jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_right_oj )
THEN
    (* we need key to idendifiy one record for auxiliary RIGHT OUTER JOIN file *)
    ak684roj_key_stack( acv, dmli, jinfos );
(*ENDIF*) 
;
IF  (jinfos.ji_act_join = 1)
THEN
    jinfos.ji_nxtjinfo.nj_r_len := jinfos.ji_outpos;
&ifdef trace
(*ENDIF*) 
t01p2int4 (ak_join, 'ji_outpos   ', jinfos.ji_outpos,
      'ji_keylen   ', jinfos.ji_keylen);
t01p2int4 (ak_join, 'nj_nk_len   ', jinfos.ji_nxtjinfo.nj_nk_len,
      'nj_r_len    ', jinfos.ji_nxtjinfo.nj_r_len);
&endif
IF  (jinfos.ji_nxtjinfo.nj_nk_len > mxsp_key)
THEN
    a07_b_put_error (acv, e_join_fields_too_long, 1);
(*ENDIF*) 
;
(* 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);
&ifdef trace
t01int4 (ak_join, 'jumpout epos',
      acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mqual_pos ].epos);
&endif
IF  ( acv.a_outer_join )
THEN
    BEGIN
    acv.a_mblock.mb_st^
          [ acv.a_mblock.mb_qual^.mqual_pos ].ecol_tab[ 1 ] := chr(0);
    END;
(*ENDIF*) 
IF  ( acv.a_returncode = 0 )
THEN
    ak684qualification_stack( acv, dmli, jinfos, _joinp );
(*ENDIF*) 
acv.a_mblock.mb_qual^.mstrat_pos := acv.a_mblock.mb_qual^.mfirst_free;
acv.a_mblock.mb_qual^.mstrat_cnt := 0;
IF  (acv.a_returncode = 0)
THEN
    BEGIN
    IF  (jinfos.ji_act_join = 1)
    THEN
        BEGIN
        (* reserve space for strategy *)
        IF  ( acv.a_mblock.mb_qual^.mfirst_free + 1 <=
            acv.a_mblock.mb_qual^.mst_max )
        THEN
            BEGIN
            acv.a_mblock.mb_qual^.mfirst_free :=
                  succ (acv.a_mblock.mb_qual^.mfirst_free);
            g09StratStackentry( acv.a_mblock.mb_qual^.
                  mst_addr^[ acv.a_mblock.mb_qual^.mfirst_free-1 ], 0, 0 );
            END
        ELSE
            a07_b_put_error (acv, e_too_many_mb_stackentries, 1);
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        (* reserve space for strategies *)
        IF  ( acv.a_mblock.mb_qual^.mfirst_free + 4 <=
            acv.a_mblock.mb_qual^.mst_max )
        THEN
            BEGIN
            acv.a_mblock.mb_qual^.mfirst_free :=
                  acv.a_mblock.mb_qual^.mfirst_free + 4;
            g09StratStackentry( acv.a_mblock.mb_qual^.
                  mst_addr^[ acv.a_mblock.mb_qual^.mfirst_free-4 ], 0, 0 );
            g09StratStackentry( acv.a_mblock.mb_qual^.
                  mst_addr^[ acv.a_mblock.mb_qual^.mfirst_free-3 ], 0, 0 );
            g09StratStackentry( acv.a_mblock.mb_qual^.
                  mst_addr^[ acv.a_mblock.mb_qual^.mfirst_free-2 ], 0, 0 );
            g09StratStackentry( acv.a_mblock.mb_qual^.
                  mst_addr^[ acv.a_mblock.mb_qual^.mfirst_free-1 ], 0, 0 );
            END
        ELSE
            a07_b_put_error (acv, e_too_many_mb_stackentries, 1);
        (*ENDIF*) 
        ;
        (* build info for shifting columns from       *)
        (* <i-1.th temp result> to <i.th temp result> *)
        a685output_columns_shift (acv, dmli, jinfos,
              (* is outer join active *)
              (jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_right_oj));
        ;
        IF  (jinfos.ji_act_join = dmli.d_cntfromtab)
        THEN
            a685olast_order_fields( jinfos, _colcopy_inf )
        ELSE
            BEGIN
            IF  (jinfos.ji_nxtjinfo.nj_nxt_klen_filled <
                jinfos.ji_nxtjinfo.nj_nk_len)
                AND
                (jinfos.ji_nxtjinfo.nj_joincols_to_be_shifted > 0)
            THEN
                a685join_columns_last_shift (acv, dmli, jinfos);
            (*ENDIF*) 
            IF  (jinfos.ji_nxtjinfo.nj_joincols_to_be_shifted > 0)
            THEN
                a685join_columns_shift (acv, dmli, jinfos);
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
;
IF  (acv.a_returncode = 0)
THEN
    ak684write_strat_info( acv, dmli, jinfos, _colcopy_inf, res_tree,
          _joinp, series, ak_strat_interface,
          table_stats[ jinfos.ji_acttabno ].ts_inv_only_strat );
(*ENDIF*) 
;
IF  ( acv.a_returncode = 0 ) AND ( jinfos.ji_act_join = dmli.d_cntfromtab )
THEN
    BEGIN
    (* write result qualification in last messblock *)
    IF  ( jinfos.ji_stack_desc.mresqual_cnt > 0 )
    THEN
        BEGIN
        IF  ( acv.a_mblock.mb_qual^.mfirst_free +
            jinfos.ji_stack_desc.mresqual_cnt ) > acv.a_mblock.mb_st_max
        THEN
            a07_b_put_error( acv, e_too_many_mb_stackentries, 1 )
        ELSE
            BEGIN
&           ifdef trace
            t01name( ak_join, 'write result qual ' );
&           endif
            SAPDB_PascalMove ('VAK684',   8,    
                  (jinfos.ji_stack_desc.mst_max * STACK_ENTRY_MXGG00),
                  acv.a_mblock.mb_st_size,
                  @jinfos.ji_st_addr^,
                  (jinfos.ji_stack_desc.mresqual_pos - 1) * STACK_ENTRY_MXGG00 + 1,
                  @acv.a_mblock.mb_st^,
                  (acv.a_mblock.mb_qual^.mfirst_free - 1) * STACK_ENTRY_MXGG00 + 1,
                  jinfos.ji_stack_desc.mresqual_cnt * STACK_ENTRY_MXGG00,
                  acv.a_returncode);
            ;
            (* update messblock *)
            acv.a_mblock.mb_qual^.mresqual_cnt := jinfos.ji_stack_desc.mresqual_cnt;
            acv.a_mblock.mb_qual^.mresqual_pos := acv.a_mblock.mb_qual^.mfirst_free;
            acv.a_mblock.mb_qual^.mfirst_free  := acv.a_mblock.mb_qual^.mfirst_free +
                  jinfos.ji_stack_desc.mresqual_cnt;
            _i  := acv.a_mblock.mb_qual^.mresqual_pos;
            WHILE ( _i < acv.a_mblock.mb_qual^.mresqual_pos +
                  acv.a_mblock.mb_qual^.mresqual_cnt ) AND
                  NOT acv.a_mblock.mb_qual^.msubquery DO
                (* loop over result qualification columns *)
                (* search for EXISTS <subquery>           *)
                BEGIN
                acv.a_mblock.mb_qual^.msubquery :=
                      ( acv.a_mblock.mb_st^[ _i ].etype = st_subquery );
                _i := succ( _i );
                END;
            (*ENDWHILE*) 
            IF  ( acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].
                etype = st_jump_output )
            THEN
                BEGIN
                (* write keylen of result, see ak660more_phase() *)
                acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mstrat_pos + 1 ].
                      ecol_pos := acv.a_mblock.
                      mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].elen_var;
                (* set right d_keylen for reskey handling *)
                dmli.d_keylen := acv.a_mblock.
                      mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].elen_var;
                END
            ELSE
                acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mstrat_pos + 1 ].
                      ecol_pos := dmli.d_keylen;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( jinfos.ji_acttabno in dmli.d_oj_tables )
    THEN
        BEGIN
        (* we have constant output expression and outer joins         *)
        (* if an outer join gets no record from participated relation *)
        (* we have to stamp these output in any event                 *)
        (* therefore write result qualification                       *)
        ak684transfer_const_expressions (acv, dmli, jinfos);
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  ( jinfos.ji_set_output_filter )
THEN
    BEGIN
    (* write output filter if constant expression in part of *)
    (* table which is filled with NULL values (OUTER JOIN)   *)
    (* so that constant expression survive OUTER JOIN        *)
    _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
        _const_expr_fnd := false;
        _column_fnd     := false;
        _stack_pos      := _ix;
        (* step to next st_join_output *)
        WHILE ( _ix < _istop ) AND ( acv.a_mblock.mb_st^[ _ix ].etype <> st_output_join ) DO
            BEGIN
            (* on the way collect info *)
            IF  (acv.a_mblock.mb_st^[ _ix ].etype = st_value ) AND
                ( NOT _column_fnd )
            THEN
                _const_expr_fnd := true
            ELSE
                IF  ( acv.a_mblock.mb_st^[ _ix ].etype in
                    [ st_fixkey, st_varkey, st_fixcol, st_varcol,
                    st_fixinv, st_varinv,
                    st_fixprimkey, st_varprimkey, st_varlongchar ] )
                THEN
                    BEGIN
                    _column_fnd     := true;
                    _const_expr_fnd := false;
                    END
                ELSE
                    IF  ( acv.a_mblock.mb_st^[ _ix ].etype = st_output )
                    THEN
                        BEGIN
                        _column_fnd     := false;
                        _const_expr_fnd := false;
                        _stack_pos      := succ( _ix );
                        END;
                    (*ENDIF*) 
                (*ENDIF*) 
            (*ENDIF*) 
            _ix := succ( _ix );
            END;
        (*ENDWHILE*) 
        IF  (( _ix < _istop ) AND _const_expr_fnd )
        THEN
            ak684out_filter_stack( acv, _stack_pos, _ix - _stack_pos + 1 );
        (*ENDIF*) 
        _ix := succ( _ix );
        END;
    (*ENDWHILE*) 
    END;
(*ENDIF*) 
;
&ifdef trace
a683_output (ak_join, dmli);
a683trace_kbjrec (ak_join, jinfos.ji_nxtjinfo.nj_kbjrec);
&endif
IF  ( acv.a_returncode = 0 )
THEN
    BEGIN
    _ke := _joinp^.syskey;
    IF  ( jinfos.ji_use_operator_join in [ jopu_op_legacy, jopu_op_improved ] )
    THEN
        (* don't calculate optimize info *)
        a682_mbuf_to_tmpbuf( acv, _ke, _e, mtc_generate_join_info_operator_join )
    ELSE
        a682_mbuf_to_tmpbuf( acv, _ke, _e, mtc_generate_join_info );
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a684move_infos_strategy (
            VAR acv             : tak_all_command_glob;
            VAR strat           : tgg07_StrategyInfo;
            VAR joinp           : tak_sysbufferaddress;
            StratInfo_len       : tsp00_Int2;
            new_strat_created   : boolean);
 
BEGIN
&ifdef trace
t01name( ak_join, 'write strategy    ' );
&endif
IF  ( acv.a_mblock.mb_strat_len + 1 + StratInfo_len > acv.a_mblock.mb_strat_size )
THEN
    a07_b_put_error (acv, e_too_many_mb_strat, 1)
ELSE
    BEGIN
&   ifdef trace
    a725output_gg_strat( ak_join, 'join strat  ', strat );
&   endif
    IF  ( NOT ( strat.str_strategy in [ strat_more_than_one, strat_undecided] ))
    THEN
        BEGIN
        SAPDB_PascalForcedMove (
              sizeof( strat ), acv.a_mblock.mb_strat_size,
              @strat, 1,
              @acv.a_mblock.mb_strat^, acv.a_mblock.mb_strat_len + 1,
              StratInfo_len);
        END
    ELSE
        (* ( str_strategy in [ more_than, undecided ] ) *)
        BEGIN
        SAPDB_PascalForcedMove (
              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);
        IF  ( NOT new_strat_created )
        THEN
            BEGIN
            SAPDB_PascalForcedMove (
                  joinp^.smessblock.mbr_mess_block.mb_strat_size,
                  acv.a_mblock.mb_strat_size,
                  @joinp^.smessblock.mbr_mess_block.mb_strat^,
                  STRATEGY_START_MXGG07 + 1,
                  @acv.a_mblock.mb_strat^,
                  acv.a_mblock.mb_strat_len + 1 + STRATEGY_START_MXGG07,
                  StratInfo_len - STRATEGY_START_MXGG07);
            END
        ELSE
            ; (* up-to-date data already in strat part *)
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    g09StratStackentry( acv.a_mblock.mb_qual^.mst_addr^[ acv.a_mblock.mb_qual^.
          mstrat_pos ],
          succ (acv.a_mblock.mb_strat_len), StratInfo_len );
    acv.a_mblock.mb_qual^.mstrat_cnt := succ (acv.a_mblock.mb_qual^.mstrat_cnt);
    acv.a_mblock.mb_strat_len  := acv.a_mblock.mb_strat_len + StratInfo_len;
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684move_infos_result_shift (
            VAR acv        : tak_all_command_glob;
            VAR colcopy_inf: tgg07_JoinColCopyInfo;
            VAR result_inf : tgg07_JoinResInfo);
 
VAR
      _ilen : tsp00_Int4;
&     ifdef trace
      _j    : tsp00_Int2;
&     endif
 
BEGIN
&ifdef trace
t01name( ak_join, 'write result/shift' );
&endif
(* result_inf, shift info *)
_ilen := sizeof(result_inf) +
      (sizeof(colcopy_inf) - sizeof(colcopy_inf.n_j_arr)) +
      (sizeof(colcopy_inf.n_j_arr[1]) * colcopy_inf.n_j_cnt);
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)
ELSE
    BEGIN
&   ifdef trace
    t01name(ak_join, 'write result info ');
    IF  t01trace( kb ) OR t01trace( ak_join )
    THEN
        BEGIN
        t01name(td_always, 'gi_result_info :  ');
        t01treeid (td_always, 'o_tree      ', result_inf.o_tree );
        t01p2int4 (td_always, 'n_rec_len   ', result_inf.n_rec_len,
              'n_key_len   ', result_inf.n_key_len);
        t01int4 (td_always, 'n_res_rec_le', result_inf.n_res_rec_len);
        t01sname(td_always, '------------');
        END;
&   endif
    (*ENDIF*) 
    SAPDB_PascalForcedMove (
          sizeof(result_inf), acv.a_mblock.mb_strat_size,
          @result_inf, 1,
          @acv.a_mblock.mb_strat^, acv.a_mblock.mb_strat_len + 1,
          sizeof(result_inf));
    _ilen := _ilen - sizeof(result_inf);
    (*!! strategy entry will points behind result info !!          *)
    (* info will be read from this strat_pointer up to             *)
    (* strat_pointer - sizeof(result_inf), see k74get_join_infos() *)
    acv.a_mblock.mb_strat_len := acv.a_mblock.mb_strat_len +
          sizeof(result_inf);
&   ifdef trace
    t01name(ak_join, 'write shift info  ');
    IF  t01trace( kb ) OR t01trace( ak_join )
    THEN
        BEGIN
        t01name(td_always, 'cols to be copied ');
        t01sname(td_always, 'gi_copy_inf:');
        t01int4 (td_always, 'n_j_cnt     ', colcopy_inf.n_j_cnt);
        FOR _j := 1 TO colcopy_inf.n_j_cnt DO
            BEGIN
            t01p2int4 (td_always, 'jfrom       ', colcopy_inf.n_j_arr[ _j ].jfrom,
                  'jlen        ', colcopy_inf.n_j_arr[ _j ].jlen);
            t01int4 (td_always, 'jto         '  , colcopy_inf.n_j_arr[ _j ].jto);
            END;
        (*ENDFOR*) 
        t01sname(td_always, '------------');
        END;
&   endif
    (*ENDIF*) 
    SAPDB_PascalForcedMove (
          sizeof (colcopy_inf), acv.a_mblock.mb_strat_size,
          @colcopy_inf, 1,
          @acv.a_mblock.mb_strat^, acv.a_mblock.mb_strat_len + 1,
          _ilen );
    g09StratStackentry( acv.a_mblock.mb_qual^.mst_addr^[ acv.a_mblock.mb_qual^.
          mstrat_pos + 1 ],
          succ (acv.a_mblock.mb_strat_len), _ilen );
    acv.a_mblock.mb_qual^.mstrat_cnt := succ (acv.a_mblock.mb_qual^.mstrat_cnt);
    acv.a_mblock.mb_strat_len  := acv.a_mblock.mb_strat_len + _ilen;
    END
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684move_infos_join (
            VAR acv        : tak_all_command_glob;
            VAR kbjrec     : tgg07_KbJoinRec);
 
VAR
      _ilen : tsp00_Int4;
 
BEGIN
&ifdef trace
t01name( ak_join, 'write join info   ' );
a683trace_kbjrec( ak_join, kbjrec );
&endif
_ilen := sizeof (kbjrec.kbjr_jointrans_cnt) +
      sizeof (kbjrec.kbjr_jpath) + sizeof (kbjrec.kbjr_filler) +
      sizeof (kbjrec.kbjr_right_oj) + sizeof (kbjrec.kbjr_left_oj) +
      (kbjrec.kbjr_jointrans_cnt * sizeof (tgg07_KbJoinInfo));
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)
ELSE
    BEGIN
    SAPDB_PascalForcedMove (
          sizeof (kbjrec), acv.a_mblock.mb_strat_size,
          @kbjrec, 1,
          @acv.a_mblock.mb_strat^, acv.a_mblock.mb_strat_len + 1,
          _ilen );
    g09StratStackentry( acv.a_mblock.mb_qual^.mst_addr^[ acv.a_mblock.mb_qual^.
          mstrat_pos + 2 ],
          succ (acv.a_mblock.mb_strat_len), _ilen );
    acv.a_mblock.mb_qual^.mstrat_cnt := succ (acv.a_mblock.mb_qual^.mstrat_cnt);
    acv.a_mblock.mb_strat_len  := acv.a_mblock.mb_strat_len + _ilen;
    END
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a684move_infos_onetabstrat (
            VAR acv             : tak_all_command_glob;
            VAR strat           : tgg07_StrategyInfo;
            VAR joinp           : tak_sysbufferaddress;
            StratInfo_len       : tsp00_Int2;
            new_strat_created   : boolean);
 
BEGIN
&ifdef trace
t01name( ak_join, 'write onetabstrat ' );
&endif
IF  ( acv.a_mblock.mb_strat_len + 1 + StratInfo_len > acv.a_mblock.mb_strat_size )
THEN
    a07_b_put_error (acv, e_too_many_mb_strat, 1)
ELSE
    BEGIN
    IF  ( NOT new_strat_created )
    THEN
        BEGIN
&       ifdef trace
        t01name( ak_join, 'get existing strat' );
&       endif
        SAPDB_PascalForcedMove (
              joinp^.smessblock.mbr_mess_block.mb_strat_size,
              acv.a_mblock.mb_strat_size,
              @joinp^.smessblock.mbr_mess_block.mb_strat^,
              joinp^.smessblock.mbr_mess_block.mb_st^[ joinp^.smessblock.
              mbr_mess_block.mb_qual^.mstrat_pos ].epos,
              @acv.a_mblock.mb_strat^, acv.a_mblock.mb_strat_len + 1,
              StratInfo_len );
        END
    ELSE
        BEGIN
&       ifdef trace
        a725output_gg_strat( ak_join, 'new strat   ', strat );
&       endif
        IF  ( strat.str_strategy in [ strat_more_than_one, strat_undecided ] )
        THEN
            BEGIN
            SAPDB_PascalForcedMove (
                  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 );
            (* remaining info already in strat part *)
            END
        ELSE
            BEGIN
            SAPDB_PascalForcedMove (
                  sizeof( strat ), acv.a_mblock.mb_strat_size,
                  @strat, 1,
                  @acv.a_mblock.mb_strat^, acv.a_mblock.mb_strat_len + 1,
                  StratInfo_len );
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    g09StratStackentry( acv.a_mblock.mb_qual^.mst_addr^[ acv.a_mblock.mb_qual^.
          mstrat_pos + 3 ],
          succ (acv.a_mblock.mb_strat_len), StratInfo_len );
    acv.a_mblock.mb_qual^.mstrat_cnt := succ (acv.a_mblock.mb_qual^.mstrat_cnt);
    acv.a_mblock.mb_strat_len  := acv.a_mblock.mb_strat_len + StratInfo_len;
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684output_columns_stack (
            VAR acv    : tak_all_command_glob;
            VAR dmli   : tak_dml_info;
            VAR jinfos : tak68_joininfos);
 
VAR
      _is_acttabno : boolean;
      _col_found : boolean;
      _starts    : tsp00_Int2;
      _stops     : tsp00_Int2;
      _startd    : tsp00_Int2;
      _i         : tsp00_Int2;
      _j         : tsp00_Int2;
      _scnt      : tsp00_Int2;
&     ifdef trace
      _out_fnd   : boolean;
&     endif
 
BEGIN
(* get output fields for actual table <i.th tab> *)
&ifdef trace
t01p2int4 (ak_join, 'JOIN STEP   ', jinfos.ji_act_join,
      'i.th tab    ', jinfos.ji_acttabno);
_out_fnd := false;
&endif
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
    (* avoid looping *)
    _stops := jinfos.ji_stack_desc.mmult_pos;
(*ENDIF*) 
;
(* search through output columns without 'packed' columns *)
_i      := succ (jinfos.ji_stack_desc.mmult_pos);
_starts := _i;
_startd := pred (acv.a_mblock.mb_qual^.mfirst_free);
WHILE ( _i <= _stops ) AND  (acv.a_returncode = 0) 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 from <i.th tab> found *)
            BEGIN
            _col_found := true;
            _is_acttabno :=
                  (( ord(jinfos.ji_st_addr^[ _i ].ecol_tab[ 2 ]) MOD 100 ) =
                  jinfos.ji_acttabno );
            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, 'orig outp-> new mb');
        FOR _j := _starts TO _starts + _scnt - 1 DO
            t01stackentry( ak_join, jinfos.ji_st_addr^[ _j ], _j );
        (*ENDFOR*) 
        _out_fnd := true;
&       endif
        (* get colunms until output column *)
        SAPDB_PascalMove ('VAK684',   9,    
              (jinfos.ji_stack_desc.mst_max * STACK_ENTRY_MXGG00),
              acv.a_mblock.mb_st_size,
              (* source *)
              @jinfos.ji_st_addr^, (_starts - 1) * STACK_ENTRY_MXGG00 + 1,
              (* destination *)
              @acv.a_mblock.mb_st^, _startd * STACK_ENTRY_MXGG00 + 1,
              _scnt * STACK_ENTRY_MXGG00,
              acv.a_returncode);
        IF  ( acv.a_returncode = 0 )
        THEN
            BEGIN
            _startd := _startd + _scnt;
            _j      := _i; (* mark actual output stack entry *)
            (* 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 = op_o_output_hold ) AND
                (acv.a_mblock.mb_st^[ _startd ].etype
                in [ st_output, st_output_join ]))
            THEN
                BEGIN
                (* ORDER BY col found, which is also in output  *)
                (* this stackentry describes output column      *)
                (* this two output could have different length  *)
                (* e.g. output has to be converted to UNICODE   *)
                (* therefore we need more space for this column *)
                (* ORDER BY keeps in ASCII                      *)
&               ifdef trace
                t01name(ak_join, 'OUT HOLD found    ');
&               endif
                IF  (jinfos.ji_st_addr^[ _i + 1 ].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 + 1 ].etype in
                    [ st_output ,st_output_join ])
                THEN
                    BEGIN
                    (* this stackentry describes sorting key column *)
&                   ifdef trace
                    t01name(ak_join, 'mark outcol pos   ');
                    t01Int4(ak_join, 'on orig mblock    ', _i + 1);
&                   endif
                    a685set_output_join (jinfos.ji_st_addr^[ _i + 1 ],
                          (* mark position of output column on column   *)
                          (* for soring (key column) in orig. messblock *)
                          jinfos.ji_st_addr^[ _j ].epos);
                    END;
                (*ENDIF*) 
                CASE jinfos.ji_st_addr^[ _i + 1 ].eop_out OF
                    op_o_output_oflw,
                    op_o_output_no_oflw :
                        acv.a_mblock.mb_st^[ _startd ].eop_out :=
                              jinfos.ji_st_addr^[ _i + 1 ].eop_out;
                    OTHERWISE
                        (* avoid ORDER BY optimizations *)
                        acv.a_mblock.mb_st^[ _startd ].eop_out :=
                              op_o_none;
                    END
                (*ENDCASE*) 
                END;
&           ifdef trace
            (*ENDIF*) 
            t01p2int4 (ak_join, 'd_inoutpos  ', dmli.d_inoutpos,
                  'elen_var    ', acv.a_mblock.mb_st^[ _startd ].elen_var);
&           endif
            dmli.d_inoutpos :=
                  dmli.d_inoutpos + acv.a_mblock.mb_st^[ _startd ].elen_var;
            IF  ( dmli.d_inoutpos > MAX_RECLEN_GG00 + 1 )
            THEN
                a07_b_put_error( acv, e_join_fields_too_long, 1 );
            (*ENDIF*) 
            IF  (jinfos.ji_act_join = 1)
            THEN
                BEGIN
&               ifdef trace
                t01Int4(ak_join, 'mark on orig mbloc', _j);
&               endif
                a685set_output_join (jinfos.ji_st_addr^[ _j ],
                      jinfos.ji_outpos);
                END
            ELSE
                BEGIN
&               ifdef trace
                t01Int4(ak_join, 'mark on i.th mbloc', _startd);
&               endif
                IF  (jinfos.ji_act_join = dmli.d_cntfromtab)
                THEN
                    BEGIN
                    a685set_output_join (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
                    BEGIN
                    a685set_output_join (acv.a_mblock.mb_st^[ _startd ],
                          a685evaluate_new_ecol_pos (dmli, jinfos,
                          _starts,
                          (*! take elen_var from output column !*)
                          (*! and not from to ORDER BY column  !*)
                          jinfos.ji_st_addr^[ _i ].elen_var));
                    END;
                (*ENDIF*) 
                ;
                (* save <i.th temp result> pos in ecol_pos *)
                (* of corresponding output colunm of       *)
                (* original mblock                         *)
&               ifdef trace
                t01Int4(ak_join, 'mark on orig mbloc', _j);
&               endif
                a685set_output_join (jinfos.ji_st_addr^[ _j ],
                      (* set ecol_pos from copied stack entry *)
                      acv.a_mblock.mb_st^[ _startd ].ecol_pos);
                END;
            (*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
        (* overstep ORDER BY key column, which describes ORDER BY key *)
        (* to avoid copying ORDER BY column for output and for        *)
        (* ORDER BY key column from base table                        *)
        (* copying of ORDER BY key column to <i. temp result>         *)
        (* will be described with the aid of a685olast_order_fields() *)
        _i := _i + 2
    ELSE
        _i := succ(_i);
    (*ENDIF*) 
    _starts := _i;
    END;
(*ENDWHILE*) 
&ifdef trace
IF  (_out_fnd)
THEN
    BEGIN
    t01stackdesc (ak_join, 'orig mblock ', jinfos.ji_st_addr,
          jinfos.ji_stack_desc);
    t01stackdesc (ak_join, 'i.th mblock ', acv.a_mblock.mb_st,
          acv.a_mblock.mb_qual^.mstack_desc);
    END
ELSE
    t01name(ak_join, 'no output found   ');
(*ENDIF*) 
&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 jinfos              : tak68_joininfos;
            VAR ak_strat_interface  : tak71_strat_rec;
            VAR jvrec               : tak68_joinview_rec;
            VAR table_stats         : tak68_table_stats);
 
VAR
      _old_return      : tsp00_Int4;
 
BEGIN
&ifdef trace
a683output_joins( ak_join, acv, dmli, dmli.d_joins );
a683_output( ak_join, dmli );
t01stackdesc (ak_join, 'ORIG MBLOCK ', jinfos.ji_st_addr, jinfos.ji_stack_desc);
t01int4 (ak_join, 'operat join ', ord(jinfos.ji_use_operator_join) );
&endif
_old_return := acv.a_returncode;
(* initialize jinfos *)
jinfos.ji_act_join                         := 1;
jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_left_oj := false;
jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_right_oj  := false;
jinfos.ji_nxtjinfo.nj_left_side := [ series[ 1 ].jos_source ];
jinfos.ji_nxtjinfo.nj_joincols_to_be_shifted := 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_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   ', dmli, jinfos.ji_nxtjinfo.nj_left_side);
&   endif
    ak684generate_join_info( acv, dmli, jinfos, series, res_tree,
          ak_strat_interface, jvrec, table_stats );
&   ifdef trace
    t01int4 (ak_join, 'JOIN STEP   ', jinfos.ji_act_join);
    t01qual1 (ak_join, 'i.th 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_returncode <> 0))
THEN
    (* error handling - remove all build messblocks *)
    a680rollback_temp_jinfo( acv, dmli, jinfos.ji_parskey,
          jvrec.jv_tabid, dmli.d_cntfromtab
          (* created in ak680prepare_join()/replaced while
          ak684generate_join_info()*) );
(*ENDIF*) 
dmli.d_inoutpos := succ (jinfos.ji_nxtjinfo.nj_r_len);
&ifdef trace
t01int4 (ak_join, 'd_inoutpos  ', dmli.d_inoutpos );
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684transfer_const_expressions (
            VAR acv    : tak_all_command_glob;
            VAR dmli   : tak_dml_info;
            VAR jinfos : tak68_joininfos);
 
VAR
      _starts          : tsp00_Int2;
      _stops           : tsp00_Int2;
      _startd          : tsp00_Int2;
      _i               : tsp00_Int2;
      _j               : tsp00_Int2;
      _scnt            : tsp00_Int2;
      _aux_resqual_cnt : tsp00_Int2;
      _col_found       : boolean;
 
BEGIN
_aux_resqual_cnt := acv.a_mblock.mb_qual^.mresqual_cnt;
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
    (* avoid looping *)
    _stops := jinfos.ji_stack_desc.mmult_pos;
(*ENDIF*) 
(* search through output columns without 'packed' columns *)
_i := succ (jinfos.ji_stack_desc.mmult_pos);
_starts := _i;
_startd := pred (acv.a_mblock.mb_qual^.mfirst_free);
WHILE ( _i <= _stops ) AND (acv.a_returncode = 0) DO
    (* loop over output columns of original stack *)
    BEGIN
    _col_found := false;
    (* step to output column *)
    WHILE ((_i <= _stops) AND
          (NOT (jinfos.ji_st_addr^[ _i ].etype in [ st_output, st_output_join ])
          OR
          ((jinfos.ji_st_addr^[ _i ].etype in [ st_output, st_output_join ]) AND
          (jinfos.ji_st_addr^[ _i ].eop_out = op_o_output_hold)))) DO
        BEGIN
        IF  (jinfos.ji_st_addr^[ _i ].etype in [ st_fixkey, st_varkey,
            st_fixcol, st_varcol, st_varlongchar, st_rowno ])
        THEN
            _col_found := true;
        (*ENDIF*) 
        _i := succ (_i);
        END;
    (*ENDWHILE*) 
    _scnt := _i - _starts + 1;
    IF  ((_i <= _stops) AND (NOT _col_found) AND (_scnt > 1))
    THEN
        (* constant expression found     *)
        (* write as result qualification *)
        BEGIN
        IF  (acv.a_mblock.mb_qual^.mresqual_pos = 0)
        THEN
            BEGIN
&           ifdef trace
            t01sname( ak_join, 'new mresqual' );
&           endif
            acv.a_mblock.mb_qual^.mresqual_pos :=
                  acv.a_mblock.mb_qual^.mfirst_free;
            acv.a_mblock.mb_qual^.mfirst_free  :=
                  succ (acv.a_mblock.mb_qual^.mfirst_free);
            _startd := succ (_startd);
            acv.a_mblock.mb_qual^.mresqual_cnt :=
                  succ (acv.a_mblock.mb_qual^.mresqual_cnt);
            END;
&       ifdef trace
        (*ENDIF*) 
        t01int4 (ak_join, '_scnt       ', _scnt );
&       endif
        SAPDB_PascalMove ('VAK684',  10,    
              (acv.a_mblock.mb_qual^.mst_max * STACK_ENTRY_MXGG00),
              acv.a_mblock.mb_st_size,
              @jinfos.ji_st_addr^,
              (_starts - 1) * STACK_ENTRY_MXGG00 + 1,
              @acv.a_mblock.mb_st^,
              _startd * STACK_ENTRY_MXGG00 + 1,
              _scnt * STACK_ENTRY_MXGG00,
              acv.a_returncode);
        _startd := _startd + _scnt;
        _j      := _i; (* mark output column *)
        IF  (acv.a_returncode = 0)
        THEN
            BEGIN
            acv.a_mblock.mb_qual^.mresqual_cnt  :=
                  acv.a_mblock.mb_qual^.mresqual_cnt + _scnt;
            acv.a_mblock.mb_qual^.mfirst_free   :=
                  acv.a_mblock.mb_qual^.mfirst_free + _scnt;
            acv.a_mblock.mb_st^[ _startd ].epos :=
                  jinfos.ji_st_addr^[ _j ].epos;
            acv.a_mblock.mb_st^[ _startd ].etype         := st_output;
            acv.a_mblock.mb_st^[ _startd ].eop_out       := op_o_none;
            acv.a_mblock.mb_st^[ _startd ].ecol_tab[ 1 ] := chr(0);
            acv.a_mblock.mb_st^[ _startd ].ecol_tab[ 2 ] := chr(0);
            (* output hold -> order by *)
            IF  (acv.a_mblock.mb_st^[ _startd -1 ].etype
                in [st_output, st_output_join])
            THEN
                BEGIN
                acv.a_mblock.mb_st^[ _startd -1 ].etype
                      := st_output;
                acv.a_mblock.mb_st^[ _startd -1 ].eop_out
                      := op_o_output_hold;
                acv.a_mblock.mb_st^[ _startd -1 ].ecol_tab[ 1 ]
                      := chr(0);
                acv.a_mblock.mb_st^[ _startd -1 ].ecol_tab[ 2 ]
                      := chr(0);
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    _i      := succ(_i);
    _starts := _i;
    END;
(*ENDWHILE*) 
IF  (_aux_resqual_cnt < acv.a_mblock.mb_qual^.mresqual_cnt) AND
    (acv.a_mblock.mb_qual^.mresqual_pos > 0)
THEN
    BEGIN
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].etype := st_jump_output;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].eop   := op_none;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].epos  :=
          acv.a_mblock.mb_qual^.mfirst_free -
          acv.a_mblock.mb_qual^.mresqual_pos + 1;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].
          elen_var      := 0;
    (* for kb741build_new_rec(), Join_JoinOperator::build_new_rec() *)
    (* we don't have complete output of record *)
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].ecol_pos := -1;
    END;
(*ENDIF*) 
;
(* write key length for result qualification *)
acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mstrat_pos + 1 ].
      ecol_pos := dmli.d_keylen;
&ifdef trace
t01stackdesc (ak_join, 'ji_stack_des', jinfos.ji_st_addr, jinfos.ji_stack_desc);
t01stackdesc (ak_join, 'i.th mblock ', acv.a_mblock.mb_st,
      acv.a_mblock.mb_qual^.mstack_desc);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684update_kbjoininfo(
            VAR dmli     : tak_dml_info;
            VAR jinfos   : tak68_joininfos;
            currj        : integer;
            further_cols : boolean;
            jarr_side    : tsp00_Int2;  (* side with act. tabno, dest./right side *)
            kb_side      : tsp00_Int2);
 
VAR
      _kb_oside   : tsp00_Int2;
      _jarr_oside : tsp00_Int2;
 
      _hop : PACKED RECORD
            CASE boolean OF
                TRUE :
                    (c : char);
                FALSE :
                    (op : tgg00_StackOpType);
                END;
            (*ENDCASE*) 
 
 
BEGIN
CASE kb_side OF
    1 :
        _kb_oside := 2;
    2 :
        _kb_oside := 1;
    END;
(*ENDCASE*) 
CASE jarr_side OF
    1 :
        _jarr_oside := 2;
    2 :
        _jarr_oside := 1;
    END;
(*ENDCASE*) 
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[ jarr_side ].jop_outer_join;
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[ _jarr_oside ].jop_outer_join;
;
IF  ((jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt = 0)
    (* initialize *)
    OR
    (NOT further_cols))
THEN
    BEGIN
    jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt :=
          succ (jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt);
    IF  (jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt > 1)
    THEN
        (* last column of more than one join column *)
        BEGIN
        (* new recpos := last recpos + last len *)
        jinfos.ji_nxtjinfo.nj_kbjrec.
              kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
              kbji_parts[ 1 ].kboj_recpos :=
              jinfos.ji_nxtjinfo.nj_kbjrec.
              kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt - 1 ].
              kbji_parts[ 1 ].kboj_recpos +
              jinfos.ji_nxtjinfo.nj_kbjrec.
              kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt - 1 ].
              kbji_parts[ 1 ].kboj_len;
        jinfos.ji_nxtjinfo.nj_kbjrec.
              kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
              kbji_parts[ 2 ].kboj_recpos :=
              jinfos.ji_nxtjinfo.nj_kbjrec.
              kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt - 1 ].
              kbji_parts[ 2 ].kboj_recpos +
              jinfos.ji_nxtjinfo.nj_kbjrec.
              kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt - 1 ].
              kbji_parts[ 2 ].kboj_len;
        END
    ELSE
        BEGIN
        (* initialize            *)
        (* first join transition *)
        (* set first recpos      *)
        jinfos.ji_nxtjinfo.nj_kbjrec.
              kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
              kbji_parts[ kb_side ].kboj_recpos := cgg_rec_key_offset + 1;
        jinfos.ji_nxtjinfo.nj_kbjrec.
              kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
              kbji_parts[ _kb_oside ].kboj_recpos := cgg_rec_key_offset + 1;
        END;
    (*ENDIF*) 
    ;
    (* calculate length := first joincol length *)
    jinfos.ji_nxtjinfo.nj_kbjrec.
          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
          kbji_parts[ kb_side ].kboj_len :=
          dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ jarr_side ].jop_inoutlen;
    jinfos.ji_nxtjinfo.nj_kbjrec.
          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
          kbji_parts[ _kb_oside ].kboj_len :=
          dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ _jarr_oside ].jop_inoutlen;
    jinfos.ji_nxtjinfo.nj_kbjrec.
          kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
          kbji_parts[ 1 ].kboj_reverse_operands := false;
    IF  (jarr_side = 1)
    THEN
        BEGIN
        (* <i.th tab> op <???> *)
        (* reverse join operation if necessary: *)
        (* for <i.th tab col> op <any tab col>  *)
        (* <any tab col> is in temporary result *)
        (* because in KB we compare             *)
        (* <temporary result> op <base tab>     *)
        (* we have to reverse some join operator*)
&       ifdef trace
        t01op( ak_join, '            ', dmli.d_joins.jrc_joinarr[ currj ].jo_op );
&       endif
        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_jointrans_cnt ].
                      kbji_parts[ 1 ].kboj_op := op_gt;
            op_le :
                jinfos.ji_nxtjinfo.nj_kbjrec.
                      kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.
                      kbjr_jointrans_cnt ].
                      kbji_parts[ 1 ].kboj_op := op_ge;
            op_gt :
                jinfos.ji_nxtjinfo.nj_kbjrec.
                      kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.
                      kbjr_jointrans_cnt ].
                      kbji_parts[ 1 ].kboj_op := op_lt;
            op_ge :
                jinfos.ji_nxtjinfo.nj_kbjrec.
                      kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.
                      kbjr_jointrans_cnt ].
                      kbji_parts[ 1 ].kboj_op := op_le;
            OTHERWISE
                BEGIN
                jinfos.ji_nxtjinfo.nj_kbjrec.
                      kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.
                      kbjr_jointrans_cnt ].kbji_parts[ 1 ].
                      kboj_op :=
                      dmli.d_joins.jrc_joinarr[ currj ].jo_op;
                (* for op_like, op_not_like, op_sounds, op_not_sounds   *)
                (* kboj_reverse_operands has no effect for op_eq, op_ne *)
                jinfos.ji_nxtjinfo.nj_kbjrec.
                      kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.
                      kbjr_jointrans_cnt ].kbji_parts[ 1 ].
                      kboj_reverse_operands := true;
                END;
            END
        (*ENDCASE*) 
        END
    ELSE
        BEGIN
        jinfos.ji_nxtjinfo.nj_kbjrec.
              kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.
              kbjr_jointrans_cnt ].kbji_parts[ 1 ].kboj_op :=
              dmli.d_joins.jrc_joinarr[ currj ].jo_op;
        END;
    (*ENDIF*) 
    END
ELSE
    (* jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt <> 0     *)
    (* AND further_cols                                         *)
    (* we have column which is part of an larger join transition*)
    (* calc length := length + adddnl. length *)
    BEGIN
    IF  (jinfos.ji_nxtjinfo.nj_kbjrec.
        kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
        kbji_parts[ kb_side ].kboj_len +
        dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ jarr_side ].jop_inoutlen)
        < mxsp_key
    THEN
        jinfos.ji_nxtjinfo.nj_kbjrec.
              kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
              kbji_parts[ kb_side ].kboj_len :=
              jinfos.ji_nxtjinfo.nj_kbjrec.
              kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
              kbji_parts[ kb_side ].kboj_len + dmli.d_joins.
              jrc_joinarr[ currj ].jo_recs[ jarr_side ].jop_inoutlen;
    (*ENDIF*) 
    IF  (jinfos.ji_nxtjinfo.nj_kbjrec.
        kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
        kbji_parts[ _kb_oside ].kboj_len +
        dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ _jarr_oside ].jop_inoutlen)
        < mxsp_key
    THEN
        jinfos.ji_nxtjinfo.nj_kbjrec.
              kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
              kbji_parts[ _kb_oside ].kboj_len :=
              jinfos.ji_nxtjinfo.nj_kbjrec.
              kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
              kbji_parts[ _kb_oside ].kboj_len +
              dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ _jarr_oside ].
              jop_inoutlen;
    (*ENDIF*) 
    END;
(*ENDIF*) 
;
(* set length comparision information *)
IF  (jinfos.ji_nxtjinfo.nj_kbjrec.
    kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
    kbji_parts[ 1 ].kboj_len =
    jinfos.ji_nxtjinfo.nj_kbjrec.
    kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
    kbji_parts[ 2 ].kboj_len)
THEN
    (* same length *)
    _hop.c := chr (cgg07_left_len_eq_right_len)
ELSE
    IF  (jinfos.ji_nxtjinfo.nj_kbjrec.
        kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
        kbji_parts[ 1 ].kboj_len >
        jinfos.ji_nxtjinfo.nj_kbjrec.
        kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
        kbji_parts[ 2 ].kboj_len)
    THEN
        _hop.c := chr (cgg07_left_len_gt_right_len)
    ELSE
        _hop.c := chr (cgg07_left_len_le_right_len);
    (*ENDIF*) 
(*ENDIF*) 
jinfos.ji_nxtjinfo.nj_kbjrec.
      kbjr_jarr[ jinfos.ji_nxtjinfo.nj_kbjrec.kbjr_jointrans_cnt ].
      kbji_parts[ 2 ].kboj_op := _hop.op;
;
&ifdef trace
a683trace_kbjrec(ak_join, jinfos.ji_nxtjinfo.nj_kbjrec);
&ENDIF
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684roj_key_stack (
            VAR acv    : tak_all_command_glob;
            VAR dmli   : tak_dml_info;
            VAR jinfos : tak68_joininfos);
 
VAR
      _sysbuf     : tak_sysbufferaddress;
      _colbuf     : tak00_colinfo_ptr;
      _keylen     : tsp00_Int4;
      _fieldno    : tsp00_Int2;
      _align_offs : tsp00_Int2;
 
BEGIN
a684get_relation_info( acv, dmli.d_tabarr[ jinfos.ji_acttabno ], d_release, _sysbuf );
IF  ( _sysbuf <> NIL )
THEN
    BEGIN
    _fieldno := 1;
    _keylen  := 0;
    _colbuf  := _sysbuf^.sbase.bcolumn[ _sysbuf^.sbase.bfirstcolind ];
    WHILE (( _fieldno <= _sysbuf^.sbase.bkeycolcount ) AND ( acv.a_returncode = 0 )) DO
        BEGIN
        IF  ( acv.a_mblock.mb_qual^.mfirst_free + 2 <= acv.a_mblock.mb_st_max )
        THEN
            BEGIN
            acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free ]     := _colbuf^.ccolstack;
            acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free + 1 ] := _colbuf^.ccolstack;
            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 ].eop_out := op_o_output_outer_join;
            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(0);
            acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free + 1 ].epos := jinfos.ji_outpos;
&           ifdef trace
            t01stackentry( ak_join,
                  acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free ],
                  acv.a_mblock.mb_qual^.mfirst_free );
            t01stackentry( ak_join,
                  acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free + 1 ],
                  acv.a_mblock.mb_qual^.mfirst_free + 1 );
&           endif
            jinfos.ji_outpos := jinfos.ji_outpos +
                  acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free + 1 ].elen_var;
            dmli.d_inoutpos :=
                  dmli.d_inoutpos + acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free + 1 ].elen_var;
            _keylen := _keylen +
                  acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free ].elen_var;
            IF  ( dmli.d_inoutpos > MAX_RECLEN_GG00 + 1 )
            THEN
                a07_b_put_error( acv, e_join_fields_too_long, 1 );
            (*ENDIF*) 
            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;
            END
        ELSE
            a07_b_put_error( acv, e_too_many_mb_stackentries, 1 );
        (*ENDIF*) 
        IF  ( _colbuf^.cnextind > 0 )
        THEN
            _colbuf := _sysbuf^.sbase.bcolumn[ _colbuf^.cnextind ];
        (*ENDIF*) 
        _fieldno := succ( _fieldno );
        END;
    (*ENDWHILE*) 
    IF  ( _fieldno = 1 )
    THEN
        (* we expect at least one key column *)
        a07ak_system_error( acv, 684, 1 )
    ELSE
        BEGIN
        IF  (( _keylen MOD  ALIGNMENT_GG00 ) <> 0 )
        THEN
            BEGIN
            (* later we skip over key and use this position as object *)
            (* pointer therefore _keylen has to be aligned            *)
&           ifdef trace
            t01int4 (ak_join, 'align _keyle', _keylen );
&           endif
            _align_offs := ALIGNMENT_GG00 - ( _keylen MOD ALIGNMENT_GG00 );
            _keylen     := _keylen + _align_offs;
&           ifdef trace
            t01int4 (ak_join, '_keylen     ', _keylen );
&           endif
            (* adjust output column *)
            acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].elen_var :=
                  acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
                  elen_var + _align_offs;
            dmli.d_inoutpos  := dmli.d_inoutpos  + _align_offs;
            jinfos.ji_outpos := jinfos.ji_outpos + _align_offs;
            IF  ( dmli.d_inoutpos > MAX_RECLEN_GG00 + 1 )
            THEN
                a07_b_put_error( acv, e_join_fields_too_long, 1 );
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        ;
        (* write whole key length into VARKEY column ecol_pos *)
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 2 ].ecol_pos := _keylen;
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a684get_relation_info(
            VAR acv         : tak_all_command_glob;
            VAR tabledesc   : tak_one_table;
            dstate          : tak_directory_state;
            VAR pbasep      : tak_sysbufferaddress (* OUT *));
 
VAR
      _mt         : tak_fromsel_tabid;
      _resid      : tsp00_Int4;
      _ok         : boolean;
 
BEGIN
IF  ( a661_is_fromsel_table( acv, tabledesc.otreeid ) )
THEN
    BEGIN
    a661_get_from_select_table( acv, tabledesc.otreeid.fileTabId_gg00,
          pbasep, dstate, true, _ok );
    END
ELSE
    BEGIN
    IF  ( oresfile in tabledesc.ospecialname )
    THEN
        BEGIN
&       ifdef trace
        t01sname(ak_join, 'result table');
&       endif
        _ok := true;
        IF  ( tabledesc.otable = a01_into_res_name )
        THEN
            _resid := cak_into_res_fid
        ELSE
            BEGIN
            a663_get_result_info( acv, tabledesc.otable,
                  acv.a_modul_name, pbasep, false, ttfnNone_egg00, d_release, _ok );
            IF  ( _ok )
            THEN
                _resid := pbasep^.sresname.restreeid.fileTempCnt_gg00;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  ( _ok )
        THEN
            BEGIN
            (* PTS 1118098 E.Z. *)
            IF  ( acv.a_recursive_state in [
                rs_check_select_list, rs_recursive_select, rs_last_select ] ) AND
                ( pbasep^.sresname.restreeid.fileTfn_gg00     = tfnTemp_egg00 ) AND
                ( pbasep^.sresname.restreeid.fileTfnTemp_gg00 = ttfnRecursive_egg00 )
            THEN
                BEGIN
                _mt.fparschar[1] := cak_tempinfo_byte;
                _mt.fcmd_count   := acv.a_curr_ex_parskey.p_count;
                _mt.ffill        := 0;
                _mt.ft1          := ttfnRecursive_egg00;
                _mt.fs_no1       := ord( rs_first_select );
                a663recurs_result_records( acv, dstate, _mt.tabid, pbasep, _ok );
                END
            ELSE
                a663get_result_records( acv, dstate, _resid, pbasep, _ok );
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        IF  ( tabledesc.oview OR ( tabledesc.ouser = a01_i_temp ) )
        THEN
            BEGIN
&           ifdef trace
            IF  tabledesc.oview
            THEN
                t01sname(ak_join, 'view table  ')
            ELSE
                t01sname(ak_join, 'user = temp ');
            (*ENDIF*) 
&           endif
            a06_systable_get( acv, dstate,
                  tabledesc.ofromtableid, pbasep, true, _ok );
            END
        ELSE
            BEGIN
            IF  ( tabledesc.otreeid.fileTfn_gg00 = tfnTemp_egg00 ) AND
                ( tabledesc.otreeid.fileTfnTemp_gg00 = ttfnGatewayResult_egg00 )
            THEN
                BEGIN
&               ifdef trace
                t01sname(ak_join, 'temp table  ');
&               endif
                a663get_result_records( acv, dstate,
                      tabledesc.otreeid.fileTempCnt_gg00, pbasep, _ok );
                END
            ELSE
                BEGIN
&               ifdef trace
                t01sname(ak_join, 'base table  ');
&               endif
                a06_systable_get( acv, dstate,
                      tabledesc.otreeid.fileTabId_gg00, pbasep, true, _ok );
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  ( NOT _ok )
THEN
    BEGIN
    IF  ( tabledesc.oview )
    THEN
        BEGIN
        a07_tb_put_error (acv, e_unknown_tablename, 1, tabledesc.ofromtableid);
        acv.a_error_tableid := tabledesc.ofromtableid;
        END
    ELSE
        BEGIN
        a07_tb_put_error (acv, e_unknown_tablename, 1,
              tabledesc.otreeid.fileTabId_gg00);
        acv.a_error_tableid := tabledesc.otreeid.fileTabId_gg00
        END;
    (*ENDIF*) 
    pbasep := NIL;
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak684out_filter_stack (
            VAR acv    : tak_all_command_glob;
            srcpos     : tsp00_Int4;
            srclen     : tsp00_Int4);
 
VAR
      _i       : tsp00_Int4;
      _srclen  : tsp00_Int4;
      _mreslen : tsp00_Int4;
 
BEGIN
(* write output filter if constant expression in part of *)
(* table which is filled with NULL values (OUTER JOIN)   *)
(* so that constant expression survive OUTER JOIN        *)
&ifdef trace
FOR _i := 1 TO srclen DO
    BEGIN
    t01stackentry( ak_join, acv.a_mblock.mb_st^[ srcpos + _i - 1 ], srcpos + _i - 1 );
    END;
(*ENDFOR*) 
&endif
IF  ( acv.a_mblock.mb_qual^.mresqual_pos = 0 )
THEN
    BEGIN
&   ifdef trace
    t01sname( ak_join, 'new mresqual' );
&   endif
    acv.a_mblock.mb_qual^.mresqual_pos := acv.a_mblock.mb_qual^.mfirst_free;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].etype := st_jump_output;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].eop   := op_none;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].epos  := 2;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].elen_var := 0;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].ecol_tab[1] := chr( 0 );
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].ecol_tab[2] := chr( 0 );
    acv.a_mblock.mb_qual^.mfirst_free  := succ( acv.a_mblock.mb_qual^.mfirst_free );
    acv.a_mblock.mb_qual^.mresqual_cnt := 1;
    _i      := acv.a_mblock.mb_qual^.mresqual_pos + 1;
    _srclen := srclen;
    IF  ( acv.a_mblock.mb_qual^.mfirst_free + srclen >=
        acv.a_mblock.mb_qual^.mst_max )
    THEN
        a07_b_put_error( acv, e_too_many_mb_stackentries, 1 );
    (*ENDIF*) 
    END
ELSE
    BEGIN
    IF  ( acv.a_mblock.mb_qual^.mfirst_free + srclen <
        acv.a_mblock.mb_qual^.mst_max )
    THEN
        BEGIN
&       ifdef trace
        t01name( ak_join, 'append outfilter  ' );
&       endif
        _srclen := srclen;
        IF  ( acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].etype = st_jump_output )
        THEN
            BEGIN
            _i := acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].epos +
                  acv.a_mblock.mb_qual^.mresqual_pos - 1;
            _srclen  := srclen;
            _mreslen := acv.a_mblock.mb_qual^.mfirst_free -
                  ( acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].epos +
                  acv.a_mblock.mb_qual^.mresqual_pos - 1 );
            END
        ELSE
            BEGIN
            _i       := acv.a_mblock.mb_qual^.mresqual_pos;
            _srclen  := succ( srclen );
            _mreslen := acv.a_mblock.mb_qual^.mresqual_cnt;
            END;
        (*ENDIF*) 
        ;
        (* move qualification stack entries following output stack entries *)
        SAPDB_PascalOverlappingMove ('VAK684',  11,    
              ( acv.a_mblock.mb_qual^.mst_max * STACK_ENTRY_MXGG00 ),
              acv.a_mblock.mb_st_size,
              @acv.a_mblock.mb_st^, ( _i - 1 ) * STACK_ENTRY_MXGG00 + 1,
              @acv.a_mblock.mb_st^,
              ( _i + _srclen - 1 ) * STACK_ENTRY_MXGG00 + 1,
              _mreslen * STACK_ENTRY_MXGG00, acv.a_returncode );
        IF  ( _srclen > srclen )
        THEN
            _i := succ( _i );
        (*ENDIF*) 
        END
    ELSE
        a07_b_put_error( acv, e_too_many_mb_stackentries, 1 );
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  ( acv.a_returncode = 0 )
THEN
    BEGIN
    SAPDB_PascalMove ('VAK684',  12,    
          ( acv.a_mblock.mb_qual^.mst_max * STACK_ENTRY_MXGG00 ),
          acv.a_mblock.mb_st_size,
          @acv.a_mblock.mb_st^, ( srcpos - 1 ) * STACK_ENTRY_MXGG00 + 1,
          @acv.a_mblock.mb_st^, ( _i - 1 ) * STACK_ENTRY_MXGG00 + 1,
          srclen * STACK_ENTRY_MXGG00, acv.a_returncode );
    IF  ( acv.a_returncode = 0 )
    THEN
        BEGIN
        (* update messblock *)
        acv.a_mblock.mb_qual^.mresqual_cnt  :=
              acv.a_mblock.mb_qual^.mresqual_cnt + _srclen;
        acv.a_mblock.mb_qual^.mfirst_free   :=
              acv.a_mblock.mb_qual^.mfirst_free + _srclen;
        (* set st_output stack entry *)
        acv.a_mblock.mb_st^[ _i + srclen - 1 ].epos :=
              acv.a_mblock.mb_st^[ srcpos + srclen - 1 ].ecol_pos;
        acv.a_mblock.mb_st^[ _i + srclen - 1 ].etype         := st_output;
        acv.a_mblock.mb_st^[ _i + srclen - 1 ].eop           := op_none;
        acv.a_mblock.mb_st^[ _i + srclen - 1 ].ecol_tab[ 1 ] := chr(0);
        acv.a_mblock.mb_st^[ _i + srclen - 1 ].ecol_tab[ 2 ] := chr(0);
        (* set epos of st_jump_out *)
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].epos  :=
              acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].epos + srclen;
        (* for kb741build_new_rec(), Join_JoinOperator::build_new_rec() *)
        (* we don't have complete output of record *)
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mresqual_pos ].ecol_pos := -1;
        END;
    (*ENDIF*) 
    ;
&   ifdef trace
    t01stackdesc (ak_join, 'ak684out_fil', acv.a_mblock.mb_st,
          acv.a_mblock.mb_qual^.mstack_desc);
&   endif
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a684update_strategy( VAR strat   : tgg07_StrategyInfo );
 
VAR
      _ix     : tsp00_Int2;
 
BEGIN
&ifdef trace
t01int4( ak_join, 'offset      ', strat.str_stack_output_offs );
&endif
IF  ( strat.str_stack_output_offs <> 0 )
THEN
    BEGIN
    IF  ( strat.str_strategy in [ strat_key_in, strat_key_subq ] )
    THEN
        BEGIN
        strat.str_key_in_range.skir_IN_SUBQ_stpos :=
              strat.str_key_in_range.skir_IN_SUBQ_stpos + strat.str_stack_output_offs;
        END
    ELSE
        BEGIN
        IF  ( strat.str_strategy in a70glob_inv_strats )
        THEN
            BEGIN
            FOR _ix := 0 TO strat.str_inv_in_range.siir_startcnt - 1 DO
                IF  ( strat.str_inv_in_range.siir_invstart[ _ix ] > 0 )
                THEN
                    strat.str_inv_in_range.siir_invstart[ _ix ] :=
                          strat.str_inv_in_range.siir_invstart[ _ix ] +
                          strat.str_stack_output_offs
                ELSE
                    strat.str_inv_in_range.siir_invstart[ _ix ] :=
                          strat.str_inv_in_range.siir_invstart[ _ix ] -
                          strat.str_stack_output_offs;
                (*ENDIF*) 
            (*ENDFOR*) 
            FOR _ix := 0 TO strat.str_inv_in_range.siir_stopcnt - 1 DO
                IF  ( strat.str_inv_in_range.siir_invstop[ _ix ] > 0 )
                THEN
                    strat.str_inv_in_range.siir_invstop[ _ix ] :=
                          strat.str_inv_in_range.siir_invstop[ _ix ] +
                          strat.str_stack_output_offs
                ELSE
                    strat.str_inv_in_range.siir_invstop[ _ix ] :=
                          strat.str_inv_in_range.siir_invstop[ _ix ] -
                          strat.str_stack_output_offs;
                (*ENDIF*) 
            (*ENDFOR*) 
            IF  strat.str_inv_in_range.siir_IN_SUBQ_stpos <> IS_UNDEFINED_GG07
            THEN
                strat.str_inv_in_range.siir_IN_SUBQ_stpos :=
                      strat.str_inv_in_range.siir_IN_SUBQ_stpos +
                      strat.str_stack_output_offs;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  NOT ( strat.str_strategy in
        [ strat_more_than_one, strat_join_viewkey, strat_viewkey,
        strat_catalog, strat_undecided ] )
    THEN
        FOR _ix := 0 TO MAX_COLPOSARR_IDX_GG07 DO
            BEGIN
            IF  ( strat.str_key_in_range.skir_keystart[ _ix ] <> 0 )
            THEN
                IF  ( strat.str_key_in_range.skir_keystart[ _ix ] > 0 )
                THEN
                    strat.str_key_in_range.skir_keystart[ _ix ] :=
                          strat.str_key_in_range.skir_keystart[ _ix ] +
                          strat.str_stack_output_offs
                ELSE
                    strat.str_key_in_range.skir_keystart[ _ix ] :=
                          strat.str_key_in_range.skir_keystart[ _ix ] -
                          strat.str_stack_output_offs;
                (*ENDIF*) 
            (*ENDIF*) 
            IF  ( strat.str_key_in_range.skir_keystop[ _ix ] <> 0 )
            THEN
                IF  ( strat.str_key_in_range.skir_keystop[ _ix ] > 0 )
                THEN
                    strat.str_key_in_range.skir_keystop[ _ix ] :=
                          strat.str_key_in_range.skir_keystop[ _ix ] +
                          strat.str_stack_output_offs
                ELSE
                    strat.str_key_in_range.skir_keystop[ _ix ] :=
                          strat.str_key_in_range.skir_keystop[ _ix ] -
                          strat.str_stack_output_offs;
                (*ENDIF*) 
            (*ENDIF*) 
            END;
        (*ENDFOR*) 
    (*ENDIF*) 
    strat.str_stack_output_offs := 0;
&   ifdef trace
    a725output_gg_strat( ak_join, 'upd strat   ', strat );
&   endif
    END
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
FUNCTION
      a684get_used_invlen(
            VAR acv    : tak_all_command_glob;
            VAR tabid  : tgg00_Surrogate;
            index_no   : tsp00_Int4;
            used_cols  : tsp00_Int2) : tsp00_Int4;
 
VAR
      _index_scan_rec   : tak_index_scan_record;
      _invlen           : tsp00_Int4;
      _i                : tsp00_Int2;
 
BEGIN
a24fnd_indexno( acv, tabid, index_no, _index_scan_rec );
IF  ( _index_scan_rec.isr_buf <> NIL )
THEN
    BEGIN
    _invlen := 0;
    FOR _i := 1 TO used_cols DO
        BEGIN
        _invlen := _invlen + _index_scan_rec.isr_buf^.smindex.
              indexdef[ _index_scan_rec.isr_index ].
              icolstack[ _i ].elen_var;
        END;
    (*ENDFOR*) 
&   ifdef trace
    t01int4 (ak_join, 'inv def len ', _invlen);
&   endif
    END
ELSE
    BEGIN
    a07ak_system_error( acv, 684, 2 );
    _invlen := IS_UNDEFINED_GG07;
    END;
(*ENDIF*) 
a684get_used_invlen := _invlen;
END;
 
(*------------------------------*) 
 
PROCEDURE
      a684set_filehandling(
            VAR acv    : tak_all_command_glob;
            VAR dmli   : tak_dml_info);
 
BEGIN
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
        BEGIN
        acv.a_mblock.mb_qual^.mtree.fileHandling_gg00 :=
              acv.a_mblock.mb_qual^.mtree.fileHandling_gg00 -
              [ hsPermLock_egg00 ];
        IF  ( NOT ( 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 +
                  [ hsWithoutLock_egg00 ];
        (*ENDIF*) 
        END
    ELSE
        acv.a_mblock.mb_qual^.mtree.fileHandling_gg00 :=
              acv.a_mblock.mb_qual^.mtree.fileHandling_gg00 -
              [ hsTempLock_egg00 ];
    (*ENDIF*) 
(*ENDIF*) 
END;
 
.CM *-END-* code---------------
.SP 2 
***********************************************************
.PA 
