.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 : VAK681
changed : 2000-11-22
module  : Join_Select_help_routines
 
Author  : ElkeZ
Created : 1985-10-16
*****************************************************
 
Purpose : The module determines the most favourable order for
          table processing and sends the Mess-Buffers that have
          been built by VAK69 to KB
 
Define  :
 
        PROCEDURE
              a681jnew_seq (
                    VAR acv            : tak_all_command_glob;
                    VAR dmli           : tak_dml_info;
                    config             : tak_sysbufferaddress;
                    VAR table_stats    : tak68_table_stats;
                    VAR jtrans         : tak68_join_transitions;
                    VAR sequence_info  : tak68_sequence_info;
                    VAR jinfos         : tak68_joininfos;
                    VAR res_info       : tak68_result_info;
                    VAR mul_tabs       : tak68_mult_tabs;
                    VAR lastsuccession : tak68_lastsuccession);
 
        FUNCTION
              a681tmp_table_length (
                    VAR dmli    : tak_dml_info;
                    VAR jinfos  : tak68_joininfos;
                    tabno       : tsp00_Int2) : tsp00_Int4;
 
        PROCEDURE
              a681opt_conditions (
                    VAR acv    : tak_all_command_glob;
                    VAR dmli   : tak_dml_info;
                    VAR series : tak68_sequence;
                    VAR jinfos : tak68_joininfos;
                    VAR eq_rec : tak68_eq_record);
 
        FUNCTION
              a681keval_key_kind (
                    VAR acv         : tak_all_command_glob;
                    VAR dmli        : tak_dml_info;
                    VAR table_stats : tak68_table_stats;
                    VAR mul_tabs    : tak68_mult_tabs;
                    pos_jarr        : tsp00_Int2;
                    pos_jrec        : tsp00_Int2;
                    is_join_value   : boolean) : tak68_one_jointype;
 
        PROCEDURE
              a681key_sort_joinarr (
                    VAR acv      : tak_all_command_glob;
                    VAR dmli     : tak_dml_info;
                    VAR series   : tak68_sequence;
                    ser_pos      : tsp00_Int2;
                    VAR sort_pos : tsp00_Int2;
                    VAR mul_tabs : tak68_mult_tabs);
 
        PROCEDURE
              a681lowest_multiple_strat (
                    VAR acv             : tak_all_command_glob;
                    VAR dmli            : tak_dml_info;
                    config              : tak_sysbufferaddress;
                    VAR jtrans          : tak68_join_transitions;
                    VAR succession      : tak68_succession;
                    VAR mul_tabs        : tak68_mult_tabs;
                    src_table           : tsp00_Int2;
                    dst_table           : tsp00_Int2;
                    VAR best_strat      : tak68_best_jstrat;
                    processed_table_cnt : tsp00_Int2;
                    update_jtrans       : boolean);
 
        FUNCTION
              a681ieval_inv_kind (
                    VAR acv          : tak_all_command_glob;
                    VAR dmli         : tak_dml_info;
                    VAR table_stats  : tak68_table_stats;
                    VAR mul_tabs     : tak68_mult_tabs;
                    pos_jarr         : tsp00_Int2;
                    pos_jrec         : tsp00_Int2;
                    is_join_value    : boolean) : tak68_one_jointype;
 
        PROCEDURE
              a681inv_sort_joinarr (
                    VAR acv      : tak_all_command_glob;
                    VAR dmli     : tak_dml_info;
                    VAR jinfos   : tak68_joininfos;
                    VAR series   : tak68_sequence;
                    ser_pos      : tsp00_Int2;
                    VAR sort_pos : tsp00_Int2;
                    VAR mul_tabs : tak68_mult_tabs);
 
        PROCEDURE
              a681sort_conditions (
                    VAR acv    : tak_all_command_glob;
                    VAR dmli   : tak_dml_info;
                    VAR series : tak68_sequence);
 
        PROCEDURE
              a681test_outer_qualification (
                    VAR acv     : tak_all_command_glob;
                    VAR dmli    : tak_dml_info;
                    VAR jinfos  : tak68_joininfos);
 
        PROCEDURE
              a681get_oj_info (
                    VAR acv  : tak_all_command_glob;
                    VAR dmli : tak_dml_info);
 
        PROCEDURE
              a681check_outer_join (
                    VAR acv : tak_all_command_glob;
                    VAR dmli : tak_dml_info);
 
        PROCEDURE
              a681tr_multabs (
                    VAR acv      : tak_all_command_glob;
                    VAR mul_tabs : tak68_mult_tabs;
                    cntfrom      : tsp00_Int2);
 
        PROCEDURE
              a681tr_tabstats (
                    VAR acv           : tak_all_command_glob;
                    VAR dmli          : tak_dml_info;
                    VAR table_stats   : tak68_table_stats;
                    VAR res_info      : tak68_result_info;
                    cntfrom           : tsp00_Int2;
                    debug             : boolean);
 
        PROCEDURE
              a681tr_joinvals (
                    VAR acv      : tak_all_command_glob;
                    VAR jtrans   : tak68_join_transitions;
                    starttab     : tsp00_Int2;
                    stoptab      : tsp00_Int2;
                    table_cnt    : tsp00_Int2);
 
.CM *-END-* define --------------------------------------
***********************************************************
 
Use     :
 
        FROM
              Scanner : VAK01;
 
        VAR
              a01outer_join_ordered  : boolean;
 
      ------------------------------ 
 
        FROM
              AK_Identifier_Handling : VAK061;
 
        PROCEDURE
              a061get_colname (
                    VAR col_info : tak00_columninfo;
                    VAR colname  : tsp00_KnlIdentifier);
 
      ------------------------------ 
 
        FROM
              AK_error_handling : VAK07;
 
        PROCEDURE
              a07ak_system_error (
                    VAR acv  : tak_all_command_glob;
                    modul_no : integer;
                    id       : integer);
 
        PROCEDURE
              a07_b_put_error (
                    VAR acv : tak_all_command_glob;
                    b_err   : tgg00_BasisError;
                    err_code : tsp00_Int4);
 
      ------------------------------ 
 
        FROM
              AK_Index : VAK24;
 
        PROCEDURE
              a24init_index_scan (
                    VAR acv            : tak_all_command_glob;
                    VAR tabid          : tgg00_Surrogate;
                    VAR index_scan_rec : tak_index_scan_record);
 
        PROCEDURE
              a24finish_index_scan (
                    VAR acv            : tak_all_command_glob;
                    VAR index_scan_rec : tak_index_scan_record);
 
        FUNCTION
              a24next_named_index (
                    VAR acv            : tak_all_command_glob;
                    VAR index_scan_rec : tak_index_scan_record) : boolean;
 
        PROCEDURE
              a24fnd_indexno (
                    VAR acv            : tak_all_command_glob;
                    VAR tabid          : tgg00_Surrogate;
                    indexno            : integer;
                    VAR index_scan_rec : tak_index_scan_record);
 
      ------------------------------ 
 
        FROM
              AK_universal_show_tools : VAK40;
 
        PROCEDURE
              a40sequence_expl_row (
                    VAR acv  : tak_all_command_glob;
                    VAR line : tsp00_Line;
                    change_to_unicode : boolean);
 
      ------------------------------ 
 
        FROM
              Select_List : VAK61;
 
        PROCEDURE
              a61_rel_old_table (
                    VAR acv  : tak_all_command_glob;
                    VAR dmli : tak_dml_info;
                    i        : integer);
 
      ------------------------------ 
 
        FROM
              Join_Select: VAK680;
 
        PROCEDURE
              a680_first_table_cost (
                    VAR sequence_info : tak68_sequence_info;
                    VAR table_stats   : tak68_table_stats;
                    first_table       : tsp00_Int2;
                    VAR res_info      : tak68_result_info);
 
        PROCEDURE
              a680standard_cost (
                    VAR acv            : tak_all_command_glob;
                    VAR dmli           : tak_dml_info;
                    config             : tak_sysbufferaddress;
                    VAR table_stats    : tak68_table_stats;
                    VAR jtrans         : tak68_join_transitions;
                    VAR jinfos         : tak68_joininfos;
                    VAR res_info       : tak68_result_info;
                    VAR mul_tabs       : tak68_mult_tabs;
                    VAR lastsuccession : tak68_lastsuccession;
                    VAR lowest_costs   : tsp00_Longreal;
                    VAR sequence_info  : tak68_sequence_info;
                    succ_length        : tsp00_Int2;
                    final_call         : boolean);
 
        PROCEDURE
              a680next_join_eval (
                    VAR acv                : tak_all_command_glob;
                    VAR jtrans             : tak68_join_transition;
                    VAR table_stat         : tak68_one_table_stat;
                    VAR counted_multiplier : tsp00_Longreal;
                    VAR reverse_multiplier : tsp00_Longreal;
                    VAR newsum             : tsp00_Longreal;
                    VAR newpages           : tsp00_Longreal;
                    old_recs_per_respage   : tsp00_Int4;
                    recs_per_respage       : tsp00_Int4;
                    is_distinct            : boolean);
 
      ------------------------------ 
 
        FROM
              join_trace_routines : VAK683;
 
        PROCEDURE
              a683trans_to_line (
                    VAR acv         : tak_all_command_glob;
                    VAR dmli        : tak_dml_info;
                    tableno         : tsp00_Int2;
                    colno           : tsp00_Int2;
                    VAR line        : tsp00_DataLine;
                    maxlen          : tsp00_Int2;
                    VAR res_state   : boolean);
&       ifdef TRACE
 
        PROCEDURE
              a683joinset_trace (
                    debug        : tgg00_Debug;
                    nam          : tsp00_Sname;
                    VAR dmli     : tak_dml_info;
                    VAR join_set : tak_joinset);
 
        PROCEDURE
              a683trace_jointype (
                    debug : tgg00_Debug;
                    desc  : tsp00_Sname;
                    jtype : tak68_one_jointype);
 
        PROCEDURE
              a683_output (
                    debug    : tgg00_Debug;
                    VAR dmli : tak_dml_info);
 
        PROCEDURE
              a683multabs_trace (
                    debug        : tgg00_Debug;
                    VAR mul_tabs : tak68_mult_tabs;
                    size_multabs : integer;
                    position     : integer;
                    table_cnt    : integer);
 
        PROCEDURE
              a683tr_newsucc (
                    debug          : tgg00_Debug;
                    VAR succession : tak68_succession;
                    start          : integer;
                    stop           : integer;
                    dst_table      : boolean);
 
        PROCEDURE
              a683tr_tableset (
                    debug           : tgg00_Debug;
                    nam             : tsp00_Sname;
                    VAR dmli        : tak_dml_info;
                    VAR table_set   : tak_joinset);
&       endif
 
      ------------------------------ 
 
        FROM
              Hint_Handling : VAK80;
 
        FUNCTION
              a80is_predefined_join_order(
                    VAR acv         : tak_all_command_glob;
                    VAR dmli        : tak_dml_info) : boolean;
 
      ------------------------------ 
 
        FROM
              Configuration_Parameter : VGG01;
 
        VAR
              g01vtrace        : tgg00_VtraceState;
              g01unicode       : boolean;
 
        FUNCTION
              g01userstackoverflow : boolean;
 
        FUNCTION
              g01join_search_level : tgg00_JoinSearchLevel;
 
        FUNCTION
              g01join_maxtab_level4 : tsp00_Int2;
 
        FUNCTION
              g01join_maxtab_level9 : tsp00_Int2;
 
      ------------------------------ 
 
        FROM
              Unicode-Utilities : VGG20;
 
        PROCEDURE
              g20unifill (
                    size      : tsp00_Int4;
                    m         : tsp00_MoveObjPtr;
                    pos       : tsp00_Int4;
                    len       : tsp00_Int4;
                    filluchar : tsp00_C2);
 
      ------------------------------ 
 
        FROM
              RTE_kernel : VEN101;
 
        PROCEDURE
              vsleep (
                    pid   : tsp00_TaskId;
                    limit : tsp00_Int2);
&       ifdef TRACE
 
        PROCEDURE
              vabort (write_core : boolean);
 
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        PROCEDURE
              t01line (debug : tgg00_Debug; VAR ln : tsp00_Line);
 
        PROCEDURE
              t01name (
                    level : tgg00_Debug;
                    nam : tsp00_Name);
 
        PROCEDURE
              t01sname (
                    level : tgg00_Debug;
                    nam : tsp00_Sname);
 
        PROCEDURE
              t01stackdesc (
                    debug          : tgg00_Debug;
                    nam            : tsp00_Sname;
                    stack_addr     : tgg00_StackListPtr;
                    VAR stack_desc : tgg00_StackDesc);
 
        PROCEDURE
              t01real (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    r        : tsp00_Longreal;
                    digits   : integer);
 
        PROCEDURE
              t01stackentry (
                    level       : tgg00_Debug;
                    VAR st      : tgg00_StackEntry;
                    entry_index : integer);
 
        PROCEDURE
              t01lidentifier (
                    level      : tgg00_Debug;
                    identifier : tsp00_KnlIdentifier);
 
        PROCEDURE
              t01int4 (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    int      : tsp00_Int4);
 
        PROCEDURE
              t01p2int4 (
                    debug : tgg00_Debug;
                    nam_1 : tsp00_Sname;
                    int_1 : tsp00_Int4;
                    nam_2 : tsp00_Sname;
                    int_2 : tsp00_Int4);
 
        PROCEDURE
              t01bool (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname ;
                    curr_bool: boolean);
 
        PROCEDURE
              t01c30 (
                    debug : tgg00_Debug;
                    msg : tsp00_C30 );
&       endif
 
      ------------------------------ 
 
        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 (
                    source_upb  : tsp00_Int4;
                    destin_upb  : tsp00_Int4;
                    source      : tsp00_MoveObjPtr;
                    source_pos  : tsp00_Int4;
                    destin      : tsp00_MoveObjPtr;
                    destin_pos  : tsp00_Int4;
                    length      : tsp00_Int4);
 
        PROCEDURE
              SAPDB_PascalOverlappingMove (
                    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_PascalForcedFill (
                    size     : tsp00_Int4;
                    m        : tsp00_MoveObjPtr;
                    pos      : tsp00_Int4;
                    len      : tsp00_Int4;
                    fillchar : char);
 
      ------------------------------ 
 
        FROM
              GG_edit_routines: VGG17;
 
        PROCEDURE
              g17longreal_to_line (
                    r         : tsp00_Longreal;
                    digits    : integer;
                    pos       : integer;
                    VAR ln    : tsp00_Line);
 
        PROCEDURE
              g17int4to_line (
                    int       : tsp00_Int4;
                    with_zero : boolean;
                    int_len   : integer;
                    ln_pos    : integer;
                    VAR ln    : tsp00_Line);
 
        PROCEDURE
              g17stratenum_to_line (
                    strat      : tgg07_StratEnum;
                    VAR ln_len : integer;
                    VAR ln     : tsp00_Line);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_1  : VBD01;
 
        PROCEDURE
              b01filestate (
                    VAR t       : tgg00_TransContext;
                    VAR file_id : tgg00_FileId);
 
      ------------------------------ 
 
        FROM
              Trace : VBD120;
 
        PROCEDURE
              b120InsertTrace (
                    VAR t        : tgg00_TransContext;
                    trace_layer  : tgg00_Debug;
                    trace_object : tgg00_VtraceType;
                    body_len     : tsp00_Int2;
                    trace_body   : tsp00_Addr);
 
.CM *-END-* use -----------------------------------------
***********************************************************
 
Synonym :
 
        PROCEDURE
              b120InsertTrace;
 
              tgg11_VtraceBodyPtr tsp00_Addr
 
.CM *-END-* synonym -------------------------------------
***********************************************************
Specification:
.CM *-END-* specification -------------------------------
***********************************************************
Description:
 
A681OPT_CONDITIONS
 
This procedure eliminates all unnecessary (transitive) join conditions,
which were added by GET_ALL_EQ_CONDITIONS or which were given by the
user.
At first all tables with special strategies (jos_joinno differs to
CARTESIAN_PRODUCT) were transfered into EQ_REC in order of the
processing sequence. The second step is to transfer all join conditions
into EQ_REC which weren't found in EQ_REC (determined by function
FOUND_IN_EQ_REC) and which coressponding tablenumber is equal to the next
tablenumber. The sequence of tablenumbers is stored in SERIES.
The current tablenumber is series[ j ].jos_source.
The next tablenumber is series[ j + offset ].jos_source. In a loop all
conditions of current tables and its next tables (offset is constant).
Then offset is increased and it starts with the first table again. This
will be repeated until offset is is equal to ATCNT.
As a join condition is transfered into EQ_REC the position of
joinarr-element is added to the set USED_REC_SET.
At last all unused join conditions (position not contained in
USED_REC_SET) were eliminated by AK681PACK_JOIN_COND.
 
FOUND_IN_EQ_REC
 
This function returns whether the given join condition is contained
in EQ_REC or whether it is possible to derive the join condition.
 
AK681PACK_JOIN_COND
 
This procedure deletes the element of jrc_joinarr on DEL_POS, all following
elements will be moved one place before.
The SJOINNUMs, which points to elements of jrc_joinarr and which are
greater than DEL_POS were decresed by one.
 
A681KEVAL_KEY_KIND
 
This functions determs if a better strategy than TO_FIRST_KEYFIELD
between two tables can be used. If all keyfields of a multiple key
were found it returns TO_KEY, else TO_KEYPART for more than one field or
if only the first keyfield is found TO_FIRST_KEYFIELD.
 
A681KEY_SORT_JOINARR
 
This procedure sorts the jrc_joinarr depended on the two tables, which
gives the connection between the two tables via multipekeycolumns.
 The sort is started at START_POS. The conditions for the
multiplekey-strategy will be moved to START_POS in order of the
multiplekey.
After sort is finished the fieldcount (jos_FIELDCNT) is updated to
the number of detached multiple key columns which were used for the
strategy.
Finally A681UPDATE_SEQUENCE is called for correcting the pointers
(jos_joinno) of jrc_joinarr for used strategy.
 
A681IEVAL_INV_KIND
 
This function determs if a better strategy than TO_EQ_FIELD
between two tables can be used. It calls the procdure
A681EVAL_ONE_MINV until no more multiple_index is found or a full
multiple_index is found. The number of multiple_index is returned in
the current joinarry_element in jo_recs[ 2 ].jop_outpos.
 
AK681MEVAL_ONE_MINV
 
This procedure determines if a multiple_index between the two
tables can be used.
 
A681INV_SORT_JOINARR
 
This procedure sorts the jrc_joinarr depended on the two tables, which
gives the connection between the two tables via multipe-indexcolumns.
 The sort is started at START_POS. The conditions for the multiple
index strategy will be moved to START_POS in order of the multiple index.
After sort is finished the fieldcount (jos_FIELDCNT) is updated to
the number of detached multiple key columns which were used for the
strategy.
Finally A681UPDATE_SEQUENCE is called for correcting the pointers
(jos_joinno) of jrc_joinarr for used strategy.
 
A681UPDATE_SEQUENCE
 
This procedure dates the SJOINNUMS up. This is nessaisary after sorting
the joinarry, because the SJOINNUMS will points to the old positions.
 Before the joinarry is sorted the sequence of joinarry_elements
is stored by puting the positionnumber into each joinarry-element in
jo_recs[ 1 ].jop_outpos. If a jos_joinno is equal to jo_recs[ 1 ].jop_outpos,
jos_joinno is updated to the position.
 
.CM *-END-* description ---------------------------------
***********************************************************
Structure :
 
.CM *-END-* structure -----------------------------------
***********************************************************
.CM -lll-
Code    :
 
 
CONST
      c_update_jtrans       = true; (* a681lowest_multiple_strat *)
      c_final_call          = true;
      c_write_core          = true; (* vabort                    *)
      c_debug_output        = true;
      c_change_to_unicode   = true;
      c_find_start_table    = true;
 
TYPE
      tak681_used_jrc_set_type   =  PACKED SET OF 0..MAX_JOINS_GG04;
 
      tak681_unknown_table_rec = RECORD
            ut_tableno     : tsp00_Int2;
            ut_joinno      : tak68_joinarr_index;
      END;
 
      tak681_unknown_table_arr = ARRAY [ 1..MAX_JOINS_GG04 ]
            OF tak681_unknown_table_rec;
 
      tak681_best_jstrat_rec = RECORD
            bjr_stratinfo   : tak68_best_jstrat;
            bjr_mtab_ind    : tsp00_Int2;
            bjr_is_mt_join  : boolean;
            bjr_filler      : boolean;
            bjr_costs       : tsp00_Longreal;
      END;
 
      tak681_best_jstrat_rec_arr = ARRAY [ 1..cak00_maxsources ]
            OF tak681_best_jstrat_rec;
 
      tak681_jseq_info_record = RECORD
            jir_sequenced_tables    : tak_joinset;
            jir_best_jstrat         : tak681_best_jstrat_rec_arr;
            jir_comp_sequences      : tsp00_Int4;
            jir_i                   : tsp00_Int2;
            jir_non_best_trans      : tsp00_Int2;
            jir_swap_cnt            : tsp00_Int2;
            jir_last_swap_pos       : tsp00_Int2;
            jir_beststratcnt        : tsp00_Int2;
            jir_max_tables          : tsp00_Int2;
            jir_stop_sequence       : boolean;
            jir_better_seq_exists   : boolean;
            jir_lowest_cost         : tsp00_Longreal;
            jir_lowest_succession   : tak68_succession;
            jir_start_succession    : tak68_succession;
      END;
 
 
 
(*------------------------------*) 
 
FUNCTION
      a681tmp_table_length (
            VAR dmli    : tak_dml_info;
            VAR jinfos  : tak68_joininfos;
            tabno       : tsp00_Int2) : tsp00_Int4;
 
VAR
      _len       : tsp00_Int4;
      _used_cols : tak_columnset;
      _i         : tsp00_Int2;
      _j         : tsp00_Int2;
      _stop      : tsp00_Int2;
 
BEGIN
(* precondition: first stack entry is st_jump_out *)
_stop := jinfos.ji_stack_desc.mqual_pos +
      jinfos.ji_st_addr^[ jinfos.ji_stack_desc.mqual_pos ].epos - 1;
_i    := succ (jinfos.ji_stack_desc.mqual_pos);
_len  := cgg_rec_key_offset (* reclen + keylen + varcolcount + varcoloffset *)
      + RESCNT_MXGG04 (* resultcount counter *);
&ifdef TRACE
t01int4 (ak_join, '_stop       ', _stop);
t01stackdesc (ak_join, 'j_stack_desc', jinfos.ji_st_addr, jinfos.ji_stack_desc);
&endif
WHILE (_i < _stop) DO
    BEGIN
    (* loop while not column stackentry *)
    WHILE ((_i < _stop) AND (NOT (jinfos.ji_st_addr^[ _i ].etype IN
          [ st_fixkey, st_varkey, st_fixcol, st_varcol,
          st_varlongchar ]))) DO
        _i := succ (_i);
    (*ENDWHILE*) 
    IF  ((_i < _stop) AND
        ((ord(jinfos.ji_st_addr^[ _i ].ecol_tab[ 2 ]) MOD 100) = tabno))
    THEN
        BEGIN
        (* loop to OUTPUT description *)
        WHILE ((_i < _stop) AND
              (jinfos.ji_st_addr^[ _i ].etype <> st_output)) DO
            _i := succ (_i);
        (*ENDWHILE*) 
&       ifdef TRACE
        t01stackentry (ak_join, jinfos.ji_st_addr^[ _i ], _i);
&       endif
        IF  (_i < _stop)
        THEN
            _len := _len + jinfos.ji_st_addr^[ _i ].elen_var;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    _i := succ (_i);
    END;
(*ENDWHILE*) 
_used_cols := [ ];
IF  dmli.d_join
THEN
    FOR _i := 0 TO dmli.d_joins.jrc_cnt - 1 DO
        (* add key columns (join predicates for EQ-joins)  *)
        (* worst case: all join columns are output colunms *)
        (* i.e. all columns must be written twice          *)
        FOR _j :=  1 TO 2 DO
            IF  ( dmli.d_joins.jrc_joinarr[ _i ].
                jo_recs[ _j ].jop_tableno = tabno )
                AND
                NOT ( dmli.d_joins.jrc_joinarr[ _i ].
                jo_recs[ _j ].jop_fieldno in _used_cols )
                AND
                ( dmli.d_joins.jrc_joinarr[ _i ].jo_op = op_eq )
            THEN
                BEGIN
                _used_cols := _used_cols +
                      [ dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].jop_fieldno ];
                _len := _len +
                      dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].jop_inoutlen;
                END;
            (*ENDIF*) 
        (*ENDFOR*) 
    (*ENDFOR*) 
(*ENDIF*) 
;
&ifdef TRACE
t01int4 (ak_join, 'tableno     ', tabno);
t01int4 (ak_join, 'table_length', _len);
&endif
a681tmp_table_length := _len;
END;
 
(*------------------------------*) 
 
PROCEDURE
      a681opt_conditions (
            VAR acv    : tak_all_command_glob;
            VAR dmli   : tak_dml_info;
            VAR series : tak68_sequence;
            VAR jinfos : tak68_joininfos;
            VAR eq_rec : tak68_eq_record);
 
VAR
      _end_pos      : tsp00_Int2;
      _i            : tsp00_Int2;
      _j            : tsp00_Int2;
      _curr_tab     : tsp00_Int2;
      _nxt_tab      : tsp00_Int2;
      _offset       : tsp00_Int2;
      _used_jrc_set : tak681_used_jrc_set_type;
 
BEGIN
eq_rec.eqr_cnt        := 0;
_used_jrc_set  := [  ];
_end_pos       := pred (dmli.d_joins.jrc_cnt);
FOR _j := 0 TO _end_pos DO
    IF  ((dmli.d_joins.jrc_joinarr[ _j ].jo_recs [ 1 ].jop_cntstack > 1) OR
        (dmli.d_joins.jrc_joinarr[ _j ].jo_recs [ 2 ].jop_cntstack > 1 )    ) OR
        (dmli.d_joins.jrc_joinarr[ _j ].jo_recs [ 1 ].jop_outer_join OR
        dmli.d_joins.jrc_joinarr[ _j ].jo_recs [ 2 ].jop_outer_join    )
    THEN
        _used_jrc_set  := _used_jrc_set + [ _j ];
    (* evaluate the number of equal-joininfos *)
    (*ENDIF*) 
(*ENDFOR*) 
;
&ifdef TRACE
FOR _i := 0 TO dmli.d_joins.jrc_cnt DO
    IF  (_i in _used_jrc_set)
    THEN
        t01int4 (ak_join, 'cnt > 0 ==> ', _i);
    (*ENDIF*) 
(*ENDFOR*) 
;
&endif
(* evaluate the number of equal-joininfos *)
WHILE (_end_pos > 0) AND ((dmli.d_joins.jrc_joinarr[ _end_pos ].jo_op <> op_eq)  OR
      (dmli.d_joins.jrc_joinarr[ _end_pos ].jo_recs [ 1 ].jop_cntstack <> 1) OR
      (dmli.d_joins.jrc_joinarr[ _end_pos ].jo_recs [ 2 ].jop_cntstack <> 1)   ) DO
    _end_pos := pred (_end_pos);
(*ENDWHILE*) 
&ifdef TRACE
t01int4 (ak_join, 'end_pos     ', _end_pos);
&endif
IF  (_end_pos > 0)
THEN
    BEGIN
    FOR _j := 1 TO dmli.d_cntfromtab DO
        WITH series[ _j ] DO
            IF  (jos_joinno <> cak68_cartesian_product)
            THEN
                FOR _i := jos_joinno TO (jos_joinno + jos_fieldcnt - 1) DO
                    WITH dmli.d_joins.jrc_joinarr[ _i ] DO
                        BEGIN
&                       ifdef TRACE
                        t01int4 (ak_join, 'i jos_joinnu', _i);
                        t01int4 (ak_join, 'used_jrc_set', _i);
                        t01int4 (ak_join, 'eqr_cnt     ', eq_rec.eqr_cnt);
&                       endif
                        IF  (NOT (_i in _used_jrc_set))
                        THEN
                            BEGIN
                            _used_jrc_set := _used_jrc_set + [ _i ];
                            IF  (jo_recs[ 1 ].jop_cntstack = 1) AND
                                (jo_recs[ 2 ].jop_cntstack = 1)
                            THEN
                                BEGIN
                                eq_rec.eqr_cnt := succ (eq_rec.eqr_cnt);
                                WITH eq_rec.eqr_arr[ eq_rec.eqr_cnt ][ cak68_left ], jo_recs[ 1 ] DO
                                    BEGIN
                                    IF  NOT jop_outer_join
                                    THEN
                                        eqi_fieldid.eqt_tabno := jop_tableno
                                    ELSE
                                        eqi_fieldid.eqt_tabno :=
                                              jop_tableno + 20;
                                    (*ENDIF*) 
                                    eqi_fieldid.eqt_colno  := jop_fieldno;
                                    eqi_stackpos       := jop_startstack;
                                    eqi_joinno         := _i;
                                    eqi_jrecs          := 1;
                                    IF  jop_datatyp in [ dcha, ddate, dtime ]
                                    THEN
                                        eqi_codetype := csp_ascii
                                    ELSE
                                        eqi_codetype := csp_codeneutral;
                                    (*ENDIF*) 
                                    END;
                                (*ENDWITH*) 
                                WITH eq_rec.eqr_arr[ eq_rec.eqr_cnt ][ cak68_right ], jo_recs[ 2 ] DO
                                    BEGIN
                                    IF  NOT jop_outer_join
                                    THEN
                                        eqi_fieldid.eqt_tabno := jop_tableno
                                    ELSE
                                        eqi_fieldid.eqt_tabno :=
                                              jop_tableno + 20;
                                    (*ENDIF*) 
                                    eqi_fieldid.eqt_colno  := jop_fieldno;
                                    eqi_stackpos       := jop_startstack;
                                    eqi_joinno         := _i;
                                    eqi_jrecs          := 2;
&                                   ifdef TRACE
                                    t01int4 (ak_join, 'i           ', _i);
                                    t01int4 (ak_join, 'jop_startsta', jop_startstack);
&                                   endif
                                    eqi_codetype := eq_rec.eqr_arr[ eq_rec.eqr_cnt ][ cak68_left ].eqi_codetype;
                                    END;
                                (*ENDWITH*) 
                                END;
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDWITH*) 
                (*ENDFOR*) 
&           ifdef TRACE
            (*ENDIF*) 
        (*ENDWITH*) 
    (*ENDFOR*) 
    FOR _i := 0 TO _end_pos DO
        IF  (_i in _used_jrc_set)
        THEN
            t01int4 (ak_join, 'eq used ==> ', _i);
        (*ENDIF*) 
    (*ENDFOR*) 
    FOR _j := 1 TO eq_rec.eqr_cnt DO
        BEGIN
        t01int4 (ak_join, 'j           ', _j);
        t01int4 (ak_join, 'left.tabno  ', eq_rec.eqr_arr[ _j ][ cak68_left ].eqi_fieldid.eqt_tabno);
        t01int4 (ak_join, 'left.colno  ', eq_rec.eqr_arr[ _j ][ cak68_left ].eqi_fieldid.eqt_colno);
        t01int4 (ak_join, 'right.tabno ', eq_rec.eqr_arr[ _j ][ cak68_right ].eqi_fieldid.eqt_tabno);
        t01int4 (ak_join, 'right.colno ', eq_rec.eqr_arr[ _j ][ cak68_right ].eqi_fieldid.eqt_colno);
        END;
    (*ENDFOR*) 
&   endif
    FOR _offset := 1 TO (dmli.d_cntfromtab - 1) DO
        FOR _j := 1 TO (dmli.d_cntfromtab - _offset) DO
            WITH series[ _j ] DO
                BEGIN
                _curr_tab := jos_source;
                _nxt_tab  := series[ _j + _offset ].jos_source;
&               ifdef TRACE
                t01int4 (ak_join, 'offset      ', _offset);
                t01int4 (ak_join, 'j           ', _j);
                t01int4 (ak_join, 'curr_tab    ', _curr_tab);
                t01int4 (ak_join, 'nxt_tab     ', _nxt_tab);
&               endif
                FOR _i := 0 TO _end_pos DO
                    WITH dmli.d_joins.jrc_joinarr[ _i ] DO
                        BEGIN
                        IF  (NOT (_i in _used_jrc_set))
                        THEN
                            IF  (((jo_recs[ 1 ].jop_tableno = _curr_tab) AND
                                (jo_recs[ 2 ].jop_tableno = _nxt_tab)       ) OR
                                ((jo_recs[ 2 ].jop_tableno = _curr_tab) AND
                                (jo_recs[ 1 ].jop_tableno = _nxt_tab)      )    )
                            THEN
                                BEGIN
                                IF  (jo_recs[ 1 ].jop_cntstack = 1) AND
                                    (jo_recs[ 2 ].jop_cntstack = 1)
                                THEN
                                    BEGIN
&                                   ifdef TRACE
                                    t01int4 (ak_join, 'i <> sjoinum', _i);
&                                   endif
                                    WITH eq_rec.eqr_arr[ eq_rec.eqr_cnt + 1 ][ cak68_left ], jo_recs[ 1 ] DO
                                        BEGIN
                                        IF  NOT jop_outer_join
                                        THEN
                                            eqi_fieldid.eqt_tabno := jop_tableno
                                        ELSE
                                            eqi_fieldid.eqt_tabno :=
                                                  jop_tableno + 20;
                                        (*ENDIF*) 
                                        eqi_fieldid.eqt_colno  := jop_fieldno;
                                        eqi_stackpos       := jop_startstack;
                                        eqi_joinno         := _i;
                                        eqi_jrecs          := 1;
                                        IF  jop_datatyp in [ dcha, ddate, dtime ]
                                        THEN
                                            eqi_codetype := csp_ascii
                                        ELSE
                                            eqi_codetype := csp_codeneutral;
                                        (*ENDIF*) 
                                        END;
                                    (*ENDWITH*) 
                                    WITH eq_rec.eqr_arr[ eq_rec.eqr_cnt + 1 ][ cak68_right ],jo_recs[ 2 ] DO
                                        BEGIN
                                        IF  NOT jop_outer_join
                                        THEN
                                            eqi_fieldid.eqt_tabno := jop_tableno
                                        ELSE
                                            eqi_fieldid.eqt_tabno :=
                                                  jop_tableno + 20;
                                        (*ENDIF*) 
                                        eqi_fieldid.eqt_colno  := jop_fieldno;
                                        eqi_stackpos       := jop_startstack;
                                        eqi_joinno         := _i;
                                        eqi_jrecs          := 2;
                                        eqi_codetype :=
                                              eq_rec.eqr_arr[ eq_rec.eqr_cnt + 1 ][ cak68_left ].
                                              eqi_codetype;
                                        END;
                                    (*ENDWITH*) 
                                    IF  NOT ak681found_in_eq_rec (eq_rec,
                                        eq_rec.eqr_cnt + 1)
                                    THEN
                                        BEGIN
                                        _used_jrc_set := _used_jrc_set + [ _i ];
                                        eq_rec.eqr_cnt       := succ (eq_rec.eqr_cnt);
&                                       ifdef TRACE
                                        t01int4 (ak_join, 'used_jrc_set', _i);
                                        t01int4 (ak_join, 'eqr_cnt     ', eq_rec.eqr_cnt);
&                                       endif
                                        END;
                                    (*ENDIF*) 
                                    END
                                ELSE
                                    _used_jrc_set := _used_jrc_set + [ _i ];
                                (*ENDIF*) 
                                END;
                            (*ENDIF*) 
                        (*ENDIF*) 
                        END;
                    (*ENDWITH*) 
                (*ENDFOR*) 
                END;
            (*ENDWITH*) 
        (*ENDFOR*) 
    (*ENDFOR*) 
    (* make shure that stackentries be used only one time *)
&   ifdef TRACE
    FOR _i := 0 TO _end_pos DO
        IF  (_i in _used_jrc_set)
        THEN
            t01int4 (ak_join, 'eq used ==> ', _i);
        (*ENDIF*) 
    (*ENDFOR*) 
    a683_output (ak_join, dmli);
&   endif
    ak681elim_duplicate_st_pos (acv, jinfos, dmli, eq_rec, _used_jrc_set);
    FOR _i := _end_pos DOWNTO 0 DO
        IF  NOT (_i in _used_jrc_set) AND
            (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ 1 ].jop_cntstack = 1) AND
            (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ 2 ].jop_cntstack = 1)
        THEN
            BEGIN
&           ifdef TRACE
            t01int4  (ak_join, 'i before    ', _i);
&           endif
            ak681pack_join_cond (dmli, series, _i);
&           ifdef TRACE
            t01int4  (ak_join, 'i after     ', _i);
&           endif
            END;
        (*ENDIF*) 
    (*ENDFOR*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
FUNCTION
      ak681found_in_eq_rec (
            VAR eq_rec  : tak68_eq_record;
            pos         : tsp00_Int4) : boolean;
 
VAR
      _i        : tsp00_Int2;
      _j        : tsp00_Int2;
      _eq_start : tak68_eqfieldinfo;
      _eq_dest  : tak68_eqfieldinfo;
      _found    : boolean;
 
BEGIN
_eq_start := eq_rec.eqr_arr[ pos ][ cak68_left ];
_eq_dest  := eq_rec.eqr_arr[ pos ][ cak68_right ];
_found    := false;
_i        := 1;
&ifdef TRACE
t01int4  (ak_join, 'eqr_cnt     ', eq_rec.eqr_cnt);
t01int4  (ak_join, 'pos         ', pos);
t01int4 (ak_join, 'start.tabno ', _eq_start.eqi_fieldid.eqt_tabno);
t01int4 (ak_join, 'start.colno ', _eq_start.eqi_fieldid.eqt_colno);
t01int4 (ak_join, 'dest.tabno  ', _eq_dest.eqi_fieldid.eqt_tabno);
t01int4 (ak_join, 'dest.colno  ', _eq_dest.eqi_fieldid.eqt_colno);
&endif
WHILE ((_i <= eq_rec.eqr_cnt) AND (NOT _found)) DO
    BEGIN
&   ifdef TRACE
    t01int4  (ak_join, 'i           ', _i);
&   endif
    _j := 1;
    WHILE ((_j <= eq_rec.eqr_cnt) AND (NOT _found)) DO
        BEGIN
        IF  (_j <> pos)
        THEN
            BEGIN
&           ifdef TRACE
            t01int4 (ak_join, 'j           ', _j);
            t01int4 (ak_join, 'left.tabno  ', eq_rec.eqr_arr[ _j ][ cak68_left ].eqi_fieldid.eqt_tabno);
            t01int4 (ak_join, 'left.colno  ', eq_rec.eqr_arr[ _j ][ cak68_left ].eqi_fieldid.eqt_colno);
            t01int4 (ak_join, 'right.tabno ', eq_rec.eqr_arr[ _j ][ cak68_right ].eqi_fieldid.eqt_tabno);
            t01int4 (ak_join, 'right.colno ', eq_rec.eqr_arr[ _j ][ cak68_right ].eqi_fieldid.eqt_colno);
&           endif
            IF  (eq_rec.eqr_arr[ _j ][ cak68_left ].eqi_fieldid.eqt_whole = _eq_start.eqi_fieldid.eqt_whole)
            THEN
                _eq_start := eq_rec.eqr_arr[ _j ][ cak68_right ]
            ELSE
                IF  (eq_rec.eqr_arr[ _j ][ cak68_right ].eqi_fieldid.eqt_whole = _eq_start.eqi_fieldid.eqt_whole)
                THEN
                    _eq_start := eq_rec.eqr_arr[ _j ][ cak68_left ];
                (*ENDIF*) 
            (*ENDIF*) 
            IF  (_eq_start.eqi_fieldid.eqt_whole = _eq_dest.eqi_fieldid.eqt_whole)
            THEN
                _found := true;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        _j := succ (_j);
        END;
    (*ENDWHILE*) 
    _i := succ (_i);
    END;
(*ENDWHILE*) 
&ifdef TRACE
t01int4  (ak_join, 'j ende      ', _j);
t01int4 (ak_join, 'start.tabno ', _eq_start.eqi_fieldid.eqt_tabno);
t01int4 (ak_join, 'start.colno ', _eq_start.eqi_fieldid.eqt_colno);
t01int4 (ak_join, 'dest.tabno  ', _eq_dest.eqi_fieldid.eqt_tabno);
t01int4 (ak_join, 'dest.colno  ', _eq_dest.eqi_fieldid.eqt_colno);
IF  _found
THEN
    t01int4  (ak_join, 'found       ', ord (_found))
ELSE
    t01int4  (ak_join, 'not found   ', ord (_found));
(*ENDIF*) 
&endif
ak681found_in_eq_rec := _found;
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681pack_join_cond (
            VAR dmli   : tak_dml_info;
            VAR series : tak68_sequence;
            del_pos    : tsp00_Int2);
 
VAR
      _i : tsp00_Int2;
 
BEGIN
dmli.d_joins.jrc_cnt := pred (dmli.d_joins.jrc_cnt);
_i    := del_pos;
WHILE (_i < dmli.d_joins.jrc_cnt) DO
    BEGIN
    dmli.d_joins.jrc_joinarr[ _i ] := dmli.d_joins.jrc_joinarr[ _i + 1 ];
    _i            := succ (_i);
    END;
(*ENDWHILE*) 
FOR _i := 1 TO dmli.d_cntfromtab DO
    IF  ((series[ _i ].jos_joinno > del_pos) AND
        (series[ _i ].jos_joinno <> cak68_cartesian_product))
    THEN
        series[ _i ].jos_joinno := pred (series[ _i ].jos_joinno);
    (*ENDIF*) 
(*ENDFOR*) 
END;
 
(*------------------------------*) 
 
FUNCTION
      a681keval_key_kind (
            VAR acv         : tak_all_command_glob;
            VAR dmli        : tak_dml_info;
            VAR table_stats : tak68_table_stats;
            VAR mul_tabs    : tak68_mult_tabs;
            pos_jarr        : tsp00_Int2;
            pos_jrec        : tsp00_Int2;
            is_join_value   : boolean) : tak68_one_jointype;
 
CONST
      c_max_keycount = (MAX_COL_PER_TAB_GG00 + 1) DIV 2;
 
VAR
      _ix                  : tsp00_Int2;
      _unknown_table_idx   : tsp00_Int2;(* index in jrc_joinarr *)
      _dst, _src           : tsp00_Int2;
      _keycol_cnt          : tsp00_Int2;
      _col_buf             : tak00_colinfo_ptr;
      _nxt_fieldno         : tsp00_Int2;
      _start_ut_cnt        : tsp00_Int2;
      _start_mt_cnt        : tsp00_Int2;
      _virt_mt_cnt         : tsp00_Int2;
      _unknown_table_pos   : tsp00_Int2;
      _unknown_table_cnt   : tsp00_Int2;
      _combined_multiplier : tsp00_Int4;
      _all_rows            : tsp00_Int4;
      _unknown_table_arr   : tak681_unknown_table_arr;
      _keyextcol_arr       : PACKED ARRAY [ 1 .. c_max_keycount ] OF tsp00_Int2;
      _new_tables          : tak_joinset;
      _jointype            : tak68_one_jointype;
      _dst_tab             : tsp00_Int2;
      _known_table         : boolean;
      _reset_loop          : boolean;
 
BEGIN
&ifdef TRACE
t01int4(ak_join, 'joinarr pos ', pos_jarr );
IF  pos_jrec = 1
THEN
    t01sname(ak_join, 'left site   ')
ELSE
    t01sname(ak_join, 'right site  ');
(*ENDIF*) 
&endif
(* join transition to first key column found, and *)
(* there are further key columns                  *)
(* look for more key transitions for actual table *)
_jointype       := to_first_keyfield;
(* try to insert into mul_tabs.mt_arr        *)
(* insertion is done if we increase mt_cnt ! *)
mul_tabs.mt_pos := succ (mul_tabs.mt_cnt);
IF  ( mul_tabs.mt_pos <= mxak68_mt_arr )
THEN
    BEGIN
    _virt_mt_cnt   := mul_tabs.mt_pos;
    _start_mt_cnt  := mul_tabs.mt_pos;
    _start_ut_cnt  := 0; (* initial unknown table count *)
    _keycol_cnt    := 0;
    _new_tables    := [ ];
    CASE pos_jrec OF
        1 :
            _src := 2;
        2 :
            _src := 1;
        END;
    (*ENDCASE*) 
    _dst_tab := dmli.d_joins.jrc_joinarr[ pos_jarr ].jo_recs[ pos_jrec ].jop_tableno;
    (* fill new entry in mul_tabs.mt_arr *)
    mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_dst_table:= _dst_tab;
    mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_jointype := to_first_keyfield;
    mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_multipl  := dmli.d_joins.
          jrc_joinarr[ pos_jarr ].jo_recs[ pos_jrec ].jop_multiplier;
    mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist := 1;
    _all_rows := (table_stats[mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_dst_table].ts_all_pages *
          table_stats[mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_dst_table].ts_recs_per_page);
    IF  (dmli.d_joins.jrc_joinarr[ pos_jarr ].jo_recs[ pos_jrec ].jop_multiplier > 1)
    THEN
        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist :=
              round (_all_rows /dmli.d_joins.jrc_joinarr[ pos_jarr ].jo_recs[ pos_jrec ].jop_multiplier);
    (*ENDIF*) 
    IF  (mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist > _all_rows)
    THEN
        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist := _all_rows;
    (*ENDIF*) 
    IF  (mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist < 1)
    THEN
        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist := 1;
    (*ENDIF*) 
    mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_joinno   := pos_jarr;
    mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_filler   := 0;
    IF  ( NOT is_join_value )
    THEN
        BEGIN
        (* S.column <op> D.column *)
        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tab_seq :=
              [ dmli.d_joins.jrc_joinarr[ pos_jarr ].
              jo_recs[ _src ].jop_tableno ];
        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tablecnt  := 1;
        END
    ELSE
        BEGIN
        (* S.column <op> <constant> *)
        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tab_seq   := [ ];
        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tablecnt  := 0;
        END;
    (*ENDIF*) 
    mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_fieldcnt := 1;
    mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_indexno  := 0;
&   ifdef trace
    t01p2int4(ak_join, 'src len     ', dmli.d_joins.jrc_joinarr[ pos_jarr ].
          jo_recs[ _src ].jop_inoutlen,
          'dest len    ', dmli.d_joins.jrc_joinarr[ pos_jarr ].
          jo_recs[ pos_jrec ].jop_inoutlen);
&   endif
    (* first column is key column because jtfirstkey in tak_jcolpropset         *)
    (* get second column, we know that second column is key column (jtfirstkey) *)
    IF  ( dmli.d_joins.jrc_joinarr[ pos_jarr ].
        jo_recs[ _src ].jop_inoutlen <= dmli.d_joins.jrc_joinarr[ pos_jarr ].
        jo_recs[ pos_jrec ].jop_inoutlen )
    THEN
        (* len(srccol) <= len(dstcol) *)
        BEGIN
        (* get first external key field no *)
        ak681first_keyfield_no( acv, dmli, _col_buf, _dst_tab, _nxt_fieldno );
        IF  ( acv.a_returncode = 0 )
        THEN
            BEGIN
            (* remember field no *)
            _keycol_cnt := 1;
            _keyextcol_arr[ _keycol_cnt ] := _nxt_fieldno;
            IF  ( dmli.d_sparr.pbasep^.sbase.bkeycolcount > 1 )
            THEN
                BEGIN
                (* get second external field no *)
                ak681next_keyfield_no (dmli, _col_buf, _nxt_fieldno);
                (* remember field no *)
                _keycol_cnt := succ (_keycol_cnt);
                _keyextcol_arr[ _keycol_cnt ] := _nxt_fieldno;
                END
            ELSE
                BEGIN
                mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_jointype := to_single_keyfield;
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        ;
&       ifdef TRACE
        t01name(ak_join, '--start  mul_tabs-');
        a683multabs_trace (ak_join, mul_tabs, _virt_mt_cnt, 0, dmli.d_cntfromtab);
&       endif
        _unknown_table_pos := 1;
        _unknown_table_cnt := 0;
        REPEAT
            (* UNTIL (_unknown_table_pos > _unknown_table_cnt) *)
            (* i.e. UNTIL no input into _unknown_table_arr     *)
            (* foreach REPEAT we have a new addnl. table in mtr_tab_seq *)
            IF  ( _unknown_table_pos <= _unknown_table_cnt )
            THEN
                (* earlier insert into _unknown_table_arr *)
                BEGIN
                _start_ut_cnt  := _unknown_table_cnt;
                _start_mt_cnt  := _virt_mt_cnt;
                _new_tables    := [ ];
                (* just switch the first unknown table to known table *)
                _ix := _unknown_table_arr[ _unknown_table_pos ].ut_joinno;
                IF  mul_tabs.mt_pos < mxak68_mt_arr
                THEN
                    BEGIN
                    (* there are X entries in mul_tabs *)
                    (* save the first entry            *)
                    mul_tabs.mt_pos := succ (mul_tabs.mt_pos);
                    _virt_mt_cnt    := mul_tabs.mt_pos;
&                   ifdef TRACE
                    t01int4 (ak_join, 'act mt_pos  ', mul_tabs.mt_pos);
&                   endif
                    END;
                (*ENDIF*) 
                ;
&               ifdef TRACE
                t01name(ak_join, '-- upd mul_tabs --');
&               endif
                (* first loop through WHILE will lead to _known_table=true *)
                mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tab_seq  :=
                      mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tab_seq +
                      [ _unknown_table_arr[ _unknown_table_pos ].ut_tableno ];
                mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tablecnt :=
                      succ (mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tablecnt);
                _nxt_fieldno :=
                      _keyextcol_arr[ mul_tabs.mt_arr[ mul_tabs.mt_pos ].
                      mtr_fieldcnt + 1 ];
                (* update _unknown_table_pos concerning new entry *)
                _unknown_table_pos   := succ (_unknown_table_pos);
                END
            ELSE
                _ix := 0;
            (*ENDIF*) 
&           ifdef TRACE
            a683multabs_trace (ak_join, mul_tabs, _virt_mt_cnt, 0, dmli.d_cntfromtab);
            t01int4(ak_join, '-act keycol-', _nxt_fieldno);
&           endif
            _unknown_table_idx := _ix;
            _reset_loop := false;
            WHILE ( _ix < dmli.d_joins.jrc_cnt ) AND ( acv.a_returncode = 0 ) DO
                BEGIN
                IF  ((_ix <> pos_jarr) AND
                    (dmli.d_joins.jrc_joinarr[ _ix ].jo_op = op_eq))
                THEN
                    BEGIN
                    (* walk through join conditions 'S.col = D.col' *)
                    (* wherby skip actual entry,                    *)
                    (* until complete key for _dst_tab found       *)
&                   ifdef TRACE
                    IF  _unknown_table_idx = _ix
                    THEN
                        t01int4(ak_join, 're-run pos  ', _ix)
                    ELSE
                        t01int4(ak_join, 'act jarr pos', _ix);
                    (*ENDIF*) 
&                   endif
                    _dst := 1;
                    _src := 2;
                    WHILE ( _dst <= 2 ) DO
                        BEGIN
&                       ifdef TRACE
                        IF  _src = 1
                        THEN
                            t01sname(ak_join, 'left site   ')
                        ELSE
                            t01sname(ak_join, 'right site  ');
                        (*ENDIF*) 
&                       endif
                        (* inspect join condition *)
                        IF  (( dmli.d_joins.jrc_joinarr[ _ix ].
                            jo_recs[ _dst ].jop_tableno = _dst_tab )
                            AND
                            (* field successor *)
                            ( dmli.d_joins.jrc_joinarr[ _ix ].
                            jo_recs[ _dst ].jop_fieldno = _nxt_fieldno )
                            AND
                            (* ? for correct key comparsion ? *)
                            ( dmli.d_joins.jrc_joinarr[ _ix ].
                            jo_recs[ _src ].jop_inoutlen <=
                            dmli.d_joins.jrc_joinarr[ _ix ].
                            jo_recs[ _dst ].jop_inoutlen )
                            AND
                            (* no function code *)
                            ( dmli.d_joins.jrc_joinarr[ _ix ].
                            jo_recs[ _dst ].jop_cntstack = 1 )
                            AND
                            (* is key field *)
                            ( jtkey in dmli.d_joins.jrc_joinarr[ _ix ].
                            jo_recs[ _dst ].jop_propset ))
                        THEN
                            (* we found transition to actual *)
                            (* table with next key column    *)
                            BEGIN
                            (* check state of involved table *)
                            IF  (dmli.d_joins.jrc_joinarr[ _ix ].
                                jo_recs[ _src ].jop_tableno = cak68_join_value)
                            THEN
                                (* S.column <op> <constant> *)
                                _known_table := true
                            ELSE
                                _known_table := dmli.d_joins.jrc_joinarr[ _ix ].
                                      jo_recs[ _src ].jop_tableno in
                                      mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tab_seq;
                            (*ENDIF*) 
                            IF  ( _known_table )
                            THEN
                                BEGIN
&                               ifdef TRACE
                                t01int4(ak_join, 'known table ', dmli.d_joins.
                                      jrc_joinarr[ _ix ].jo_recs[ _src ].
                                      jop_tableno);
&                               endif
                                (* we found 'wider' transition to current table *)
                                (* D.column1 -> S.keycol1 and D.column2 -> S.keycol2 *)
                                (* reject useless transition combination  *)
                                (* A.col -> S.keycol1, B.col -> S.keycol2 *)
                                (* reject earlier insert into _unknown_table_arr *)
                                _unknown_table_cnt := _start_ut_cnt;
                                (* reject earlier insert into mult_tabs  *)
                                _virt_mt_cnt := _start_mt_cnt;
                                (* rememeber new key transition   *)
                                (* count new key field transition *)
                                mul_tabs.mt_arr[ mul_tabs.mt_pos ].
                                      mtr_fieldcnt := succ (mul_tabs.
                                      mt_arr[ mul_tabs.mt_pos ].
                                      mtr_fieldcnt);
&                               ifdef trace
                                a683multabs_trace (ak_join, mul_tabs,
                                      _virt_mt_cnt, 0, dmli.d_cntfromtab);
&                               endif
                                _new_tables  := [ ];
                                (* store smallest multiplier *)
                                IF  mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_multipl >
                                    dmli.d_joins.jrc_joinarr[ _ix ].jo_recs[ _dst ].jop_multiplier
                                THEN
                                    mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_multipl :=
                                          dmli.d_joins.jrc_joinarr[ _ix ].jo_recs[ _dst ].jop_multiplier;
                                (* calculate combined distinctvalues *)
                                (*ENDIF*) 
                                _all_rows := (table_stats[mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_dst_table].ts_all_pages *
                                      table_stats[mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_dst_table].ts_recs_per_page);
                                IF  (dmli.d_joins.jrc_joinarr[ _ix ].jo_recs[ _dst ].jop_multiplier > 1) AND
                                    (mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist < _all_rows)
                                THEN
                                    mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist :=
                                          mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist *
                                          round(_all_rows/dmli.d_joins.jrc_joinarr[ _ix ].jo_recs[ _dst ].jop_multiplier);
                                (*ENDIF*) 
                                IF  (mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist > _all_rows)
                                THEN
                                    mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist := _all_rows;
                                (*ENDIF*) 
                                IF  (mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist < 1)
                                THEN
                                    mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist := 1;
                                (*ENDIF*) 
                                IF  mul_tabs.mt_arr[ mul_tabs.mt_pos ].
                                    mtr_fieldcnt <
                                    dmli.d_sparr.pbasep^.sbase.bkeycolcount
                                THEN
                                    (* there are other key columns *)
                                    BEGIN
                                    (* get next considered key column *)
                                    IF  (mul_tabs.mt_arr[ mul_tabs.mt_pos ].
                                        mtr_fieldcnt < _keycol_cnt)
                                    THEN
                                        BEGIN
                                        _nxt_fieldno :=
                                              _keyextcol_arr[
                                              mul_tabs.mt_arr[ mul_tabs.mt_pos ].
                                              mtr_fieldcnt + 1 ];
&                                       ifdef TRACE
                                        t01int4(ak_join, '-nxtkeycol1-', _nxt_fieldno);
&                                       endif
                                        END
                                    ELSE
                                        BEGIN
                                        ak681next_keyfield_no (dmli,
                                              _col_buf, _nxt_fieldno);
                                        _keycol_cnt
                                              := succ (_keycol_cnt);
                                        _keyextcol_arr[ _keycol_cnt ]
                                              := _nxt_fieldno;
&                                       ifdef TRACE
                                        t01int4(ak_join, '-nxtkeycol2-', _nxt_fieldno);
&                                       endif
                                        END;
                                    (*ENDIF*) 
                                    (* more than one key transition found *)
                                    mul_tabs.mt_arr[ mul_tabs.mt_pos ].
                                          mtr_jointype := to_keypart;
                                    _reset_loop := true;
                                    END
                                ELSE
                                    BEGIN
                                    (* we found complete key   *)
                                    (* there are no other keys *)
&                                   ifdef TRACE
                                    t01name(ak_join, '-  complete key  -');
&                                   endif
                                    mul_tabs.mt_arr[ mul_tabs.mt_pos ].
                                          mtr_jointype := to_key;
                                    mul_tabs.mt_arr [ mul_tabs.mt_pos ].
                                          mtr_multipl :=
                                          cak68_only_field_multiplier;
                                    (* exit while*)
                                    _ix := dmli.d_joins.jrc_cnt;
                                    END;
                                (*ENDIF*) 
                                END
                            ELSE
                                (* NOT _known_table *)
                                (* valid for every entry in       *)
                                (* jrc_joinarr while first REPEAT *)
                                (* loop unless it's a join value  *)
                                BEGIN
                                IF  ( NOT ( dmli.d_joins.jrc_joinarr[ _ix ].
                                    jo_recs[ _src ].jop_tableno in _new_tables ))
                                    AND
                                    ( _unknown_table_cnt < MAX_JOINS_GG04 )
                                    AND
                                    ( _virt_mt_cnt < mxak68_mt_arr )
                                THEN
                                    BEGIN
                                    (* insert unknown table into _unknown_table_arr *)
                                    (* assure next outer REPEAT LOOP                *)
                                    _unknown_table_cnt :=
                                          succ (_unknown_table_cnt);
                                    (* remember tabnleno and entry in joinarr *)
                                    _unknown_table_arr
                                          [ _unknown_table_cnt ].ut_tableno := dmli.d_joins.
                                          jrc_joinarr[ _ix ].jo_recs[ _src ].jop_tableno;
                                    _unknown_table_arr
                                          [ _unknown_table_cnt ].ut_joinno  := _ix;
                                    _virt_mt_cnt := succ( _virt_mt_cnt );
                                    (* create new entry in mult_tabs *)
                                    (* copy content from origin      *)
                                    mul_tabs.mt_arr[ _virt_mt_cnt ] :=
                                          mul_tabs.mt_arr[ mul_tabs.mt_pos ];
                                    (* remember found new table in new table set *)
                                    _new_tables := _new_tables +
                                          [ _unknown_table_arr [ _unknown_table_cnt ].
                                          ut_tableno ];
&                                   ifdef TRACE
                                    t01int4(ak_join, 'uknown table',
                                          dmli.d_joins.jrc_joinarr[ _ix ].
                                          jo_recs[ _src ].jop_tableno);
                                    t01int4(ak_join, 'uknwn tabcnt',
                                          _unknown_table_cnt);
                                    a683multabs_trace (ak_join, mul_tabs,
                                          _virt_mt_cnt, 0, dmli.d_cntfromtab);
&                                   endif
                                    END;
                                (*ENDIF*) 
                                END;
                            (*ENDIF*) 
                            _dst := 3; (* exit work for parts *)
                            END;
                        (*ENDIF*) 
                        ;
                        (* swap considered direction of join transition *)
                        _dst := succ (_dst);
                        _src := pred (_src);
                        END;
                    (*ENDWHILE*) 
                    END;
                (*ENDIF*) 
                ;
                (* -- one join entry observed -- *)
                IF  ( mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_jointype = to_key )
                    AND
                    ( NOT is_join_value )
                    AND
                    ( mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tablecnt = 1 )
                THEN
                    (* best join transition found *)
                    BEGIN
                    _ix := dmli.d_joins.jrc_cnt; (* exit while *)
                    END
                ELSE
                    BEGIN
                    IF  ( _unknown_table_idx > 0 )
                        (* we found already a unknown table        *)
                        (* in a first walk through join conditions *)
                        AND
                        ( _ix = _unknown_table_idx )
                    THEN
                        BEGIN
                        (* now we have inserted first unknown table into*)
                        (* mtr_tab_seq; loop with this this start table *)
                        (* sequence through join conditions             *)
                        _ix                 := 0;
                        _unknown_table_idx  := 0;
                        END
                    ELSE
                        (* get next join condition *)
                        IF  ( NOT _reset_loop )
                        THEN
                            (* we have found a unknown table OR *)
                            (* known table with whole key       *)
                            (* exit while loop                  *)
                            _ix := succ( _ix )
                        ELSE
                            (* we have found a known table and *)
                            (* there are further key columns   *)
                            BEGIN
                            _reset_loop := false;
                            _ix         := 0;
                            END;
                        (*ENDIF*) 
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDWHILE*) 
        UNTIL
            ( _unknown_table_pos > _unknown_table_cnt );
        (*ENDREPEAT*) 
        IF  ( mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_fieldcnt = 1 ) AND
            ( mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_jointype = to_key )
        THEN
            (* *** all other join conditions of key are 'S.col <op> <CONST>' *** *)
            BEGIN
            _jointype := to_key;
            dmli.d_joins.jrc_joinarr[ pos_jarr ].jo_recs[ pos_jrec ].
                  jop_multiplier := cak68_only_field_multiplier;
            END
        ELSE
            BEGIN
            (* accept new entries into mult_tabs *)
            _jointype := to_mt_join;
            FOR _ix := mul_tabs.mt_cnt + 1 TO mul_tabs.mt_pos DO
                BEGIN
                IF  (mul_tabs.mt_arr[ _ix ].mtr_jointype = to_keypart) AND
                    (mul_tabs.mt_arr[ _ix ].mtr_fieldcnt > 1)
                THEN
                    BEGIN (* take combined multiplier into acount *)
                    _combined_multiplier :=    round((table_stats[mul_tabs.mt_arr[ _ix ].mtr_dst_table].ts_all_pages *
                          table_stats[mul_tabs.mt_arr[ _ix ].mtr_dst_table].ts_recs_per_page) /
                          mul_tabs.mt_arr[ _ix ].mtr_combdist);
                    IF  (_combined_multiplier  < cak68_only_field_multiplier)
                    THEN
                        _combined_multiplier := cak68_only_field_multiplier;
                    (*ENDIF*) 
                    IF  (mul_tabs.mt_arr[ _ix ].mtr_multipl > _combined_multiplier)
                    THEN
                        mul_tabs.mt_arr[ _ix ].mtr_multipl :=
                              (mul_tabs.mt_arr[ _ix ].mtr_multipl + _combined_multiplier) DIV 2;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                ;
                (* avoid wrong (something error case) multiplier *)
                IF  mul_tabs.mt_arr[ _ix ].mtr_multipl
                    < cak68_only_field_multiplier
                THEN
                    mul_tabs.mt_arr[ _ix ].mtr_multipl := cak68_only_field_multiplier;
                (*ENDIF*) 
                END;
            (*ENDFOR*) 
            mul_tabs.mt_cnt := mul_tabs.mt_pos;
            END;
        (*ENDIF*) 
        END
    ELSE
        (* destination key field small than source column *)
        (* but there are furhter key columns              *)
        _jointype := to_eq_field;
    (*ENDIF*) 
    END;
(*ENDIF*) 
a681keval_key_kind := _jointype;
&ifdef TRACE
a683multabs_trace (ak_join, mul_tabs, mul_tabs.mt_cnt, 0, dmli.d_cntfromtab);
a683trace_jointype(ak_join, 'return      ', _jointype);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      a681key_sort_joinarr (
            VAR acv      : tak_all_command_glob;
            VAR dmli     : tak_dml_info;
            VAR series   : tak68_sequence;
            ser_pos      : tsp00_Int2;
            VAR sort_pos : tsp00_Int2;
            VAR mul_tabs : tak68_mult_tabs);
 
VAR
      _joinpred       : tak_one_join;
      _joinpred_pos   : tsp00_Int2;
      _j, _k          : tsp00_Int2;
      _ins_pos        : tsp00_Int2;
      _m              : tsp00_Int2;
      _old_sfieldcnt  : tsp00_Int2;
      _end_found      : boolean;
      _used_tables    : boolean;
      _curr_tab       : tsp00_Int2;
      _nxt_fieldno    : tsp00_Int2;
      _tab_sequence   : tak_joinset;
      _col_buf        : tak00_colinfo_ptr;
 
BEGIN
_end_found := false;
(* remember original sort order *)
FOR _m := 0 TO dmli.d_joins.jrc_cnt - 1 DO
    dmli.d_joins.jrc_joinarr[ _m ].jo_recs[ 1 ].jop_outpos := _m;
(*ENDFOR*) 
_m         := 0;
_old_sfieldcnt := series[ ser_pos ].jos_fieldcnt;
series[ ser_pos ].jos_fieldcnt := 0;
_curr_tab := series[ ser_pos ].jos_source;
IF  (dmli.d_joins.jrc_joinarr
    [ series[ ser_pos ].jos_joinno ].jo_recs[ 1 ].jop_tableno = _curr_tab)
THEN
    BEGIN
    IF  (dmli.d_joins.jrc_joinarr[ series[ ser_pos ].jos_joinno ].
        jo_recs[ 2 ].jop_tableno = cak68_join_value)
    THEN
        _tab_sequence := [ ]
    ELSE
        _tab_sequence := [ dmli.d_joins.jrc_joinarr[ series[ ser_pos ].
              jos_joinno ].jo_recs[ 2 ].jop_tableno ];
    (*ENDIF*) 
    END
ELSE
    _tab_sequence := [ dmli.d_joins.jrc_joinarr
          [ series[ ser_pos ].jos_joinno ].jo_recs[ 1 ].jop_tableno ];
(*ENDIF*) 
IF  ( mul_tabs.mt_pos <> 0 )
THEN
    (* decided for one of mult. transistions *)
    BEGIN
    _tab_sequence := mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tab_seq;
    _curr_tab     := mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_dst_table;
    END;
&ifdef TRACE
(*ENDIF*) 
t01int4 (ak_join, 'ser_pos     ', ser_pos);
t01int4 (ak_join, 'sort_pos    ', sort_pos);
t01int4 (ak_join, 'mt_pos      ', mul_tabs.mt_pos);
t01int4 (ak_join, 'jcnt        ', dmli.d_joins.jrc_cnt);
&endif
ak681first_keyfield_no (acv, dmli, _col_buf, _curr_tab, _nxt_fieldno );
_ins_pos := sort_pos;
_joinpred_pos := series[ ser_pos ].jos_joinno;
WHILE ((_ins_pos < dmli.d_joins.jrc_cnt) AND
      ( acv.a_returncode = 0 ) AND (NOT _end_found)) DO
    (* loop over remaining entries *)
    BEGIN
&   ifdef TRACE
    t01int4 (ak_join, '_ins_pos    ', _ins_pos);
&   endif
    WHILE ((_joinpred_pos < dmli.d_joins.jrc_cnt) AND (NOT _end_found)) DO
        BEGIN
&       ifdef TRACE
        t01int4 (ak_join, 'i           ', _joinpred_pos);
&       endif
        IF  ( dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_op = op_eq )
        THEN
            BEGIN
            _j := 1;
            _k := 2;
            WHILE (_j <= 2) DO
                BEGIN
                IF  (dmli.d_joins.jrc_joinarr[ _joinpred_pos ].
                    jo_recs[ _k ].jop_tableno = cak68_join_value)
                THEN
                    _used_tables := true
                ELSE
                    BEGIN
                    _used_tables :=
                          dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_recs[ _k ].jop_tableno
                          in _tab_sequence;
                    IF  (_tab_sequence = [ ])
                    THEN
                        (* join value *)
                        BEGIN
                        _m := ser_pos;
                        WHILE (NOT _used_tables) AND (_m > 1) DO
                            BEGIN
                            _m := pred (_m);
                            _used_tables := series [ _m ].jos_source =
                                  dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_recs[ _k ].jop_tableno;
                            END;
                        (*ENDWHILE*) 
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                IF  ((dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_recs[ _j ].
                    jop_tableno = _curr_tab)
                    AND
                    (dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_recs[ _j ].
                    jop_fieldno = _nxt_fieldno)
                    AND
                    (dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_recs[ _j ].
                    jop_cntstack = 1)
                    AND
                    (dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_recs[ _k ].jop_inoutlen <=
                    dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_recs[ _j ].jop_inoutlen)
                    AND
                    (jtkey in dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_recs[ _j ].
                    jop_propset)
                    AND
                    _used_tables)
                THEN
                    BEGIN
                    series[ ser_pos ].jos_fieldcnt :=
                          succ (series[ ser_pos ].jos_fieldcnt);
                    IF  series[ ser_pos ].jos_fieldcnt <
                        dmli.d_sparr.pbasep^.sbase.bkeycolcount
                    THEN
                        BEGIN
                        ak681next_keyfield_no (dmli,
                              _col_buf, _nxt_fieldno);
                        IF  (_m > 0)
                        THEN
                            _tab_sequence :=
                                  [ series[ _m ].jos_source ];
                        (*ENDIF*) 
                        IF  (series[ ser_pos ].jos_fieldcnt >= _old_sfieldcnt)
                        THEN
                            _end_found := true;
                        (*ENDIF*) 
                        IF  (dmli.d_joins.jrc_joinarr[ _joinpred_pos ].
                            jo_recs[ _j ].jop_inoutlen > dmli.d_joins.jrc_joinarr[ _joinpred_pos ].
                            jo_recs[ _k ].jop_inoutlen)
                        THEN
                            BEGIN
                            dmli.d_joins.jrc_joinarr[ _joinpred_pos ].
                                  jo_recs[ _k ].jop_inoutlen := dmli.d_joins.
                                  jrc_joinarr[ _joinpred_pos ].
                                  jo_recs[ _j ].jop_inoutlen;
                            END
                        ELSE
                            BEGIN
                            dmli.d_joins.jrc_joinarr[ _joinpred_pos ].
                                  jo_recs[ _j ].jop_inoutlen := dmli.d_joins.
                                  jrc_joinarr[ _joinpred_pos ].
                                  jo_recs[ _k ].jop_inoutlen;
                            END;
                        (*ENDIF*) 
                        END
                    ELSE
                        _end_found := true;
                    (*ENDIF*) 
                    IF  (_ins_pos < _joinpred_pos + 1)
                    THEN
                        BEGIN
                        _joinpred := dmli.d_joins.jrc_joinarr[ _ins_pos ];
                        dmli.d_joins.jrc_joinarr[ _ins_pos ] :=
                              dmli.d_joins.jrc_joinarr[ _joinpred_pos ];
                        dmli.d_joins.jrc_joinarr[ _joinpred_pos ] := _joinpred;
                        _joinpred_pos := dmli.d_joins.jrc_cnt; (* exit while *)
                        END;
                    (*ENDIF*) 
                    _j := 3; (* exit while *)
                    END;
                (*ENDIF*) 
                _j := succ (_j);
                _k := pred (_k);
                END;
            (*ENDWHILE*) 
            END;
        (*ENDIF*) 
        _joinpred_pos := succ (_joinpred_pos);
        END;
    (*ENDWHILE*) 
    _ins_pos := succ (_ins_pos);
    IF  (_ins_pos = series[ ser_pos ].jos_joinno)
    THEN
        _joinpred_pos := sort_pos
    ELSE
        _joinpred_pos := _ins_pos;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
dmli.d_joins.jrc_joinarr[ sort_pos ].jo_recs[ 2 ].jop_outpos :=
      series[ ser_pos ].jos_fieldcnt;
sort_pos := sort_pos + series[ ser_pos ].jos_fieldcnt;
&ifdef TRACE
a683_output (ak_join, dmli);
IF  (series[ ser_pos ].jos_fieldcnt <> _old_sfieldcnt)
THEN
    vabort (c_write_core);
&endif
(*ENDIF*) 
ak681update_sequence (dmli, series, mul_tabs);
END;
 
(*------------------------------*) 
 
FUNCTION
      a681ieval_inv_kind (
            VAR acv          : tak_all_command_glob;
            VAR dmli         : tak_dml_info;
            VAR table_stats  : tak68_table_stats;
            VAR mul_tabs     : tak68_mult_tabs;
            pos_jarr         : tsp00_Int2;
            pos_jrec         : tsp00_Int2;
            is_join_value    : boolean) : tak68_one_jointype;
 
VAR
      _curr_tabid        : tgg00_Surrogate;
      _index_scan_rec    : tak_index_scan_record;
      _jointype          : tak68_one_jointype;
      _curr_tab          : tsp00_Int2;
 
BEGIN
_jointype := to_eq_field;
(* set correct mt_pos *)
mul_tabs.mt_pos := mul_tabs.mt_cnt;
IF  ( mul_tabs.mt_pos < mxak68_mt_arr )
THEN
    BEGIN
&   ifdef TRACE
    t01int4 (ak_join, 'pos_jarr    ', pos_jarr);
    t01int4 (ak_join, 'pos_jrec    ', pos_jrec);
&   endif
    _curr_tab   := dmli.d_joins.jrc_joinarr[ pos_jarr ].
          jo_recs[ pos_jrec ].jop_tableno;
    _curr_tabid := dmli.d_tabarr[ _curr_tab ].otreeid.fileTabId_gg00;
    a24init_index_scan (acv, _curr_tabid, _index_scan_rec);
    WHILE a24next_named_index( acv, _index_scan_rec ) AND
          ( mul_tabs.mt_pos < mxak68_mt_arr ) DO
        BEGIN
        ak681meval_one_minv( acv, dmli, table_stats, mul_tabs, pos_jarr, pos_jrec,
              _index_scan_rec.isr_buf^.
              smindex.indexdef[_index_scan_rec.isr_index],
              _jointype, _curr_tab, is_join_value );
        END;
    (*ENDWHILE*) 
    a24finish_index_scan (acv, _index_scan_rec);
    END;
(*ENDIF*) 
a681ieval_inv_kind := _jointype;
&ifdef TRACE
a683trace_jointype(ak_join, 'return      ', _jointype);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681meval_one_minv(
            VAR acv         : tak_all_command_glob;
            VAR dmli        : tak_dml_info;
            VAR table_stats : tak68_table_stats;
            VAR mul_tabs    : tak68_mult_tabs;
            pos_jarr        : integer;
            pos_jrec        : integer;
            VAR m_inddef    : tak_multindex;
            VAR jointype    : tak68_one_jointype;
            dest_tab        : tsp00_Uint1;
            is_join_value   : boolean);
 
VAR
      _ix                  : tsp00_Int2;
      (* index in jrc_joinarr *)
      _unknown_table_idx   : tsp00_Int2;
      _dst, _src           : tsp00_Int2;
      _nxt_fieldno         : tsp00_Int2;
      _start_ut_cnt        : tsp00_Int2;
      _start_mt_cnt        : tsp00_Int2;
      _virt_mt_cnt         : tsp00_Int2;
      _unknown_table_pos   : tsp00_Int2;
      _unknown_table_cnt   : tsp00_Int2;
      _combined_multiplier : tsp00_Int4;
      _all_rows            : tsp00_Int4;
      _unknown_table_arr   : tak681_unknown_table_arr;
      _index_tree          : tgg00_FileId;
      _new_tables          : tak_joinset;
      _f_ok                : boolean;
      _known_table         : boolean;
      _reset_loop          : boolean;
 
BEGIN
(* jo_recs[ pos_jrec ].jop_source is destination table         *)
(* i.e. we would like to access jo_recs[ pos_jrec ].jop_source *)
(* with index described in m_inddef                            *)
CASE pos_jrec OF
    1:
        _src := 2;
    2:
        _src := 1;
    END;
(*ENDCASE*) 
&ifdef trace
t01int4 (ak_join, 'jop_fieldno ', dmli.d_joins.jrc_joinarr[ pos_jarr ].
      jo_recs[ pos_jrec ].jop_fieldno );
t01int4 (ak_join, '1. inv field', m_inddef.icolseq[ 1 ] );
&endif
IF  ( NOT m_inddef.idisabled )
    AND
    (* run for first index column *)
    ( dmli.d_joins.jrc_joinarr[ pos_jarr ].
    jo_recs[ pos_jrec ].jop_fieldno = m_inddef.icolseq[ 1 ] )
    AND
    (( dmli.d_joins.jrc_joinarr[ pos_jarr ].jo_recs[ _src ].jop_inoutlen <=
    dmli.d_joins.jrc_joinarr[ pos_jarr ].jo_recs[ pos_jrec ].jop_inoutlen ) OR
    ( m_inddef.icount = 1 ))
THEN
    BEGIN
    _index_tree := dmli.d_tabarr[ dest_tab ].otreeid;
    (* set mindex file type *)
    _index_tree.fileTfn_gg00        := tfnMulti_egg00;
    _index_tree.fileTfnNo_gg00[ 1 ] := chr( m_inddef.indexno );
    _index_tree.fileRoot_gg00       := NIL_PAGE_NO_GG00;
    b01filestate( acv.a_transinf.tri_trans, _index_tree );
    ;
    IF  ( acv.a_transinf.tri_trans.trError_gg00 <> e_file_not_accessible )
    THEN
        BEGIN
        (* create 'virtual' entry in mul_tabs *)
        mul_tabs.mt_pos := succ( mul_tabs.mt_cnt );
        ;
        (* initialize mul_tab entry *)
        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_dst_table := dest_tab;
        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_jointype  := jointype;
        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_fieldcnt  := 1;
        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_indexno   := m_inddef.indexno;
        IF  ( NOT is_join_value )
        THEN
            BEGIN
            mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tab_seq  :=
                  [ dmli.d_joins.jrc_joinarr[ pos_jarr ].jo_recs[ _src ].jop_tableno ];
            mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tablecnt := 1;
            END
        ELSE
            BEGIN
            mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tab_seq  := [ ];
            mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tablecnt := 0;
            END;
        (*ENDIF*) 
        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_multipl  := dmli.d_joins.
              jrc_joinarr[ pos_jarr ].jo_recs[ pos_jrec ].jop_multiplier;
        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist := 1;
        _all_rows := (table_stats[mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_dst_table].ts_all_pages *
              table_stats[mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_dst_table].ts_recs_per_page);
        IF  (dmli.d_joins.jrc_joinarr[ pos_jarr ].jo_recs[ pos_jrec ].jop_multiplier > 1)
        THEN
            mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist :=
                  round (_all_rows /dmli.d_joins.jrc_joinarr[ pos_jarr ].jo_recs[ pos_jrec ].jop_multiplier);
        (*ENDIF*) 
        IF  (mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist > _all_rows)
        THEN
            mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist := _all_rows;
        (*ENDIF*) 
        IF  (mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist < 1)
        THEN
            mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist := 1;
        (*ENDIF*) 
        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_joinno   := pos_jarr;
        ;
        _f_ok := true;
        IF  ( m_inddef.icount = 1 )
        THEN
            BEGIN
&           ifdef trace
            t01name( ak_join, 'single index      ' );
            t01bool( ak_join, 'unique index', m_inddef.iunique );
&           endif
            IF  ( m_inddef.iunique )
            THEN
                BEGIN
                mul_tabs.mt_arr [ mul_tabs.mt_pos ].mtr_jointype := to_unique_field;
                mul_tabs.mt_arr [ mul_tabs.mt_pos ].mtr_multipl  := cak68_only_field_multiplier;
                END
            ELSE
                mul_tabs.mt_arr [ mul_tabs.mt_pos ].mtr_jointype := to_all_invfields;
            (*ENDIF*) 
            jointype        := to_mt_join;
            (* ensure new entry *)
            mul_tabs.mt_cnt := mul_tabs.mt_pos;
            END
        ELSE
            (* multiple index *)
            BEGIN
            IF  ( dmli.d_joins.jrc_joinarr[ pos_jarr ].jo_recs[ _src ].
                jop_inoutlen >
                dmli.d_joins.jrc_joinarr[ pos_jarr ].jo_recs[ pos_jrec ].
                jop_inoutlen )
            THEN
                BEGIN
&               ifdef trace
                t01sname(ak_join, '_f_ok false ');
&               endif
                (* ensure non complete join transition *)
                _f_ok := false;
                END;
            (*ENDIF*) 
            jointype := to_invpart;
            mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_jointype := jointype;
            (* get second index field number *)
            _nxt_fieldno   := m_inddef.
                  icolseq [ mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_fieldcnt + 1 ];
            _virt_mt_cnt   := mul_tabs.mt_pos;
            _start_mt_cnt  := mul_tabs.mt_pos;
            _start_ut_cnt  := 0;
            _new_tables    := [ ];
&           ifdef TRACE
            t01name(ak_join, '--start  mul_tabs-');
            a683multabs_trace (ak_join, mul_tabs, _virt_mt_cnt, 0, dmli.d_cntfromtab);
&           endif
            _unknown_table_cnt := 0;
            _unknown_table_pos := 1;
            REPEAT
                (* UNTIL (_unknown_table_pos > _unknown_table_cnt)   *)
                (* i.e. UNTIL no input into _unknown_table_arr *)
                IF  ( _unknown_table_pos <= _unknown_table_cnt )
                THEN
                    (* earlier insert into _unknown_table_arr *)
                    BEGIN
                    _start_ut_cnt := _unknown_table_cnt;
                    _start_mt_cnt := _virt_mt_cnt;
                    _new_tables   := [ ];
                    (* just switch the first unknown table to known table *)
                    _ix := _unknown_table_arr [ _unknown_table_pos ].ut_joinno;
                    IF  ( mul_tabs.mt_pos < mxak68_mt_arr )
                    THEN
                        BEGIN
                        (* there are X entries in mul_tabs *)
                        (* save the first entry            *)
                        mul_tabs.mt_pos := succ( mul_tabs.mt_pos );
                        _virt_mt_cnt    := mul_tabs.mt_pos;
&                       ifdef TRACE
                        t01int4 (ak_join, 'act mt_pos  ', mul_tabs.mt_pos);
&                       endif
                        END;
&                   ifdef TRACE
                    (*ENDIF*) 
                    t01name(ak_join, '-- upd mul_tabs --');
&                   endif
                    (* first loop through WHILE will lead to _known_table=true *)
                    mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tab_seq  :=
                          mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tab_seq +
                          [ _unknown_table_arr [ _unknown_table_pos ].ut_tableno ];
                    mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tablecnt :=
                          succ( mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tablecnt );
                    _nxt_fieldno :=
                          m_inddef.icolseq[ mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_fieldcnt + 1 ];
                    (* update _unknown_table_pos concerning new entry *)
                    _unknown_table_pos   := succ( _unknown_table_pos );
                    END
                ELSE
                    _ix := 0;
                (*ENDIF*) 
&               ifdef TRACE
                a683multabs_trace (ak_join, mul_tabs, _virt_mt_cnt, 0, dmli.d_cntfromtab);
                t01int4(ak_join, '-act keycol-', _nxt_fieldno);
&               endif
                _unknown_table_idx := _ix;
                _reset_loop        := false;
                WHILE ( mul_tabs.mt_arr [ mul_tabs.mt_pos ].mtr_fieldcnt <
                      m_inddef.icount ) AND
                      (_ix < dmli.d_joins.jrc_cnt) AND _f_ok DO
                    BEGIN
                    IF  (( _ix <> pos_jarr )
                        AND
                        ( dmli.d_joins.jrc_joinarr[ _ix ].jo_op = op_eq ))
                    THEN
                        (* walk through join conditions 'S.col = D.col' *)
                        (* wherby skip actual entry,                    *)
                        (* until complete key for dest_tab found       *)
&                       ifdef TRACE
                        IF  _unknown_table_idx = _ix
                        THEN
                            t01int4(ak_join, 're-run pos  ', _ix)
                        ELSE
                            t01int4(ak_join, 'act jarr pos', _ix);
                        (*ENDIF*) 
&                   endif
                    (*ENDIF*) 
                    WITH dmli.d_joins.jrc_joinarr[ _ix ] DO
                        BEGIN
                        _dst := 1;
                        _src := 2;
                        WHILE ( _dst <= 2 ) DO
                            BEGIN
&                           ifdef TRACE
                            IF  _src = 1
                            THEN
                                t01sname(ak_join, 'left site   ')
                            ELSE
                                t01sname(ak_join, 'right site  ');
                            (*ENDIF*) 
&                           endif
                            (* inspect join condition *)
                            IF  (( jo_recs[ _dst ].jop_tableno = dest_tab )
                                AND
                                (* field successor *)
                                ( jo_recs[ _dst ].jop_fieldno = _nxt_fieldno )
                                AND
                                (* ? for correct index comparsion ? *)
                                ( jo_recs[ _src ].jop_inoutlen <=
                                jo_recs[ _dst ].jop_inoutlen )
                                AND
                                (* no function code *)
                                ( jo_recs[ _dst ].jop_cntstack = 1 )
                                AND
                                ( jtmulti in jo_recs[ _dst ].jop_propset ))
                            THEN
                                (* we found transition to actual *)
                                (* table with next key column    *)
                                BEGIN
                                (* check state of involved table *)
                                IF  ( jo_recs[ _src ].jop_tableno =
                                    cak68_join_value )
                                THEN
                                    _known_table := true
                                ELSE
                                    _known_table := jo_recs[ _src ].
                                          jop_tableno in
                                          mul_tabs.mt_arr [ mul_tabs.mt_pos ].
                                          mtr_tab_seq;
                                (*ENDIF*) 
                                IF  ( _known_table )
                                THEN
                                    BEGIN
&                                   ifdef TRACE
                                    t01int4(ak_join, 'known table ', dmli.d_joins.
                                          jrc_joinarr[ _ix ].jo_recs[ _src ].
                                          jop_tableno);
&                                   endif
                                    (* we found 'wider' transition to current table *)
                                    (* D.column1 -> S.invcol1 and D.column2 -> S.invcol2 *)
                                    (* reject useless transition combination  *)
                                    (* A.col -> S.invcol1, B.col -> S.invcol2 *)
                                    (* reject earlier insert into _unknown_table_arr *)
                                    _unknown_table_cnt := _start_ut_cnt;
                                    (* reject earlier insert into mult_tabs  *)
                                    _virt_mt_cnt       := _start_mt_cnt;
                                    (* remark new minv transition      *)
                                    (* count new minv field transition *)
                                    mul_tabs.mt_arr [ mul_tabs.mt_pos ].
                                          mtr_fieldcnt := succ (mul_tabs.
                                          mt_arr [ mul_tabs.mt_pos ].mtr_fieldcnt);
&                                   ifdef trace
                                    a683multabs_trace (ak_join, mul_tabs,
                                          _virt_mt_cnt, 0, dmli.d_cntfromtab);
&                                   endif
                                    _new_tables  := [ ];
                                    (* store smallest multiplier *)
                                    IF  ( mul_tabs.mt_arr[ mul_tabs.mt_pos ].
                                        mtr_multipl > jo_recs[ _dst ].jop_multiplier )
                                    THEN
                                        mul_tabs.mt_arr[ mul_tabs.mt_pos ].
                                              mtr_multipl := jo_recs[ _dst ].jop_multiplier;
                                    (* calculate combined distinctvalue *)
                                    (*ENDIF*) 
                                    _all_rows := (table_stats[mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_dst_table].ts_all_pages *
                                          table_stats[mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_dst_table].ts_recs_per_page);
                                    IF  (jo_recs[ _dst ].jop_multiplier > 1) AND
                                        (mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist < _all_rows)
                                    THEN
                                        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist :=
                                              mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist *
                                              round(_all_rows/jo_recs[ _dst ].jop_multiplier);
                                    (*ENDIF*) 
                                    IF  (mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist > _all_rows)
                                    THEN
                                        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist := _all_rows;
                                    (*ENDIF*) 
                                    IF  (mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist < 1)
                                    THEN
                                        mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_combdist := 1;
                                    (*ENDIF*) 
                                    IF  ( mul_tabs.mt_arr [ mul_tabs.mt_pos ].
                                        mtr_fieldcnt < m_inddef.icount )
                                    THEN
                                        BEGIN
                                        _nxt_fieldno := m_inddef.icolseq
                                              [ mul_tabs.mt_arr [ mul_tabs.mt_pos ].
                                              mtr_fieldcnt + 1 ];
                                        _reset_loop := true;
&                                       ifdef TRACE
                                        t01int4(ak_join, '-nxtkeycol1-', _nxt_fieldno);
&                                       endif
                                        END
                                    ELSE
                                        (* we found complete index *)
                                        BEGIN
                                        IF  ( m_inddef.iunique )
                                        THEN
                                            BEGIN
                                            mul_tabs.mt_arr [ mul_tabs.mt_pos ].
                                                  mtr_jointype := to_unique_field;
                                            mul_tabs.mt_arr [ mul_tabs.mt_pos ].
                                                  mtr_multipl  :=
                                                  cak68_only_field_multiplier;
                                            END
                                        ELSE
                                            mul_tabs.mt_arr [ mul_tabs.mt_pos ].
                                                  mtr_jointype := to_all_invfields;
                                        (*ENDIF*) 
                                        (* exit while*)
                                        _ix := dmli.d_joins.jrc_cnt;
                                        END;
                                    (*ENDIF*) 
                                    END
                                ELSE
                                    (* NOT _known_table *)
                                    (* valid for every entry in       *)
                                    (* jrc_joinarr while first REPEAT *)
                                    (* loop unless it's a join value  *)
                                    BEGIN
                                    IF  ( _unknown_table_cnt < MAX_JOINS_GG04 )
                                        AND
                                        ( _virt_mt_cnt < mxak68_mt_arr )
                                        AND
                                        ( NOT (jo_recs[ _src ].jop_tableno in
                                        _new_tables ))
                                    THEN
                                        BEGIN
                                        (* insert unknown table into _unknown_table_arr *)
                                        (* assure next outer REPEAT LOOP                *)
                                        _unknown_table_cnt :=
                                              succ( _unknown_table_cnt );
                                        _unknown_table_arr [ _unknown_table_cnt ].
                                              ut_tableno := jo_recs[ _src ].jop_tableno;
                                        (* remember index of join condition *)
                                        _unknown_table_arr [ _unknown_table_cnt ].
                                              ut_joinno := _ix;
                                        _virt_mt_cnt := succ( _virt_mt_cnt );
                                        (* create new entry in mult_tabs *)
                                        (* copy content from predecessor *)
                                        mul_tabs.mt_arr[ _virt_mt_cnt ] :=
                                              mul_tabs.mt_arr[ mul_tabs.mt_pos ];
                                        (* remember found new table in new table set *)
                                        _new_tables := _new_tables +
                                              [ _unknown_table_arr [ _unknown_table_cnt ].
                                              ut_tableno ];
&                                       ifdef TRACE
                                        t01int4(ak_join, 'uknown table',
                                              dmli.d_joins.jrc_joinarr[ _ix ].
                                              jo_recs[ _src ].jop_tableno);
                                        t01int4(ak_join, 'uknwn tabcnt',
                                              _unknown_table_cnt);
                                        a683multabs_trace (ak_join, mul_tabs,
                                              _virt_mt_cnt, 0, dmli.d_cntfromtab);
&                                       endif
                                        END;
                                    (*ENDIF*) 
                                    END;
                                (*ENDIF*) 
                                _dst := 3; (* exit work for parts      *)
                                END;
                            (* swap considered direction of join transition *)
                            (*ENDIF*) 
                            _dst := succ (_dst);
                            _src := pred (_src);
                            END;
                        (*ENDWHILE*) 
                        END;
                    (*ENDWITH*) 
                    ;
                    (* -- one join entry observed -- *)
                    IF  ( mul_tabs.mt_arr [ mul_tabs.mt_pos ].mtr_jointype = to_all_invfields )
                        AND
                        ( NOT is_join_value )
                        AND
                        ( mul_tabs.mt_arr [ mul_tabs.mt_pos ].mtr_tablecnt = 1 )
                    THEN
                        (* best join transition found *)
                        BEGIN
                        (* exit inner while *)
                        _ix       := dmli.d_joins.jrc_cnt;
                        END
                    ELSE
                        IF  ( _unknown_table_idx > 0 )
                            (* we found already a unknown table        *)
                            (* in a first walk through join conditions *)
                            AND
                            ( _ix = _unknown_table_idx )
                        THEN
                            BEGIN
                            (* now we have inserted unknown table mtr_tab_seq *)
                            (* loop with this this start table sequence       *)
                            (* through join conditions                        *)
                            _ix       := 0;
                            _unknown_table_idx := 0;
                            END
                        ELSE
                            (* get next join condition *)
                            IF  ( NOT _reset_loop )
                            THEN
                                (* we have found a unknown table OR *)
                                (* known table with whole key       *)
                                (* exit while loop                  *)
                                _ix := succ( _ix )
                            ELSE
                                (* we have found a known table and *)
                                (* there are further key columns   *)
                                BEGIN
                                _reset_loop := false;
                                _ix         := 0;
                                END;
                            (*ENDIF*) 
                        (*ENDIF*) 
                    (*ENDIF*) 
                    END;
                (*ENDWHILE*) 
            UNTIL
                ( _unknown_table_pos > _unknown_table_cnt );
            (*ENDREPEAT*) 
            IF  ( mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_fieldcnt > 0 )
            THEN
                BEGIN
                jointype := to_mt_join;
                (* *** Multiplier update *** *)
                FOR _ix := mul_tabs.mt_cnt + 1 TO mul_tabs.mt_pos DO
                    BEGIN
                    IF  (mul_tabs.mt_arr[ _ix ].mtr_fieldcnt > 1)
                    THEN
                        BEGIN (* take combined multiplier into acount *)
                        _combined_multiplier :=    round((table_stats[mul_tabs.mt_arr[ _ix ].mtr_dst_table].ts_all_pages *
                              table_stats[mul_tabs.mt_arr[ _ix ].mtr_dst_table].ts_recs_per_page) /
                              mul_tabs.mt_arr[ _ix ].mtr_combdist);
                        IF  (_combined_multiplier  < cak68_only_field_multiplier)
                        THEN
                            _combined_multiplier := cak68_only_field_multiplier;
                        (*ENDIF*) 
                        IF  (mul_tabs.mt_arr[ _ix ].mtr_multipl > _combined_multiplier)
                        THEN
                            mul_tabs.mt_arr[ _ix ].mtr_multipl :=
                                  (mul_tabs.mt_arr[ _ix ].mtr_multipl + _combined_multiplier) DIV 2;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    ;
                    (* avoid wrong (something error case) multiplier *)
                    IF  (mul_tabs.mt_arr[ _ix ].mtr_multipl < cak68_only_field_multiplier)
                    THEN
                        mul_tabs.mt_arr[ _ix ].mtr_multipl :=
                              cak68_only_field_multiplier;
                    (*ENDIF*) 
                    END;
                (*ENDFOR*) 
                (* ensure new entries *)
                mul_tabs.mt_cnt := mul_tabs.mt_pos;
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
&       ifdef TRACE
        a683multabs_trace (ak_join, mul_tabs, mul_tabs.mt_cnt, 0, dmli.d_cntfromtab);
&       endif
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a681inv_sort_joinarr(
            VAR acv      : tak_all_command_glob;
            VAR dmli     : tak_dml_info;
            VAR jinfos   : tak68_joininfos;
            VAR series   : tak68_sequence;
            ser_pos      : tsp00_Int2;
            VAR sort_pos : tsp00_Int2;
            VAR mul_tabs : tak68_mult_tabs);
 
VAR
      _curr_tab       : tsp00_Int2;
      _index_no       : tsp00_Int2;
      _old_sfieldcnt  : tsp00_Int2;
      _joinpred_pos   : tsp00_Int2;
      _j, _k          : tsp00_Int2;
      _ins_pos        : tsp00_Int2;
      _m              : tsp00_Int2;
      _nxt_fieldno    : tsp00_Int2;
      _joinpred       : tak_one_join;
      _index_scan_rec : tak_index_scan_record;
      _tab_sequence   : tak_joinset;
      _inv_tabid      : tgg00_Surrogate;
      _index_found    : boolean;
      _end_found      : boolean;
      _used_tables    : boolean;
 
BEGIN
_end_found := false;
(* remember original sort order *)
FOR _m := 0 TO dmli.d_joins.jrc_cnt - 1 DO
    dmli.d_joins.jrc_joinarr[ _m ].jo_recs[ 1 ].jop_outpos := _m;
(*ENDFOR*) 
_m         := 0;
_old_sfieldcnt := series[ ser_pos ].jos_fieldcnt;
series[ ser_pos ].jos_fieldcnt := 0;
_curr_tab := series[ ser_pos ].jos_source;
&ifdef TRACE
t01int4 (ak_join, 'sort_pos    ', sort_pos);
t01int4 (ak_join, 'jcnt        ', dmli.d_joins.jrc_cnt);
a683_output (ak_join, dmli);
&endif
IF  (dmli.d_joins.jrc_joinarr
    [ series[ ser_pos ].jos_joinno ].jo_recs[ 1 ].jop_tableno = _curr_tab)
THEN
    BEGIN
    IF  (dmli.d_joins.jrc_joinarr[ series[ ser_pos ].jos_joinno ].
        jo_recs[ 2 ].jop_tableno = cak68_join_value)
    THEN
        _tab_sequence := [ ]
    ELSE
        _tab_sequence := [ dmli.d_joins.jrc_joinarr[ series[ ser_pos ].
              jos_joinno ].jo_recs[ 2 ].jop_tableno ];
    (*ENDIF*) 
    END
ELSE
    _tab_sequence := [ dmli.d_joins.jrc_joinarr[ series[ ser_pos ].
          jos_joinno ].jo_recs[ 1 ].jop_tableno ];
(*ENDIF*) 
IF  ( mul_tabs.mt_pos <> 0 )
THEN
    BEGIN
    _tab_sequence := mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_tab_seq;
    _curr_tab     := mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_dst_table;
    _index_no     := mul_tabs.mt_arr[ mul_tabs.mt_pos ].mtr_indexno;  (* used multiple indexno *)
    END
ELSE
    _index_no := series[ ser_pos ].jos_indexno;
(*ENDIF*) 
_inv_tabid := dmli.d_tabarr[ series[ ser_pos ].jos_source ].otreeid.fileTabId_gg00;
a24init_index_scan (acv, _inv_tabid, _index_scan_rec);
_index_found := false;
REPEAT
    IF  a24next_named_index (acv, _index_scan_rec)
    THEN
        _index_found := (_index_no = _index_scan_rec.isr_buf^.
              smindex.indexdef[_index_scan_rec.isr_index].indexno)
    ELSE
        a07ak_system_error (acv, 681, 1);
    (*ENDIF*) 
UNTIL
    _index_found OR (acv.a_returncode <> 0);
(*ENDREPEAT*) 
a24finish_index_scan (acv, _index_scan_rec);
IF  _index_found
THEN
    BEGIN
    _ins_pos     := sort_pos;
    _joinpred_pos:= series[ ser_pos ].jos_joinno;
    _nxt_fieldno := _index_scan_rec.isr_buf^.smindex.
          indexdef[_index_scan_rec.isr_index].icolseq[ series[ ser_pos ].
          jos_fieldcnt + 1 ];
    WHILE ((_ins_pos < dmli.d_joins.jrc_cnt) AND (NOT _end_found)) DO
        BEGIN
&       ifdef TRACE
        t01int4 (ak_join, '_ins_pos    ', _ins_pos);
&       endif
        WHILE ((_joinpred_pos < dmli.d_joins.jrc_cnt) AND (NOT _end_found)) DO
            BEGIN
&           ifdef TRACE
            t01int4 (ak_join, '_joinpred_po', _joinpred_pos);
            t01int4 (ak_join, 'nxt_fieldno ', _nxt_fieldno);
&           endif
            IF  ( dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_op = op_eq )
            THEN
                BEGIN
                _j := 1;
                _k := 2;
                WHILE (_j <= 2) DO
                    (* process both sides of predicate *)
                    BEGIN
                    IF  (dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_recs[ _k ].jop_tableno =
                        cak68_join_value)
                    THEN
                        _used_tables := true
                    ELSE
                        BEGIN
                        _used_tables :=
                              dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_recs[ _k ].jop_tableno
                              in _tab_sequence;
                        IF  (_tab_sequence = [ ])
                        THEN
                            (* join value found, look for supplier of value *)
                            BEGIN
                            _m := ser_pos;
                            WHILE (NOT _used_tables) AND (_m > 1) DO
                                BEGIN
                                _m := pred (_m);
                                _used_tables := series [ _m ].jos_source =
                                      dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_recs[ _k ].
                                      jop_tableno;
                                END;
                            (*ENDWHILE*) 
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    IF  ((dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_recs[ _j ].
                        jop_tableno = _curr_tab)
                        AND
                        (dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_recs[ _j ].
                        jop_fieldno = _nxt_fieldno)
                        AND
                        (dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_recs[ _j ].
                        jop_cntstack = 1)
                        AND
                        (jtmulti in dmli.d_joins.jrc_joinarr[ _joinpred_pos ].jo_recs[ _j ].
                        jop_propset)
                        AND
                        _used_tables)
                    THEN
                        BEGIN
                        series[ ser_pos ].jos_fieldcnt :=
                              succ (series[ ser_pos ].jos_fieldcnt);
                        IF  _index_scan_rec.isr_buf^.smindex.
                            indexdef[_index_scan_rec.isr_index].
                            icolstack[ series[ ser_pos ].jos_fieldcnt ].eop in
                            [ op_order_desc, op_unique_desc ]
                        THEN
                            CASE jinfos.ji_st_addr^[ dmli.d_joins.jrc_joinarr[ _joinpred_pos ].
                                  jo_recs[ _j ].jop_startstack ].eop OF
                                op_ascii :
                                    IF  (_index_scan_rec.isr_buf^.smindex.
                                        indexdef[_index_scan_rec.isr_index].
                                        icolstack[ series[ ser_pos ].jos_fieldcnt ].eop =
                                        op_order_desc)
                                    THEN
                                        jinfos.ji_st_addr^
                                              [ dmli.d_joins.jrc_joinarr[ _joinpred_pos ].
                                              jo_recs[ _j ].jop_startstack ].
                                              eop := op_order_desc_ascii
                                    ELSE
                                        jinfos.ji_st_addr^
                                              [ dmli.d_joins.jrc_joinarr[ _joinpred_pos ].
                                              jo_recs[ _j ].jop_startstack ].
                                              eop := op_unique_desc_ascii;
                                    (*ENDIF*) 
                                OTHERWISE
                                    jinfos.ji_st_addr^
                                          [ dmli.d_joins.jrc_joinarr[ _joinpred_pos ].
                                          jo_recs[ _j ].jop_startstack ].eop :=
                                          _index_scan_rec.isr_buf^.smindex.
                                          indexdef[_index_scan_rec.isr_index].
                                          icolstack[ series[ ser_pos ].jos_fieldcnt ].eop;
                                END;
                            (*ENDCASE*) 
                        (*ENDIF*) 
                        IF  ( series[ ser_pos ].jos_fieldcnt < _index_scan_rec.isr_buf^.
                            smindex.indexdef[_index_scan_rec.isr_index].icount )
                        THEN
                            BEGIN
                            _nxt_fieldno := _index_scan_rec.isr_buf^.
                                  smindex.indexdef[_index_scan_rec.isr_index].
                                  icolseq [ series[ ser_pos ].jos_fieldcnt + 1 ];
                            IF  (_m > 0)
                            THEN
                                (* join value found at any time *)
                                _tab_sequence :=
                                      [ series[ _m ].jos_source ];
                            (*ENDIF*) 
                            IF  (series[ ser_pos ].jos_fieldcnt >= _old_sfieldcnt)
                            THEN
                                _end_found := true;
                            (*ENDIF*) 
                            IF  (dmli.d_joins.jrc_joinarr[ _joinpred_pos ].
                                jo_recs[ _j ].jop_inoutlen > dmli.d_joins.jrc_joinarr[ _joinpred_pos ].
                                jo_recs[ _k ].jop_inoutlen)
                            THEN
                                BEGIN
                                dmli.d_joins.jrc_joinarr[ _joinpred_pos ].
                                      jo_recs[ _k ].jop_inoutlen := dmli.d_joins.
                                      jrc_joinarr[ _joinpred_pos ].
                                      jo_recs[ _j ].jop_inoutlen;
                                END
                            ELSE
                                BEGIN
                                dmli.d_joins.jrc_joinarr[ _joinpred_pos ].
                                      jo_recs[ _j ].jop_inoutlen := dmli.d_joins.
                                      jrc_joinarr[ _joinpred_pos ].
                                      jo_recs[ _k ].jop_inoutlen;
                                END;
                            (*ENDIF*) 
                            END
                        ELSE
                            _end_found := true;
                        (*ENDIF*) 
                        IF  (_ins_pos < _joinpred_pos + 1)
                        THEN
                            (* put content in front *)
                            BEGIN
                            _joinpred := dmli.d_joins.jrc_joinarr[ _ins_pos ];
                            dmli.d_joins.jrc_joinarr[ _ins_pos ] :=
                                  dmli.d_joins.jrc_joinarr[ _joinpred_pos ];
                            dmli.d_joins.jrc_joinarr[ _joinpred_pos ] := _joinpred;
                            _joinpred_pos := dmli.d_joins.jrc_cnt; (* exit while *)
                            END;
                        (*ENDIF*) 
                        _j := 3; (* exit while *)
                        END;
                    (*ENDIF*) 
                    _j := succ (_j);
                    _k := pred (_k);
                    END;
                (*ENDWHILE*) 
                END
            ELSE
                BEGIN
                (* sort equal joins only *)
                END;
            (*ENDIF*) 
            _joinpred_pos := succ (_joinpred_pos);
            END;
        (*ENDWHILE*) 
        _ins_pos := succ (_ins_pos);
        IF  (_ins_pos = series[ ser_pos ].jos_joinno)
        THEN
            _joinpred_pos := sort_pos
        ELSE
            _joinpred_pos := _ins_pos;
        (*ENDIF*) 
        END;
    (*ENDWHILE*) 
    dmli.d_joins.jrc_joinarr[ sort_pos ].jo_recs[ 2 ].jop_outpos :=
          series[ ser_pos ].jos_fieldcnt;
    sort_pos := sort_pos + series[ ser_pos ].jos_fieldcnt;
&   ifdef TRACE
    a683_output (ak_join, dmli);
    IF  (series[ ser_pos ].jos_fieldcnt <> _old_sfieldcnt)
    THEN
        vabort (c_write_core);
&   endif
    (*ENDIF*) 
    END;
(*ENDIF*) 
ak681update_sequence (dmli, series, mul_tabs);
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681update_sequence (
            VAR dmli     : tak_dml_info;
            VAR series   : tak68_sequence;
            VAR mul_tabs : tak68_mult_tabs);
 
VAR
      _i : tsp00_Int2;
      _j : tsp00_Int2;
 
BEGIN
FOR _i := 1 TO dmli.d_cntfromtab DO
    BEGIN
    _j := 0;
    WHILE (_j < dmli.d_joins.jrc_cnt) DO
        BEGIN
        IF  (series[ _i ].jos_joinno = dmli.d_joins.jrc_joinarr[ _j ].
            jo_recs[ 1 ].jop_outpos)
        THEN
            BEGIN
            series[ _i ].jos_joinno  := _j;
&           ifdef TRACE
            t01int4 (ak_join, 'i -->series ', _i);
            t01int4 (ak_join, 'j -->joinarr', _j);
            t01int4 (ak_join, 'jos_joinno  ', series[ _i ].jos_joinno);
            t01int4 (ak_join, 'jos_fieldcnt', series[ _i ].jos_fieldcnt);
&           endif
            _j := dmli.d_joins.jrc_cnt; (* exit while *)
            END;
        (*ENDIF*) 
        _j := succ (_j);
        END;
    (*ENDWHILE*) 
    END;
(*ENDFOR*) 
FOR _i := 1 TO mul_tabs.mt_cnt DO
    BEGIN
    _j := 0;
    WHILE (_j < dmli.d_joins.jrc_cnt) DO
        BEGIN
        IF  (mul_tabs.mt_arr [ _i ].mtr_joinno =
            dmli.d_joins.jrc_joinarr[ _j ].jo_recs[ 1 ].jop_outpos)
        THEN
            BEGIN
            mul_tabs.mt_arr [ _i ].mtr_joinno  := _j;
            _j := dmli.d_joins.jrc_cnt; (* exit while *)
            END;
        (*ENDIF*) 
        _j := succ (_j);
        END;
    (*ENDWHILE*) 
    END;
(*ENDFOR*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681elim_duplicate_st_pos (
            VAR acv      : tak_all_command_glob;
            VAR jinfos   : tak68_joininfos;
            VAR dmli     : tak_dml_info;
            VAR eq_rec   : tak68_eq_record;
            VAR used_set : tak681_used_jrc_set_type);
 
VAR
      _i           : tsp00_Int2;
      _k           : tsp00_Int2;
      _cnt         : tsp00_Int2;
      _free_st_pos : tsp00_Int2;
 
BEGIN
&ifdef TRACE
t01int4 (ak_join, 'eqr_cnt     ', eq_rec.eqr_cnt);
FOR _i := 1 TO eq_rec.eqr_cnt DO
    BEGIN
    t01int4 (ak_join, 'eq used ==>l', eq_rec.eqr_arr[ _i ][ cak68_left ].eqi_joinno);
    t01int4 (ak_join, 'eq used ==>r', eq_rec.eqr_arr[ _i ][ cak68_right ].eqi_joinno);
    END;
(*ENDFOR*) 
&endif
_k := 0;
FOR _i := eq_rec.eqr_cnt DOWNTO 1 DO
    BEGIN
&   ifdef TRACE
    t01int4 (ak_join, 'eqr_left i  ', _i);
    t01int4 (ak_join, 'eq stpos==>l', eq_rec.eqr_arr[ _i ][ cak68_left ].eqi_stackpos);
    t01int4 (ak_join, 'eq stpos==>r', eq_rec.eqr_arr[ _i ][ cak68_right ].eqi_stackpos);
&   endif
    _cnt := ak681cnt_st_entry_in_use (eq_rec, eq_rec.eqr_arr[ _i ][ cak68_left ].eqi_stackpos);
    IF  (_cnt > 1) AND (_k < dmli.d_joins.jrc_cnt)
    THEN
        BEGIN
&       ifdef TRACE
        t01int4 (ak_join, 'eqi_stackpos', eq_rec.eqr_arr[ _i ][ cak68_left ].eqi_stackpos);
&       endif
        _free_st_pos := -1;
        WHILE (_free_st_pos < 1) AND (_k < dmli.d_joins.jrc_cnt) DO
            IF  NOT (_k in used_set)
            THEN
                WITH dmli.d_joins.jrc_joinarr[ _k ] DO
                    BEGIN
                    IF  (ak681cnt_st_entry_in_use (eq_rec,
                        jo_recs[ 1 ].jop_startstack) = 0)
                    THEN
                        _free_st_pos := jo_recs[ 1 ].jop_startstack
                    ELSE
                        IF  (ak681cnt_st_entry_in_use (eq_rec,
                            jo_recs[ 2 ].jop_startstack) = 0)
                        THEN
                            _free_st_pos := jo_recs[ 2 ].jop_startstack
                        ELSE
                            _k := succ (_k);
                        (*ENDIF*) 
                    (*ENDIF*) 
                    END
                (*ENDWITH*) 
            ELSE
                _k := succ (_k);
            (*ENDIF*) 
        (*ENDWHILE*) 
&       ifdef TRACE
        t01int4 (ak_join, 'k  left     ', _k);
&       endif
        IF  _free_st_pos > 0
        THEN
            BEGIN
            WITH jinfos.ji_stack_desc, eq_rec.eqr_arr[ _i ][ cak68_left ] DO
                BEGIN
&               ifdef TRACE
                t01int4 (ak_join, 'k found  l  ', _k);
                t01int4 (ak_join, 'eqi_joinno  ', eqi_joinno);
                t01int4 (ak_join, 'eqi_jrecs   ', eqi_jrecs);
                t01int4 (ak_join, 'free_st_pos ', _free_st_pos);
&               endif
                SAPDB_PascalMove ('VAK681',   1,    
                      (mst_max * STACK_ENTRY_MXGG00),
                      (mst_max * STACK_ENTRY_MXGG00),
                      @jinfos.ji_st_addr^, (eqi_stackpos - 1) * STACK_ENTRY_MXGG00 + 1,
                      @jinfos.ji_st_addr^, (_free_st_pos - 1) * STACK_ENTRY_MXGG00 + 1,
                      STACK_ENTRY_MXGG00, acv.a_returncode);
                dmli.d_joins.jrc_joinarr[ eqi_joinno ].jo_recs[ eqi_jrecs ].jop_startstack :=
                      _free_st_pos;
                eqi_stackpos := _free_st_pos;
                _cnt        := pred (_cnt);
                END;
            (*ENDWITH*) 
            END;
        (*ENDIF*) 
        END;
&   ifdef TRACE
    (*ENDIF*) 
    t01int4 (ak_join, 'eqr_right i ', _i);
    t01int4 (ak_join, 'eq stpos==>l', eq_rec.eqr_arr[ _i ][ cak68_left ].eqi_stackpos);
    t01int4 (ak_join, 'eq stpos==>r', eq_rec.eqr_arr[ _i ][ cak68_right ].eqi_stackpos);
&   endif
    _cnt := ak681cnt_st_entry_in_use (eq_rec, eq_rec.eqr_arr[ _i ][ cak68_right ].eqi_stackpos);
    IF  (_cnt > 1) AND (_k < dmli.d_joins.jrc_cnt)
    THEN
        BEGIN
&       ifdef TRACE
        t01int4 (ak_join, 'eqi_stackpos', eq_rec.eqr_arr[ _i ][ cak68_right ].eqi_stackpos);
&       endif
        _free_st_pos := -1;
        WHILE (_free_st_pos < 1) AND (_k < dmli.d_joins.jrc_cnt) DO
            IF  NOT (_k in used_set)
            THEN
                WITH dmli.d_joins.jrc_joinarr[ _k ] DO
                    BEGIN
                    IF  (ak681cnt_st_entry_in_use (eq_rec,
                        jo_recs[ 1 ].jop_startstack) = 0)
                    THEN
                        _free_st_pos := jo_recs[ 1 ].jop_startstack
                    ELSE
                        IF  (ak681cnt_st_entry_in_use (eq_rec,
                            jo_recs[ 2 ].jop_startstack) = 0)
                        THEN
                            _free_st_pos := jo_recs[ 2 ].jop_startstack
                        ELSE
                            _k := succ (_k);
                        (*ENDIF*) 
                    (*ENDIF*) 
                    END
                (*ENDWITH*) 
            ELSE
                _k := succ (_k);
            (*ENDIF*) 
        (*ENDWHILE*) 
&       ifdef TRACE
        t01int4 (ak_join, 'k right     ', _k);
&       endif
        IF  _free_st_pos > 0
        THEN
            BEGIN
            WITH jinfos.ji_stack_desc, eq_rec.eqr_arr[ _i ][ cak68_right ] DO
                BEGIN
&               ifdef TRACE
                t01int4 (ak_join, 'k found  r  ', _k);
                t01int4 (ak_join, 'eqi_joinno  ', eqi_joinno);
                t01int4 (ak_join, 'eqi_jrecs   ', eqi_jrecs);
                t01int4 (ak_join, 'free_st_pos ', _free_st_pos);
&               endif
                SAPDB_PascalMove ('VAK681',   2,    
                      (mst_max * STACK_ENTRY_MXGG00),
                      (mst_max * STACK_ENTRY_MXGG00),
                      @jinfos.ji_st_addr^, (eqi_stackpos - 1) * STACK_ENTRY_MXGG00 + 1,
                      @jinfos.ji_st_addr^, (_free_st_pos - 1) * STACK_ENTRY_MXGG00 + 1,
                      STACK_ENTRY_MXGG00, acv.a_returncode);
                dmli.d_joins.jrc_joinarr[ eqi_joinno ].jo_recs[ eqi_jrecs ].jop_startstack :=
                      _free_st_pos;
                eqi_stackpos := _free_st_pos;
                _cnt        := pred (_cnt);
                END;
            (*ENDWITH*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDFOR*) 
END;
 
(*------------------------------*) 
 
FUNCTION
      ak681cnt_st_entry_in_use (
            VAR eq_rec  : tak68_eq_record;
            st_pos      : tsp00_Int2) : tsp00_Int2;
 
VAR
      _i   : tsp00_Int2;
      _cnt : tsp00_Int2;
 
BEGIN
_cnt := 0;
FOR _i := 1 TO eq_rec.eqr_cnt DO
    IF  ((eq_rec.eqr_arr[ _i ][ cak68_left ].eqi_stackpos = st_pos) OR
        ( eq_rec.eqr_arr[ _i ][ cak68_right ].eqi_stackpos = st_pos))
    THEN
        _cnt := succ (_cnt);
&   ifdef TRACE
    (*ENDIF*) 
(*ENDFOR*) 
t01int4 (ak_join, 'st_pos      ', st_pos);
t01int4 (ak_join, 'cnt         ', _cnt);
&endif
ak681cnt_st_entry_in_use := _cnt;
END;
 
(*------------------------------*) 
 
PROCEDURE
      a681sort_conditions (
            VAR acv    : tak_all_command_glob;
            VAR dmli   : tak_dml_info;
            VAR series : tak68_sequence);
 
VAR
      _i, _j     : tsp00_Int2;
      _end_pos   : tsp00_Int2;
      _sort_pos  : tsp00_Int2;
 
BEGIN
(* **** sort in order of special-strategies give by jos_joinno *** *)
_sort_pos := 0;
series[ 1 ].jos_joinno := cak68_cartesian_product;
FOR _i := 2 TO dmli.d_cntfromtab DO
    IF  (series[ _i ].jos_joinno <> cak68_cartesian_product)
    THEN
        BEGIN
&       ifdef TRACE
        t01int4 (ak_join, 'join_num    ', series[ _i ].jos_joinno);
        t01int4 (ak_join, 'sort_pos    ', _sort_pos);
        t01int4 (ak_join, 'i           ', _i);
&       endif
        IF  (_sort_pos <> series[ _i ].jos_joinno)
        THEN
            BEGIN
            ak681move_in_front (acv, dmli, series[ _i ].jos_joinno, _sort_pos, series[ _i ].jos_fieldcnt);
            FOR _j := (_i + 1) TO dmli.d_cntfromtab DO
                IF  series[ _j ].jos_joinno = series[ _i ].jos_joinno
                THEN
                    BEGIN
                    _sort_pos := _sort_pos + series[ _j ].jos_fieldcnt -
                          series[ _i ].jos_fieldcnt;
                    series[ _j ].jos_joinno := cak68_cartesian_product;
                    END
                ELSE
                    IF  series[ _j ].jos_joinno < series[ _i ].jos_joinno
                    THEN
                        series[ _j ].jos_joinno :=
                              series[ _j ].jos_joinno + series[ _i ].jos_fieldcnt;
                    (*ENDIF*) 
                (*ENDIF*) 
            (*ENDFOR*) 
            END
        ELSE
            FOR _j := (_i + 1) TO dmli.d_cntfromtab DO
                IF  series[ _j ].jos_joinno = series[ _i ].jos_joinno
                THEN
                    BEGIN
                    _sort_pos := _sort_pos + series[ _j ].jos_fieldcnt -
                          series[ _i ].jos_fieldcnt;
                    series[ _j ].jos_joinno := cak68_cartesian_product;
                    END;
                (*ENDIF*) 
            (*ENDFOR*) 
        (*ENDIF*) 
        _sort_pos := _sort_pos + series[ _i ].jos_fieldcnt;
        series[ _i ].jos_joinno := cak68_cartesian_product;
        END;
&   ifdef TRACE
    (*ENDIF*) 
(*ENDFOR*) 
FOR _i := 1 TO dmli.d_cntfromtab DO
    BEGIN
    t01int4 (ak_join, 'table_no    ', series[ _i ].jos_source);
    t01int4 (ak_join, 'join_strat  ', ord(series[ _i ].jos_joinstrat));
    t01int4 (ak_join, 'join_invinde', series[ _i ].jos_indexno);
    t01int4 (ak_join, 'join_num    ', ord(series[ _i ].jos_joinno));
    t01int4 (ak_join, 'jos_fieldcnt', ord(series[ _i ].jos_fieldcnt));
    END;
(*ENDFOR*) 
t01int4  (ak_join, 'sort_pos    ', _sort_pos);
&endif
_end_pos := pred (dmli.d_joins.jrc_cnt);
(* evaluate the number of equal-joininfos *)
WHILE (_end_pos > _sort_pos) AND (dmli.d_joins.jrc_joinarr[ _end_pos ].jo_op <> op_eq) DO
    _end_pos := pred (_end_pos);
(*ENDWHILE*) 
_i := _end_pos;
&ifdef TRACE
t01int4  (ak_join, 'end_pos     ', _i);
&endif
WHILE (_i >= 0) DO
    BEGIN
    IF  (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ 2 ].jop_tableno  = cak68_join_value) AND
        (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ 2 ].jop_cntstack = 1)               AND
        (NOT dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ 1 ].jop_outer_join)
    THEN
        (* *** try to eliminate value-join-condition *** *)
        BEGIN
&       ifdef TRACE
        t01int4  (ak_join, 'JOIN_VALUE  ', _i);
&       endif
        IF  _i >= _sort_pos
        THEN
            (* *** join_value not used by join-strategies *** *)
            BEGIN
&           ifdef TRACE
            t01int4  (ak_join, 'i before    ', _i);
&           endif
            ak681pack_join_cond (dmli, series, _i);
            _end_pos := pred (_end_pos);
            END
        ELSE
            BEGIN
            _j := _end_pos;
&           ifdef TRACE
            t01int4  (ak_join, 'JOIN_VALUE 2', _j);
&           endif
            WHILE (_j >= _sort_pos) DO
                BEGIN
                WITH dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ 1 ], dmli.d_joins.jrc_joinarr[ _j ] DO
                    BEGIN
                    IF  (((jo_recs[ 1 ].jop_tableno  = jop_tableno ) AND
                        (  jo_recs[ 1 ].jop_fieldno  = jop_fieldno ) AND
                        (  jo_recs[ 1 ].jop_cntstack = 1   )    ) OR
                        ( (jo_recs[ 2 ].jop_tableno  = jop_tableno ) AND
                        (  jo_recs[ 2 ].jop_fieldno  = jop_fieldno ) AND
                        (  jo_recs[ 2 ].jop_cntstack = 1   )    )   ) AND
                        (NOT jo_recs[ 1 ].jop_outer_join) AND
                        (NOT jo_recs[ 2 ].jop_outer_join)
                    THEN
                        BEGIN
&                       ifdef TRACE
                        t01int4  (ak_join, 'j before    ', _j);
&                       endif
                        ak681pack_join_cond (dmli, series, _j);
                        _end_pos := pred (_end_pos);
                        _j       := -3; (* exit while *)
                        END
                    ELSE
                        _j := pred (_j);
                    (*ENDIF*) 
                    END;
                (*ENDWITH*) 
                END;
            (*ENDWHILE*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    _i := pred (_i);
    END;
(*ENDWHILE*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681move_in_front (
            VAR acv  : tak_all_command_glob;
            VAR dmli : tak_dml_info;
            from_pos : tsp00_Int2;
            to_pos   : tsp00_Int2;
            cnt      : tsp00_Int2);
 
VAR
      _i          : tsp00_Int2;
      _j          : tsp00_Int2;
      _m_one_join : tak_one_join;
 
BEGIN
IF  (cnt > 0)
THEN
    IF  ((dmli.d_joins.jrc_cnt + from_pos - to_pos) > MAX_JOINS_GG04)
    THEN
        FOR _i := 0 TO (cnt - 1) DO
            BEGIN
            _m_one_join := dmli.d_joins.jrc_joinarr[ from_pos + _i ];
            FOR _j := (from_pos + _i) DOWNTO (to_pos + _i + 1) DO
                dmli.d_joins.jrc_joinarr[ _j ] := dmli.d_joins.jrc_joinarr[ _j - 1 ];
            (*ENDFOR*) 
            dmli.d_joins.jrc_joinarr[ to_pos + _i ] := _m_one_join;
            END
        (*ENDFOR*) 
    ELSE
        BEGIN
        SAPDB_PascalOverlappingMove ('VAK681',   3,    
              sizeof(dmli.d_joins.jrc_joinarr), sizeof(dmli.d_joins.jrc_joinarr),
              @dmli.d_joins.jrc_joinarr, to_pos * sizeof(tak_one_join) + 1,
              @dmli.d_joins.jrc_joinarr, dmli.d_joins.jrc_cnt * sizeof(tak_one_join) + 1,
              (from_pos - to_pos) * sizeof(tak_one_join),
              acv.a_returncode);
        SAPDB_PascalMove ('VAK681',   4,    
              sizeof(dmli.d_joins.jrc_joinarr), sizeof(dmli.d_joins.jrc_joinarr),
              @dmli.d_joins.jrc_joinarr, from_pos * sizeof(tak_one_join) + 1,
              @dmli.d_joins.jrc_joinarr, to_pos * sizeof(tak_one_join) + 1,
              cnt * sizeof(tak_one_join),
              acv.a_returncode);
        SAPDB_PascalOverlappingMove ('VAK681',   5,    
              sizeof(dmli.d_joins.jrc_joinarr), sizeof(dmli.d_joins.jrc_joinarr),
              @dmli.d_joins.jrc_joinarr, dmli.d_joins.jrc_cnt * sizeof(tak_one_join) + 1,
              @dmli.d_joins.jrc_joinarr, (to_pos + cnt) * sizeof(tak_one_join) + 1,
              (from_pos - to_pos) * sizeof(tak_one_join),
              acv.a_returncode);
        END;
    (*ENDIF*) 
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
FUNCTION
      ak681all_multabs_in_succ (
            VAR mul_tab         : tak68_mul_tab_rec;
            VAR newsuccession   : tak68_succession;
            processed_table_cnt : tsp00_Int2) : boolean;
 
VAR
      _xi         : tsp00_Int2;
      _found_tabs : tsp00_Int2;
 
BEGIN
_found_tabs := 0;
FOR _xi := 1 TO processed_table_cnt DO
    IF  (newsuccession[ _xi ].s_tableno in mul_tab.mtr_tab_seq)
    THEN
        _found_tabs := succ (_found_tabs);
    (*ENDIF*) 
(*ENDFOR*) 
ak681all_multabs_in_succ := (_found_tabs = mul_tab.mtr_tablecnt);
END;
 
(*------------------------------*) 
 
PROCEDURE
      a681test_outer_qualification (
            VAR acv     : tak_all_command_glob;
            VAR dmli    : tak_dml_info;
            VAR jinfos  : tak68_joininfos);
 
VAR
      _xi               : tsp00_Int2;
      _xj               : tsp00_Int2;
      _table_qual_found : boolean;
      _pack_joinarr     : boolean;
 
BEGIN
&ifdef trace
a683_output (ak_join, dmli);
&endif
_table_qual_found := false;
_pack_joinarr     := false;
_xi := 0;
_xj := 0;
WHILE (_xi < dmli.d_joins.jrc_cnt) DO
    BEGIN
    IF  (dmli.d_joins.jrc_joinarr[ _xi ].jo_recs[ 1 ].jop_tableno MOD 100 =
        jinfos.ji_acttabno)
    THEN
        (* actual table T found on left side of join *)
        BEGIN
        IF  ( NOT dmli.d_joins.jrc_joinarr[ _xi ].jo_recs[ 1 ].jop_outer_join )
        THEN
            (* actual table T isn't an outer join table *)
            BEGIN
            _table_qual_found := NOT dmli.d_joins.jrc_joinarr[ _xi ].jo_recs[ 2 ].jop_outer_join;
            IF  (dmli.d_joins.jrc_joinarr[ _xi ].jo_recs[ 2 ].jop_tableno =
                cak68_join_value)
            THEN
                (* T.column <op> <constant>          *)
                (* realize local non-equal predicate *)
                _pack_joinarr := _pack_joinarr OR
                      (dmli.d_joins.jrc_joinarr[ _xi ].jo_op <> op_eq);
            (*ENDIF*) 
            END
        ELSE
            (* actual table T is an outer join part *)
            IF  (dmli.d_joins.jrc_joinarr[ _xi ].jo_recs[ 2 ].jop_tableno =
                cak68_join_value)
            THEN
                (* T.column (+) <op> <constant>                     *)
                (* mean to evaluate condition before evaluation     *)
                (* of other outer join on the table T               *)
                (* important only in case of 'T.column (+) IS NULL' *)
                _pack_joinarr     := true;
            (*ENDIF*) 
        (*ENDIF*) 
        END
    ELSE
        IF  (dmli.d_joins.jrc_joinarr[ _xi ].jo_recs[ 2 ].jop_tableno MOD 100 =
            jinfos.ji_acttabno)
        THEN
            (* actual table T found on right side of join *)
            BEGIN
            IF  (dmli.d_joins.jrc_joinarr[ _xi ].jo_recs[ 1 ].jop_tableno =
                dmli.d_joins.jrc_joinarr[ _xi ].jo_recs[ 2 ].jop_tableno)
            THEN
                _pack_joinarr := true;
            (*ENDIF*) 
            IF  ( NOT dmli.d_joins.jrc_joinarr[ _xi ].jo_recs[ 2 ].jop_outer_join )
            THEN
                _table_qual_found := NOT dmli.d_joins.jrc_joinarr[ _xi ].jo_recs[ 1 ].jop_outer_join;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
    (*ENDIF*) 
    _xi := succ (_xi);
    END;
(*ENDWHILE*) 
IF  _pack_joinarr
THEN
    (* delete all 'X.column <non-equalop> <constant>' entries *)
    (* from d_joinarr                                         *)
    BEGIN
    _xi := 0;
    WHILE (_xi < dmli.d_joins.jrc_cnt) DO
        IF  (dmli.d_joins.jrc_joinarr[ _xi ].jo_op <> op_eq)
            AND
            (dmli.d_joins.jrc_joinarr[ _xi ].jo_recs[ 2 ].
            jop_tableno = cak68_join_value)
            OR
            (dmli.d_joins.jrc_joinarr[ _xi ].jo_recs[ 1 ].jop_tableno =
            dmli.d_joins.jrc_joinarr[ _xi ].jo_recs[ 2 ].jop_tableno)
        THEN
            (* delete this entry *)
            BEGIN
            dmli.d_joins.jrc_cnt := pred (dmli.d_joins.jrc_cnt);
            _xj     := _xi;
            WHILE (_xj < dmli.d_joins.jrc_cnt) DO
                BEGIN
                dmli.d_joins.jrc_joinarr[ _xj ] :=
                      dmli.d_joins.jrc_joinarr[ _xj + 1 ];
                _xj := succ (_xj);
                END;
            (*ENDWHILE*) 
            END
        ELSE
            _xi := succ (_xi);
        (*ENDIF*) 
    (*ENDWHILE*) 
    END;
(*ENDIF*) 
IF  _table_qual_found
THEN
    (* we don't need an outer join *)
    BEGIN
    acv.a_mblock.mb_trns^.trError_gg00 := e_ok;
    FOR _xi := 0 TO dmli.d_joins.jrc_cnt - 1 DO
        BEGIN
        _xj := 1;
        REPEAT
            (* work for left and right join part *)
            IF  (dmli.d_joins.jrc_joinarr[ _xi ].jo_recs[ _xj ].
                jop_tableno = jinfos.ji_acttabno)
            THEN
                BEGIN
                dmli.d_oj_tables := dmli.d_oj_tables -
                      [ dmli.d_joins.jrc_joinarr[ _xi ].
                      jo_recs[ _xj ].jop_tableno ];
                dmli.d_joins.jrc_joinarr[ _xi ].jo_recs[ _xj ].
                      jop_outer_join := false;
                _xj := 3;  (* exit repeat *)
                END;
            (*ENDIF*) 
            _xj := succ (_xj);
        UNTIL
            (_xj > 2);
        (*ENDREPEAT*) 
        END;
    (*ENDFOR*) 
    acv.a_outer_join := false;
    (* search for other outer joins *)
    FOR _xi := 1 TO dmli.d_cntfromtab DO
        IF  (_xi <> jinfos.ji_acttabno)
        THEN
            IF  ( _xi in dmli.d_oj_tables )
            THEN
                acv.a_outer_join := true;
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDFOR*) 
    END;
&ifdef trace
(*ENDIF*) 
a683_output (ak_join, dmli);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      a681get_oj_info (
            VAR acv     : tak_all_command_glob;
            VAR dmli        : tak_dml_info);
 
VAR
      _i, _j, _k    : tsp00_Int2;
      _roj_tabs     : tak_joinset;
 
BEGIN
dmli.d_oj_tables := [ ];
_roj_tabs        := [ ];
_i := 0;
WHILE ( _i < dmli.d_joins.jrc_cnt ) DO
    BEGIN
    _j := 1;
    _k := 2;
    REPEAT
        (* work for part 1 and 2 *)
        IF  ( dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].
            jop_outer_join )
        THEN
            BEGIN
            dmli.d_oj_tables  := dmli.d_oj_tables +
                  [ dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].jop_tableno ];
            IF  ( dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].
                jop_tableno <> cak68_join_value ) AND
                ( dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].
                jop_tableno <> cak68_join_value ) AND
                ( dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].
                jop_tableno < dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].
                jop_tableno )
            THEN
                (* tab1 (+) op tab2 *)
                BEGIN
                _roj_tabs := _roj_tabs +
                      [ dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].jop_tableno ];
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        _j := succ (_j);
        _k := pred (_k);
    UNTIL
        ( _j > 2 );
    (*ENDREPEAT*) 
    _i := succ (_i);
    END;
(*ENDWHILE*) 
&ifdef TRACE
a683joinset_trace( ak_join, 'fill up NULL', dmli, dmli.d_oj_tables );
a683joinset_trace( ak_join, 'poss ROJ tab', dmli, _roj_tabs );
&endif
IF  ( dmli.d_cntfromtab >= 2 )
THEN
    BEGIN
    _i := 0;
    WHILE ( _i < dmli.d_joins.jrc_cnt ) DO
        BEGIN
        _j := 1;
        _k := 2;
        REPEAT
            IF  ( dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].
                jop_tableno <> cak68_join_value ) AND
                ( dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].jop_tableno
                in _roj_tabs )
            THEN
                BEGIN
                (* right outer join isn't implemented with *)
                (* join transition !!!                     *)
                (* precondition: table sequence for outer joins *)
                (* is given join sequence                       *)
&               ifdef trace
                t01int4 (ak_join, 'del props on',
                      dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _j ].jop_tableno);
                t01int4( ak_join, 'index       ', _i );
                t01int4 (ak_join, 'other tab   ',
                      dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].jop_tableno);
&               endif
                dmli.d_joins.jrc_joinarr[ _i ].
                      jo_recs[ _j ].jop_propset := [ ]
                END;
            (*ENDIF*) 
            _j := succ (_j);
            _k := pred (_k);
        UNTIL
            (_j > 2);
        (*ENDREPEAT*) 
        _i := succ (_i);
        END;
    (*ENDWHILE*) 
    END
ELSE
    a07_b_put_error( acv, e_outer_join_def_error, 1 );
(*ENDIF*) 
;
END;
 
(*------------------------------*) 
 
PROCEDURE
      a681check_outer_join (
            VAR acv : tak_all_command_glob;
            VAR dmli : tak_dml_info);
 
VAR
      _i : integer;
      _j : integer;
      _k : integer;
 
BEGIN
a681get_oj_info(acv, dmli);
IF  ( acv.a_returncode = 0 )
THEN
    BEGIN
    dmli.d_oj_tables := [  ];
    FOR _i := 0 TO (dmli.d_joins.jrc_cnt - 1) DO
        FOR _k := 1 TO 2 DO
            IF  dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].jop_outer_join
            THEN
                BEGIN
                IF  dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].jop_tableno = 1
                THEN
                    _j := 2
                ELSE
                    _j := 1;
                (*ENDIF*) 
                dmli.d_oj_tables := dmli.d_oj_tables +
                      [ dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].jop_tableno ];
                _j := dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].jop_startstack;
                WHILE (_j <
                      (dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].
                      jop_startstack + dmli.d_joins.jrc_joinarr[ _i ].
                      jo_recs[ _k ].jop_cntstack)) DO
                    BEGIN
                    IF  (acv.a_mblock.mb_st^[ _j ].etype in [ st_varkey,
                        st_varcol, st_fixkey, st_fixcol, st_varlongchar ])
                    THEN
                        BEGIN
                        acv.a_mblock.mb_st^[ _j ].eop := op_outer_join;
                        _j := _j + dmli.d_joins.jrc_joinarr[ _i ].jo_recs[ _k ].jop_cntstack;
                        END;
                    (*ENDIF*) 
                    _j := succ (_j);
                    END;
                (*ENDWHILE*) 
                END;
            (*ENDIF*) 
        (*ENDFOR*) 
    (*ENDFOR*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681first_keyfield_no (
            VAR acv         : tak_all_command_glob;
            VAR dmli        : tak_dml_info;
            VAR col_buf     : tak00_colinfo_ptr;
            curr_tab        : tsp00_Int2;
            VAR fieldno     : tsp00_Int2);
&     ifdef trace
 
VAR
      _colname : tsp00_KnlIdentifier;
&     endif
 
BEGIN
a61_rel_old_table (acv, dmli, curr_tab);
IF  acv.a_returncode = 0
THEN
    BEGIN
    col_buf := dmli.d_sparr.pbasep^.sbase.
          bcolumn[ dmli.d_sparr.pbasep^.sbase.bfirstcolind ];
    fieldno := col_buf^.cextcolno;
&   ifdef TRACE
    a061get_colname (col_buf^, _colname);
    t01lidentifier (ak_join, _colname);
&   endif
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681next_keyfield_no (
            VAR dmli        : tak_dml_info;
            VAR col_buf     : tak00_colinfo_ptr;
            VAR nxt_fieldno : tsp00_Int2);
&     ifdef trace
 
VAR
      _colname : tsp00_KnlIdentifier;
&     endif
 
BEGIN
IF  ( col_buf^.cnextind <> 0 )
THEN
    BEGIN
    col_buf     := dmli.d_sparr.pbasep^.sbase.bcolumn[col_buf^.cnextind];
    nxt_fieldno := col_buf^.cextcolno;
&   ifdef TRACE
    a061get_colname (col_buf^, _colname);
    t01lidentifier (ak_join, _colname);
&   endif
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a681lowest_multiple_strat (
            VAR acv             : tak_all_command_glob;
            VAR dmli            : tak_dml_info;
            config              : tak_sysbufferaddress;
            VAR jtrans          : tak68_join_transitions; (* IN/OUT *)
            VAR succession      : tak68_succession; (* IN *)
            VAR mul_tabs        : tak68_mult_tabs; (* IN/OUT change of mt_pos *)
            src_table           : tsp00_Int2;
            dst_table           : tsp00_Int2;
            VAR best_strat      : tak68_best_jstrat; (* IN/OUT *)
            processed_table_cnt : tsp00_Int2;
            update_jtrans       : boolean);
 
VAR
      _best_mult            : tsp00_Longreal;
      _new_mult             : tsp00_Longreal;
      _l                    : tsp00_Int2;
      _sequenced_table_cnt  : tsp00_Int2;
      _hint_exists          : boolean;
      _new_strat_is_better  : boolean;
 
BEGIN
(* if possible, return better transition than best_strat        *)
(* to dst_tab, if better trans is found, grab better strategy   *)
_sequenced_table_cnt := 0;
FOR _l := 1 TO processed_table_cnt DO
    IF  ( succession[ _l ].s_tableno <> 0 )
    THEN
        _sequenced_table_cnt := succ( _sequenced_table_cnt );
    (*ENDIF*) 
(*ENDFOR*) 
_hint_exists := ( config <> NIL ) AND ( dst_table <= config^.shint.hint_joincfg_cnt );
;
&ifdef TRACE
t01p2int4( ak_join, 'src_table   ', src_table , 'dst_table   ', dst_table );
t01bool( ak_join, 'hint key ?  ', _hint_exists AND ( cj_keyaccess in config^.shint.
      hint_join_config[ dst_table ].cfg_join_switches ) );
t01bool( ak_join, 'hint hindex?', _hint_exists AND ( cj_indexaccess in config^.shint.
      hint_join_config[ dst_table ].cfg_join_switches ) );
IF  (( _hint_exists ) AND ( cj_indexaccess in config^.shint.
    hint_join_config[ dst_table ].cfg_join_switches ) AND
    ( config^.shint.hint_join_config[ dst_table ].cfg_indexno <> 0 ))
THEN
    t01int4( ak_join, 'given index ', config^.shint.
          hint_join_config[ dst_table ].cfg_indexno );
(*ENDIF*) 
t01p2int4( ak_join, 'proc tab cnt', processed_table_cnt
      , 'seq tab cnt ', _sequenced_table_cnt );
a683tr_newsucc( ak_join, succession, 1, processed_table_cnt, true );
&endif
_l := 1;
WHILE ( _l <= mul_tabs.mt_cnt ) DO
    (* loop over mul_tabs.mt_arr *)
    BEGIN
    IF  ( dst_table = mul_tabs.mt_arr[ _l ].mtr_dst_table )
        AND
        ( _sequenced_table_cnt >= mul_tabs.mt_arr[ _l ].mtr_tablecnt )
        AND
        ak681all_multabs_in_succ( mul_tabs.mt_arr[ _l ],
        succession, processed_table_cnt )
    THEN
        BEGIN
        (*
&             ifdef TRACE
              a683trace_jointype( ak_join, 'new join    ', mul_tabs.mt_arr[ _l ].mtr_jointype );
              IF  ( mul_tabs.mt_arr[ _l ].mtr_jointype
              in [ to_unique_field, to_all_invfields, to_invpart, to_invfield ] )
              THEN
              t01int4( ak_join, 'indexno     ', mul_tabs.mt_arr[ _l ].mtr_indexno );
              a683trace_jointype( ak_join, 'old best joi', best_strat.bj_jtype );
              IF  ( best_strat.bj_jtype
              in [ to_unique_field, to_all_invfields, to_invpart, to_invfield ] )
              THEN
              t01int4( ak_join, 'indexno     ', best_strat.bj_indexno );
&             endif
              *)
        _best_mult := best_strat.bj_multiplier;
        IF  ( best_strat.bj_jtype in
            [ to_unique_field, to_all_invfields, to_invpart, to_invfield ] )
        THEN
            _best_mult := _best_mult * cak68_inv_overhead;
        (*ENDIF*) 
        _new_mult := mul_tabs.mt_arr [ _l ].mtr_multipl;
        IF  ( mul_tabs.mt_arr [ _l ].mtr_jointype in
            [ to_unique_field, to_all_invfields, to_invpart, to_invfield ] )
        THEN
            _new_mult := _new_mult * cak68_inv_overhead;
        (*ENDIF*) 
        ;
        IF  ( _hint_exists AND
            (* 'keyaccess' is given *)
            ( cj_keyaccess in config^.shint.
            hint_join_config[ dst_table ].cfg_join_switches )
            AND
            (* new strat is key strat *)
            ( mul_tabs.mt_arr [ _l ].mtr_jointype
            in [ to_single_keyfield, to_key, to_keypart, to_first_keyfield ] )
            AND
            (* old strat isn't key strat *)
            NOT ( best_strat.bj_jtype
            in [ to_single_keyfield, to_key, to_keypart, to_first_keyfield ] ))
        THEN
            BEGIN
&           ifdef trace
            t01name( ak_join, 'keyaccess1 !      ' );
&           endif
            _new_strat_is_better := true;
            END
        ELSE
            BEGIN
            IF  ( _hint_exists AND
                (* 'keyaccess' is given *)
                ( cj_keyaccess in config^.shint.
                hint_join_config[ dst_table ].cfg_join_switches )
                AND
                (* new strat isn't key strat *)
                NOT ( mul_tabs.mt_arr [ _l ].mtr_jointype
                in [ to_single_keyfield, to_key, to_keypart, to_first_keyfield ] )
                AND
                (* old strat is key strat *)
                ( best_strat.bj_jtype
                in [ to_single_keyfield, to_key, to_keypart, to_first_keyfield ] ))
            THEN
                BEGIN
&               ifdef trace
                t01name( ak_join, 'keyaccess2 !      ' );
&               endif
                _new_strat_is_better := false;
                END
            ELSE
                BEGIN
                IF  ( _hint_exists AND
                    (* 'indexaccess' is given *)
                    ( cj_indexaccess in config^.shint.
                    hint_join_config[ dst_table ].cfg_join_switches )
                    AND
                    (* new strat is index strat *)
                    ( mul_tabs.mt_arr [ _l ].mtr_jointype
                    in [ to_unique_field, to_all_invfields, to_invpart, to_invfield ] )
                    AND
                    (* old strat isn't index strat *)
                    NOT ( best_strat.bj_jtype
                    in [ to_unique_field, to_all_invfields, to_invpart, to_invfield ] ))
                THEN
                    BEGIN
&                   ifdef trace
                    t01name( ak_join, 'indexaccess1 !    ' );
&                   endif
                    _new_strat_is_better := true;
                    END
                ELSE
                    BEGIN
                    IF  ( _hint_exists AND
                        (* 'indexaccess' is given *)
                        ( cj_indexaccess in config^.shint.
                        hint_join_config[ dst_table ].cfg_join_switches )
                        AND
                        (* new strat isn't index strat *)
                        NOT ( mul_tabs.mt_arr [ _l ].mtr_jointype
                        in [ to_unique_field, to_all_invfields, to_invpart, to_invfield ] )
                        AND
                        (* old strat is index strat *)
                        ( best_strat.bj_jtype
                        in [ to_unique_field, to_all_invfields, to_invpart, to_invfield ] ))
                    THEN
                        BEGIN
&                       ifdef trace
                        t01name( ak_join, 'indexaccess2 !    ' );
&                       endif
                        _new_strat_is_better := false;
                        END
                    ELSE
                        BEGIN
                        IF  ( _hint_exists AND
                            (* 'indexaccess' is given *)
                            ( cj_indexaccess in config^.shint.
                            hint_join_config[ dst_table ].cfg_join_switches )
                            AND
                            (* new strat is index strat *)
                            ( mul_tabs.mt_arr [ _l ].mtr_jointype
                            in [ to_unique_field, to_all_invfields,
                            to_invpart, to_invfield ] )
                            AND
                            (* old strat is index strat *)
                            ( best_strat.bj_jtype
                            in [ to_unique_field, to_all_invfields,
                            to_invpart, to_invfield ] )
                            AND
                            (* there is dedicated index *)
                            ( config^.shint.hint_join_config[ dst_table ].
                            cfg_indexno <> 0 )
                            AND
                            (* new strat has given index *)
                            ( mul_tabs.mt_arr[ _l ].mtr_indexno =
                            config^.shint.hint_join_config[ dst_table ].
                            cfg_indexno )
                            AND
                            ( mul_tabs.mt_arr[ _l ].mtr_indexno <>
                            best_strat.bj_indexno ))
                        THEN
                            BEGIN
&                           ifdef trace
                            t01name( ak_join, 'indexaccess()1 !  ' );
&                           endif
                            _new_strat_is_better := true;
                            END
                        ELSE
                            BEGIN
                            IF  ( _hint_exists AND
                                (* 'indexaccess' is given *)
                                ( cj_indexaccess in config^.shint.
                                hint_join_config[ dst_table ].cfg_join_switches )
                                AND
                                (* new strat is index strat *)
                                ( mul_tabs.mt_arr [ _l ].mtr_jointype
                                in [ to_unique_field, to_all_invfields,
                                to_invpart, to_invfield ] )
                                AND
                                (* old strat is index strat *)
                                ( best_strat.bj_jtype
                                in [ to_unique_field, to_all_invfields,
                                to_invpart, to_invfield ] )
                                AND
                                (* there is dedicated index *)
                                ( config^.shint.hint_join_config[ dst_table ].
                                cfg_indexno <> 0 )
                                AND
                                (* old strat has given index *)
                                ( best_strat.bj_indexno =
                                config^.shint.hint_join_config[ dst_table ].
                                cfg_indexno )
                                AND
                                ( mul_tabs.mt_arr[ _l ].mtr_indexno <>
                                best_strat.bj_indexno ))
                            THEN
                                BEGIN
&                               ifdef trace
                                t01name( ak_join, 'indexaccess()2 !  ' );
&                               endif
                                _new_strat_is_better := false;
                                END
                            ELSE
                                BEGIN
                                (* ordinary decision *)
                                IF  (( mul_tabs.mt_arr [ _l ].
                                    mtr_jointype in [ to_single_keyfield, to_key ])
                                    OR
                                    ( to_mt_join < best_strat.bj_jtype )
                                    OR
                                    ( _new_mult < _best_mult )
                                    OR
                                    (( _new_mult = _best_mult ) AND
                                    ( mul_tabs.mt_arr [ _l ].mtr_fieldcnt >
                                    best_strat.bj_fieldcnt ))
                                    OR
                                    (( _new_mult = _best_mult ) AND
                                    ( mul_tabs.mt_arr [ _l ].mtr_fieldcnt =
                                    best_strat.bj_fieldcnt ) AND
                                    ( mul_tabs.mt_arr [ _l ].mtr_indexno <> 0 ) AND
                                    ( best_strat.bj_indexno <> 0 ) AND
                                    ak681is_smaller_inv( acv,
                                    dmli.d_tabarr[ dst_table ].otreeid.
                                    fileTabId_gg00,
                                    mul_tabs.mt_arr [ _l ].mtr_indexno,
                                    best_strat.bj_indexno )))
                                THEN
                                    _new_strat_is_better := true
                                ELSE
                                    _new_strat_is_better := false;
                                (*ENDIF*) 
                                END;
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  ( _new_strat_is_better )
        THEN
            (* transition in mul_tabs is better than input *)
            BEGIN
&           ifdef trace
            t01name( ak_join, 'new strat is bette' );
&           endif
            best_strat.bj_srctab     := src_table;
            best_strat.bj_multiplier := mul_tabs.mt_arr[ _l ].mtr_multipl;
            best_strat.bj_fieldcnt   := mul_tabs.mt_arr[ _l ].mtr_fieldcnt;
            best_strat.bj_indexno    := mul_tabs.mt_arr[ _l ].mtr_indexno;
            best_strat.bj_jtype      := mul_tabs.mt_arr[ _l ].mtr_jointype;
            mul_tabs.mt_pos          := _l;
            IF  ( update_jtrans )
            THEN
                BEGIN
                jtrans[ src_table, dst_table ].jt_indexno  :=
                      mul_tabs.mt_arr[ _l ].mtr_indexno;
                jtrans[ src_table, dst_table ].jt_joinno   :=
                      mul_tabs.mt_arr[ _l ].mtr_joinno;
                jtrans[ src_table, dst_table ].jt_multipl  :=
                      mul_tabs.mt_arr[ _l ].mtr_multipl;
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    _l := succ (_l)
    END;
(*ENDWHILE*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a681jnew_seq (
            VAR acv            : tak_all_command_glob;
            VAR dmli           : tak_dml_info;
            config             : tak_sysbufferaddress;
            VAR table_stats    : tak68_table_stats; (* IN/OUT *)
            VAR jtrans         : tak68_join_transitions;
            VAR sequence_info  : tak68_sequence_info; (* IN/OUT *)
            VAR jinfos         : tak68_joininfos;
            VAR res_info       : tak68_result_info; (* IN/OUT *)
            VAR mul_tabs       : tak68_mult_tabs; (* IN/OUT change of mt_pos *)
            VAR lastsuccession : tak68_lastsuccession);
 
VAR
      _i               : tsp00_Int2;
      _ix              : tsp00_Int2;
      _jx              : tsp00_Int2;
      _max             : tsp00_Int2;
      _inner_table     : tsp00_Int2;
      _start_table     : tsp00_Int2;
      _start_table_idx : tsp00_Int2;
      _reschedule_cnt  : tsp00_Int2;
      _context         : tak681_jseq_info_record;
      _ln              : tsp00_Line;
      _searchkind      : tsp00_C42;
      _ready           : boolean;
 
BEGIN
SAPDB_PascalForcedFill (sizeof (_ln), @_ln, 1, sizeof (_ln), bsp_c1);
_context.jir_beststratcnt      := 0;
_context.jir_comp_sequences    := 0;
_context.jir_lowest_cost       := cak68_max_real;
_context.jir_better_seq_exists := false;
_context.jir_max_tables        := dmli.d_cntfromtab;
(* *** find best strategy to each table *** *)
ak681best_join_strat( acv, dmli, config, table_stats, jtrans,
      sequence_info, res_info, mul_tabs, _context.jir_best_jstrat );
dmli.d_standard :=
      dmli.d_standard                               OR
      (dmli.d_outer_join AND a01outer_join_ordered) OR
      a80is_predefined_join_order( acv, dmli );
IF  dmli.d_outer_join AND NOT dmli.d_standard
THEN
    BEGIN
&   ifdef TRACE
    t01sname (ak_join, '>>oj tabmove');
    a683tr_newsucc (ak_join, sequence_info.si_sequence,
          1, dmli.d_cntfromtab, true);
&   endif
    _ix  := 1;
    _max := _context.jir_max_tables;
    WHILE ( _ix <= _max )  DO
        BEGIN
        IF  ( sequence_info.si_sequence[ _ix ].s_tableno in dmli.d_oj_tables )
        THEN
            BEGIN
            _inner_table := sequence_info.si_sequence[ _ix ].s_tableno;
&           ifdef TRACE
            t01int4 (ak_join, '_ix         ', _ix);
            t01int4 (ak_join, '_inner_tab  ', _inner_table);
&           endif
            FOR _jx := _ix TO _context.jir_max_tables - 1 DO
                sequence_info.si_sequence[ _jx ].s_tableno :=
                      sequence_info.si_sequence[ _jx + 1 ].s_tableno;
            (*ENDFOR*) 
            sequence_info.si_sequence[ _context.jir_max_tables ].s_tableno := _inner_table;
            _max := pred(_max);
            END
        ELSE
            _ix := succ(_ix);
        (*ENDIF*) 
        END;
    (*ENDWHILE*) 
    _context.jir_max_tables := _max;
    (* only one table without outer flag or only two tables at all *)
    (* => no sequence search necessary                             *)
    IF  (_context.jir_max_tables = 1) OR
        (dmli.d_cntfromtab = 2)
    THEN
        dmli.d_standard := true;
&   ifdef TRACE
    (*ENDIF*) 
    a683tr_newsucc (ak_join, sequence_info.si_sequence,
          1, dmli.d_cntfromtab, true);
    IF  dmli.d_standard
    THEN
        t01sname (ak_join, '>>oj predef ');
&   endif
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  ( NOT ( dmli.d_standard  OR a80is_predefined_join_order( acv, dmli )) )
THEN
    (* search best join transition *)
    BEGIN
    IF  ( dmli.d_joins.jrc_cnt = 0 ) AND
        ( g01join_search_level = jsLevel0_egg00 )
    THEN
        BEGIN
&       ifdef TRACE
        t01sname (ak_join, '>> JSS CART ');
&       endif
        IF  ( acv.a_intern_explain OR g01vtrace.vtrStrategy_gg00 ) AND
            ( acv.a_explain_kind = ex_sequence )
        THEN
            BEGIN
            _searchkind := 'JOIN SEQUENCE SEARCH = AUTOMATIC - CARTES ';
            SAPDB_PascalForcedMove (sizeof(_searchkind), sizeof(_ln),
                  @_searchkind, 1, @_ln, 1, sizeof(_searchkind));
            a40sequence_expl_row (acv, _ln, c_change_to_unicode);
            END;
        (* take sorted sequence, if join conditions *)
        (* wasn't found in WHERE clause             *)
        (*ENDIF*) 
        ak681sort_by_costs (dmli, sequence_info, _context.jir_best_jstrat,
              table_stats);
        END
    ELSE
        IF  ( g01join_search_level = jsLevel9_egg00 ) OR
            ( (g01join_search_level = jsLevel0_egg00)
            AND (dmli.d_cntfromtab <= g01join_maxtab_level9) )
        THEN
            BEGIN
&           ifdef TRACE
            t01sname (ak_join, '>> JSS PERMU');
&           endif
            IF  ( acv.a_intern_explain OR g01vtrace.vtrStrategy_gg00 ) AND
                ( acv.a_explain_kind = ex_sequence )
            THEN
                BEGIN
                IF  g01join_search_level = jsLevel9_egg00
                THEN
                    BEGIN
                    _searchkind :=
                          'JOIN SEQUENCE SEARCH = LEVEL 9            ';
                    SAPDB_PascalForcedMove (sizeof(_searchkind), sizeof(_ln),
                          @_searchkind, 1, @_ln, 1, 30);
                    a40sequence_expl_row (acv, _ln, c_change_to_unicode);
                    END
                ELSE
                    BEGIN
                    _searchkind :=
                          'JOIN SEQUENCE SEARCH = AUTOMATIC - LEVEL 9';
                    SAPDB_PascalForcedMove (sizeof(_searchkind), sizeof(_ln),
                          @_searchkind, 1, @_ln, 1, sizeof(_searchkind));
                    a40sequence_expl_row (acv, _ln, c_change_to_unicode);
                    END
                (*ENDIF*) 
                END;
            (* build optimized permutation *)
            (*ENDIF*) 
            _context.jir_i := 1;
            IF  dmli.d_outer_join
            THEN
                _context.jir_sequenced_tables := dmli.d_oj_tables
            ELSE
                _context.jir_sequenced_tables := [];
            (*ENDIF*) 
            _reschedule_cnt := 0;
            ak681permut_sequence( acv, dmli, config, table_stats, jtrans,
                  sequence_info, jinfos, res_info, mul_tabs, lastsuccession,
                  _context, _reschedule_cnt );
            END
        ELSE
            IF  ( g01join_search_level = jsLevel4_egg00 ) OR
                ( (g01join_search_level = jsLevel0_egg00)
                AND (dmli.d_cntfromtab <= g01join_maxtab_level4) )
            THEN
                BEGIN
&               ifdef TRACE
                t01sname (ak_join, '>> JSS HEUR ');
&               endif
                IF  ( acv.a_intern_explain OR g01vtrace.vtrStrategy_gg00 ) AND
                    ( acv.a_explain_kind = ex_sequence )
                THEN
                    BEGIN
                    IF  g01join_search_level = jsLevel4_egg00
                    THEN
                        BEGIN
                        _searchkind :=
                              'JOIN SEQUENCE SEARCH = LEVEL 4            ';
                        SAPDB_PascalForcedMove (sizeof(_searchkind), sizeof(_ln),
                              @_searchkind, 1, @_ln, 1, 30);
                        a40sequence_expl_row (acv, _ln, c_change_to_unicode);
                        END
                    ELSE
                        BEGIN
                        _searchkind :=
                              'JOIN SEQUENCE SEARCH = AUTOMATIC - LEVEL 4';
                        SAPDB_PascalForcedMove (sizeof(_searchkind), sizeof(_ln),
                              @_searchkind, 1, @_ln, 1, sizeof(_searchkind));
                        a40sequence_expl_row (acv, _ln, c_change_to_unicode);
                        END
                    (*ENDIF*) 
                    END;
                (* save start sequence *)
                (* PTS 1112102 *)
                (*ENDIF*) 
                _context.jir_start_succession := sequence_info.si_sequence;
                _start_table_idx := 1;
                _ready := false;
                WHILE ( NOT _ready ) AND ( acv.a_returncode = 0 ) DO
                    BEGIN
                    (* restore start sequence *)
                    sequence_info.si_sequence :=
                          _context.jir_start_succession;
                    (*  enqueue first table *)
                    _start_table := sequence_info.
                          si_sequence[ _start_table_idx ].s_tableno;
                    FOR _i := _start_table_idx DOWNTO 2 DO
                        sequence_info.si_sequence[ _i ].s_tableno :=
                              sequence_info.si_sequence[ _i - 1 ].s_tableno;
                    (*ENDFOR*) 
                    sequence_info.si_sequence[ 1 ].s_tableno := _start_table;
                    (* PTS 1112102 *)
                    ak681greedy( acv, dmli, config, jtrans, mul_tabs,
                          table_stats, sequence_info, _context.jir_max_tables,
                          NOT c_find_start_table );
&                   ifdef TRACE
                    t01int4 (ak_join, '1. TABLE ==>',
                          sequence_info.si_sequence[ 1 ].s_tableno);
                    a683tr_newsucc (ak_join, sequence_info.si_sequence,
                          1, dmli.d_cntfromtab, true);
&                   endif
                    (* put start table in used table set *)
                    _context.jir_sequenced_tables    :=
                          [ sequence_info.si_sequence[ 1 ].s_tableno ];
                    _context.jir_stop_sequence := false;
                    (* contains jir_i if no transition from sequence found *)
                    _context.jir_last_swap_pos := 0;
                    _context.jir_i  := 2;
                    (* there are (jir_max_tables - 1) - (jir_i - 1) join strategies *)
                    (* between predecessor table and successor table, jir_i is      *)
                    (* position of one table in sequecen                            *)
                    (* ((jir_max_tables - 1) - jir_i) join strategies are eligible  *)
                    (* for election                                                 *)
                    (* we have to decide for join strategy to table jir_i, hence    *)
                    (* there are ((jir_max_tables - 1) - jir_i + 1 =                *)
                    (* jir_max_tables - jir_i decisions for join transition         *)
                    _context.jir_beststratcnt :=
                          _context.jir_max_tables - _context.jir_i;
                    ak681one_sequence( acv, dmli, config, table_stats, jtrans,
                          sequence_info, jinfos, res_info, mul_tabs,
                          lastsuccession, _context );
                    _ready := (_start_table_idx >= _context.jir_max_tables);
                    _start_table_idx := succ( _start_table_idx );
                    END;
                (*ENDWHILE*) 
                END
            ELSE
                BEGIN
&               ifdef TRACE
                t01sname (ak_join, '>> JSS GRDY ');
&               endif
                IF  ( acv.a_intern_explain OR g01vtrace.vtrStrategy_gg00 ) AND
                    ( acv.a_explain_kind = ex_sequence )
                THEN
                    BEGIN
                    IF  g01join_search_level = jsLevel1_egg00
                    THEN
                        BEGIN
                        _searchkind :=
                              'JOIN SEQUENCE SEARCH = LEVEL 1            ';
                        SAPDB_PascalForcedMove (sizeof(_searchkind), sizeof(_ln),
                              @_searchkind, 1, @_ln, 1, 30);
                        a40sequence_expl_row (acv, _ln, c_change_to_unicode);
                        END
                    ELSE
                        BEGIN
                        _searchkind :=
                              'JOIN SEQUENCE SEARCH = AUTOMATIC - LEVEL 1';
                        SAPDB_PascalForcedMove (sizeof(_searchkind), sizeof(_ln),
                              @_searchkind, 1, @_ln, 1, sizeof(_searchkind));
                        a40sequence_expl_row (acv, _ln, c_change_to_unicode);
                        END
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                ak681greedy( acv, dmli, config, jtrans, mul_tabs, table_stats,
                      sequence_info, _context.jir_max_tables,
                      c_find_start_table );
                END;
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    IF  ( _context.jir_lowest_cost < cak68_max_real ) OR
        ( _context.jir_comp_sequences = 1 )
    THEN
        sequence_info.si_sequence := _context.jir_lowest_succession;
    (*ENDIF*) 
    END
ELSE
    IF  ( acv.a_intern_explain OR g01vtrace.vtrStrategy_gg00 ) AND
        ( acv.a_explain_kind = ex_sequence )
    THEN
        BEGIN
        _searchkind := 'JOIN SEQUENCE SEARCH = PREDEFINED         ';
        SAPDB_PascalForcedMove (sizeof(_searchkind), sizeof(_ln),
              @_searchkind, 1, @_ln, 1, sizeof(_searchkind));
        a40sequence_expl_row (acv, _ln, c_change_to_unicode);
        END;
    (*ENDIF*) 
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681one_sequence (
            VAR acv            : tak_all_command_glob;
            VAR dmli           : tak_dml_info;
            config             : tak_sysbufferaddress;
            VAR table_stats    : tak68_table_stats;
            VAR jtrans         : tak68_join_transitions;
            VAR sequence_info  : tak68_sequence_info;
            VAR jinfos         : tak68_joininfos;
            VAR res_info       : tak68_result_info;
            VAR mul_tabs       : tak68_mult_tabs;
            VAR lastsuccession : tak68_lastsuccession;
            VAR context        : tak681_jseq_info_record);
 
VAR
      _aux_multiplier1     : tsp00_Int4;
      _actual_table        : tsp00_Int2;
      _i                   : tsp00_Int2;
      _seq_table           : tsp00_Int2;
      _nonseq_table        : tsp00_Int2;
      _l                   : tsp00_Int2;
      _n                   : tsp00_Int2;
      _next_table          : tsp00_Int2;
      _best_strat          : tak68_best_jstrat;
      _join_other_table    : boolean;
      _mt_jtrans_check     : boolean;
      _aux_c               : tak681_jseq_info_record;
      _aux_l               : tak68_sequence_info;
 
BEGIN
&ifdef trace
t01name(ak_join, 'unprocessed sequen');
t01int4(ak_join, 'length      ', context.jir_max_tables - context.jir_i + 1);
&endif
context.jir_better_seq_exists := false;
_best_strat.bj_srctab := cak_is_undefined;
REPEAT
    (* UNTIL context.jir_stop_sequence *)
    BEGIN
&   ifdef trace
    t01sname(ak_join, 'repeat loop ');
&   endif
    FOR _i := 1 TO context.jir_max_tables DO
        sequence_info.si_sequence[ _i ].s_backup :=
              sequence_info.si_sequence[ _i ].s_tableno;
    (*ENDFOR*) 
    context.jir_swap_cnt       := 0;
    context.jir_non_best_trans := context.jir_i;
    (* si_sequence[1 .. jir_i - 1] forms found sequence !!!! *)
    WHILE ( context.jir_i < context.jir_max_tables )
          AND
          ( context.jir_i + context.jir_swap_cnt <= context.jir_max_tables )
          AND
          ( acv.a_returncode = 0 ) DO
        BEGIN
        (* check if join transition to _actual_table *)
        (* is possible from sequence                 *)
        _actual_table := sequence_info.si_sequence[ context.jir_i ].s_tableno;
        context.jir_better_seq_exists := false;
&       ifdef trace
        t01p2int4(ak_join, 'while loop i', context.jir_i,
              'actual table', _actual_table );
&       endif
        IF  ( context.jir_best_jstrat[ _actual_table ].
            bjr_stratinfo.bj_jtype < to_cartesian_prod )
        THEN
            BEGIN
&           ifdef TRACE
            ak681tr_context( dmli, sequence_info, context );
&           endif
            (* there is a join transition to considered table *)
            _join_other_table := false;
            _aux_c            := context;
            _aux_l            := sequence_info;
            (* check transitions from already sequenced tables  *)
            (* to considered table                              *)
            IF  context.jir_best_jstrat[ _actual_table ].bjr_is_mt_join
            THEN
                ak681mtj_check( acv, dmli, config, jtrans, sequence_info, context,
                      table_stats, res_info, mul_tabs, _join_other_table )
            ELSE
                ak681j_check( dmli, jtrans, sequence_info,
                      context, _join_other_table );
            (*ENDIF*) 
&           ifdef trace
            t01sname( ak_join, 'sequence1   ');
            a683tr_newsucc (ak_join, sequence_info.si_sequence, 1, context.jir_i, true);
&           endif
            IF  ( _join_other_table )
            THEN
                BEGIN
                _best_strat.bj_jtype      := to_cartesian_prod;
                _best_strat.bj_multiplier := csp_maxint4;
                _best_strat.bj_srctab     := cak_is_undefined;
                _best_strat.bj_fieldcnt   := 1;
                _best_strat.bj_indexno    := 0;
                _n              := _aux_c.jir_i;
                _next_table     :=
                      _aux_l.si_sequence[ _aux_c.jir_i ].s_tableno;
                FOR _l := _aux_c.jir_i + 1 TO _aux_c.jir_max_tables DO
                    BEGIN
                    _mt_jtrans_check := true;
                    _nonseq_table :=
                          _aux_l.si_sequence[ _l ].s_tableno;
                    FOR _i := 1 TO _aux_c.jir_i - 1 DO
                        BEGIN
                        _seq_table :=
                              _aux_l.si_sequence[ _i ].s_tableno;
                        (* look for best join transitions to remaining tables *)
                        IF  jtrans[ _seq_table, _nonseq_table ].
                            jt_jointype = to_mt_join
                        THEN
                            BEGIN
                            IF  ( _mt_jtrans_check )
                            THEN
                                BEGIN
                                _mt_jtrans_check := false;
                                _aux_multiplier1 := _best_strat.bj_multiplier;
                                a681lowest_multiple_strat( acv, dmli, config,
                                      jtrans, sequence_info.si_sequence,
                                      mul_tabs, _seq_table, _nonseq_table,
                                      _best_strat,
                                      _aux_c.jir_i, NOT c_update_jtrans );
                                IF  ( _aux_multiplier1 > _best_strat.bj_multiplier )
                                THEN
                                    BEGIN
                                    (* all other data was set in *)
                                    (* a681lowest_multiple_strat *)
                                    _next_table := _nonseq_table;
                                    _n          := _l;
                                    END;
                                (*ENDIF*) 
                                END;
                            (*ENDIF*) 
                            END
                        ELSE
                            (* single table transition *)
                            IF  ( _best_strat.bj_jtype >
                                jtrans[ _seq_table, _nonseq_table ].jt_jointype )
                                OR
                                (( _best_strat.bj_jtype =
                                jtrans[ _seq_table, _nonseq_table ].jt_jointype )
                                AND
                                ( _best_strat.bj_multiplier >
                                jtrans[ _seq_table, _nonseq_table ].jt_multipl ))
                            THEN
                                BEGIN
                                _best_strat.bj_jtype :=
                                      jtrans[ _seq_table, _nonseq_table ].jt_jointype;
                                _best_strat.bj_multiplier :=
                                      jtrans[ _seq_table, _nonseq_table ].jt_multipl;
                                _best_strat.bj_indexno :=
                                      jtrans[ _seq_table, _nonseq_table ].jt_indexno;
                                _best_strat.bj_fieldcnt := 1;
                                _best_strat.bj_srctab   := _seq_table;
                                _next_table    := _nonseq_table;
                                _n             := _l;
                                END;
                            (* all multiple table transition from sequence *)
                            (* to non-sequenced tables checked             *)
                            (*ENDIF*) 
                        (*ENDIF*) 
                        END;
                    (*ENDFOR*) 
                    END;
                (*ENDFOR*) 
                IF  (_next_table <>
                    _aux_l.si_sequence[ _aux_c.jir_i ].s_tableno)
                    AND
                    (_best_strat.bj_srctab <> cak_is_undefined)
                THEN
                    BEGIN
&                   ifdef trace
                    t01p2int4(ak_join, 'recursive ca', context.jir_i ,
                          'get table   ',  _next_table);
&                   endif
                    (* there is a join transition to one remaining table *)
                    (* move this table on sequence end *)
                    FOR _l := _n DOWNTO _aux_c.jir_i + 1 DO
                        _aux_l.si_sequence[ _l ].s_tableno :=
                              _aux_l.si_sequence[ _l - 1 ].s_tableno;
                    (*ENDFOR*) 
                    _aux_l.si_sequence[ _aux_c.jir_i ].s_tableno :=
                          _next_table;
                    _aux_c.jir_sequenced_tables   :=
                          _aux_c.jir_sequenced_tables + [ _next_table ];
                    _aux_c.jir_beststratcnt   := pred (_aux_c.jir_beststratcnt);
                    _aux_c.jir_stop_sequence  := false;
                    _aux_c.jir_i              := succ (_aux_c.jir_i);
                    _aux_c.jir_non_best_trans := _aux_c.jir_i;
                    IF  g01userstackoverflow
                    THEN
                        (* stack usage too high to call kb layer *)
                        a07_b_put_error (acv, e_program_stack_overflow, 9)
                    ELSE
                        ak681one_sequence( acv, dmli, config, table_stats,
                              jtrans, _aux_l, jinfos, res_info, mul_tabs,
                              lastsuccession, _aux_c );
                    (*ENDIF*) 
&                   ifdef TRACE
                    t01int4 (ak_join, 'come up recu', context.jir_i);
                    t01int4 (ak_join, 'stop sequenc',
                          ord (context.jir_stop_sequence));
                    t01int4 (ak_join, 'beststratcnt', context.jir_beststratcnt);
                    a683tr_newsucc (ak_join, sequence_info.si_sequence, 1,
                          context.jir_i, true);
                    a683tr_newsucc (ak_join, sequence_info.si_sequence, context.jir_i + 1,
                          context.jir_max_tables, true);
                    t01int4 (ak_join, '$$$$$$$$$$$>', _aux_c.jir_i);
                    t01int4 (ak_join, 'beststratcnt', _aux_c.jir_beststratcnt);
                    a683tr_newsucc (ak_join, _aux_l.si_sequence,
                          1, context.jir_max_tables, true);
&                   endif
                    context.jir_stop_sequence :=
                          context.jir_stop_sequence
                          OR
                          ((NOT context.jir_better_seq_exists)
                          (**) AND
                          (context.jir_comp_sequences <
                          _aux_c.jir_comp_sequences));
                    context.jir_lowest_cost := _aux_c.jir_lowest_cost;
                    context.jir_lowest_succession :=
                          _aux_c.jir_lowest_succession;
                    context.jir_comp_sequences := _aux_c.jir_comp_sequences;
                    _n := 0;
                    FOR _l := 1 TO context.jir_i DO
                        IF  (_aux_l.si_sequence[ _l ].s_tableno =
                            sequence_info.si_sequence[ _l ].s_tableno)
                        THEN
                            _n := succ (_n);
                        (*ENDIF*) 
                    (*ENDFOR*) 
                    IF  (_n = context.jir_i)
                    THEN
                        BEGIN
                        (* no new start sequence computed *)
                        (* *** exit while without costcheck *** *)
                        context.jir_swap_cnt     :=
                              context.jir_max_tables - context.jir_i + 1;
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            (* there isn't a join transition to considered table *)
            context.jir_beststratcnt   := pred (context.jir_beststratcnt);
            (* cartesian product tables could be sequenced any time *)
            context.jir_sequenced_tables := context.jir_sequenced_tables +
                  [ _actual_table ];
            END;
        (*ENDIF*) 
        context.jir_i := succ (context.jir_i);
        END;
    (*ENDWHILE*) 
&   ifdef TRACE
    ak681tr_context( dmli, sequence_info, context );
&   endif
    context.jir_stop_sequence :=
          context.jir_stop_sequence
          OR
          (context.jir_i + 1 >= context.jir_max_tables)
          AND
          (
          (context.jir_beststratcnt <= 0)
          (**) OR
          (* initial value *)
          (context.jir_beststratcnt = context.jir_max_tables - 2)
          (**) OR
          (* mt join trans:                                              *)
          (* jir_i wasn't best transition and jir_i + 1 < jir_max_tables *)
          (* single join trans :                                         *)
          (* jir_i wasn't best transition                                *)
          (context.jir_better_seq_exists)
          )
          OR
          (* not a transition from first table to second table *)
          (* therefore try other start table                 *)
          (context.jir_i = 2);
&   ifdef TRACE
    t01bool (ak_join, 'stop sequenc', context.jir_stop_sequence);
    t01bool (ak_join, 'better_seq_e', context.jir_better_seq_exists);
&   endif
    IF  (NOT context.jir_stop_sequence) AND
        (acv.a_returncode = 0)
    THEN
        BEGIN
        _aux_l := sequence_info;
        ak681get_other_transition( acv, dmli, config, jtrans,
              sequence_info, context, mul_tabs, table_stats, res_info );
        _n := 0;
        FOR _l := 1 TO context.jir_i DO
            IF  (_aux_l.si_sequence[ _l ].s_tableno =
                sequence_info.si_sequence[ _l ].s_tableno)
            THEN
                _n := succ (_n);
            (*ENDIF*) 
        (*ENDFOR*) 
        context.jir_stop_sequence :=
              context.jir_stop_sequence OR ( _n = context.jir_i );
        END;
    (*ENDIF*) 
    END;
UNTIL
    context.jir_stop_sequence OR (acv.a_returncode <> 0);
(*ENDREPEAT*) 
&ifdef trace
t01sname( ak_join, 'full seq2   ');
a683tr_newsucc (ak_join, sequence_info.si_sequence, 1, dmli.d_cntfromtab, true);
&endif
IF  ( context.jir_beststratcnt <= 0 ) AND ( acv.a_returncode = 0 )
THEN
    ak681sequence_eval( acv, dmli, config, table_stats, jtrans, sequence_info,
          jinfos, res_info, mul_tabs, lastsuccession, context );
&ifdef trace
(*ENDIF*) 
ak681tr_context( dmli, sequence_info, context );
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681get_other_transition (
            VAR acv            : tak_all_command_glob;
            VAR dmli           : tak_dml_info;
            config             : tak_sysbufferaddress;
            VAR jtrans         : tak68_join_transitions;
            VAR sequence_info  : tak68_sequence_info;
            VAR context        : tak681_jseq_info_record;
            VAR mul_tabs       : tak68_mult_tabs;
            VAR table_stats    : tak68_table_stats;
            VAR res_info       : tak68_result_info);
 
VAR
      _xsum                : tsp00_Longreal;
      _aux_costs           : tsp00_Longreal;
      _next_table          : tsp00_Int2;
      _j                   : tsp00_Int2;
      _k                   : tsp00_Int2;
      _actual_table        : tsp00_Int2;
      _nonseq_table        : tsp00_Int2;
      _seq_table           : tsp00_Int2;
      _n                   : tsp00_Int2;
      _best_strat          : tak68_best_jstrat;
      _mt_jtrans_check     : boolean;
 
BEGIN
context.jir_beststratcnt := context.jir_max_tables - context.jir_i;
(* *** restore sequenced table set from si_sequence *** *)
context.jir_sequenced_tables := [ ];
FOR _j := 1 TO context.jir_i - 1 DO
    context.jir_sequenced_tables := context.jir_sequenced_tables +
          [ sequence_info.si_sequence[ _j ].s_tableno ];
(*ENDFOR*) 
_k := 1;
(* from jir_i on save non sequenced tables from start succession *)
FOR _j := context.jir_i TO context.jir_max_tables DO
    BEGIN
    IF  _k < context.jir_max_tables
    THEN
        WHILE (context.jir_start_succession[ _k ].s_tableno
              in context.jir_sequenced_tables) DO
            _k := succ (_k);
        (*ENDWHILE*) 
    (*ENDIF*) 
    sequence_info.si_sequence[ _j ].s_tableno :=
          context.jir_start_succession[ _k ].s_tableno;
    sequence_info.si_sequence[ _j ].s_backup :=
          context.jir_start_succession[ _k ].s_tableno;
    _k := succ (_k);
    END;
(*ENDFOR*) 
_actual_table := sequence_info.si_sequence[ context.jir_i ].s_tableno;
&ifdef TRACE
t01int4 (ak_join, 'other_wayi->', context.jir_i);
t01int4 (ak_join, 'beststratcnt', context.jir_beststratcnt);
a683tr_newsucc (ak_join, sequence_info.si_sequence, 1, context.jir_i, true);
a683tr_newsucc (ak_join, sequence_info.si_sequence, context.jir_i + 1,
      context.jir_max_tables,true);
a683tr_tableset(ak_join, 'seq_table_se', dmli, context.jir_sequenced_tables);
&endif
context.jir_stop_sequence := true;
_xsum       := cak68_max_real;
_next_table := 0;
_n := 0;
_mt_jtrans_check := true;
FOR _j := 1 TO context.jir_i - 1 DO
    BEGIN
    (* check for transitions from sequence *)
    _seq_table := sequence_info.si_sequence[ _j ].s_tableno;
    _k := succ (context.jir_i);
    WHILE (_k <= context.jir_max_tables) DO
        BEGIN
        _nonseq_table := sequence_info.si_sequence[ _k ].s_tableno;
        IF  context.jir_best_jstrat[ _nonseq_table ].bjr_is_mt_join
        THEN
            (* multiple table join transition to non-sequenced table *)
            BEGIN
            IF  _mt_jtrans_check
            THEN
                BEGIN
                (* all multiple table transition from sequence *)
                (* to non-sequenced tables checked             *)
                _mt_jtrans_check := false;
                _best_strat.bj_multiplier := csp_maxint4;
                _best_strat.bj_srctab     := 1;
                _best_strat.bj_jtype      := to_cartesian_prod;
                _best_strat.bj_fieldcnt   := 1;
                _best_strat.bj_indexno    := 0;
                a681lowest_multiple_strat( acv, dmli, config, jtrans,
                      sequence_info.si_sequence, mul_tabs, _seq_table,
                      _nonseq_table(*dst table*),
                      _best_strat, context.jir_i - 1, NOT c_update_jtrans );
                _aux_costs := ak681jtable_cost (acv, table_stats,
                      _nonseq_table, _best_strat.bj_jtype,
                      _best_strat.bj_multiplier, res_info);
                IF   (_aux_costs < _xsum)
                THEN
                    BEGIN
                    context.jir_stop_sequence := false;
                    _xsum       := _aux_costs;
                    _next_table := _nonseq_table;
                    _n          := _k;
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END
        ELSE
            (* join transition with single table to non-sequenced table *)
            IF  (context.jir_best_jstrat[ _nonseq_table ].
                bjr_stratinfo.bj_jtype <= to_eq_field)
                AND
                (* best transition comes from sequence *)
                (jtrans[ _seq_table, _nonseq_table ].
                jt_jointype = context.jir_best_jstrat[ _nonseq_table ].
                bjr_stratinfo.bj_jtype)
                AND
                (context.jir_best_jstrat[ _nonseq_table ].
                bjr_costs < _xsum)
            THEN
                BEGIN
                _xsum := context.jir_best_jstrat[ _nonseq_table ].bjr_costs;
                _next_table := _nonseq_table;
                context.jir_stop_sequence := false;
                _n          := _k;
                END;
            (*ENDIF*) 
        (*ENDIF*) 
        _k := succ (_k);
        END;
    (*ENDWHILE*) 
    END;
(*ENDFOR*) 
IF  (_next_table = 0)
THEN
    (* no transition from sequence to non-sequenced tables *)
    (* check for transitions from actual considered table  *)
    (* to non_sequenced table                              *)
    IF  context.jir_best_jstrat[ _actual_table ].bjr_is_mt_join
    THEN
        (* best join transition to considered table is multiple table transition *)
        BEGIN
        _k := succ (context.jir_i);
        WHILE (_k <= context.jir_max_tables) DO
            BEGIN
            _nonseq_table := sequence_info.si_sequence[ _k ].s_tableno;
            IF  (_nonseq_table
                in mul_tabs.mt_arr [ context.jir_best_jstrat[ _actual_table ].
                bjr_mtab_ind ].mtr_tab_seq)
            THEN
                BEGIN
                (* table from non-sequence has transition *)
                (* to actual considered table             *)
                _next_table := _nonseq_table;
                context.jir_stop_sequence := false;
                _n  := _k;
                (* exit while *)
                _k  := context.jir_max_tables;
                END;
            (*ENDIF*) 
            _k := succ (_k);
            END;
        (*ENDWHILE*) 
        END
    ELSE
        (* best join transition to considered table is single table transition *)
        (* table transition from sequence or non-sequence *)
        BEGIN
        IF  (context.jir_i >= context.jir_non_best_trans)
        THEN
            BEGIN
            (* sequence actual table *)
            context.jir_beststratcnt     := pred (context.jir_beststratcnt);
            context.jir_sequenced_tables := context.jir_sequenced_tables +
                  [ _actual_table ];
&           ifdef TRACE
            t01sname( ak_join, 'set nonbest5' );
&           endif
            context.jir_non_best_trans    := context.jir_i;
            context.jir_i                 := succ (context.jir_i);
            context.jir_stop_sequence     := false;
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
(*ENDIF*) 
IF  (_next_table > 0)
THEN
    (* best single table transition from sequence *)
    (* OR *)
    (* good mult. table transition from sequence  *)
    (* OR *)
    (* mult. transition to actual considered table *)
    (* from non-sequenced tables                   *)
    BEGIN
    (* move transition table in front of actual considered table  *)
    FOR _k := _n DOWNTO context.jir_i + 1 DO
        sequence_info.si_sequence[ _k ].s_tableno :=
              sequence_info.si_sequence[ _k - 1 ].s_tableno;
    (*ENDFOR*) 
    sequence_info.si_sequence[ context.jir_i ].s_tableno := _next_table;
    context.jir_beststratcnt     := pred (context.jir_beststratcnt);
    context.jir_sequenced_tables := context.jir_sequenced_tables +
          [ sequence_info.si_sequence[ context.jir_i ].s_tableno ];
&   ifdef TRACE
    t01sname( ak_join, 'set nonbest6' );
&   endif
    context.jir_non_best_trans := context.jir_i;
    context.jir_i              := succ (context.jir_i);
    END;
&ifdef TRACE
(*ENDIF*) 
t01int4 (ak_join, '.........i->', context.jir_i);
t01int4 (ak_join, 'beststratcnt', context.jir_beststratcnt);
t01bool (ak_join, 'stop sequenc', context.jir_stop_sequence);
a683tr_newsucc (ak_join, sequence_info.si_sequence, 2, context.jir_i, true);
a683tr_newsucc (ak_join, sequence_info.si_sequence, context.jir_i + 1,
      context.jir_max_tables, true);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681best_join_strat (
            VAR acv           : tak_all_command_glob; (* IN *)
            VAR dmli          : tak_dml_info; (* IN *)
            config            : tak_sysbufferaddress;
            VAR table_stats   : tak68_table_stats; (* IN *)
            VAR jtrans        : tak68_join_transitions; (* IN *)
            VAR sequence_info : tak68_sequence_info; (* IN/OUT *)
            VAR res_info      : tak68_result_info; (* IN/OUT *)
            VAR mul_tabs      : tak68_mult_tabs; (* IN/OUT change of mt_pos *)
            VAR best_jstrat   : tak681_best_jstrat_rec_arr (* IN/OUT *));
 
VAR
      _src_tab              : tsp00_Int2;
      _src_tab_idx          : tsp00_Int2;
      _dst_tab              : tsp00_Int2;
      _dst_tab_idx          : tsp00_Int2;
      _used_tablecnt        : tsp00_Int2;
      _best_strat           : tak68_best_jstrat;
 
BEGIN
_used_tablecnt       := dmli.d_cntfromtab;
FOR _dst_tab_idx := 1 TO dmli.d_cntfromtab DO
    BEGIN
    _dst_tab := sequence_info.si_sequence[ _dst_tab_idx ].s_tableno;
    (* initialize best join record *)
    best_jstrat[ _dst_tab ].bjr_stratinfo.bj_multiplier := csp_maxint4;
    best_jstrat[ _dst_tab ].bjr_stratinfo.bj_srctab     := 0;
    best_jstrat[ _dst_tab ].bjr_stratinfo.bj_jtype      := to_cartesian_prod;
    best_jstrat[ _dst_tab ].bjr_stratinfo.bj_fieldcnt   := 1;
    best_jstrat[ _dst_tab ].bjr_stratinfo.bj_indexno    := 0;
    best_jstrat[ _dst_tab ].bjr_mtab_ind    := 0;
    best_jstrat[ _dst_tab ].bjr_is_mt_join  := false;
    (* work for all possible join transitions *)
    FOR _src_tab_idx := 1 TO dmli.d_cntfromtab DO
        BEGIN
        _src_tab := sequence_info.si_sequence[ _src_tab_idx ].s_tableno;
        IF  ( _src_tab <> _dst_tab )
        THEN
            (* consider every possible join transition *)
            (* decide for best join strategy           *)
            BEGIN
            IF  ( jtrans[ _src_tab, _dst_tab ].jt_jointype = to_mt_join )
            THEN
                (* there is information in mul_tabs *)
                BEGIN
                _best_strat := best_jstrat[ _dst_tab ].bjr_stratinfo;
                a681lowest_multiple_strat( acv, dmli, config, jtrans,
                      sequence_info.si_sequence,
                      mul_tabs, _src_tab, _dst_tab,
                      _best_strat, _used_tablecnt, NOT c_update_jtrans );
                IF  (_best_strat.bj_multiplier < best_jstrat[ _dst_tab ].bjr_stratinfo.bj_multiplier)
                THEN
                    BEGIN
                    (* get better join transition *)
                    best_jstrat[ _dst_tab ].bjr_stratinfo  := _best_strat;
                    best_jstrat[ _dst_tab ].bjr_mtab_ind   := mul_tabs.mt_pos;
                    best_jstrat[ _dst_tab ].bjr_is_mt_join := true;
                    END;
                (*ENDIF*) 
                END
            ELSE
                BEGIN
                IF  ( best_jstrat[ _dst_tab ].bjr_stratinfo.bj_jtype    >
                    jtrans[ _src_tab, _dst_tab ].jt_jointype)
                    OR
                    (
                    (best_jstrat[ _dst_tab ].bjr_stratinfo.bj_jtype    =
                    jtrans[ _src_tab, _dst_tab ].jt_jointype)
                    AND
                    ( best_jstrat[ _dst_tab ].bjr_stratinfo.bj_multiplier >
                    jtrans[ _src_tab, _dst_tab ].jt_multipl)
                    )
                THEN
                    BEGIN
                    (* get better join transition *)
                    best_jstrat[ _dst_tab ].bjr_stratinfo.bj_jtype :=
                          jtrans[ _src_tab, _dst_tab ].jt_jointype;
                    best_jstrat[ _dst_tab ].bjr_stratinfo.bj_multiplier :=
                          jtrans[ _src_tab, _dst_tab ].jt_multipl;
                    best_jstrat[ _dst_tab ].bjr_stratinfo.bj_fieldcnt := 1;
                    best_jstrat[ _dst_tab ].bjr_stratinfo.bj_srctab   := _src_tab;
                    best_jstrat[ _dst_tab ].bjr_mtab_ind    := 0;
                    best_jstrat[ _dst_tab ].bjr_is_mt_join  := false;
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDFOR*) 
    a680_first_table_cost( sequence_info, table_stats, _dst_tab, res_info );
    best_jstrat[ _dst_tab ].bjr_costs :=
          ak681jtable_cost( acv, table_stats, _dst_tab,
          best_jstrat[ _dst_tab ].bjr_stratinfo.bj_jtype (*in*), best_jstrat[ _dst_tab ].
          bjr_stratinfo.bj_multiplier(*in*), res_info );
    END;
(*ENDFOR*) 
IF  ( acv.a_intern_explain OR g01vtrace.vtrStrategy_gg00 )
THEN
    ak681tr_best_joinstrat( acv, dmli, best_jstrat, sequence_info, NOT c_debug_output );
(*ENDIF*) 
;
&ifdef trace
ak681tr_best_joinstrat (acv, dmli, best_jstrat, sequence_info, c_debug_output);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681sort_by_costs (
            VAR dmli          : tak_dml_info;
            VAR sequence_info : tak68_sequence_info;
            VAR best_jstrat   : tak681_best_jstrat_rec_arr;
            VAR table_stats   : tak68_table_stats);
 
VAR
      _i           : tsp00_Int2;
      _j           : tsp00_Int2;
      _k           : tsp00_Int2;
      _first_table : tsp00_Int2;
 
BEGIN
&ifdef TRACE
a683tr_newsucc (ak_join, sequence_info.si_sequence, 1, dmli.d_cntfromtab, true);
&endif
(***************************************************************)
(* *** searching for the smallest table for joining first,     *)
(*     which offers not a very good joinstrategy           *** *)
(***************************************************************)
(* first table is table with lowest one table access costs *)
_first_table := sequence_info.si_sequence[ 1 ].s_tableno;
FOR _i := 2 TO dmli.d_cntfromtab DO
    IF  table_stats[ _i ].ts_cost < table_stats[ _first_table ].ts_cost
    THEN
        _first_table := _i;
    (* get first table *)
    (*ENDIF*) 
(*ENDFOR*) 
_k := sequence_info.si_sequence[ 1 ].s_tableno;
sequence_info.si_sequence[ 1 ].s_tableno :=
      sequence_info.si_sequence[ _first_table ].s_tableno;
sequence_info.si_sequence[ _first_table ].s_tableno := _k;
(* now sort remaining tables with costs for joining *)
FOR _i := 2 TO dmli.d_cntfromtab - 1 DO
    FOR _j := _i + 1 TO dmli.d_cntfromtab DO
        BEGIN
        IF  ( best_jstrat[ sequence_info.si_sequence[ _j ].s_tableno ].
            bjr_costs <
            best_jstrat[ sequence_info.si_sequence[ _i ].s_tableno ].
            bjr_costs   )
        THEN
            BEGIN
            (* swap destination tables *)
            _k := sequence_info.si_sequence[ _j ].s_tableno;
            sequence_info.si_sequence[ _j ].s_tableno :=
                  sequence_info.si_sequence[ _i ].s_tableno;
            sequence_info.si_sequence[ _i ].s_tableno := _k;
            END;
        (*ENDIF*) 
        END;
    (*ENDFOR*) 
(*ENDFOR*) 
&ifdef TRACE
t01sname(ak_join, 'sorted seq  ');
a683tr_newsucc (ak_join, sequence_info.si_sequence, 1, dmli.d_cntfromtab, true);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681greedy (
            VAR acv           : tak_all_command_glob;
            VAR dmli          : tak_dml_info;
            config            : tak_sysbufferaddress;
            VAR jtrans        : tak68_join_transitions;
            VAR mul_tabs      : tak68_mult_tabs;
            VAR table_stats   : tak68_table_stats;
            VAR sequence_info : tak68_sequence_info;
            last_table        : tsp00_Int2;
            find_start_table  : boolean);
 
VAR
      _aux_multiplier      : tsp00_Int4;
      _act_table_pos       : tsp00_Int2;
      _seq_table           : tsp00_Int2;
      _nonseq_table        : tsp00_Int2;
      _l                   : tsp00_Int2;
      _i                   : tsp00_Int2;
      _k                   : tsp00_Int2;
      _first_table         : tsp00_Int2;
      _next_table_pos      : tsp00_Int2;
      _best_strat          : tak68_best_jstrat;
      _mt_jtrans_check     : boolean;
 
BEGIN
&ifdef TRACE
a683tr_newsucc (ak_join,
      sequence_info.si_sequence, 1, last_table, true);
&endif
IF  find_start_table
THEN
    BEGIN
    _first_table :=  1;
    FOR _i := 2 TO last_table DO
        BEGIN (* PTS 1112102 *)
        IF  table_stats[sequence_info.si_sequence[_i].s_tableno].ts_pages_searched <
            table_stats[sequence_info.si_sequence[_first_table].s_tableno].
            ts_pages_searched
        THEN
            _first_table :=  _i;
        (*ENDIF*) 
        END;
    (*ENDFOR*) 
    _k := sequence_info.si_sequence[ 1 ].s_tableno;
    sequence_info.si_sequence[ 1 ].s_tableno :=
          sequence_info.si_sequence[ _first_table ].s_tableno;
    sequence_info.si_sequence[ _first_table ].s_tableno := _k;
    END;
(*ENDIF*) 
FOR _act_table_pos := 2 TO last_table DO
    BEGIN
    _next_table_pos := _act_table_pos; (* PTS 1112102 *)
    _best_strat.bj_multiplier   := csp_maxint4;
    _best_strat.bj_srctab    := 1;
    _best_strat.bj_jtype     := to_cartesian_prod;
    _best_strat.bj_fieldcnt  := 1;
    _best_strat.bj_indexno   := 0;
    FOR _l := _act_table_pos TO last_table DO
        BEGIN
        _mt_jtrans_check := true;
        _nonseq_table :=
              sequence_info.si_sequence[ _l ].s_tableno;
        FOR _i := 1 TO _act_table_pos - 1 DO
            BEGIN
            _seq_table :=
                  sequence_info.si_sequence[ _i ].s_tableno;
            IF  jtrans[ _seq_table, _nonseq_table ].
                jt_jointype = to_mt_join
            THEN
                BEGIN
                IF  _mt_jtrans_check
                THEN
                    BEGIN
                    _mt_jtrans_check := false;
                    _aux_multiplier := _best_strat.bj_multiplier;
                    a681lowest_multiple_strat( acv, dmli, config, jtrans,
                          sequence_info.si_sequence, mul_tabs,
                          _seq_table, _nonseq_table,
                          _best_strat, _act_table_pos - 1, NOT c_update_jtrans );
                    IF  _aux_multiplier > _best_strat.bj_multiplier
                    THEN
                        _next_table_pos := _l;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END
            ELSE
                IF  ( _best_strat.bj_jtype >
                    jtrans[ _seq_table, _nonseq_table ].jt_jointype )
                    OR
                    (( _best_strat.bj_jtype =
                    jtrans[ _seq_table, _nonseq_table ].jt_jointype )
                    AND
                    ( _best_strat.bj_multiplier >
                    jtrans[ _seq_table, _nonseq_table ].jt_multipl ))
                THEN
                    BEGIN
                    _best_strat.bj_jtype       :=
                          jtrans[ _seq_table, _nonseq_table ].jt_jointype;
                    _best_strat.bj_multiplier  :=
                          jtrans[ _seq_table, _nonseq_table ].jt_multipl;
                    _best_strat.bj_indexno     :=
                          jtrans[ _seq_table, _nonseq_table ].jt_indexno;
                    _best_strat.bj_fieldcnt    := 1;
                    _best_strat.bj_srctab      := _seq_table;
                    _next_table_pos   := _l;
                    END;
                (*ENDIF*) 
            (*ENDIF*) 
            END;
        (*ENDFOR*) 
        END;
    (*ENDFOR*) 
    _k := sequence_info.si_sequence[ _act_table_pos ].s_tableno;
    sequence_info.si_sequence[ _act_table_pos ].s_tableno :=
          sequence_info.si_sequence[ _next_table_pos ].s_tableno;
    sequence_info.si_sequence[ _next_table_pos ].s_tableno := _k;
    END;
(*ENDFOR*) 
&ifdef TRACE
t01sname(ak_join, 'greedy seq  ');
a683tr_newsucc (ak_join, sequence_info.si_sequence, 1, last_table, true);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681mtj_check (
            VAR acv               : tak_all_command_glob;
            VAR dmli              : tak_dml_info;
            config                : tak_sysbufferaddress;
            VAR jtrans            : tak68_join_transitions;
            VAR sequence_info     : tak68_sequence_info;
            VAR context           : tak681_jseq_info_record;
            VAR table_stats       : tak68_table_stats;
            VAR res_info          : tak68_result_info;
            VAR mul_tabs          : tak68_mult_tabs;
            VAR join_other_table  : boolean);
 
VAR
      _actual_table        : tsp00_Int2;
      _n                   : tsp00_Int2;
      _xi                  : tsp00_Int2;
      _best_strat          : tak68_best_jstrat;
      _join_table          : boolean;
 
BEGIN
join_other_table  := false;
_actual_table     := sequence_info.si_sequence[ context.jir_i ].s_tableno;
_best_strat.bj_multiplier  := csp_maxint4;
_best_strat.bj_fieldcnt    := 1;
_best_strat.bj_srctab      := 1;
_best_strat.bj_indexno     := 0;
_best_strat.bj_jtype       := to_cartesian_prod;
(* are all needed tables for mult table join in sequence ? *)
(* test for best transition from sequence *)
_join_table :=
      context.jir_sequenced_tables >= mul_tabs.mt_arr[ context.jir_best_jstrat
      [ _actual_table ].bjr_mtab_ind ].mtr_tab_seq;
IF  ( NOT _join_table )
THEN
    BEGIN
    a681lowest_multiple_strat( acv, dmli, config, jtrans,
          sequence_info.si_sequence, mul_tabs,
          sequence_info.si_sequence[ 1 ].s_tableno, _actual_table,
          _best_strat, context.jir_i - 1, NOT c_update_jtrans );
    (* test for best transition from sequence *)
    _join_table :=
          (* TRUE, if mt join transition to _actual_table with  *)
          (* same quality found; all tables in si_sequence *)
          ( context.jir_best_jstrat[ _actual_table ].
          bjr_stratinfo.bj_jtype = _best_strat.bj_jtype )
          AND
          ( context.jir_best_jstrat[ _actual_table ].
          bjr_stratinfo.bj_multiplier >= _best_strat.bj_multiplier );
    IF  NOT _join_table
    THEN
        BEGIN
        IF  ( _best_strat.bj_jtype = to_cartesian_prod )
        THEN
            (* don't found multiple table transition from sequence *)
            (* *** no index- or keystratgey found ! *** *)
            BEGIN
            (* find best join transition to dst_table *)
            (* from tables in sequence                *)
            _xi := 1;
            WHILE (_xi <= dmli.d_cntfromtab) DO
                BEGIN
                IF  (_xi in context.jir_sequenced_tables)
                THEN
                    IF  ( _best_strat.bj_jtype > jtrans[ _xi, _actual_table ].jt_jointype)
                        OR
                        (
                        (_best_strat.bj_jtype = jtrans[ _xi, _actual_table ].jt_jointype)
                        AND
                        ( _best_strat.bj_multiplier > jtrans[ _xi, _actual_table ].jt_multipl)
                        )
                    THEN
                        BEGIN
                        _best_strat.bj_jtype      :=
                              jtrans[ _xi, _actual_table ].jt_jointype;
                        _best_strat.bj_multiplier :=
                              jtrans[ _xi, _actual_table ].jt_multipl;
                        _best_strat.bj_indexno :=
                              jtrans[ _xi, _actual_table ].jt_indexno;
                        END;
                    (*ENDIF*) 
                (*ENDIF*) 
                _xi := succ (_xi);
                END;
            (*ENDWHILE*) 
            END;
        (*ENDIF*) 
        _join_table :=
              (* there is a possible transition from sequence *)
              (_best_strat.bj_jtype <> to_cartesian_prod)
              AND
              (
              (
              (ak681jtable_cost (acv, table_stats, _actual_table, _best_strat.bj_jtype,
              _best_strat.bj_multiplier, res_info) <
              (context.jir_best_jstrat
              [ sequence_info.si_sequence[ context.jir_i + 1 ].s_tableno ].
              bjr_costs))
              (**) AND
              (context.jir_best_jstrat
              [ sequence_info.si_sequence[ context.jir_i + 1 ].s_tableno ].
              bjr_stratinfo.bj_jtype < to_eq_field)
              )
              OR
              (* good transition to next table *)
              (context.jir_best_jstrat
              [ sequence_info.si_sequence[ context.jir_i + 1 ].s_tableno ].
              bjr_stratinfo.bj_jtype = to_single_keyfield)
              );
        join_other_table :=
              ( _join_table AND (context.jir_i + 1 < context.jir_max_tables))
              OR
              (
              (NOT _join_table)
              (* no transition from first table to second table *)
              (**) AND
              (context.jir_i = 2)
              (**) AND
              (dmli.d_cntfromtab > 2)
              (**) AND
              (table_stats[ sequence_info.si_sequence[ 1 ].s_tableno ].
              ts_strat_value < 0.98)
              );
        (* note: there isn't a key or index transition from sequence *)
        context.jir_better_seq_exists :=
              (context.jir_i + 1 < context.jir_max_tables);
&       ifdef trace
        t01sname( ak_join, 'set nonbest1' );
&       endif
        context.jir_non_best_trans := context.jir_i;
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  _join_table
THEN
    BEGIN
    (* trace found sequence from mtr_tab_seq *)
    context.jir_beststratcnt     := pred (context.jir_beststratcnt);
    context.jir_sequenced_tables := context.jir_sequenced_tables +
          [ _actual_table ];
    _best_strat.bj_jtype := context.jir_best_jstrat[ _actual_table ].bjr_stratinfo.bj_jtype;
    context.jir_swap_cnt     := 0;
    END
ELSE
    (* no transition from sequence *)
    IF  NOT join_other_table
    THEN
        BEGIN
        (* *** change tables *** *)
        FOR _n := 1 TO context.jir_max_tables DO
            sequence_info.si_sequence[ _n ].s_backup :=
                  sequence_info.si_sequence[ _n ].s_tableno;
        (*ENDFOR*) 
        context.jir_last_swap_pos := context.jir_i;
        IF  (context.jir_i + 1 = context.jir_max_tables)
        THEN
            BEGIN
            sequence_info.si_sequence[ context.jir_i ].s_tableno :=
                  sequence_info.si_sequence[ context.jir_i + 1 ].s_tableno;
            sequence_info.si_sequence[ context.jir_i + 1 ].
                  s_tableno := _actual_table;
            _join_table := true;
            END
        ELSE
            BEGIN
            ak681mt_next_table( acv, dmli, config, sequence_info, jtrans,
                  mul_tabs, context, table_stats, res_info, _join_table );
            join_other_table :=
                  (* at least 2 tables remaining *)
                  (context.jir_i + 1 < context.jir_max_tables);
            context.jir_better_seq_exists :=
                  (context.jir_i + 1 < context.jir_max_tables);
&           ifdef trace
            t01sname( ak_join, 'set nonbest2' );
&           endif
            context.jir_non_best_trans    := context.jir_i;
            IF  (NOT _join_table)
            THEN
                BEGIN
                (* ** no good join-condition    *)
                (*    from first table       ** *)
                (* ** leave loop             ** *)
                context.jir_stop_sequence := true;
                context.jir_swap_cnt      :=
                      context.jir_max_tables - context.jir_i + 1;
                context.jir_i             := context.jir_max_tables;
                context.jir_beststratcnt  := context.jir_max_tables;
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  _join_table
        THEN
            BEGIN
            (* tables swaped *)
            context.jir_beststratcnt   := pred (context.jir_beststratcnt);
            context.jir_sequenced_tables := context.jir_sequenced_tables +
                  [sequence_info.si_sequence[ context.jir_i ].s_tableno ];
            END;
        (*ENDIF*) 
        context.jir_swap_cnt := 0;
        END;
    (*ENDIF*) 
(*ENDIF*) 
IF  ( _best_strat.bj_jtype > to_eq_field )
THEN
    (* we need cartesian product join transition *)
    join_other_table := true;
(*ENDIF*) 
;
(* *** one_to_n check *** *)
IF  (NOT join_other_table)
    AND
    (* we are in first half the sequence *)
    (context.jir_i + 1 <= context.jir_max_tables DIV 2)
    AND
    (* NOT one join result row *)
    (NOT ( _best_strat.bj_jtype in
    [ to_single_keyfield, to_key, to_unique_field ] ))
THEN
    BEGIN
    _xi := context.jir_i + 1;
    WHILE ((_xi <= context.jir_max_tables) AND (NOT join_other_table)) DO
        BEGIN
        join_other_table := (context.jir_best_jstrat
              [ sequence_info.si_sequence[ _xi ].s_tableno ].bjr_stratinfo.bj_jtype in
              [ to_single_keyfield, to_key, to_unique_field ]);
        _xi := succ (_xi);
        END;
    (*ENDWHILE*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681mt_next_table (
            VAR acv            : tak_all_command_glob;
            VAR dmli           : tak_dml_info;
            config             : tak_sysbufferaddress;
            VAR sequence_info  : tak68_sequence_info;
            VAR jtrans         : tak68_join_transitions;
            VAR mul_tabs       : tak68_mult_tabs;
            VAR context        : tak681_jseq_info_record;
            VAR table_stats    : tak68_table_stats;
            VAR res_info       : tak68_result_info;
            VAR table_swaped   : boolean);
 
VAR
      _jmultipl_to_next     : tsp00_Int4;
      _n                    : tsp00_Int2;
      _i                    : tsp00_Int2;
      _j                    : tsp00_Int2;
      _seq_table            : tsp00_Int2;
      _actual_table         : tsp00_Int2;
      _nonseq_table         : tsp00_Int2;
      _next_table           : tsp00_Int2;
      _mt_index             : tsp00_Int2;
      _cost_to_nonseqtab    : tsp00_Longreal;
      _cost_to_nexttab      : tsp00_Longreal;
      _best_strat           : tak68_best_jstrat;
      _processed_table_set  : tak_joinset;
      _mt_jtrans_check      : boolean;
      _best_jtype_to_next   : tak68_one_jointype;
 
BEGIN
_actual_table := sequence_info.si_sequence[ context.jir_i ].s_tableno;
_next_table   := 0;
_n  := 0;
_i  := context.jir_best_jstrat[ _actual_table ].bjr_mtab_ind;
IF  ((mul_tabs.mt_arr[ _i ].mtr_tab_seq - context.jir_sequenced_tables) =
    mul_tabs.mt_arr[ _i ].mtr_tab_seq)
THEN
    (* sets are disjunct, i.e. there is no transition from sequence *)
    (* to considered table *)
    BEGIN
    (* *** try to find same joinstrategy via other tablesequence *** *)
    _i := mul_tabs.mt_cnt;
    END;
(*ENDIF*) 
WHILE (_i >= context.jir_best_jstrat[ _actual_table ].bjr_mtab_ind) DO
    BEGIN
    IF  (mul_tabs.mt_arr [ _i ].mtr_dst_table = _actual_table)
        AND
        (* there is the same best join transition *)
        (mul_tabs.mt_arr [ _i ].mtr_jointype =
        context.jir_best_jstrat[ _actual_table ].bjr_stratinfo.bj_jtype)
        AND
        (* we found best join transition *)
        ((_i = context.jir_best_jstrat[ _actual_table ].bjr_mtab_ind)
        OR
        (* we found join without transition from sequence *)
        ((mul_tabs.mt_arr [ _i ].mtr_tab_seq - context.jir_sequenced_tables) =
        mul_tabs.mt_arr [ _i ].mtr_tab_seq))
    THEN
        BEGIN
        (* look for non-sequenced table with multiple  *)
        (* transition to considered table              *)
        (* all participated tables are not in sequence *)
        _j := succ (context.jir_i);
        WHILE (_j <= context.jir_max_tables) DO
            BEGIN
            IF  (sequence_info.si_sequence[ _j ].s_tableno in
                mul_tabs.mt_arr [ _i ].mtr_tab_seq) AND
                NOT (sequence_info.si_sequence[ _j ].s_tableno in
                context.jir_sequenced_tables)
            THEN
                BEGIN
                (* _next_table is participant in multiple join transition *)
                _next_table := sequence_info.si_sequence[ _j ].s_tableno;
                _n          := _j;
                _mt_index   := _i;
                _j          := context.jir_max_tables;
                END;
            (*ENDIF*) 
            _j := succ (_j);
            END;
        (*ENDWHILE*) 
        END;
    (*ENDIF*) 
    _i := pred (_i);
    END;
(*ENDWHILE*) 
IF  (_next_table <> 0)
THEN
    BEGIN
    table_swaped := true;
    (* *** try to find a cheaper table for next joinstep *** *)
    _processed_table_set := [ ];
    _best_strat.bj_srctab:= 1;
    _jmultipl_to_next   := csp_maxint4;
    _best_jtype_to_next := to_cartesian_prod;
    _cost_to_nexttab    := ak681jtable_cost (acv, table_stats, _next_table(*dst_tab*),
          _best_jtype_to_next(*in*), _jmultipl_to_next(*in*), res_info);
    FOR _i := context.jir_i + 1 TO context.jir_max_tables DO
        BEGIN
        _mt_jtrans_check := true;
        _nonseq_table := sequence_info.si_sequence[ _i ].s_tableno;
        IF  (NOT (_nonseq_table in _processed_table_set))
            AND
            (_nonseq_table in mul_tabs.mt_arr[ _mt_index ].mtr_tab_seq )
        THEN
            FOR _j := 1 TO context.jir_i - 1 DO
                BEGIN
                _seq_table := sequence_info.si_sequence[ _j ].s_tableno;
                IF  jtrans[ _seq_table, _nonseq_table ].
                    jt_jointype = to_mt_join
                THEN
                    BEGIN
                    (* multiple join transition *)
                    IF  ( _mt_jtrans_check )
                    THEN
                        BEGIN
                        (* better transition from sequence to choosen table *)
                        (* than transition from sequence to _next_table ?   *)
                        _mt_jtrans_check      := false;
                        _best_strat.bj_multiplier   := csp_maxint4;
                        _best_strat.bj_fieldcnt  := 1;
                        _best_strat.bj_indexno   := 0;
                        _best_strat.bj_jtype := to_cartesian_prod;
                        a681lowest_multiple_strat( acv, dmli, config, jtrans,
                              sequence_info.si_sequence, mul_tabs,
                              _seq_table, _nonseq_table(*dst tab*),
                              _best_strat, context.jir_i - 1, NOT c_update_jtrans );
                        _cost_to_nonseqtab := ak681jtable_cost( acv, table_stats,
                              _nonseq_table(*dst table*),
                              _best_strat.bj_jtype(*in*),
                              _best_strat.bj_multiplier(*in*),
                              res_info );
                        IF  (_cost_to_nonseqtab = context.jir_best_jstrat
                            [ _nonseq_table ].bjr_costs)
                            OR
                            ((_cost_to_nonseqtab / context.jir_best_jstrat
                            [ _nonseq_table ].bjr_costs) <
                            (_cost_to_nexttab / context.jir_best_jstrat
                            [ _next_table ].bjr_costs))
                        THEN
                            BEGIN
                            IF  (NOT (context.jir_best_jstrat
                                [ _nonseq_table ].bjr_stratinfo.bj_jtype in
                                [ to_key, to_all_invfields ]))
                                (* NOT multi table transitions *)
                            THEN
                                BEGIN
                                _next_table := _nonseq_table;
                                _n          := _i;
                                _jmultipl_to_next   := _best_strat.bj_multiplier;
                                _best_jtype_to_next := _best_strat.bj_jtype;
                                _cost_to_nexttab    := _cost_to_nonseqtab;
                                _processed_table_set := _processed_table_set +
                                      [ _nonseq_table ];
                                END;
                            (*ENDIF*) 
                            END
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    END
                ELSE
                    (* single join transition to non-sequenced table *)
                    (* which is participant in multiple join         *)
                    IF  (_best_jtype_to_next  >
                        jtrans[ _seq_table, _nonseq_table ].jt_jointype)
                        AND
                        (context.
                        jir_best_jstrat[ _nonseq_table ].bjr_stratinfo.bj_jtype =
                        jtrans[ _seq_table, _nonseq_table ].jt_jointype)
                    THEN
                        BEGIN
                        (* best transition from sequenced *)
                        (* to non-sequenced table found   *)
                        _cost_to_nonseqtab :=
                              ak681jtable_cost (acv, table_stats,
                              _nonseq_table(*dst tab*),
                              jtrans[ _seq_table, _nonseq_table ].
                              jt_jointype(*in*),
                              jtrans[ _seq_table, _nonseq_table ].
                              jt_multipl(*in*),
                              res_info);
                        IF  (_cost_to_nonseqtab  / context.jir_best_jstrat
                            [ _nonseq_table ].bjr_costs) <
                            (_cost_to_nexttab / context.jir_best_jstrat
                            [ _next_table ].bjr_costs)
                        THEN
                            BEGIN
                            _next_table := _nonseq_table;
                            _n          := _i;
                            _jmultipl_to_next   := _best_strat.bj_multiplier;
                            _cost_to_nexttab    := _cost_to_nonseqtab;
                            _best_jtype_to_next :=
                                  jtrans[ _seq_table, _nonseq_table ].
                                  jt_jointype;
                            _processed_table_set := [ _nonseq_table ] +
                                  _processed_table_set;
                            END;
                        (*ENDIF*) 
                        END;
                    (* all multiple table transition from sequence *)
                    (* to non-sequenced tables checked             *)
                    (*ENDIF*) 
                (*ENDIF*) 
                END;
            (*ENDFOR*) 
        (*ENDIF*) 
        END;
    (*ENDFOR*) 
    (* move found table in front of sequence *)
&   ifdef trace
    t01int4( ak_join, 'next table  ', _next_table );
&   endif
    FOR _j := _n DOWNTO context.jir_i + 1 DO
        sequence_info.si_sequence[ _j ].s_tableno :=
              sequence_info.si_sequence[ _j - 1 ].s_tableno;
    (*ENDFOR*) 
    sequence_info.si_sequence[ context.jir_i ].s_tableno := _next_table;
&   ifdef trace
    a683tr_newsucc (ak_join, sequence_info.si_sequence, 1, dmli.d_cntfromtab, true);
&   endif
    END
ELSE
    table_swaped := false;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681j_check (
            VAR dmli              : tak_dml_info;
            VAR jtrans            : tak68_join_transitions;
            VAR sequence_info     : tak68_sequence_info;
            VAR context           : tak681_jseq_info_record;
            VAR join_other_table  : boolean);
 
VAR
      _j            : tsp00_Int2;
      _xi           : tsp00_Int2;
      _seq_table    : tsp00_Int2;
      _actual_table : tsp00_Int2;
      _join_table   : boolean;
 
BEGIN
(* there is a transition to _actual_table *)
_actual_table := sequence_info.si_sequence[ context.jir_i ].s_tableno;
_j          := 1;
_join_table := false;
WHILE (_j <= context.jir_i - 1) DO
    BEGIN
    (* consider all transitions to _actual_table *)
    _seq_table := sequence_info.si_sequence[ _j ].s_tableno;
    IF  (_seq_table <> _actual_table)
        AND
        (jtrans[ _seq_table, _actual_table ].jt_jointype < to_cartesian_prod)
        AND
        (_seq_table in context.jir_sequenced_tables)
    THEN
        (* there is a possible transition to dst_table  *)
        (* from already sequenced table                 *)
        BEGIN
        IF  (context.jir_best_jstrat[ _actual_table ].bjr_stratinfo.bj_jtype =
            jtrans[ _seq_table, _actual_table ].jt_jointype)
            AND
            (jtrans[ _seq_table, _actual_table ].jt_multipl =
            context.jir_best_jstrat[ _actual_table ].bjr_stratinfo.bj_multiplier)
        THEN
            BEGIN
            (* best join transition to dst_table  *)
            (* from already sequenced table       *)
            context.jir_best_jstrat[ _actual_table ].bjr_stratinfo.bj_srctab :=
                  _seq_table;
            context.jir_beststratcnt := pred (context.jir_beststratcnt);
            context.jir_sequenced_tables := context.jir_sequenced_tables +
                  [ _actual_table ];
            _j := context.jir_max_tables + 2; (* exit while *)
            context.jir_swap_cnt     := 0;
            (* *** cak68_join_value can offer a     *)
            (*     cartesianproduct strategy  *** *)
            join_other_table :=
                  (context.jir_i < context.jir_max_tables)
                  AND
                  (* join transition carriers cartesian product *)
                  (
                  (jtrans[ _seq_table, _actual_table ].jt_jointype > to_eq_field)
                  (* transition without access path and non-equal conditions *)
                  OR
                  (dmli.d_joins.jrc_joinarr
                  [ jtrans[ _seq_table, _actual_table ].jt_joinno ].
                  jo_recs[ 2 ].jop_tableno = cak68_join_value)
                  (* transition to constant value *)
                  );
            IF  join_other_table
            THEN
                BEGIN
&               ifdef trace
                t01sname( ak_join, 'set nonbest3' );
&               endif
                context.jir_non_best_trans := context.jir_i
                END
            ELSE
                (* *** one_to_n check *** *)
                IF  (context.jir_i + 2 <= context.jir_max_tables DIV 2)
                    (* we are in first half the sequence *)
                    AND
                    (NOT (jtrans[ _seq_table, _actual_table ].jt_jointype
                    in [ to_single_keyfield, to_key, to_unique_field ]))
                    (* NOT one join result row *)
                THEN
                    BEGIN
                    _xi := context.jir_i + 1;
                    WHILE ((_xi <= context.jir_max_tables) AND
                          (NOT join_other_table)) DO
                        BEGIN
                        join_other_table := (context.jir_best_jstrat
                              [ sequence_info.si_sequence[ _xi ].s_tableno ].
                              bjr_stratinfo.bj_jtype in
                              [ to_single_keyfield, to_key, to_unique_field ]);
                        _xi := succ (_xi);
                        END;
                    (*ENDWHILE*) 
                    END;
                (* *** *** *)
                (*ENDIF*) 
            (*ENDIF*) 
            END
        ELSE
            (* this isn't the best join transition to dst_table *)
            (* from already sequenced table                     *)
            BEGIN
            IF  jtrans[ _seq_table, _actual_table ].jt_jointype < to_eq_field
            THEN
                (* we have an access path to column from sequenced tables *)
                _join_table := true;
            (*ENDIF*) 
            context.jir_better_seq_exists := true;
&           ifdef TRACE
            a683trace_jointype (ak_join, 'better_seq  ',
                  jtrans[ _seq_table, _actual_table ].jt_jointype);
            a683trace_jointype (ak_join, 'bjr_bestjoin',
                  context.jir_best_jstrat[ _actual_table ].bjr_stratinfo.bj_jtype);
&           endif
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    _j := succ (_j);
    END;
(*ENDWHILE*) 
IF  (_j < (context.jir_max_tables + 2))
THEN
    (* we don't found best join transition from sequence to _actual_table *)
    BEGIN
    join_other_table := join_other_table OR
          (* at least 1 tables remaining *)
          (context.jir_i < context.jir_max_tables);
    IF  join_other_table
    THEN
        BEGIN
&       ifdef trace
        t01sname( ak_join, 'set nonbest4' );
&       endif
        context.jir_non_best_trans := context.jir_i;
        context.jir_stop_sequence  := false;
        END;
    (*ENDIF*) 
    IF  (_join_table)
    THEN
        (* there was any join transition to _actual_table  *)
        (* with access path from sequenced tables       *)
        BEGIN
        context.jir_beststratcnt     := pred (context.jir_beststratcnt);
        context.jir_sequenced_tables := context.jir_sequenced_tables +
              [ _actual_table ];
        END
    ELSE
        (* there wasn't any join transition to _actual_table with access path *)
        BEGIN
&       ifdef trace
        t01sname(ak_join, 'swap tables ');
&       endif
        IF  (context.jir_last_swap_pos = context.jir_i)
        THEN
            BEGIN
            (* prior table hasn't join transition from sequence *)
            (* *** restore sequence *** *)
            FOR _j := context.jir_i TO context.jir_max_tables DO
                sequence_info.si_sequence[ _j ].s_tableno := sequence_info.
                      si_sequence[ _j ].s_backup;
            (*ENDFOR*) 
            END
        ELSE
            (* prior table has join transition from sequence *)
            FOR _j := context.jir_i TO context.jir_max_tables DO
                sequence_info.si_sequence[ _j ].s_backup := sequence_info.
                      si_sequence[ _j ].s_tableno;
            (*ENDFOR*) 
        (*ENDIF*) 
        context.jir_swap_cnt      := succ (context.jir_swap_cnt);
        context.jir_last_swap_pos := context.jir_i;
        IF  (context.jir_i + context.jir_swap_cnt <= context.jir_max_tables)
        THEN
            BEGIN
            _actual_table := sequence_info.si_sequence
                  [ context.jir_i + context.jir_swap_cnt ].s_tableno;
            (* restore old sequence *)
            FOR _j := context.jir_i + context.jir_swap_cnt DOWNTO
                  context.jir_i + 1 DO
                sequence_info.si_sequence[ _j ].s_tableno :=
                      sequence_info.si_sequence[ _j - 1 ].s_tableno;
            (*ENDFOR*) 
            sequence_info.si_sequence[ context.jir_i ].
                  s_tableno := _actual_table;
            (* try swaped table *)
            context.jir_i := pred (context.jir_i);
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a681tr_tabstats (
            VAR acv           : tak_all_command_glob;
            VAR dmli          : tak_dml_info;
            VAR table_stats   : tak68_table_stats;
            VAR res_info      : tak68_result_info;
            cntfrom           : tsp00_Int2;
            debug             : boolean);
 
CONST
      c_no_column = 0;
 
VAR
      _pos  : tsp00_Int4;
      _i    : tsp00_Int2;
      _ln   : tsp00_DataLine;
      _nam  : tsp00_Sname;
      _res  : boolean;
 
BEGIN
IF  ( acv.a_intern_explain OR debug )
THEN
    FOR _i := 1 TO cntfrom DO
        BEGIN
        WITH table_stats [ _i ], res_info DO
            BEGIN
            SAPDB_PascalForcedFill (sizeof (_ln.text), @_ln.text, 1, sizeof (_ln.text), bsp_c1);
            _ln.pos := 1;
            _nam    := 'TABLE No.   ';
            SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln.text),
                  @_nam, 1, @_ln.text, _ln.pos, sizeof(_nam));
            _ln.pos := _ln.pos + sizeof(_nam);
            g17int4to_line (_i, false, 2, _ln.pos - 2, _ln.text);
&           ifdef trace
            IF  debug
            THEN
                t01line(ak_join, _ln.text)
            ELSE
&               endif
                IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
                THEN
                    a40sequence_expl_row (acv, _ln.text, c_change_to_unicode);
                (*ENDIF*) 
            (*ENDIF*) 
            IF  g01unicode
            THEN
                g20unifill (sizeof(_ln.text), @_ln.text, 1,
                      sizeof (_ln.text), csp_unicode_blank)
            ELSE
                SAPDB_PascalForcedFill (sizeof (_ln.text), @_ln.text, 1,
                      sizeof (_ln.text), bsp_c1);
            (*ENDIF*) 
            _ln.pos := 1;
            a683trans_to_line( acv, dmli, _i, c_no_column, _ln,
                  sizeof(_ln.text), _res );
&           ifdef trace
            IF  debug
            THEN
                t01line(ak_join, _ln.text)
            ELSE
&               endif
                IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
                THEN
                    a40sequence_expl_row (acv, _ln.text, NOT c_change_to_unicode);
                (*ENDIF*) 
            (*ENDIF*) 
            SAPDB_PascalForcedFill (sizeof (_ln.text), @_ln.text, 1, sizeof (_ln.text), bsp_c1);
            (* solve parameter develivery problems *)
            _pos := 2;
            g17stratenum_to_line (ri_single_strat[ _i ], _pos, _ln.text);
            _ln.pos := _pos;
            _ln.pos := _ln.pos + 2;
            IF  ri_inv_only_strat [ _i ]
            THEN
                BEGIN
                _nam  := '(Index Only)';
                SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln.text),
                      @_nam, 1, @_ln.text, _ln.pos, sizeof(_nam));
                END;
&           ifdef trace
            (*ENDIF*) 
            IF  debug
            THEN
                t01line(ak_join, _ln.text)
            ELSE
&               endif
                IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
                THEN
                    a40sequence_expl_row (acv, _ln.text, c_change_to_unicode);
                (*ENDIF*) 
            (*ENDIF*) 
            SAPDB_PascalForcedFill (sizeof (_ln.text), @_ln.text, 1, sizeof (_ln.text), bsp_c1);
            _ln.pos := 1;
            _nam    := ' strat      ';
            SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln.text),
                  @_nam, 1, @_ln.text, _ln.pos, sizeof(_nam));
            _ln.pos := _ln.pos + sizeof(_nam);
            g17longreal_to_line (ts_strat_value, 3, _ln.pos, _ln.text);
&           ifdef trace
            IF  debug
            THEN
                t01line(ak_join, _ln.text)
            ELSE
&               endif
                IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
                THEN
                    a40sequence_expl_row (acv, _ln.text, c_change_to_unicode);
                (*ENDIF*) 
            (*ENDIF*) 
            SAPDB_PascalForcedFill (sizeof (_ln.text), @_ln.text, 1, sizeof (_ln.text), bsp_c1);
            _ln.pos := 1;
            _nam    := ' pages searc';
            SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln.text),
                  @_nam, 1, @_ln.text, _ln.pos, sizeof(_nam));
            _ln.pos := _ln.pos + sizeof(_nam);
            g17longreal_to_line (ts_pages_searched, 3, _ln.pos, _ln.text);
&           ifdef trace
            IF  debug
            THEN
                t01line(ak_join, _ln.text)
            ELSE
&               endif
                IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
                THEN
                    a40sequence_expl_row (acv, _ln.text, c_change_to_unicode);
                (*ENDIF*) 
            (*ENDIF*) 
            SAPDB_PascalForcedFill (sizeof (_ln.text), @_ln.text, 1, sizeof (_ln.text), bsp_c1);
            _ln.pos := 1;
            _nam    := ' all_pages  ';
            SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln.text),
                  @_nam, 1, @_ln.text, _ln.pos, sizeof(_nam));
            _ln.pos := _ln.pos + sizeof(_nam);
            g17int4to_line (ts_all_pages, false, 7, _ln.pos, _ln.text);
&           ifdef trace
            IF  debug
            THEN
                t01line(ak_join, _ln.text)
            ELSE
&               endif
                IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
                THEN
                    a40sequence_expl_row (acv, _ln.text, c_change_to_unicode);
                (*ENDIF*) 
            (*ENDIF*) 
            SAPDB_PascalForcedFill (sizeof (_ln.text), @_ln.text, 1, sizeof (_ln.text), bsp_c1);
            _ln.pos := 1;
            _nam    := ' cost       ';
            SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln.text),
                  @_nam, 1, @_ln.text, _ln.pos, sizeof(_nam));
            _ln.pos := _ln.pos + sizeof(_nam);
            g17int4to_line (ts_cost, false, 7, _ln.pos, _ln.text);
&           ifdef trace
            IF  debug
            THEN
                t01line(ak_join, _ln.text)
            ELSE
&               endif
                IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
                THEN
                    a40sequence_expl_row (acv, _ln.text, c_change_to_unicode);
                (*ENDIF*) 
            (*ENDIF*) 
            SAPDB_PascalForcedFill (sizeof (_ln.text), @_ln.text, 1, sizeof (_ln.text), bsp_c1);
            _ln.pos := 1;
            _nam    := ' recs_per_p ';
            SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln.text),
                  @_nam, 1, @_ln.text, _ln.pos, sizeof(_nam));
            _ln.pos := _ln.pos + sizeof(_nam);
            g17int4to_line (ts_recs_per_page, false, 7, _ln.pos, _ln.text);
&           ifdef trace
            IF  debug
            THEN
                t01line(ak_join, _ln.text)
            ELSE
&               endif
                IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
                THEN
                    a40sequence_expl_row (acv, _ln.text, c_change_to_unicode);
                (*ENDIF*) 
            (*ENDIF*) 
            END;
        (*ENDWITH*) 
        END;
    (*ENDFOR*) 
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a681tr_multabs (
            VAR acv      : tak_all_command_glob;
            VAR mul_tabs : tak68_mult_tabs;
            cntfrom      : tsp00_Int2);
 
VAR
      _i              : tsp00_Int2;
      _j              : tsp00_Int2;
      _pos            : tsp00_Int2;
      _oldpos         : tsp00_Int2;
      _ln             : tsp00_Line;
      _nam            : tsp00_Sname;
      _dummy          : tsp00_Longreal;
 
BEGIN
WITH mul_tabs DO
    BEGIN
    SAPDB_PascalForcedFill (sizeof (_ln), @_ln, 1, sizeof (_ln), bsp_c1);
    _pos    := 1;
    _nam    := 'mt_cnt :    ';
    SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln), @_nam, 1, @_ln, _pos, sizeof(_nam));
    _pos    := _pos + sizeof (_nam);
    g17int4to_line (mt_cnt, false, 5, _pos, _ln);
    _pos    := _pos + 7;
    IF  g01vtrace.vtrStrategy_gg00
    THEN
        b120InsertTrace (acv.a_mblock.mb_trns^,
              ak_strat, ak_join_strat, _pos, @_ln);
    (*ENDIF*) 
    IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
    THEN
        a40sequence_expl_row (acv, _ln, c_change_to_unicode);
    (*ENDIF*) 
    IF  mt_cnt > 0
    THEN
        BEGIN
        SAPDB_PascalForcedFill (sizeof (_ln), @_ln, 1, sizeof (_ln), bsp_c1);
        _pos     := 1;
        _ln [ _pos ]     := 'T';
        _ln [ _pos + 1 ] := 'O';
        _pos    := _pos + 4;
        _nam    := 'via         ';
        SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln), @_nam, 1, @_ln, _pos, sizeof(_nam));
        _pos    := _pos + sizeof (_nam) + 2;
        _nam    := 'multiplier  ';
        SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln), @_nam, 1, @_ln, _pos, sizeof(_nam));
        _pos    := _pos + sizeof (_nam) + 1;
        _ln [ _pos ]     := 'T';
        _pos            := _pos + 3;
        _ln [ _pos ]     := 'F';
        _pos            := _pos + 3;
        _ln [ _pos ]     := 'J';
        _pos            := _pos + 3;
        _ln [ _pos ]     := 'I';
        _pos            := _pos + 3;
        _nam    := 'Used tables ';
        SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln), @_nam, 1, @_ln, _pos, sizeof(_nam));
        _pos    := _pos + sizeof(_nam);
        IF  g01vtrace.vtrStrategy_gg00
        THEN
            b120InsertTrace (acv.a_mblock.mb_trns^,
                  ak_strat, ak_join_strat, _pos, @_ln);
        (*ENDIF*) 
        IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
        THEN
            a40sequence_expl_row (acv, _ln, c_change_to_unicode);
        (*ENDIF*) 
        FOR _j := 1 TO mt_cnt DO
            WITH mt_arr[ _j ] DO
                BEGIN
                SAPDB_PascalForcedFill (sizeof (_ln), @_ln, 1, sizeof (_ln), bsp_c1);
                _pos     := 1;
                g17int4to_line (mtr_dst_table, false, 2, _pos, _ln);
                _pos    := _pos + 4;
                CASE mtr_jointype OF
                    to_single_keyfield :
                        _nam := 'SINGLE KEY  ';
                    to_unique_field    :
                        _nam := 'UNIQUE INDE ';
                    to_keypart  :
                        _nam := 'KEY PART    ';
                    to_key      :
                        _nam := 'KEY         ';
                    to_first_keyfield  :
                        _nam := 'FIRST KEY   ';
                    to_invfield :
                        _nam := 'INDEX       ';
                    to_all_invfields :
                        _nam := 'INDEXCOLUMNS';
                    to_invpart :
                        _nam := 'INDEX PART  ';
                    to_eq_field :
                        _nam := 'EQUAL COLUMN';
                    to_lt_gt_field :
                        _nam := '>, <, ......';
                    to_ne_field,
                    to_cartesian_prod :
                        _nam := '<>, none    ';
                    to_illegal :
                        _nam := '  ILLEGAL   ';
                    OTHERWISE
                        _nam := 'unknown cond';
                    END;
                (*ENDCASE*) 
                SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln),
                      @_nam, 1, @_ln, _pos, sizeof(_nam));
                _pos    := _pos + sizeof (_nam) + 2;
                _dummy := mt_arr[ _j ].mtr_multipl;
                g17longreal_to_line (_dummy, 3, _pos, _ln);
                _pos    := _pos + 11;
                g17int4to_line (mtr_tablecnt, false, 3, _pos, _ln);
                _pos    := _pos + 3;
                g17int4to_line (mtr_fieldcnt, false, 3, _pos, _ln);
                _pos    := _pos + 3;
                g17int4to_line (mtr_joinno, false, 3, _pos, _ln);
                _pos    := _pos + 3;
                g17int4to_line (mtr_indexno, false, 3, _pos, _ln);
                _pos    := _pos + 5;
                _ln [ _pos ] := '[';
                _pos    := _pos + 1;
                _oldpos := _pos;
                FOR _i := 1 TO cntfrom DO
                    BEGIN
                    IF  _i in mtr_tab_seq
                    THEN
                        BEGIN
                        g17int4to_line (_i, false, 3, _pos, _ln);
                        _pos := _pos + 3;
                        END;
                    (*ENDIF*) 
                    IF  (_pos >= 80) AND (_i < cntfrom)
                    THEN
                        BEGIN
                        IF  g01vtrace.vtrStrategy_gg00
                        THEN
                            b120InsertTrace (acv.a_mblock.mb_trns^,
                                  ak_strat, ak_join_strat, _pos, @_ln);
                        (*ENDIF*) 
                        IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
                        THEN
                            a40sequence_expl_row (acv, _ln, c_change_to_unicode);
                        (*ENDIF*) 
                        SAPDB_PascalForcedFill (sizeof (_ln), @_ln, 1, sizeof (_ln), bsp_c1);
                        _pos := _oldpos;
                        END
                    (*ENDIF*) 
                    END;
                (*ENDFOR*) 
                _pos := succ (_pos);
                _ln [ _pos ] := ']';
                IF  g01vtrace.vtrStrategy_gg00
                THEN
                    b120InsertTrace (acv.a_mblock.mb_trns^,
                          ak_strat, ak_join_strat, _pos, @_ln);
                (*ENDIF*) 
                IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
                THEN
                    a40sequence_expl_row (acv, _ln, c_change_to_unicode)
                (*ENDIF*) 
                END;
            (*ENDWITH*) 
        (*ENDFOR*) 
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681tr_best_joinstrat (
            VAR acv           : tak_all_command_glob;
            VAR dmli          : tak_dml_info;
            VAR bjra          : tak681_best_jstrat_rec_arr;
            VAR sequence_info : tak68_sequence_info;
            debug             : boolean);
 
VAR
      _pos            : tsp00_Int2;
      _to_tab         : tsp00_Int2;
      _to_tab_index   : tsp00_Int2;
      _ln             : tsp00_Line;
      _nam            : tsp00_Sname;
      _dummy          : tsp00_Longreal;
 
BEGIN
SAPDB_PascalForcedFill (sizeof (_ln), @_ln, 1, sizeof (_ln), bsp_c1);
_pos     := 1;
_ln [ _pos ]     := 'T';
_ln [ _pos + 1 ] := 'O';
_pos    := _pos + 4;
_nam    := 'via         ';
SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln), @_nam, 1, @_ln, _pos, sizeof(_nam));
_pos    := _pos + sizeof (_nam) + 2;
_nam    := 'multiplier  ';
SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln), @_nam, 1, @_ln, _pos, sizeof(_nam));
_pos    := _pos + sizeof (_nam) + 2;
_nam    := 'costs       ';
SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln), @_nam, 1, @_ln, _pos, sizeof(_nam));
_pos    := _pos + sizeof (_nam) + 2;
_ln [ _pos ]     := 'j';
_ln [ _pos + 1 ] := 'i';
_pos            := _pos + 4;
_ln [ _pos ]     := 'm';
_pos            := _pos + 1;
_ln [ _pos ]     := 'i';
&ifdef trace
IF  debug
THEN
    t01line(ak_join, _ln)
ELSE
    BEGIN
&   endif
    IF  g01vtrace.vtrStrategy_gg00
    THEN
        b120InsertTrace (acv.a_mblock.mb_trns^,
              ak_strat, ak_join_strat, _pos, @_ln);
    (*ENDIF*) 
    IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
    THEN
        a40sequence_expl_row (acv, _ln, c_change_to_unicode);
&   ifdef trace
    (*ENDIF*) 
    END;
(*ENDIF*) 
&endif
FOR _to_tab := 1 TO dmli.d_cntfromtab DO
    BEGIN
    _to_tab_index := 1;
    WHILE (sequence_info.si_sequence[ _to_tab_index ].s_tableno <> _to_tab) DO
        _to_tab_index := succ (_to_tab_index);
    (*ENDWHILE*) 
    SAPDB_PascalForcedFill (sizeof (_ln), @_ln, 1, sizeof (_ln), bsp_c1);
    _pos     := 1;
    g17int4to_line (_to_tab, false, 2, _pos, _ln);
    _pos    := _pos + 4;
    CASE bjra[ _to_tab_index ].bjr_stratinfo.bj_jtype OF
        to_single_keyfield :
            _nam := 'SINGLE KEY  ';
        to_unique_field    :
            _nam := 'UNIQUE INDE ';
        to_keypart  :
            _nam := 'KEY PART    ';
        to_key      :
            _nam := 'KEY         ';
        to_first_keyfield  :
            _nam := 'FIRST KEY   ';
        to_invfield :
            _nam := 'INDEX       ';
        to_all_invfields :
            _nam := 'INDEX-FIELDS';
        to_invpart :
            _nam := 'INDEX PART  ';
        to_eq_field :
            _nam := 'EQUAL FIELD ';
        to_lt_gt_field :
            _nam := '>, <, ......';
        to_ne_field,
        to_cartesian_prod :
            _nam := '<>, none    ';
        to_illegal :
            _nam := '  ILLEGAL   ';
        OTHERWISE
            _nam := 'unknown cond';
        END;
    (*ENDCASE*) 
    SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln), @_nam, 1, @_ln, _pos, sizeof(_nam));
    _pos    := _pos + sizeof (_nam) + 2;
    _dummy  := bjra[ _to_tab_index ].bjr_stratinfo.bj_multiplier;
    g17longreal_to_line (_dummy, 3, _pos, _ln);
    _pos    := _pos + sizeof (_nam) + 2;
    g17longreal_to_line (bjra[ _to_tab_index ].bjr_costs, 6, _pos, _ln);
    _pos    := _pos + sizeof (_nam) + 2;
    g17int4to_line (bjra[ _to_tab_index ].bjr_stratinfo.bj_srctab, false, 2, _pos, _ln);
    _pos    := _pos + 4;
    g17int4to_line (bjra[ _to_tab_index ].bjr_mtab_ind, false, 2, _pos, _ln);
    _pos    := _pos + 4;
    IF  bjra[ _to_tab_index ].bjr_is_mt_join
    THEN
        BEGIN
        _nam    := 'multiplejoin';
        SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln), @_nam, 1, @_ln, _pos, sizeof(_nam));
        _pos    := _pos + sizeof (_nam);
        END;
&   ifdef trace
    (*ENDIF*) 
    IF  debug
    THEN
        t01line(ak_join, _ln)
    ELSE
        BEGIN
&       endif
        IF  g01vtrace.vtrStrategy_gg00
        THEN
            b120InsertTrace (acv.a_mblock.mb_trns^,
                  ak_strat, ak_join_strat, _pos, @_ln);
        (*ENDIF*) 
        IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
        THEN
            a40sequence_expl_row (acv, _ln, c_change_to_unicode);
&       ifdef trace
        (*ENDIF*) 
        END;
    (*ENDIF*) 
&   endif
    END;
(*ENDFOR*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681tr_report_succ (
            VAR acv        : tak_all_command_glob;
            r              : tsp00_Longreal;
            VAR succession : tak68_succession;
            start          : tsp00_Int2;
            stop           : tsp00_Int2;
            is_lower       : boolean);
 
VAR
      _i              : tsp00_Int2;
      _pos            : tsp00_Int2;
      _oldpos         : tsp00_Int2;
      _ln             : tsp00_Line;
      _nam            : tsp00_Sname;
 
BEGIN
SAPDB_PascalForcedFill (sizeof (_ln), @_ln, 1, sizeof (_ln), bsp_c1);
_pos    := 1;
IF  is_lower
THEN
    _nam := '< COSTVALUE '
ELSE
    _nam := '> COSTVALUE ';
(*ENDIF*) 
SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln), @_nam, 1, @_ln, _pos, sizeof(_nam));
_pos      := _pos + sizeof (_nam);
_ln [_pos] := ':';
_pos      := _pos + 1;
g17longreal_to_line (r, 6, _pos, _ln);
_pos       := _pos + 14;
_ln[ _pos ] := '[';
_pos       := _pos + 1;
_oldpos    := _pos;
(* succession *)
FOR _i := start TO stop DO
    BEGIN
    g17int4to_line (succession[ _i ].s_tableno, false, 3, _pos, _ln);
    _pos := _pos + 3;
    IF  ((_i+1-start) MOD 16 = 0) AND (_i < stop)
    THEN
        BEGIN
        IF  g01vtrace.vtrStrategy_gg00
        THEN
            b120InsertTrace (acv.a_mblock.mb_trns^,
                  ak_strat, ak_join_strat, _pos, @_ln);
        (*ENDIF*) 
        IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
        THEN
            a40sequence_expl_row (acv, _ln, c_change_to_unicode);
        (*ENDIF*) 
        SAPDB_PascalForcedFill (sizeof (_ln), @_ln, 1, sizeof (_ln), bsp_c1);
        _pos := _oldpos
        END
    (*ENDIF*) 
    END;
(*ENDFOR*) 
_pos := succ (_pos);
_ln[ _pos ] := ']';
IF  g01vtrace.vtrStrategy_gg00
THEN
    b120InsertTrace (acv.a_mblock.mb_trns^,
          ak_strat, ak_join_strat, _pos, @_ln);
(*ENDIF*) 
IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
THEN
    a40sequence_expl_row (acv, _ln, c_change_to_unicode)
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a681tr_joinvals (
            VAR acv      : tak_all_command_glob;
            VAR jtrans   : tak68_join_transitions;
            starttab     : tsp00_Int2;
            stoptab      : tsp00_Int2;
            table_cnt    : tsp00_Int2);
 
VAR
      _i              : tsp00_Int2;
      _j              : tsp00_Int2;
      _pos            : tsp00_Int2;
      _ln             : tsp00_Line;
      _nam            : tsp00_Sname;
 
BEGIN
SAPDB_PascalForcedFill (sizeof (_ln), @_ln, 1, sizeof (_ln), bsp_c1);
_pos := 1;
_nam := ' | FROM     ';
SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln), @_nam, 1, @_ln, _pos, sizeof(_nam));
_pos := _pos + sizeof (_nam) - 9;
FOR _i (* *** fromrec *** *) := starttab TO stoptab DO
    g17int4to_line (_i, false, 3, (_i-starttab+1) * 4 + _pos, _ln);
(*ENDFOR*) 
_pos := _pos + (stoptab-starttab+1 + 1) * 4;
IF  g01vtrace.vtrStrategy_gg00
THEN
    b120InsertTrace (acv.a_mblock.mb_trns^,
          ak_strat, ak_join_strat, _pos, @_ln);
(*ENDIF*) 
IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
THEN
    a40sequence_expl_row (acv, _ln, c_change_to_unicode);
(*ENDIF*) 
SAPDB_PascalForcedFill (sizeof (_ln), @_ln, 1, sizeof (_ln), bsp_c1);
_pos := 1;
_nam := 'TO          ';
SAPDB_PascalForcedMove (sizeof(_nam), sizeof(_ln), @_nam, 1, @_ln, _pos, sizeof(_nam));
_pos := _pos + sizeof(_nam);
IF  g01vtrace.vtrStrategy_gg00
THEN
    b120InsertTrace (acv.a_mblock.mb_trns^,
          ak_strat, ak_join_strat, _pos, @_ln);
(*ENDIF*) 
IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
THEN
    a40sequence_expl_row (acv, _ln, c_change_to_unicode);
(*ENDIF*) 
FOR _j (* *** torec *** *) := 1 TO table_cnt DO
    BEGIN
    SAPDB_PascalForcedFill (sizeof (_ln), @_ln, 1, sizeof (_ln), bsp_c1);
    _pos := 1;
    g17int4to_line (_j, false, 2, _pos, _ln);
    _pos := _pos + sizeof (_nam) - 4;
    FOR _i := starttab TO stoptab DO
        BEGIN
        CASE jtrans[ _i, _j ].jt_jointype OF
            to_single_keyfield :
                BEGIN
                _ln [ _pos ]     := 'S';
                _ln [ _pos + 1 ] := 'K';
                END;
            to_unique_field    :
                BEGIN
                _ln [ _pos ]     := 'U';
                _ln [ _pos + 1 ] := 'I';
                END;
            to_keypart  :
                BEGIN
                _ln [ _pos ]     := 'K';
                _ln [ _pos + 1 ] := 'P';
                END;
            to_key      :
                BEGIN
                _ln [ _pos ]     := 'M';
                _ln [ _pos + 1 ] := 'K';
                END;
            to_first_keyfield  :
                BEGIN
                _ln [ _pos ]     := 'F';
                _ln [ _pos + 1 ] := 'K';
                END;
            to_invfield :
                BEGIN
                _ln [ _pos ]     := 'I';
                END;
            to_all_invfields :
                BEGIN
                _ln [ _pos ]     := 'M';
                _ln [ _pos + 1 ] := 'I';
                END;
            to_invpart :
                BEGIN
                _ln [ _pos ]     := 'I';
                _ln [ _pos + 1 ] := 'P';
                END;
            to_mt_join :
                BEGIN
                _ln [ _pos ]     := 'M';
                _ln [ _pos + 1 ] := 'J';
                END;
            to_eq_field :
                BEGIN
                _ln [ _pos ]     := '=';
                END;
            to_lt_gt_field :
                BEGIN
                _ln [ _pos ]     := '>';
                _ln [ _pos + 1 ] := '<';
                END;
            to_ne_field,
            to_cartesian_prod :
                BEGIN
                _ln [ _pos ]     := '?';
                _ln [ _pos + 1 ] := '?';
                END;
            to_illegal :
                BEGIN
                _ln [ _pos ]     := '-';
                _ln [ _pos + 1 ] := '-';
                END;
            OTHERWISE
                BEGIN
                _ln [ _pos ]     := '.';
                _ln [ _pos + 1 ] := '.';
                END;
            END;
        (*ENDCASE*) 
        _pos := _pos + 4;
        END;
    (*ENDFOR*) 
    IF  g01vtrace.vtrStrategy_gg00
    THEN
        b120InsertTrace (acv.a_mblock.mb_trns^,
              ak_strat, ak_join_strat, _pos, @_ln);
    (*ENDIF*) 
    IF  ( acv.a_intern_explain ) AND ( acv.a_explain_kind = ex_sequence )
    THEN
        a40sequence_expl_row (acv, _ln, c_change_to_unicode)
    (*ENDIF*) 
    END;
(*ENDFOR*) 
END;
 
(*------------------------------*) 
 
FUNCTION
      ak681jtable_cost (
            VAR acv          : tak_all_command_glob;
            VAR table_stats  : tak68_table_stats; (* IN *)
            curr_tab         : tsp00_Int2;
            best_jtype       : tak68_one_jointype;
            best_jmultipl    : tsp00_Int4;
            VAR res_info     : tak68_result_info (*IN/OUT*)) : tsp00_Longreal;
 
CONST
      _c_not_distinct = false;
 
VAR
      _counted_multiplier    : tsp00_Longreal;
      _reverse_multiplier    : tsp00_Longreal;
      _costs                 : tsp00_Longreal;
      _newpages              : tsp00_Longreal;
      _local_jtrans          : tak68_join_transition;
      _local_table_stat      : tak68_one_table_stat;
 
BEGIN
_local_jtrans.jt_joinno       := 0;
_local_jtrans.jt_indexno      := 0;
_local_jtrans.jt_jointype     := best_jtype;
_local_jtrans.jt_multipl      := best_jmultipl;
_local_table_stat             := table_stats [ curr_tab ];
_costs                        := 100;
_newpages                     := 10;
res_info.ri_old_recs_per_page := 50;
_counted_multiplier           := best_jmultipl;
_reverse_multiplier           := csp_maxint4;
a680next_join_eval( acv, _local_jtrans, _local_table_stat,
      _counted_multiplier, _reverse_multiplier,
      _costs (* inout *), _newpages (* inout *),
      res_info.ri_old_recs_per_page (* in *),
      res_info.ri_recs_per_page (* in *),
      _c_not_distinct );
_costs := _costs * _counted_multiplier * _local_table_stat.ts_strat_value;
IF  _costs = 0
THEN
    _costs := 1;
&ifdef TRACE
(*ENDIF*) 
t01real (ak_join,'costs       ', _costs, 3);
&endif
ak681jtable_cost := _costs;
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681permut_sequence(
            VAR acv             : tak_all_command_glob;
            VAR dmli            : tak_dml_info;
            config              : tak_sysbufferaddress;
            VAR table_stats     : tak68_table_stats;
            VAR jtrans          : tak68_join_transitions;
            VAR sequence_info   : tak68_sequence_info;
            VAR jinfos          : tak68_joininfos;
            VAR res_info        : tak68_result_info;
            VAR mult_tabs       : tak68_mult_tabs;
            VAR lastsuccession  : tak68_lastsuccession;
            VAR context         : tak681_jseq_info_record;
            VAR reschedule_cnt  : tsp00_Int2);
 
VAR
      _i  : tsp00_Int2;
 
BEGIN
reschedule_cnt := succ(reschedule_cnt);
IF  acv.a_transinf.tri_trans.trRteCommPtr_gg00^.to_cancel
THEN
    a07_b_put_error (acv, e_cancelled, 0);
(*ENDIF*) 
IF  (reschedule_cnt = MAX_RESCHEDULE_CNT_AK68)
THEN
    BEGIN
&   ifdef trace
    t01sname(ak_join, 'reschedule !');
&   endif
    (* give CPU time to other tasks; reschedule *)
    reschedule_cnt := 0;
    vsleep(acv.a_transinf.tri_trans.trTaskId_gg00, 0);
    END;
(*ENDIF*) 
IF  (acv.a_returncode = 0)
THEN
    BEGIN
    FOR _i := 1 TO context.jir_max_tables DO
        BEGIN
        IF  (acv.a_returncode = 0) AND
            NOT (_i in context.jir_sequenced_tables)
        THEN
            BEGIN
            sequence_info.si_sequence[ context.jir_i ].s_tableno := _i;
            IF   ( context.jir_i < context.jir_max_tables )
            THEN
                BEGIN
                a680standard_cost( acv, dmli, config, table_stats, jtrans,
                      jinfos, res_info, mult_tabs, lastsuccession,
                      context.jir_lowest_cost, sequence_info, context.jir_i,
                      NOT c_final_call );
&               ifdef trace
                t01real(ak_join, 'comp costs  ', sequence_info.si_sum, 6);
&               endif
                IF  ( sequence_info.si_sum < context.jir_lowest_cost )
                THEN
                    BEGIN
&                   ifdef trace
                    t01int4(ak_join, 'better costs', context.jir_i);
                    t01real(ak_join, 'best costs  ', context.jir_lowest_cost, 6);
&                   endif
                    context.jir_sequenced_tables :=
                          context.jir_sequenced_tables + [ _i ];
                    context.jir_i := succ(context.jir_i);
                    ak681permut_sequence( acv, dmli, config, table_stats, jtrans,
                          sequence_info, jinfos, res_info, mult_tabs,
                          lastsuccession, context, reschedule_cnt );
                    context.jir_i := pred(context.jir_i);
                    context.jir_sequenced_tables :=
                          context.jir_sequenced_tables - [ _i ];
                    END;
                (*ENDIF*) 
                END
            ELSE
                BEGIN
                (* there is a complete sequence *)
                ak681sequence_eval( acv, dmli, config, table_stats, jtrans,
                      sequence_info, jinfos, res_info, mult_tabs,
                      lastsuccession, context );
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  acv.a_transinf.tri_trans.trRteCommPtr_gg00^.to_cancel
        THEN
            a07_b_put_error (acv, e_cancelled, 0);
        (*ENDIF*) 
        END;
    (*ENDFOR*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681sequence_eval(
            VAR acv             : tak_all_command_glob;
            VAR dmli            : tak_dml_info;
            config              : tak_sysbufferaddress;
            VAR table_stats     : tak68_table_stats;
            VAR jtrans          : tak68_join_transitions;
            VAR sequence_info   : tak68_sequence_info;
            VAR jinfos          : tak68_joininfos;
            VAR res_info        : tak68_result_info;
            VAR mult_tabs       : tak68_mult_tabs;
            VAR lastsuccession  : tak68_lastsuccession;
            VAR context         : tak681_jseq_info_record);
 
VAR
      _xi : tsp00_Int2;
 
BEGIN
&ifdef TRACE
t01sname (ak_join, '-<STANDARD>-');
a683tr_newsucc (ak_join, sequence_info.si_sequence, 1, context.jir_max_tables, true);
&endif
_xi := 0;
WHILE (_xi <= context.jir_max_tables - 1) AND
      (sequence_info.si_sequence[ _xi + 1 ].s_tableno =
      lastsuccession.ls_sequence[ _xi + 1 ].s_tableno) DO
    _xi := succ (_xi);
(*ENDWHILE*) 
IF  ( _xi < context.jir_max_tables )
THEN
    (* computed sequence is a new sequence or  *)
    (* last sequence was worse than one before *)
    BEGIN
    a680standard_cost( acv, dmli, config,
          table_stats, jtrans, jinfos, res_info, mult_tabs,
          lastsuccession, context.jir_lowest_cost, sequence_info,
          dmli.d_cntfromtab, NOT c_final_call );
    IF  ( acv.a_intern_explain OR g01vtrace.vtrStrategy_gg00 )
    THEN
        ak681tr_report_succ( acv, sequence_info.si_sum,
              sequence_info.si_sequence, 1, context.jir_max_tables,
              context.jir_lowest_cost > sequence_info.si_sum );
    (*ENDIF*) 
    context.jir_comp_sequences := succ( context.jir_comp_sequences );
&   ifdef TRACE
    t01int4 (ak_join, 'check_cnt   ', context.jir_comp_sequences);
    t01int4 (ak_join, '============', context.jir_comp_sequences);
&   endif
    END;
(*ENDIF*) 
IF  sequence_info.si_sum < context.jir_lowest_cost
THEN
    BEGIN
    context.jir_lowest_cost       := sequence_info.si_sum;
    context.jir_lowest_succession := sequence_info.si_sequence;
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
FUNCTION
      ak681is_smaller_inv(
            VAR acv   : tak_all_command_glob;
            VAR tabid : tgg00_Surrogate;
            invno1    : tsp00_Int2;
            invno2    : tsp00_Int2 ) : boolean;
 
VAR
      _index_scan_rec1 : tak_index_scan_record;
      _index_scan_rec2 : tak_index_scan_record;
      _return          : boolean;
 
BEGIN
(* returns true if index with no. invno1 is smaller as index with no. invno2 *)
a24fnd_indexno( acv, tabid, invno1, _index_scan_rec1 );
a24fnd_indexno( acv, tabid, invno2, _index_scan_rec2 );
IF  (( _index_scan_rec1.isr_buf = NIL ) OR
    ( _index_scan_rec2.isr_buf = NIL ))
THEN
    _return := false
ELSE
    BEGIN
    _return := ( _index_scan_rec1.isr_buf^.smindex.
          indexdef[ _index_scan_rec1.isr_index ].ipages <
          _index_scan_rec2.isr_buf^.smindex.
          indexdef[ _index_scan_rec2.isr_index ].ipages );
    END;
(*ENDIF*) 
ak681is_smaller_inv := _return;
END;
 
&ifdef TRACE
(*------------------------------*) 
 
PROCEDURE
      ak681tr_context(
            VAR dmli          : tak_dml_info;
            VAR sequence_info : tak68_sequence_info;
            VAR context       : tak681_jseq_info_record );
 
BEGIN
t01int4(ak_join, 'jir_max_tabl', context.jir_max_tables);
t01c30 (ak_join, 'succ 1 ... context.jir_i - 1  ');
a683tr_newsucc (ak_join, sequence_info.si_sequence, 1, context.jir_i - 1, true);
t01c30 (ak_join, 'newsucc context.jir_i ... last');
a683tr_newsucc (ak_join, sequence_info.si_sequence, context.jir_i,
      context.jir_max_tables, true);
t01bool (ak_join, 'stop sequenc', context.jir_stop_sequence);
t01bool (ak_join, 'better seq  ', context.jir_better_seq_exists);
t01p2int4(ak_join, 'strat cnt   ', context.jir_beststratcnt
      , 'comp sequenc', context.jir_comp_sequences);
t01int4(ak_join, 'swap count  ', context.jir_swap_cnt);
t01p2int4(ak_join, 'non best tra', context.jir_non_best_trans
      , 'i           ', context.jir_i);
t01int4(ak_join, 'last_swap_po', context.jir_last_swap_pos);
t01real(ak_join, 'lowest_cost ', context.jir_lowest_cost, 6);
a683tr_tableset(ak_join, 'jir_seq_set ', dmli, context.jir_sequenced_tables);
END;
 
&endif
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
.PA 
