.nf
 
 
    ========== licence begin  GPL
    Copyright (c) 1999-2004 SAP AG
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end
 
.fo
*****************************************************
Copyright (c) 1999-2004 SAP AG
SAP Database Technology
 
Release :      Date : 2000-11-22
*****************************************************
modname : VAK690
changed : 2000-11-22
module  : Join2_Select
 
Author  : GertG
Created : 2004-06-01
*****************************************************
 
Purpose : This module completes the Join messbuffers that have
          been half-built by VAK680
 
Define  :
 
        PROCEDURE
              a690_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  : tak70_strat_rec;
                    VAR jvrec               : tak68_joinview_rec;
                    VAR cost_infos          : tak68_evaluation_records);
 
.CM *-END-* define --------------------------------------
Use     :
 
        FROM
              Scanner : VAK01;
 
        VAR
              a01_il_b_identifier    : tsp00_KnlIdentifier;
              a01join_hash_min_ratio : tsp00_Int4;
              a01join_parall_minsize : tsp00_Int4;
              a01use_join_hashtable  : boolean;
 
      ------------------------------ 
 
        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);
 
      ------------------------------ 
 
        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);
 
      ------------------------------ 
 
        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);
 
        PROCEDURE
              a10rel_sysinfo (syspointer : tak_sysbufferaddress);
 
      ------------------------------ 
 
        FROM
              SQLManager : VAK101;
 
        FUNCTION
              a101_GetMaxJoinHashTableSize : tsp00_Int4;
 
      ------------------------------ 
 
        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  : tak70_page_eval_rec;
                    VAR gg_strategy: tgg07_StrategyInfo;
                    VAR strat_len  : tsp00_Int2);
 
      ------------------------------ 
 
        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
              AK_universal_show_tools : VAK40;
 
        PROCEDURE
              a40add_explain_record (
                    VAR acv  : tak_all_command_glob;
                    VAR expl : tak70_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_Select_Expression : VAK660;
 
        PROCEDURE
              a660build_view_treeid (
                    VAR acv     : tak_all_command_glob;
                    VAR tableid : tgg00_Surrogate;
                    VAR tree    : tgg00_FileId);
 
      ------------------------------ 
 
        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    : tak70_page_eval_rec;
                    config           : tak00_access_configuration);
 
      ------------------------------ 
 
        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
              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);
 
        PROCEDURE
              a683trace_joininfo (
                    debug       : tgg00_Debug;
                    VAR joins   : tak_joinrec;
                    VAR joininfo: tak68_join);
 
        PROCEDURE
              a683trace_outdesc (
                    debug       : tgg00_Debug;
                    VAR outdesc : tak68_output_desc);
&       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
              Configuration_Parameter : VGG01;
 
        VAR
              gg01_operator_join_sort : boolean;
 
      ------------------------------ 
 
        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
              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);
 
      ------------------------------ 
 
        FROM
              GG_allocator_interface : VGG941;
 
        FUNCTION
              gg941Allocate(
                    VAR TransContext : tgg00_TransContext;
                    wantedBytes      : integer) : tsp00_Addr;
 
        PROCEDURE
              gg941Deallocate(
                    VAR TransContext : tgg00_TransContext;
                    VAR p            : tsp00_Addr);
 
        FUNCTION
              gg941ReAllocate(
                    VAR TransContext : tgg00_TransContext;
                    wantedBytes      : integer;
                    hint             : tsp00_Addr) : tsp00_Addr;
 
      ------------------------------ 
 
        FROM
              RTE-Extension-20 : VSP20;
 
        FUNCTION
              s20or4b (
                    VAR source    : tsp00_MoveObj;
                    source_pos    : tsp00_Int4) : tsp00_Int4;
&       ifdef TRACE
 
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        PROCEDURE
              t01messblock (
                    debug         : tgg00_Debug;
                    nam           : tsp00_Sname;
                    VAR m         : tgg00_MessBlock);
 
        PROCEDURE
              t01real (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    r        : tsp00_Longreal;
                    digits   : integer);
 
        PROCEDURE
              t01addr (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    bufaddr  : tsp00_Addr);
 
        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);
 
      ------------------------------ 
 
        FROM
              Join2_Select: VAK684;
 
        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 );
 
      ------------------------------ 
 
        FROM
              Single_Select : VKB720;
 
        PROCEDURE
              k720_maxresult_get (
                    VAR data           : tsp00_MoveObj;
                    strat_maxcnt       : tsp00_Int2;
                    VAR maxresult      : tsp00_Int4;
                    VAR b_err          : tgg00_BasisError);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_1 : VBD01;
 
        VAR
              b01niltree_id : tgg00_FileId;
 
.CM *-END-* use -----------------------------------------
Synonym :
 
.CM *-END-* synonym -------------------------------------
***********************************************************
Specification:
 
.CM *-END-* specification -------------------------------
***********************************************************
Description:
 
.CM *-END-* description ---------------------------------
***********************************************************
.CM -lll-
Code    :
 
 
CONST
      c_in_key           = true (* ak690join_columns_stack *);
 
 
(*------------------------------*) 
 
PROCEDURE
      a690_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  : tak70_strat_rec;
            VAR jvrec               : tak68_joinview_rec;
            VAR cost_infos          : tak68_evaluation_records);
 
VAR
      _stackout        : tsp00_Int4;
      _old_return      : tsp00_Int2;
      _jcontext        : tak68_join_context;
 
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);
&endif
_old_return := acv.a_returncode;
;
_jcontext.jc_act_join := 1;
_jcontext.jc_parskey := jinfos.ji_parskey;
_jcontext.jc_left_side := [ series[ 1 ].jos_source ];
_jcontext.jc_st_addr   := jinfos.ji_st_addr;
_jcontext.jc_stack_desc:= jinfos.ji_stack_desc;
_jcontext.jc_mb_data_len:= jinfos.ji_mb_data_len;
_jcontext.jc_tempresult := false;
_stackout := 1;
IF  ( _jcontext.jc_st_addr^[ _jcontext.jc_stack_desc.mqual_pos ].
    etype = st_jump_output )
THEN
    _stackout :=
          _jcontext.jc_st_addr^[ _jcontext.jc_stack_desc.mqual_pos ].epos - 2;
(*ENDIF*) 
;
ak690init_outdesc( acv, _jcontext.jc_outdesc, _stackout );
(* loop for each join step *)
WHILE (( _jcontext.jc_act_join <= dmli.d_cntfromtab ) AND
      ( acv.a_returncode = 0 )) DO
    BEGIN
&   ifdef trace
    a683joinset_trace (ak_join, 'left side   ', dmli, _jcontext.jc_left_side);
&   endif
    ak690generate_join_info( acv, dmli, _jcontext, series,
          res_tree, ak_strat_interface, jvrec, cost_infos );
&   ifdef trace
    t01int4 (ak_join, 'JOIN STEP   ', _jcontext.jc_act_join);
    t01qual1 (ak_join, 'i.th messbuf', acv.a_mblock.mb_qual^);
    a683_output( ak_join, dmli );
&   endif
    ;
    _jcontext.jc_left_side := _jcontext.jc_left_side +
          [ series[ _jcontext.jc_act_join ].jos_source ];
    _jcontext.jc_act_join := succ (_jcontext.jc_act_join);
    END;
(*ENDWHILE*) 
ak690finalize_outdesc( acv, _jcontext.jc_outdesc );
;
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*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak690generate_join_info (
            VAR acv                 : tak_all_command_glob;
            VAR dmli                : tak_dml_info;
            VAR jcontext            : tak68_join_context;
            VAR series              : tak68_sequence;
            VAR res_tree            : tgg00_FileId;
            VAR ak_strat_interface  : tak70_strat_rec;
            VAR jvrec               : tak68_joinview_rec;
            VAR cost_infos          : tak68_evaluation_records);
 
CONST
      c_max_rescnt_percent = 0.01;
 
VAR
      _rescnt             : tsp00_Int4;
      _e                  : tgg00_BasisError;
      _tabtree            : tgg00_FileId;
      _ke                 : tgg00_SysInfoKey;
      _joinp              : tak_sysbufferaddress;
      _aux_addr           : tgg00_StackListPtr;
      _i                  : tsp00_Int2;
 
BEGIN
jcontext.jc_acttabno             := series[ jcontext.jc_act_join ].jos_source;
jcontext.jc_outpos               := cgg_rec_key_offset + 1;
jcontext.jc_sortkeylen           := 0;
(* assure special case "select ... from <outer-join> where <locale predicate>" *)
jcontext.jc_joininfo.jn_leftoj   :=
      dmli.d_outer_join AND ( jcontext.jc_acttabno in dmli.d_oj_tables );
jcontext.jc_joininfo.jn_rightoj  :=
      dmli.d_outer_join AND ( dmli.d_cntfromtab = 2 ) AND
      ( jcontext.jc_act_join = 2 ) AND
      (( jcontext.jc_left_side - dmli.d_oj_tables ) <> jcontext.jc_left_side );
jcontext.jc_joininfo.jn_jarr_cnt := 0;
jcontext.jc_joininfo.jn_jarr_path:= 0;
;
IF  ( dmli.d_tabarr[ jcontext.jc_acttabno ].ocomplex_view )
THEN
    a660build_view_treeid( acv,
          dmli.d_tabarr[ jcontext.jc_acttabno ].ofromtableid, _tabtree )
ELSE
    _tabtree := dmli.d_tabarr[ jcontext.jc_acttabno ].otreeid;
(*ENDIF*) 
_aux_addr := acv.a_mblock.mb_st;
IF  ( jcontext.jc_act_join < dmli.d_cntfromtab )
THEN
    BEGIN
    IF  ( jcontext.jc_act_join = 1 )
    THEN
        a06a_mblock_init (acv, m_select, mm_first_operator_join, _tabtree)
    ELSE
        a06a_mblock_init (acv, m_select, mm_operator_join, _tabtree);
    (*ENDIF*) 
    jcontext.jc_nxttabno := series[ jcontext.jc_act_join + 1 ].jos_source;
    END
ELSE
    (* jc_act_join = dmli.d_cntfromtab *)
    BEGIN
    a06a_mblock_init (acv, m_select, mm_last_operator_join, _tabtree);
    jcontext.jc_nxttabno := jcontext.jc_acttabno;
    END;
(*ENDIF*) 
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          := jcontext.jc_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;
;
&IFDEF TRACE
t01p2int4 (ak_join, 'JOIN STEP   ', jcontext.jc_act_join,
      'i.th tab    ', jcontext.jc_acttabno);
&ENDIF
IF  ( dmli.d_joins.jrc_cnt > 0 )
THEN
    (* there is a real join *)
    BEGIN
    (* 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>*)
    ak690join_columns_stack (acv, dmli, jcontext, series, c_in_key );
    END;
(*ENDIF*) 
;
&ifdef trace
t01int4 (ak_join, 'jc_outpos   ', jcontext.jc_outpos);
&endif
IF  (( dmli.d_joins.jrc_cnt > 0 ) AND ( acv.a_returncode = 0 )
    AND ( jcontext.jc_act_join < dmli.d_cntfromtab ))
THEN
    BEGIN
    (* prepare stack for further joins, these columns *)
    (* are non key of <i.th tab> record               *)
    ak690join_columns_stack (acv, dmli, jcontext, series, NOT c_in_key );
    END;
(*ENDIF*) 
;
(* get output fields for actual table <i.th tab> *)
ak690output_columns_stack (acv, dmli, jcontext);
IF  ( jcontext.jc_joininfo.jn_rightoj )
THEN
    (* we need key to idendifiy one record for auxiliary RIGHT OUTER JOIN file *)
    ak690roj_key_stack( acv, dmli, jcontext )
ELSE
    BEGIN
    IF  (( jcontext.jc_joininfo.jn_jarr_path = 0 ) AND
        ( jcontext.jc_act_join > 1 ) AND gg01_operator_join_sort )
    THEN
        BEGIN
        _e := e_ok;
        k720_maxresult_get( acv.a_mblock.mb_data^.mbp_buf,
              dmli.d_rowno, _rescnt, _e );
&       ifdef trace
        t01int4 (ak_join, '_rescnt     ', _rescnt);
        t01int4 (ak_join, 'all recs    ',
              series[ jcontext.jc_act_join ].jos_expected_table_rec_reads );
        IF  (series[ jcontext.jc_act_join ].jos_expected_table_rec_reads <> 0)
        THEN
            t01real( ak_join, 'precent     ',
                  _rescnt / series[ jcontext.jc_act_join ].jos_expected_table_rec_reads, 6 );
&       endif
        (*ENDIF*) 
        IF  ( _e = e_ok )
        THEN
            BEGIN
            IF  ( _rescnt = csp_maxint4 )
                (* no ROWNO specification *)
                OR
                (* huge amount of recs *)
                ( series[ jcontext.jc_act_join ].
                jos_expected_table_rec_reads = 0 )
                OR
                ( _rescnt / series[ jcontext.jc_act_join ].jos_expected_table_rec_reads
                > c_max_rescnt_percent )
            THEN
                BEGIN
                (* output key to enable sorting due to missing join transition *)
                ak690sort_key_stack( acv, dmli, series,
                      jcontext, series[ jcontext.jc_act_join ] );
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*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_returncode = 0 )
THEN
    BEGIN
    (* get seperated messblock for one table *)
    a682join_parsinfo_key( acv, dmli, jcontext.jc_parskey, jvrec.jv_tabid,
          jcontext.jc_acttabno, _ke );
    a10get_sysinfo( acv, _ke, d_fix, _joinp, _e );
    IF  ( _e <> e_ok )
    THEN
        a07_b_put_error( acv, _e, 1 )
    ELSE
        ak690qualification_stack( acv, _joinp );
    (*ENDIF*) 
    END;
(*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  (jcontext.jc_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*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
;
IF  (acv.a_returncode = 0)
THEN
    ak690write_strat_info( acv, dmli, jcontext, res_tree,
          _joinp, series, ak_strat_interface,
          cost_infos[ jcontext.jc_acttabno ].ev_inv_only );
(*ENDIF*) 
;
IF  ( acv.a_returncode = 0 ) AND ( jcontext.jc_act_join = dmli.d_cntfromtab )
THEN
    BEGIN
    (* write result qualification in last messblock *)
    IF  ( jcontext.jc_stack_desc.mresqual_cnt > 0 )
    THEN
        BEGIN
        IF  ( acv.a_mblock.mb_qual^.mfirst_free +
            jcontext.jc_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 ('VAK690',   1,    
                  (jcontext.jc_stack_desc.mst_max * STACK_ENTRY_MXGG00),
                  acv.a_mblock.mb_st_size,
                  @jcontext.jc_st_addr^,
                  (jcontext.jc_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,
                  jcontext.jc_stack_desc.mresqual_cnt * STACK_ENTRY_MXGG00,
                  acv.a_returncode);
            ;
            (* update messblock *)
            acv.a_mblock.mb_qual^.mresqual_cnt := jcontext.jc_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 +
                  jcontext.jc_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*) 
    END;
(*ENDIF*) 
;
IF  ( acv.a_returncode = 0 )
THEN
    BEGIN
    _ke := _joinp^.syskey;
    (* release old messblock *)
    a10rel_sysinfo( _joinp );
    (* don't calculate optimize info *)
    a682_mbuf_to_tmpbuf( acv, _ke, _e, mtc_generate_join_info_operator_join );
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak690join_columns_stack (
            VAR acv             : tak_all_command_glob;
            VAR dmli            : tak_dml_info;
            VAR jcontext        : tak68_join_context;
            VAR series          : tak68_sequence;
            cols_for_next_join  : boolean);
 
VAR
      _i                : tsp00_Int2;
      _jarr_side        : tsp00_Int2; (* side with acttabno, i.e. act. dest *)
      _jarr_oside       : tsp00_Int2;
      _jk_field_cnt     : tsp00_Int2;
      _needed_value     : boolean;
      _needed_from_base : boolean; (* needed from base for i.th join *)
&     ifdef trace
      _colstack         : boolean;
&     endif
 
BEGIN
(**)
(* 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[ jcontext.jc_act_join ].jos_joinstrat in a70glob_join_strats )
THEN
    _jk_field_cnt := series[ jcontext.jc_act_join ].jos_fieldcnt
ELSE
    (* no join transition                           *)
    _jk_field_cnt := 0;
(*ENDIF*) 
&IFDEF TRACE
t01p2int4 (ak_join, 'JOIN STEP   ', jcontext.jc_act_join,
      'i.th tab    ', jcontext.jc_acttabno);
t01bool (ak_join, 'build key   ', cols_for_next_join);
t01int4 (ak_join, 'next tabno  ', jcontext.jc_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 =
              jcontext.jc_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
              (
              ((jcontext.jc_act_join = 1) AND cols_for_next_join)
              (* needed in 1. join step for key building *)
              (* <1st tab> = <value> *)
              OR
              ((jcontext.jc_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
        IF  ( _jarr_side = 1 )
        THEN
            BEGIN
            t01int4 (ak_join, '_i          ', _i );
            a683_one_join_entry_ex( ak_join, dmli, _i, false );
            END;
        (*ENDIF*) 
        t01bool (ak_join, 'needed value', _needed_value);
&       endif
        IF  (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _jarr_side ].jop_tableno =
            jcontext.jc_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
                  jcontext.jc_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 =
                  jcontext.jc_nxttabno) AND ( jcontext.jc_act_join = 1))
                  (* special cases for 1. join step *)
                  (* <1st tab> = <2nd tab> *)
                  OR
                  (_needed_value AND (jcontext.jc_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  ( _needed_value )
                THEN
                    _jarr_side := 2; (* jo_recs site with cak68_join_value *)
                (*ENDIF*) 
                ;
                (* create stack entry for base table access *)
                ak690one_join_column (acv, dmli, jcontext,
                      cols_for_next_join, _i,
                      (_jk_field_cnt > 0), _jarr_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, '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
      ak690one_join_column (
            VAR acv             : tak_all_command_glob;
            VAR dmli            : tak_dml_info;
            VAR jcontext        : tak68_join_context;
            cols_for_next_join  : boolean;
            currj               : tsp00_Int4;
            join_accesspath     : boolean;
            dsttab_side         : tsp00_Int4);
 
VAR
      _dstpos       : tsp00_Int2;
      _i            : 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) dsttab_side = 2 !!  *)
(* otherwise dsttab_side is side with jc_acttabno (i.th tab = ...)          *)
(* i.e.                                                                     *)
(* dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ dsttab_side ].jop_tableno =   *)
(* <i.th tab>                                                               *)
(* or                                                                       *)
(* dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ dsttab_side=2 ].jop_tableno=  *)
(* <value>                                                                  *)
&ifdef trace
t01p2int4 (ak_join, 'JOIN STEP   ', jcontext.jc_act_join,
      'i.th tab    ', jcontext.jc_acttabno);
&endif
IF  ( acv.a_mblock.mb_qual^.mfirst_free +
    dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ dsttab_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 ('VAK690',   2,    
          (jcontext.jc_stack_desc.mst_max * STACK_ENTRY_MXGG00),
          acv.a_mblock.mb_st_size,
          (* source *)
          @jcontext.jc_st_addr^,
          (* source pos *)
          (dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ dsttab_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[ dsttab_side ].jop_cntstack * STACK_ENTRY_MXGG00,
          acv.a_returncode);
&   ifdef trace
    t01bool (ak_join, 'join_accessp', join_accesspath);
    t01int4 (ak_join, 'dsttab_side ', dsttab_side );
    t01name(ak_join, 'orig jcol-> new mb');
    FOR _i := 0 TO dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ dsttab_side ].
          jop_cntstack - 1 DO
        BEGIN
        t01stackentry (ak_join,
              jcontext.jc_st_addr^[ dmli.d_joins.jrc_joinarr[ currj ].
              jo_recs[ dsttab_side ].jop_startstack + _i ],
              dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ dsttab_side ].jop_startstack + _i);
        END;
    (*ENDFOR*) 
&   endif
    (* 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[ dsttab_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[ dsttab_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
        BEGIN
        (* delete join condition *)
        (* preserve function calls *)
        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     := jcontext.jc_outpos;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
          elen_var := dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ dsttab_side ].
          jop_inoutlen;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
          eop_out := op_o_none;
    (* mark position of output column of output table *)
    dmli.d_joins.jrc_joinarr[ currj ].jo_recs[ dsttab_side ].
          jop_outpos := jcontext.jc_outpos;
    jcontext.jc_outpos := jcontext.jc_outpos + dmli.d_joins.jrc_joinarr[ currj ].
          jo_recs[ dsttab_side ].jop_inoutlen;
    ;
    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 (jcontext.jc_acttabno);
&       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
        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  ( jcontext.jc_act_join > 1 )
        THEN
            BEGIN
            (* write join information for joining with jc_acttabno ^*)
            ak690update_joininfo( acv, dmli.d_joins, jcontext,
                  currj, join_accesspath, dsttab_side );
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    ;
&   ifdef trace
    t01p2int4 (ak_join, 'jc_outpos   ', jcontext.jc_outpos,
          'jop_inoutlen', dmli.d_joins.jrc_joinarr[ currj ].
          jo_recs[ dsttab_side ].jop_inoutlen);
&   endif
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak690write_strat_info (
            VAR acv                 : tak_all_command_glob;
            VAR dmli                : tak_dml_info;
            VAR jcontext            : tak68_join_context;
            VAR res_tree            : tgg00_FileId;
            VAR joinp               : tak_sysbufferaddress;
            VAR series              : tak68_sequence;
            VAR ak_strat_interface  : tak70_strat_rec;
            get_new_strat           : boolean);
 
VAR
      _strat_len            : tsp00_Int2;
      _strat_pos            : tsp00_Int2;
      _strat_num            : tsp00_Int2;
      _StratInfo_len        : tsp00_Int2;
      _onetab_StratInfo_len : tsp00_Int2;
      _i                    : tsp00_Int2;
      _movelen              : tsp00_Int2;
      _expl                 : tak70_explain_rec;
      _bw                   : tak70_page_eval_rec;
      _onetab_strat         : tgg07_StrategyInfo;
      _join_strat           : tgg07_StrategyInfo;
      _page_eval_info       : tak70_page_eval_rec;
      _config               : tak00_access_configuration;
 
      _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   ', jcontext.jc_act_join,
      'i.th tab    ', jcontext.jc_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[ jcontext.jc_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( _onetab_strat );
    _onetab_strat.str_ordering  := ( dmli.d_distinct <> no_distinct );
    _onetab_strat.str_rec_len   := jcontext.jc_outpos - 1;
    _onetab_strat.str_key_len   := jcontext.jc_sortkeylen;
    _onetab_strat.str_all_files := ( acv.a_recursive_state = rs_last_select );
    _onetab_strat.str_strategy  := strat_undecided;
    IF  dmli.d_acttabindex <> jcontext.jc_acttabno
    THEN
        a61_rel_old_table (acv, dmli, jcontext.jc_acttabno);
    (*ENDIF*) 
    a80get_access_for_join_hint( acv, jcontext.jc_parskey,
          jcontext.jc_acttabno, _config );
    _onetab_strat.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, _onetab_strat, _StratInfo_len,
          _page_eval_info, _config );
    ;
    g09StratStackentry( acv.a_mblock.mb_qual^.
          mst_addr^[ acv.a_mblock.mb_qual^.mstrat_pos ], 1, _StratInfo_len);
    _movelen := _StratInfo_len;
    IF  ( _onetab_strat.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_StratInfo_len := _StratInfo_len;
    _join_strat           := _onetab_strat;
    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 (_onetab_strat) )
    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 ('VAK690',   3,    
          joinp^.smessblock.mbr_mess_block.mb_strat_size,
          sizeof( _onetab_strat ),
          @joinp^.smessblock.mbr_mess_block.mb_strat^, 1,
          @_onetab_strat, 1, _movelen,
          acv.a_returncode);
    IF  ( _onetab_strat.str_strategy = strat_more_than_one )
    THEN
        BEGIN
&       ifdef trace
        t01sname( ak_join, 'OR strategy ' );
&       endif
        _movelen := STRATEGY_START_MXGG07;
        END;
    (*ENDIF*) 
    ;
    (* remember stack move size for correct       *)
    (* stack positions of internal stack pointers *)
    _onetab_strat.str_stack_output_offs :=
          _onetab_strat.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);
    _onetab_strat.str_rec_len := jcontext.jc_outpos - 1;
    _onetab_strat.str_key_len := jcontext.jc_sortkeylen;
    IF  ( _onetab_strat.str_strategy = strat_more_than_one )
    THEN
        BEGIN (* PTS 1122378 *)
        _strat_num := 1;
        _strat_pos := 1 + STRATEGY_START_MXGG07;
&       ifdef trace
        SAPDB_PascalMove ('VAK690',   4,    
              sizeof(_onetab_strat), sizeof(_join_strat),
              @_onetab_strat, 1, @_join_strat, 1,
              STRATEGY_START_MXGG07, acv.a_returncode);
&       endif
        WHILE ( _strat_num <= _onetab_strat.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 ('VAK690',   5,    
                  joinp^.smessblock.mbr_mess_block.mb_strat_size,
                  sizeof( _join_strat ),
                  @joinp^.smessblock.mbr_mess_block.mb_strat^,
                  _strat_pos + cgg07_stratpos_offs,
                  @_join_strat, STRATEGY_START_MXGG07 + 1,
                  _strat_len, acv.a_returncode);
            _join_strat.str_strategy          := _str.strat_enum;
            _join_strat.str_stack_output_offs := _onetab_strat.str_stack_output_offs;
            a684update_strategy( _join_strat );
            SAPDB_PascalMove ('VAK690',   6,    
                  sizeof(_join_strat),
                  joinp^.smessblock.mbr_mess_block.mb_strat_size,
                  @_join_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( _onetab_strat );
    (*ENDIF*) 
    ;
    (* update strategy in seperated messblock *)
    SAPDB_PascalMove ('VAK690',   7,    
          sizeof( _onetab_strat ),
          joinp^.smessblock.mbr_mess_block.mb_strat_size,
          @_onetab_strat, 1,
          @joinp^.smessblock.mbr_mess_block.mb_strat^, 1,
          _movelen,
          acv.a_returncode);
    _onetab_StratInfo_len := _StratInfo_len;
    _join_strat           := _onetab_strat;
    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
    (jcontext.jc_act_join > 1)
    AND
    (series[ jcontext.jc_act_join ].jos_joinstrat in a70glob_join_key_strats)
    AND
    (NOT jcontext.jc_joininfo.jn_rightoj)
    AND
    ((series[ jcontext.jc_act_join ].jos_expected_table_rec_reads
    * _join_strat.str_rec_len) < a101_GetMaxJoinHashTableSize)
    AND
    (series[ jcontext.jc_act_join ].jos_expected_table_rec_reads <> 0)
    AND
    (series[ jcontext.jc_act_join-1 ].jos_expected_table_rec_reads
    / (series[ jcontext.jc_act_join ].jos_expected_table_rec_reads)
    > a01join_hash_min_ratio)
    AND
    NOT ( strmod_sorted in series[ jcontext.jc_act_join ].jos_access_mod )
THEN
    BEGIN
&   ifdef trace
    t01name(ak_join, 'hash join enabled ');
    t01int4 (ak_join, 'exp size    ',
          series[ jcontext.jc_act_join ].jos_expected_table_rec_reads
          * _join_strat.str_rec_len);
&   endif
    series[ jcontext.jc_act_join ].jos_access_mod :=
          series[ jcontext.jc_act_join ].jos_access_mod + [ strmod_hash ];
    END;
(*ENDIF*) 
IF  ( series[ jcontext.jc_act_join ].jos_parallel_server > 0 )
    AND
    (series[ jcontext.jc_act_join ].jos_joinstrat in
    [ strat_join_inv, strat_join_all_inv_equal ])
    AND
    (series[ jcontext.jc_act_join ].jos_expected_table_rec_reads
    > a01join_parall_minsize)
THEN
    BEGIN
&   ifdef trace
    t01name(ak_join, 'parallel inv acc. ');
&   endif
    series[ jcontext.jc_act_join ].jos_access_mod :=
          series[ jcontext.jc_act_join ].jos_access_mod + [ strmod_parallel ];
    END;
(*ENDIF*) 
;
IF  ( acv.a_returncode = 0 )
THEN
    BEGIN
    _join_strat.str_access_mod :=
          series[ jcontext.jc_act_join ].jos_access_mod; (* PTS 1127791 M.Ki. *)
    IF  ( _join_strat.str_strategy = strat_catalog )
    THEN
        BEGIN
        (* strategy must be determined again due to *)
        (* changes of the message buffer            *)
        a61_rel_old_table( acv, dmli, jcontext.jc_acttabno );
        a722strategy( acv, dmli, _bw, _join_strat, _StratInfo_len );
        END;
    (*ENDIF*) 
    IF  ( acv.a_mblock.mb_qual^.msubquery )
    THEN
        _join_strat.str_rowno := cgg04_at_least_one_record;
    (*ENDIF*) 
    ;
    (* PTS 1112079 E.Z. *)
    _join_strat.str_search_first := true;
    IF  ( dmli.d_view )
    THEN
        BEGIN
        _join_strat.str_access_mod := [];
        _join_strat.str_cnt_strat  := 1;
        IF  ( jcontext.jc_act_join = 1 )
        THEN
            _join_strat.str_strategy := strat_viewkey
        ELSE
            _join_strat.str_strategy := strat_join_viewkey;
        (*ENDIF*) 
        _StratInfo_len := STRATEGY_START_MXGG07 +
              sizeof(_join_strat.str_key_in_range);
        END
    ELSE
        BEGIN
        IF  ( series[ jcontext.jc_act_join ].jos_joinstrat in a70glob_join_strats )
        THEN
            (* we have a join strategy *)
            BEGIN
            _join_strat.str_join_multfields.sjmf_filler := 0;
            _join_strat.str_cnt_strat := 1;
            (* ! leave sjmf_keystart/stop as in _onetab_strat ! *)
            _join_strat.str_strategy := series[ jcontext.jc_act_join ].jos_joinstrat;
            CASE _join_strat.str_strategy OF
                strat_join_inv :
                    BEGIN
                    _StratInfo_len := STRATEGY_START_MXGG07 +
                          sizeof(_join_strat.str_join_multfields);
                    _join_strat.str_join_multfields.sjmf_index_no  :=
                          series[ jcontext.jc_act_join ].jos_indexno;
                    _join_strat.str_join_multfields.sjmf_invroot   :=
                          NIL_PAGE_NO_GG00;
                    _join_strat.str_join_multfields.sjmf_cntfields := 1;
                    _join_strat.str_join_multfields.sjmf_invlen    :=
                          a684get_used_invlen( acv,
                          dmli.d_tabarr[ series[ jcontext.jc_act_join ].jos_source ].
                          otreeid.fileTabId_gg00,
                          series[ jcontext.jc_act_join ].jos_indexno,
                          series[ jcontext.jc_act_join ].jos_fieldcnt );
                    series[ jcontext.jc_act_join ].jos_invlen :=
                          _join_strat.str_join_multfields.sjmf_invlen;
                    END;
                strat_join_all_inv_equal,
                strat_join_inv_range :
                    BEGIN
                    _join_strat.str_join_multfields.sjmf_cntfields :=
                          series[ jcontext.jc_act_join ].jos_fieldcnt;
                    _join_strat.str_join_multfields.sjmf_index_no  :=
                          series[ jcontext.jc_act_join ].jos_indexno;
                    _join_strat.str_join_multfields.sjmf_invroot   :=
                          NIL_PAGE_NO_GG00;
                    _join_strat.str_join_multfields.sjmf_invlen    :=
                          a684get_used_invlen( acv,
                          dmli.d_tabarr[ series[ jcontext.jc_act_join ].jos_source ].
                          otreeid.fileTabId_gg00,
                          series[ jcontext.jc_act_join ].jos_indexno,
                          series[ jcontext.jc_act_join ].jos_fieldcnt );
                    series[ jcontext.jc_act_join ].jos_invlen :=
                          _join_strat.str_join_multfields.sjmf_invlen;
                    _StratInfo_len := STRATEGY_START_MXGG07 +
                          sizeof(_join_strat.str_join_multfields);
                    END;
                strat_join_all_keys_equal,
                strat_join_key_range,
                strat_join_key_equal,
                strat_join_key_next :
                    BEGIN
                    _join_strat.str_join_multfields.sjmf_cntfields :=
                          series[ jcontext.jc_act_join ].jos_fieldcnt;
                    _join_strat.str_join_multfields.sjmf_index_no  := 1;
                    _join_strat.str_join_multfields.sjmf_invroot   :=
                          NIL_PAGE_NO_GG00;
                    _join_strat.str_join_multfields.sjmf_invlen    :=
                          IS_UNDEFINED_GG07;
                    _StratInfo_len := STRATEGY_START_MXGG07 +
                          sizeof(_join_strat.str_join_multfields);
                    END;
                OTHERWISE
                    BEGIN
                    _StratInfo_len := STRATEGY_START_MXGG07 +
                          sizeof(_join_strat.str_join_multfields)
                    END;
                END;
            (*ENDCASE*) 
            END
        ELSE
            BEGIN
            series[ jcontext.jc_act_join ].jos_joinstrat := _join_strat.str_strategy;
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( jcontext.jc_act_join = dmli.d_cntfromtab )
    THEN
        BEGIN
        _join_strat.str_use_rowno := ak_strat_interface.sr_use_rowno;
        _join_strat.str_distinc   := dmli.d_distinct;
        _join_strat.str_ordering  := ak_strat_interface.sr_distinct_bytes;
        END
    ELSE
        BEGIN
        _join_strat.str_use_rowno := false;
        _join_strat.str_distinc   := no_distinct;
        _join_strat.str_ordering  := false;
        END;
    (*ENDIF*) 
    _join_strat.str_key_len := 0;
    _join_strat.str_rec_len := jcontext.jc_outpos - 1;
    IF  ( _join_strat.str_strategy = strat_more_than_one )
    THEN
        BEGIN
        (* we have to use Join_LegacyAccessOperator *)
        (* which build result set                   *)
        _join_strat.str_key_len   := RESCNT_MXGG04;
        _onetab_strat.str_key_len := RESCNT_MXGG04;
        _join_strat.str_rec_len   := _join_strat.str_rec_len + RESCNT_MXGG04;
        _onetab_strat.str_rec_len := _onetab_strat.str_rec_len + RESCNT_MXGG04;
        ak690adjust_info_for_key_insert( acv, dmli, jcontext, series,
              cgg_rec_key_offset, RESCNT_MXGG04 );
        END;
    (*ENDIF*) 
    IF  ( jcontext.jc_act_join = dmli.d_cntfromtab )
    THEN
        BEGIN
        IF  ( dmli.d_single AND NOT dmli.d_view )
        THEN
            _join_strat.str_selinto := true;
        (*ENDIF*) 
        _join_strat.str_rowno := dmli.d_rowno;
        END
    ELSE
        _join_strat.str_rowno := cgg04_no_rowno_predicate;
    (*ENDIF*) 
    (*
          IF  ( jcontext.jc_act_join < dmli.d_cntfromtab )
          THEN
          BEGIN
          g04build_temp_tree_id ( _join_strat.str_result_id,
          acv.a_transinf.tri_trans);
          _join_strat.str_result_id.fileTfnTemp_gg00  := ttfnJoinResult_egg00;
          _join_strat.str_result_id.fileTempCnt_gg00  := jcontext.jc_act_join;
          _join_strat.str_result_id.fileHandling_gg00 :=
          _join_strat.str_result_id.fileHandling_gg00 + [ hsDropFile_egg00 ];
          END
          ELSE
          *)
    IF  ( jcontext.jc_act_join = dmli.d_cntfromtab )
    THEN
        BEGIN
        _join_strat.str_result_id := res_tree;
        _join_strat.str_result_id.fileHandling_gg00 :=
              _join_strat.str_result_id.fileHandling_gg00 + [ hsDropFile_egg00 ];
        IF  ( dmli.d_single )
        THEN
            _join_strat.str_result_id := acv.a_into_tree;
        (*ENDIF*) 
        _onetab_strat.str_result_id := _join_strat.str_result_id;
        END
    ELSE
        _join_strat.str_result_id := b01niltree_id;
    (*ENDIF*) 
    _onetab_strat.str_result_id := _join_strat.str_result_id;
    ;
    IF  ( series[ jcontext.jc_act_join ].jos_predefined_buf )
    THEN
        BEGIN
        IF  ( series[ jcontext.jc_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[ jcontext.jc_act_join ].jos_table_buffer :=
                  _join_strat.str_rec_len;
            END
        ELSE
            ; (* buffer size via hint *)
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        series[ jcontext.jc_act_join ].jos_table_buffer :=
              _join_strat.str_rec_len;
        END;
    (*ENDIF*) 
    IF  ( jcontext.jc_act_join > 1 )
    THEN
        BEGIN
        IF  ( jcontext.jc_act_join = dmli.d_cntfromtab )
        THEN
            BEGIN
            IF  ( jcontext.jc_stack_desc.mresqual_cnt > 0 ) AND
                ( jcontext.jc_st_addr^[ jcontext.jc_stack_desc.mresqual_pos ].
                etype = st_jump_output )
            THEN
                BEGIN
                jcontext.jc_joininfo.jn_res_rec_len := dmli.d_reclen;
                jcontext.jc_joininfo.jn_res_key_len := jcontext.
                      jc_st_addr^[ jcontext.jc_stack_desc.mresqual_pos ].elen_var;
                jcontext.jc_joininfo.jn_rec_len     :=
                      jcontext.jc_outdesc.od_outreclen;
                jcontext.jc_joininfo.jn_key_len     := RESCNT_MXGG04;
                END
            ELSE
                BEGIN
                jcontext.jc_joininfo.jn_res_rec_len := dmli.d_reclen;
                jcontext.jc_joininfo.jn_res_key_len := dmli.d_keylen;
                jcontext.jc_joininfo.jn_rec_len     :=
                      jcontext.jc_outdesc.od_outreclen;
                jcontext.jc_joininfo.jn_key_len     := dmli.d_keylen;
                END;
            (*ENDIF*) 
            IF  ( jcontext.jc_joininfo.jn_rec_len = 0 )
            THEN
                (* selects like "select 'TEST' from t1, t2 where t1.c=t2.c" *)
                jcontext.jc_joininfo.jn_rec_len := cgg_rec_key_offset +
                      jcontext.jc_joininfo.jn_key_len;
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            jcontext.jc_joininfo.jn_res_rec_len := IS_UNDEFINED_GG07;
            jcontext.jc_joininfo.jn_res_key_len := IS_UNDEFINED_GG07;
            jcontext.jc_joininfo.jn_rec_len     := IS_UNDEFINED_GG07;
            jcontext.jc_joininfo.jn_key_len     := IS_UNDEFINED_GG07;
            END;
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        jcontext.jc_joininfo.jn_res_rec_len := IS_UNDEFINED_GG07;
        jcontext.jc_joininfo.jn_res_key_len := IS_UNDEFINED_GG07;
        jcontext.jc_joininfo.jn_rec_len     := IS_UNDEFINED_GG07;
        jcontext.jc_joininfo.jn_key_len     := IS_UNDEFINED_GG07;
        IF  (( _join_strat.str_strategy in a70glob_key_strats ) AND
            ( ksp_exact_match in
            _join_strat.str_key_in_range.skir_strat_props ))
            OR
            (( _join_strat.str_strategy in a70glob_inv_strats ) AND
            ( isp_exact_match in
            _join_strat.str_inv_in_range.siir_strat_props ) AND
            ( isp_unique_idx in
            _join_strat.str_inv_in_range.siir_strat_props ))
        THEN
            series[ 1 ].jos_predefined_buf := true;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  ( acv.a_returncode = 0 )
THEN
    BEGIN
    (*                                                           *)
    (* +- 4. strat entry                                         *)
    (* |        +- 1. strat entry                                *)
    (* |        |          +---------- 2. strat entry (last step)*)
    (* |        |          |           + ----- 3. strat entry    *)
    (* V        V          V           V                         *)
    (* +--------+----------------------+-----------+             *)
    (* | one tab| joinstrat|  output   |   join    |             *)
    (* | strat  |   info   |  desc     |   info    |             *)
    (* +--------+----------+-----------+-----------+             *)
    (*                                                           *)
    IF  ( jcontext.jc_act_join > 1 )
    THEN
        a684move_infos_onetabstrat( acv, _onetab_strat, joinp,
              _onetab_StratInfo_len, get_new_strat );
    (**)
    (* 1. strat entry *)
    (*ENDIF*) 
    a684move_infos_strategy( acv, _join_strat, joinp,
          _StratInfo_len, get_new_strat );
    IF  ( jcontext.jc_act_join > 1 )
    THEN
        BEGIN
        IF  ( jcontext.jc_act_join = dmli.d_cntfromtab )
        THEN
            ak690move_infos_output( acv, jcontext.jc_outdesc )
        ELSE
            acv.a_mblock.mb_qual^.mstrat_cnt :=
                  succ (acv.a_mblock.mb_qual^.mstrat_cnt);
        (*ENDIF*) 
        ak690move_infos_join( acv, dmli.d_joins, jcontext.jc_joininfo );
        ;
        acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mstrat_pos ].
              ecol_tab[ 2 ] := chr (jcontext.jc_act_join);
        IF  (( series[ jcontext.jc_act_join ].jos_joinstrat in
            a70glob_join_strats ) AND
            ( jcontext.jc_joininfo.jn_jarr_cnt = 0 ))
        THEN
            a07ak_system_error( acv, 690, 2 );
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  ( acv.a_returncode = 0 )
THEN
    BEGIN
    IF  ( _join_strat.str_strategy in a70glob_inv_strats ) AND
        ( _join_strat.str_qual_kind <> inv_only )
    THEN
        a71prepare_qual_on_index( acv, _join_strat.str_qual_kind );
    (*ENDIF*) 
    ;
    IF  ( acv.a_intern_explain )
    THEN
        BEGIN
        a61_rel_old_table (acv, dmli, jcontext.jc_acttabno);
        _i := acv.a_mblock.mb_qual^.mqual_pos;
        a728_explain (acv, dmli,
              _join_strat, @jcontext.jc_joininfo,
              joinp^.smessblock.mbr_mess_block.mb_strat^,
              joinp^.smessblock.mbr_mess_block.mb_strat_size, 1);
        IF  (( dmli.d_cntfromtab = jcontext.jc_act_join ) AND
            ( NOT jcontext.jc_tempresult ))
        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
      ak690qualification_stack (
            VAR acv      : tak_all_command_glob;
            VAR joinp    : tak_sysbufferaddress);
 
VAR
      _jmbp  : tgg00_MessBlockPtr;
      _jqbp  : tgg00_QualBufPtr;
 
BEGIN
_jmbp      := @joinp^.smessblock.mbr_mess_block;
_jqbp      := _jmbp^.mb_qual;
acv.a_mblock.mb_qual^.msubquery := _jqbp^.msubquery;
IF  ( acv.a_mblock.mb_qual^.mfirst_free + _jqbp^.mqual_cnt >
    acv.a_mblock.mb_st_max )
THEN
    a07_b_put_error (acv, e_too_many_mb_stackentries, 1)
ELSE
    BEGIN
    (* get qualification from i.th messblock *)
    SAPDB_PascalMove ('VAK690',   8,    
          _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;
    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
      ak690move_infos_join (
            VAR acv        : tak_all_command_glob;
            VAR joins      : tak_joinrec;
            VAR joininfo   : tak68_join);
 
VAR
      _ilen : tsp00_Int4;
 
BEGIN
&ifdef trace
t01name( ak_join, 'write join info   ' );
a683trace_joininfo( ak_join, joins, joininfo );
&endif
_ilen := sizeof (joininfo.jn_jarr_cnt) +
      sizeof (joininfo.jn_jarr_path) +
      sizeof (joininfo.jn_res_rec_len) +
      sizeof (joininfo.jn_res_key_len) +
      sizeof (joininfo.jn_rec_len) +
      sizeof (joininfo.jn_key_len) +
      sizeof (joininfo.jn_rightoj) + sizeof (joininfo.jn_leftoj) +
      sizeof(joininfo.jn_filler) +
      (joininfo.jn_jarr_cnt * sizeof (joininfo.jn_jarr[1]));
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 (joininfo), acv.a_mblock.mb_strat_size,
          @joininfo, 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
      ak690move_infos_output (
            VAR acv        : tak_all_command_glob;
            VAR outdesc    : tak68_output_desc);
 
VAR
      _ilen : tsp00_Int4;
      _ic2  : tsp_int_map_c2;
 
BEGIN
&ifdef trace
t01name( ak_join, 'write output info ' );
&endif
_ilen := sizeof(outdesc.od_size) + ( outdesc.od_size * sizeof (tak68_outcol) );
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
    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);
    ;
    _ic2.map_int := outdesc.od_size;
    acv.a_mblock.mb_strat^[ acv.a_mblock.mb_strat_len + 1 ] := _ic2.map_c2[ 1 ];
    acv.a_mblock.mb_strat^[ acv.a_mblock.mb_strat_len + 2 ] := _ic2.map_c2[ 2 ];
    acv.a_mblock.mb_strat_len  := acv.a_mblock.mb_strat_len + sizeof( outdesc.od_size );
    _ilen := _ilen - sizeof( outdesc.od_size );
    SAPDB_PascalForcedMove (
          ( outdesc.od_capacity * sizeof (tak68_outcol) ),
          acv.a_mblock.mb_strat_size,
          @outdesc.od_outcols^, 1,
          @acv.a_mblock.mb_strat^, acv.a_mblock.mb_strat_len + 1,
          _ilen );
    acv.a_mblock.mb_strat_len  := acv.a_mblock.mb_strat_len + _ilen;
    END;
(*ENDIF*) 
&ifdef trace
a683trace_outdesc( ak_join, outdesc );
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak690update_joininfo(
            VAR acv         : tak_all_command_glob;
            VAR joins       : tak_joinrec;
            VAR jcontext    : tak68_join_context;
            currj           : tsp00_Int2;
            join_accesspath : boolean;
            dsttab_side     : tsp00_Int2);
 
VAR
      _jarr_oside : tsp00_Int2;
 
BEGIN
IF  ( jcontext.jc_joininfo.jn_jarr_cnt < MAX_JOINS_GG04 )
THEN
    BEGIN
    CASE dsttab_side OF
        1 :
            _jarr_oside := 2;
        2 :
            _jarr_oside := 1;
        END;
    (*ENDCASE*) 
    jcontext.jc_joininfo.jn_leftoj :=
          jcontext.jc_joininfo.jn_leftoj
          OR joins.jrc_joinarr[ currj ].jo_recs[ dsttab_side ].jop_outer_join;
    jcontext.jc_joininfo.jn_rightoj :=
          jcontext.jc_joininfo.jn_rightoj
          OR joins.jrc_joinarr[ currj ].jo_recs[ _jarr_oside ].jop_outer_join;
    ;
    jcontext.jc_joininfo.jn_jarr_cnt :=
          succ (jcontext.jc_joininfo.jn_jarr_cnt);
    jcontext.jc_joininfo.jn_jarr[ jcontext.jc_joininfo.jn_jarr_cnt ] := currj;
    IF  ( join_accesspath )
    THEN
        jcontext.jc_joininfo.jn_jarr_path := succ(jcontext.jc_joininfo.jn_jarr_path);
    (*ENDIF*) 
    IF  ( joins.jrc_joinarr[ currj ].jo_recs[ dsttab_side ].jop_tableno =
        jcontext.jc_acttabno )
    THEN
        joins.jrc_joinarr[ currj ].jo_partno := dsttab_side
    ELSE
        joins.jrc_joinarr[ currj ].jo_partno := _jarr_oside;
    (*ENDIF*) 
    END
ELSE
    a07_b_put_error (acv, e_too_many_joins, 1);
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak690roj_key_stack (
            VAR acv    : tak_all_command_glob;
            VAR dmli   : tak_dml_info;
            VAR jcontext : tak68_join_context);
 
VAR
      _sysbuf     : tak_sysbufferaddress;
      _colbuf     : tak00_colinfo_ptr;
      _keylen     : tsp00_Int4;
      _outpos     : tsp00_Int4;
      _i          : tsp00_Int2;
      _fieldno    : tsp00_Int2;
 
BEGIN
(* write following record layout: |key|all other cols| *)
a684get_relation_info( acv, dmli.d_tabarr[ jcontext.jc_acttabno ], d_release, _sysbuf );
IF  ( _sysbuf <> NIL )
THEN
    BEGIN
    _fieldno := 1;
    _keylen  := 0;
    _outpos  := cgg_rec_key_offset + 1;
    _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 := _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
            _outpos := _outpos +
                  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;
            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, 690, 1 )
    ELSE
        BEGIN
        (* 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*) 
;
(* update col positions of all other columns,   *)
(* to place key in front of record              *)
_outpos := acv.a_mblock.mb_qual^.mqual_pos + 1;
WHILE ( _outpos < acv.a_mblock.mb_qual^.mfirst_free )  DO
    BEGIN
    IF  ( acv.a_mblock.mb_st^[ _outpos ].etype in [ st_output, st_result ] )
    THEN
        BEGIN
        IF  ( acv.a_mblock.mb_st^[ _outpos ].eop_out <> op_o_output_outer_join )
        THEN
            BEGIN
            acv.a_mblock.mb_st^[ _outpos ].epos :=
                  acv.a_mblock.mb_st^[ _outpos ].epos + _keylen;
            END
        ELSE
            _outpos := acv.a_mblock.mb_qual^.mfirst_free; (*exit*)
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    _outpos := succ(_outpos);
    END;
(*ENDWHILE*) 
;
(* update record positions in dmli.d_joins *)
FOR _i := 0 TO dmli.d_joins.jrc_cnt - 1 DO
    BEGIN
    _outpos := 1;
    REPEAT
        IF  ( dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _outpos ].jop_tableno =
            jcontext.jc_acttabno )
        THEN
            BEGIN
            dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _outpos ].jop_outpos :=
                  dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _outpos ].jop_outpos +
                  _keylen;
            END;
        (*ENDIF*) 
        _outpos := succ( _outpos );
    UNTIL
        ( _outpos > 2 );
    (*ENDREPEAT*) 
    END;
(*ENDFOR*) 
;
(* update record positions in jc_outdesc *)
FOR  _outpos := 0 TO jcontext.jc_outdesc.od_size - 1 DO
    BEGIN
    IF  ( jcontext.jc_outdesc.od_outcols^[ _outpos ].oc_srctab =
        jcontext.jc_acttabno )
    THEN
        jcontext.jc_outdesc.od_outcols^[ _outpos ].oc_srcpos :=
              jcontext.jc_outdesc.od_outcols^[ _outpos ].oc_srcpos + _keylen;
    (*ENDIF*) 
    END;
(*ENDFOR*) 
;
(* update actual output position *)
jcontext.jc_outpos := jcontext.jc_outpos + _keylen;
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak690output_columns_stack(
            VAR acv       : tak_all_command_glob;
            VAR dmli      : tak_dml_info;
            VAR jcontext  : tak68_join_context );
 
VAR
      _is_acttabno : boolean;
      _out_hold  : boolean;
      _col_found : boolean;
      _start_src : tsp00_Int2;
      _stop_src  : tsp00_Int2;
      _start_dest: tsp00_Int2;
      _i, _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   ', jcontext.jc_act_join,
      'i.th tab    ', jcontext.jc_acttabno);
_out_fnd := false;
&endif
IF  ( jcontext.jc_st_addr^[ jcontext.jc_stack_desc.mqual_pos ].
    etype = st_jump_output )
THEN
    _stop_src := jcontext.jc_stack_desc.mqual_pos +
          jcontext.jc_st_addr^[ jcontext.jc_stack_desc.mqual_pos ].epos - 2
ELSE
    (* avoid looping *)
    _stop_src := jcontext.jc_stack_desc.mqual_pos;
(*ENDIF*) 
;
_i := succ (jcontext.jc_stack_desc.mqual_pos);
_start_src  := _i;
_start_dest := pred (acv.a_mblock.mb_qual^.mfirst_free);
WHILE ( _i <= _stop_src ) AND  (acv.a_returncode = 0) DO
    (* loop over output columns of orig. mblock *)
    BEGIN
    _out_hold    := false;
    _is_acttabno := false;
    _col_found   := false;
    (* step to next output column *)
    WHILE (( _i <= _stop_src ) AND
          ( NOT (jcontext.jc_st_addr^[ _i ].etype = st_output ))) DO
        BEGIN
        IF  ( jcontext.jc_st_addr^[ _i ].etype
            in [ st_fixkey, st_varkey, st_fixcol, st_varcol, st_varlongchar ] )
        THEN
            (* column found *)
            BEGIN
            _col_found := true;
            _is_acttabno :=
                  (( ord(jcontext.jc_st_addr^[ _i ].ecol_tab[ 2 ]) MOD 100 ) =
                  jcontext.jc_acttabno );
            END;
        (*ENDIF*) 
        _i := succ( _i );
        END;
    (*ENDWHILE*) 
    IF  ( jcontext.jc_st_addr^[ _i ].etype = st_output ) AND
        ( jcontext.jc_st_addr^[ _i ].eop_out = op_o_output_hold )
    THEN
        (* ORDER BY col found, which is also in output  *)
        (* this stackentry describes output column      *)
        BEGIN
&       ifdef trace
        t01name(ak_join, 'OUT HOLD found    ');
&       endif
        _i := succ(_i);
        _out_hold := true;
        END;
    (*ENDIF*) 
    IF  (( _i <= _stop_src )
        (* output column found *)
        AND
        (* output columns for <i.th tab> *)
        ( _is_acttabno  OR
        (* for last join step grab remaining output *)
        (( jcontext.jc_act_join = dmli.d_cntfromtab ) AND ( NOT _col_found ))
        ))
    THEN
        BEGIN
        _scnt := _i - _start_src + 1;
&       ifdef trace
        t01name(ak_join, 'orig outp-> new mb');
        FOR _j := _start_src TO _start_src + _scnt - 1 DO
            t01stackentry( ak_join, jcontext.jc_st_addr^[ _j ], _j );
        (*ENDFOR*) 
        _out_fnd := true;
&       endif
        (* get colunms until output column *)
        SAPDB_PascalMove ('VAK690',   9,    
              (jcontext.jc_stack_desc.mst_max * STACK_ENTRY_MXGG00),
              acv.a_mblock.mb_st_size,
              (* source *)
              @jcontext.jc_st_addr^, (_start_src - 1) * STACK_ENTRY_MXGG00 + 1,
              (* destination *)
              @acv.a_mblock.mb_st^, _start_dest * STACK_ENTRY_MXGG00 + 1,
              _scnt * STACK_ENTRY_MXGG00,
              acv.a_returncode);
        IF  ( acv.a_returncode = 0 )
        THEN
            BEGIN
            _start_dest := _start_dest + _scnt;
            (* 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  ( _out_hold )
            THEN
                BEGIN
                ak690insert_outdesc( acv, jcontext, _start_dest - 1 );
                acv.a_mblock.mb_st^[ _start_dest - 1 ].epos := jcontext.jc_outpos;
                jcontext.jc_outpos := jcontext.jc_outpos +
                      acv.a_mblock.mb_st^[ _start_dest - 1 ].elen_var;
                END;
            (*ENDIF*) 
            ak690insert_outdesc( acv, jcontext, _start_dest );
            acv.a_mblock.mb_st^[ _start_dest ].epos := jcontext.jc_outpos;
            jcontext.jc_outpos := jcontext.jc_outpos +
                  acv.a_mblock.mb_st^[ _start_dest ].elen_var;
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  (jcontext.jc_st_addr^[ _i ].eop_out = op_o_output_hold) AND
        (jcontext.jc_st_addr^[ _i ].etype = st_output)
    THEN
        (* overstep ORDER BYcolumn, which wich is already output column *)
        _i := _i + 2
    ELSE
        _i := succ(_i);
    (*ENDIF*) 
    _start_src := _i;
    END;
(*ENDWHILE*) 
&ifdef trace
IF  (_out_fnd)
THEN
    BEGIN
    t01stackdesc (ak_join, 'orig mblock ', jcontext.jc_st_addr,
          jcontext.jc_stack_desc);
    t01stackdesc (ak_join, 'i.th mblock ', acv.a_mblock.mb_st,
          acv.a_mblock.mb_qual^.mstack_desc);
    a683trace_outdesc( ak_join, jcontext.jc_outdesc );
    END
ELSE
    t01name(ak_join, 'no output found   ');
(*ENDIF*) 
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak690init_outdesc(
            VAR acv     : tak_all_command_glob;
            VAR outdesc : tak68_output_desc;
            stackout_cnt: tsp00_Int4);
 
VAR
 
      _cast         : RECORD
            CASE boolean OF
                true :
                    (addr: tsp00_Addr);
                false :
                    (ptr : tak68_outcols_ptr);
                END;
            (*ENDCASE*) 
 
 
BEGIN
&ifdef diagnose
outdesc.od_capacity := 1;
&else
outdesc.od_capacity := ( stackout_cnt DIV 2 ) + 1;
&endif
outdesc.od_size     := 0;
outdesc.od_outreclen:= 0;
outdesc.od_outcols  := NIL;
_cast.addr := gg941Allocate( acv.a_transinf.tri_trans,
      outdesc.od_capacity * sizeof(tak68_outcol) );
outdesc.od_outcols  := _cast.ptr;
&ifdef trace
t01int4( ak_join, 'capacity    ', outdesc.od_capacity );
t01int4( ak_join, 'mem size    ', outdesc.od_capacity * sizeof(tak68_outcol) );
t01addr( ak_join, 'od_outcols  ', _cast.addr );
&endif
IF  ( outdesc.od_outcols = NIL )
THEN
    BEGIN
    a07_b_put_error( acv, e_no_more_memory, 1 );
    outdesc.od_capacity := 0;
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak690finalize_outdesc(
            VAR acv     : tak_all_command_glob;
            VAR outdesc : tak68_output_desc);
 
VAR
 
      _cast         : RECORD
            CASE boolean OF
                true :
                    (addr: tsp00_Addr);
                false :
                    (ptr : tak68_outcols_ptr);
                END;
            (*ENDCASE*) 
 
 
BEGIN
IF  ( outdesc.od_outcols <> NIL )
THEN
    BEGIN
    _cast.ptr := outdesc.od_outcols;
&   ifdef trace
    t01addr( ak_join, 'od_outcols  ', _cast.addr );
&   endif
    gg941Deallocate( acv.a_transinf.tri_trans, _cast.addr );
    outdesc.od_outcols := NIL;
    END;
(*ENDIF*) 
outdesc.od_size     := 0;
outdesc.od_capacity := 0;
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak690expand_outdesc(
            VAR acv    : tak_all_command_glob;
            VAR outdesc : tak68_output_desc);
 
CONST
      c_chunksize = 5;
 
VAR
      _old_capacity : tsp00_Int2;
      _do_realloc   : boolean;
 
      _cast         : RECORD
            CASE boolean OF
                true :
                    (addr: tsp00_Addr);
                false :
                    (ptr : tak68_outcols_ptr);
                END;
            (*ENDCASE*) 
 
 
BEGIN
_old_capacity := outdesc.od_capacity;
_do_realloc   := true;
&ifdef diagnose
IF  ( outdesc.od_capacity <= MAX_INT2_SP00 - 1 )
THEN
    outdesc.od_capacity := outdesc.od_capacity + 1
ELSE
    _do_realloc := false;
(*ENDIF*) 
&else
IF  ( outdesc.od_capacity <= MAX_INT2_SP00 - c_chunksize )
THEN
    outdesc.od_capacity := outdesc.od_capacity + c_chunksize
ELSE
    _do_realloc := false;
(*ENDIF*) 
&endif
IF  ( _do_realloc )
THEN
    BEGIN
    _cast.ptr  := outdesc.od_outcols;
&   ifdef trace
    t01int4( ak_join, 'old capacity', _old_capacity );
    t01int4( ak_join, 'new capacity', outdesc.od_capacity );
    t01addr( ak_join, 'old ptr     ', _cast.addr );
&   endif
    _cast.addr := gg941ReAllocate( acv.a_transinf.tri_trans,
          outdesc.od_capacity * sizeof(tak68_outcol), _cast.addr );
    outdesc.od_outcols := _cast.ptr;
&   ifdef trace
    t01addr( ak_join, 'new ptr     ', _cast.addr );
&   endif
    IF  ( outdesc.od_outcols = NIL )
    THEN
        BEGIN
        outdesc.od_capacity := _old_capacity;
        a07_b_put_error( acv, e_no_more_memory, 1 );
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak690insert_outdesc(
            VAR acv     : tak_all_command_glob;
            VAR jcontext: tak68_join_context;
            stackpos    : tsp00_Int2);
 
BEGIN
IF  ( jcontext.jc_outdesc.od_size + 1 >
    jcontext.jc_outdesc.od_capacity )
THEN
    ak690expand_outdesc( acv, jcontext.jc_outdesc );
(*ENDIF*) 
IF  ( jcontext.jc_outdesc.od_size + 1 <=
    jcontext.jc_outdesc.od_capacity )
THEN
    BEGIN
    jcontext.jc_outdesc.od_size :=
          succ( jcontext.jc_outdesc.od_size );
    jcontext.jc_outdesc.od_outcols^[ jcontext.jc_outdesc.od_size-1 ].
          oc_srctab := jcontext.jc_acttabno;
    jcontext.jc_outdesc.od_outcols^[ jcontext.jc_outdesc.od_size-1 ].
          oc_srcpos := jcontext.jc_outpos;
    jcontext.jc_outdesc.od_outcols^[ jcontext.jc_outdesc.od_size-1 ].
          oc_dstpos := acv.a_mblock.mb_st^[ stackpos ].epos;
    jcontext.jc_outdesc.od_outcols^[ jcontext.jc_outdesc.od_size-1 ].
          oc_len    := acv.a_mblock.mb_st^[ stackpos ].elen_var;
    IF  ( jcontext.jc_outdesc.od_outcols^[ jcontext.jc_outdesc.od_size-1 ].
        oc_dstpos > jcontext.jc_outdesc.od_outreclen )
    THEN
        BEGIN
        jcontext.jc_outdesc.od_outreclen :=
              jcontext.jc_outdesc.od_outcols^[ jcontext.jc_outdesc.od_size-1 ].
              oc_dstpos +
              jcontext.jc_outdesc.od_outcols^[ jcontext.jc_outdesc.od_size-1 ].
              oc_len - 1;
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak690sort_key_stack (
            VAR acv             : tak_all_command_glob;
            VAR dmli            : tak_dml_info;
            VAR series          : tak68_sequence;
            VAR jcontext        : tak68_join_context;
            VAR one_sequence    : tak68_one_seq_join);
 
VAR
      _trans_cnt        : tsp00_Int2;
      _stack_cnt        : tsp00_Int2;
      _i, _j            : tsp00_Int4;
      _dsttab_side      : tsp00_Int2;
      _outpos           : tsp00_Int4;
      _keylen           : tsp00_Int4;
 
BEGIN
(* to make key unique we need a st_rowno with max value of MAX_INT4_SP00 *)
_stack_cnt := 3;
_keylen    := RESNUM_MXSP00;
_trans_cnt := 0;
_i         := 1;
WHILE ( _i <= jcontext.jc_joininfo.jn_jarr_cnt ) DO
    BEGIN
    IF  ( dmli.d_joins.jrc_joinarr[ jcontext.jc_joininfo.jn_jarr[ _i ] ].
        jo_op = op_eq )
    THEN
        BEGIN
        IF  ( dmli.d_joins.jrc_joinarr[ jcontext.jc_joininfo.jn_jarr[ _i ] ].
            jo_recs[ 1 ].jop_tableno = jcontext.jc_acttabno )
        THEN
            _dsttab_side := 1
        ELSE
            _dsttab_side := 2;
        (*ENDIF*) 
        _keylen := _keylen +
              dmli.d_joins.jrc_joinarr[ jcontext.jc_joininfo.jn_jarr[ _i ] ].
              jo_recs[ _dsttab_side ].jop_inoutlen;
        IF  ( acv.a_mblock.mb_qual^.mfirst_free + _stack_cnt
            > acv.a_mblock.mb_st_max ) OR
            ( _keylen > MAX_KEYLEN_GG00 ) OR
            ( jcontext.jc_outpos - 1 + _keylen > MAX_RECLEN_GG00 )
        THEN
            (* don't search for further columns *)
            BEGIN
&           ifdef trace
            t01sname( ak_join, 'abort search' );
&           endif
            _keylen := _keylen -
                  dmli.d_joins.jrc_joinarr[ jcontext.jc_joininfo.jn_jarr[ _i ] ].
                  jo_recs[ _dsttab_side ].jop_inoutlen;
            _i := jcontext.jc_joininfo.jn_jarr_cnt; (* exit WHILE *)
            END
        ELSE
            BEGIN
&           ifdef trace
            a683_one_join_entry_ex( ak_join, dmli,
                  jcontext.jc_joininfo.jn_jarr[ _i ], false );
&           endif
            _trans_cnt := succ( _trans_cnt );
            (* sort according new transitions *)
            _j := jcontext.jc_joininfo.jn_jarr[ _trans_cnt ];
            jcontext.jc_joininfo.jn_jarr[ _trans_cnt ] :=
                  jcontext.jc_joininfo.jn_jarr[ _i ];
            jcontext.jc_joininfo.jn_jarr[ _i ] := _j;
            END;
        (*ENDIF*) 
        _stack_cnt := 0; (* other columns already on stack *)
        END
    ELSE
        (* entries in jc_joininfo sorted according to join operator *)
        _i := jcontext.jc_joininfo.jn_jarr_cnt; (* exit WHILE *)
    (*ENDIF*) 
    _i := succ( _i );
    END;
(*ENDWHILE*) 
;
IF  ( _trans_cnt > 0 )
THEN
    BEGIN
&   ifdef trace
    t01int4( ak_join, '_keylen     ', _keylen );
    t01int4( ak_join, '_trans_cnt  ', _trans_cnt );
    t01int4( ak_join, 'jc_acttabno ', jcontext.jc_acttabno );
&   endif
    ;
    ak690adjust_info_for_key_insert( acv, dmli, jcontext, series,
          cgg_rec_key_offset + (_keylen - RESNUM_MXSP00), RESNUM_MXSP00 );
    ;
    (* update actual output position *)
    jcontext.jc_outpos := jcontext.jc_outpos + RESNUM_MXSP00;
    ;
    (* write st_rowno, st_result, st_output *)
    acv.a_mblock.mb_qual^.mqual_cnt   := acv.a_mblock.mb_qual^.mqual_cnt + 3;
    acv.a_mblock.mb_qual^.mfirst_free := acv.a_mblock.mb_qual^.mfirst_free + 3;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 3 ].
          etype := st_rowno;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 3 ].
          epos  := csp_resnum_deflen;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 3 ].
          elen_var := 0;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 3 ].
          eop  := op_none;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 3 ].
          ecol_tab[1] := chr(RESNUM_MXSP00);
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 3 ].
          ecol_tab[2] := chr(0);
    ;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 2 ].
          etype := st_result;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 2 ].
          epos  := csp_resnum_deflen;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 2 ].
          elen_var := 0;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 2 ].
          eop      := op_none;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 2 ].
          ecol_pos := 0;
    ;
    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  := cgg_rec_key_offset + _keylen - RESNUM_MXSP00 + 1;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
          elen_var := RESNUM_MXSP00;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
          eop      := op_none;
    acv.a_mblock.mb_st^[ acv.a_mblock.mb_qual^.mfirst_free - 1 ].
          ecol_pos := 0;
    ;
    jcontext.jc_sortkeylen            := _keylen;
    jcontext.jc_joininfo.jn_jarr_path := _trans_cnt;
    IF  ( _trans_cnt = 1 )
    THEN
        one_sequence.jos_joinstrat        := strat_join_key_next
    ELSE
        one_sequence.jos_joinstrat        := strat_join_key_range;
    (*ENDIF*) 
    one_sequence.jos_fieldcnt         := _trans_cnt;
    jcontext.jc_tempresult            := true;
    one_sequence.jos_access_mod       :=
          one_sequence.jos_access_mod + [ strmod_sorted ];
    END;
(*ENDIF*) 
;
&ifdef trace
IF  ( _trans_cnt > 0 )
THEN
    BEGIN
    t01stackdesc (ak_join, 'i.th mblock ', acv.a_mblock.mb_st,
          acv.a_mblock.mb_qual^.mstack_desc);
    END;
&endif
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak690adjust_info_for_key_insert(
            VAR acv         : tak_all_command_glob;
            VAR dmli        : tak_dml_info;
            VAR jcontext    : tak68_join_context;
            VAR series      : tak68_sequence;
            rec_pos         : tsp00_Int2; (* record pos from where adjustment begin *)
            key_offset      : tsp00_Int2 );
 
VAR
      _i, _j            : tsp00_Int4;
      _outpos           : tsp00_Int4;
 
BEGIN
(* update col positions of all other columns,   *)
(* to place unique key in front of record       *)
_outpos := acv.a_mblock.mb_qual^.mqual_pos + 1;
WHILE ( _outpos < acv.a_mblock.mb_qual^.mfirst_free )  DO
    BEGIN
    IF  ( acv.a_mblock.mb_st^[ _outpos ].etype in [ st_output, st_result ] )
        AND
        ( acv.a_mblock.mb_st^[ _outpos ].epos >= rec_pos )
    THEN
        BEGIN
        acv.a_mblock.mb_st^[ _outpos ].epos :=
              acv.a_mblock.mb_st^[ _outpos ].epos + key_offset;
        END;
    (*ENDIF*) 
    _outpos := succ(_outpos);
    END;
(*ENDWHILE*) 
;
(* update record positions in dmli.d_joins *)
FOR _i := 0 TO dmli.d_joins.jrc_cnt - 1 DO
    BEGIN
    _outpos := 1;
    REPEAT
        IF  ( _outpos = 1 )
        THEN
            _j := 2
        ELSE
            _j := 1;
        (*ENDIF*) 
        IF  ((( dmli.d_joins.jrc_joinarr[ _i ].
            jo_recs[ _outpos ].jop_tableno = jcontext.jc_acttabno ) OR
            (
            ( jcontext.jc_act_join < dmli.d_cntfromtab ) AND
            (dmli.d_joins.jrc_joinarr[ _i ].
            jo_recs[ _outpos ].jop_tableno = cak68_join_value ) AND
            ( dmli.d_joins.jrc_joinarr[ _i ].
            jo_recs[ _j ].jop_tableno =
            series[ jcontext.jc_act_join + 1 ].jos_source )))
            AND
            ( dmli.d_joins.jrc_joinarr[ _i ].
            jo_recs[ _outpos ].jop_outpos >= rec_pos ))
        THEN
            BEGIN
            dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _outpos ].jop_outpos :=
                  dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _outpos ].jop_outpos +
                  key_offset;
            END;
        (*ENDIF*) 
        _outpos := succ( _outpos );
    UNTIL
        ( _outpos > 2 );
    (*ENDREPEAT*) 
    END;
(*ENDFOR*) 
;
(* update record positions in jc_outdesc *)
FOR  _outpos := 0 TO jcontext.jc_outdesc.od_size - 1 DO
    BEGIN
    IF  ( jcontext.jc_outdesc.od_outcols^[ _outpos ].oc_srctab =
        jcontext.jc_acttabno )
    THEN
        jcontext.jc_outdesc.od_outcols^[ _outpos ].oc_srcpos :=
              jcontext.jc_outdesc.od_outcols^[ _outpos ].oc_srcpos +
              key_offset;
    (*ENDIF*) 
    END;
(*ENDFOR*) 
;
END;
 
.CM *-END-* code---------------
.SP 2 
***********************************************************
.PA 
