.nf
 
 .nf
 
    ========== licence begin  GPL
    Copyright (c) 1999-2005 SAP AG
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end
.fo
 
 
.fo
*****************************************************
Copyright (c) 1999-2005 SAP AG
SAP Database Technology
 
Release :      Date : 2000-11-22
*****************************************************
modname : 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;
                    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 jinfos    : tak68_joininfos;
                    VAR mul_tabs  : tak68_mult_tabs;
                    start_idx     : tsp00_Int2;
                    dst_side      : 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 jinfos   : tak68_joininfos;
                    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;
                    jtrans              : tak68_join_transitions;
                    succession          : tak68_succession_ptr;
                    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 jinfos       : tak68_joininfos;
                    VAR mul_tabs     : tak68_mult_tabs;
                    start_idx        : tsp00_Int2;
                    dst_side         : 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
              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;
                    cntfrom           : tsp00_Int2;
                    debug             : boolean);
 
        PROCEDURE
              a681tr_joinvals (
                    VAR acv      : tak_all_command_glob;
                    VAR dmli     : tak_dml_info;
                    jtrans       : tak68_join_transitions;
                    starttab     : tsp00_Int2;
                    stoptab      : tsp00_Int2;
                    table_cnt    : tsp00_Int2);
 
.CM *-END-* define --------------------------------------
***********************************************************
 
Use     :
 
        FROM
              CatalogWrapper : VAK103;
 
        FUNCTION
              a103GetColumn (
                    VAR BaseRec : tak_baserecord;
                    ColIndex    : integer
                    ) : tak00_colinfo_ptr;
 
      ------------------------------ 
 
        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;
                    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;
                    use_operator_join      : 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
              a683_one_join_entry(
                    debug    : tgg00_Debug;
                    VAR joins: tak_joinrec;
                    index    : integer;
                    trace_all: boolean);
 
        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 joins : tak_joinrec);
 
        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;
                    succession     : tak68_succession_ptr;
                    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
              Join2_Select_help_routines : VAK685;
 
        PROCEDURE
              a685expand_eq_rec(
                    VAR acv    : tak_all_command_glob;
                    VAR eq_rec : tak68_eq_record );
 
        PROCEDURE
              a685expand_multab_rec(
                    VAR acv    : tak_all_command_glob;
                    VAR multab : tak68_mult_tabs );
 
        FUNCTION
              a685get_join_trans(
                    VAR dmli    : tak_dml_info;
                    jtrans      : tak68_join_transitions;
                    dim1        : tsp00_Int2;
                    dim2        : tsp00_Int2 ) : tak68_join_transition_ptr;
 
      ------------------------------ 
 
        FROM
              Hint_Handling : VAK80;
 
        FUNCTION
              a80is_predefined_join_order(
                    VAR acv : tak_all_command_glob) : 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;
 
        FUNCTION
              g01outer_join_ordered : boolean;
&       ifdef trace
 
        PROCEDURE
              g01abort (
                    msg_no     : tsp00_Int4;
                    msg_label  : tsp00_C8;
                    msg_text   : tsp00_C24;
                    bad_value  : tsp00_Int4);
&       endif
 
      ------------------------------ 
 
        FROM
              Select_Help_Procedures : VGG04;
 
        PROCEDURE
              g04index_tree_build_surr (
                    VAR table_sur  : tgg00_Surrogate;
                    VAR index_tree : tgg00_FileId;
                    index_no       : tsp00_Int2);
 
        PROCEDURE
              g04index_tree_build (
                    VAR file_id    : tgg00_FileId (*ptocConst*);
                    VAR index_tree : tgg00_FileId;
                    index_no       : 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
 
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        PROCEDURE
              t01addr (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    bufaddr  : tsp00_Addr);
 
        PROCEDURE
              t01addr_1 (
                    debug      : tgg00_Debug;
                    nam        : tsp00_Sname;
                    bufaddr    : tak681_best_jstrat_arr_ptr);
 
        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
              Integer_SET : VGG12;
 
        FUNCTION
              gg12InitBitArray(
                    VAR TransContext : tgg00_TransContext;
                    bits             : tsp00_Int4) : tsp00_Addr;
 
        FUNCTION
              gg12GetBit (
                    IntegerSet  : tsp00_Addr;
                    number      : tsp00_Int4) : boolean;
 
        PROCEDURE
              gg12SetBit (
                    IntegerSet  : tsp00_Addr;
                    number      : tsp00_Int4;
                    value       : boolean);
 
        PROCEDURE
              gg12FinalizeBitArray(
                    VAR TransContext : tgg00_TransContext;
                    VAR IntegerSet   : tsp00_Addr);
 
      ------------------------------ 
 
        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
              GG_allocator_interface : VGG941;
 
        FUNCTION
              gg941Allocate(
                    VAR TransContext : tgg00_TransContext;
                    wantedBytes      : integer) : tsp00_Addr;
 
        PROCEDURE
              gg941Deallocate(
                    VAR TransContext : tgg00_TransContext;
                    VAR p            : tsp00_Addr);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_1  : VBD01;
 
        PROCEDURE
              b01filestate (
                    VAR t       : tgg00_TransContext;
                    VAR file_id : tgg00_FileId);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_3 : VBD03;
 
        PROCEDURE
              bd03GetInvPageCount (
                    VAR t             : tgg00_TransContext;
                    VAR indexSurr     : tgg00_Surrogate(*ptocConst*);
                    VAR leafPageCount : tsp00_Int4);
 
      ------------------------------ 
 
        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
 
        PROCEDURE
              t01addr;
 
              tsp00_Addr tsp00_BuffAddr
 
        PROCEDURE
              t01addr_1;
 
              tak681_best_jstrat_arr_ptr tsp00_BuffAddr
 
.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_debug_output        = true;
      c_change_to_unicode   = true;
      c_find_start_table    = true;
 
TYPE
 
      tak681_unknown_table_rec = RECORD
            ut_tableno     : tsp00_Int2;
            ut_joinno      : tak68_joinarr_index;
      END;
 
      tak681_unknown_table_arr = ARRAY [ 1..MAX_INT2_SP00 ]
            OF tak681_unknown_table_rec;
      tak681_unknown_table_arr_ptr = ^tak681_unknown_table_arr;
 
      tak681_best_jstrat = 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_arr = ARRAY [ 1..cak00_maxsources ]
            OF tak681_best_jstrat;
      tak681_best_jstrat_arr_ptr = ^tak681_best_jstrat_arr;
 
      tak681_jseq_info_record = RECORD
            jir_sequenced_tables  : tak_joinset;
            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_filler            : tsp00_C6;
            jir_lowest_cost       : tsp00_Longreal;
            jir_best_jstrat       : tak681_best_jstrat_arr_ptr;
            jir_lowest_succession : tak68_succession_ptr;
            jir_start_succession  : tak68_succession_ptr;
      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 ] )) = 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 := [ ];
(* up to now: output columns counted *)
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;*)
      _used_jrc_set : tsp00_Addr;
 
BEGIN
&ifdef trace
a683_output (ak_join, dmli.d_joins);
&endif
_used_jrc_set := gg12InitBitArray( acv.a_transinf.tri_trans, dmli.d_joins.jrc_cnt );
IF  ( _used_jrc_set <> NIL )
THEN
    BEGIN
    (* remove all equal conditions *)
    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 ];*)
            gg12SetBit( _used_jrc_set, _j, true );
        (*ENDIF*) 
    (*ENDFOR*) 
    ;
&   ifdef TRACE
    FOR _i := 0 TO dmli.d_joins.jrc_cnt DO
        (*IF  (_i in _used_jrc_set)*)
        IF  ( gg12GetBit( _used_jrc_set, _i ) )
        THEN
            t01int4 (ak_join, '        ==> ', _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
            (* !? series[1].jos_joinno = series[2].jos_joinno ?! *)
            IF  ( series[ _j ].jos_joinno <> cak68_cartesian_product )
            THEN
                FOR _i := series[ _j ].jos_joinno TO
                      (series[ _j ].jos_joinno + series[ _j ].jos_fieldcnt - 1) DO
                    (* loop over join transition cluster *)
                    WITH dmli.d_joins.jrc_joinarr^[ _i ] DO
                        BEGIN
                        (*IF  (NOT (_i in _used_jrc_set))*)
                        IF  ( NOT gg12GetBit( _used_jrc_set, _i ))
                        THEN
                            BEGIN
                            (*_used_jrc_set := _used_jrc_set + [ _i ];*)
                            gg12SetBit( _used_jrc_set, _i, true );
                            IF  ( jo_recs[ 1 ].jop_cntstack = 1 ) AND
                                ( jo_recs[ 2 ].jop_cntstack = 1 )
                            THEN
                                BEGIN
                                IF  ( eq_rec.eqr_cnt + 1 > eq_rec.eqr_capacity )
                                THEN
                                    a685expand_eq_rec( acv, eq_rec );
                                (*ENDIF*) 
                                IF  ( eq_rec.eqr_cnt + 1 <= eq_rec.eqr_capacity )
                                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;
                                        eqi_codetype := eq_rec.eqr_arr^[ eq_rec.eqr_cnt ][ cak68_left ].eqi_codetype;
                                        END;
                                    (*ENDWITH*) 
                                    END;
                                (*ENDIF*) 
                                END;
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDWITH*) 
                (*ENDFOR*) 
            (*ENDIF*) 
        (*ENDFOR*) 
        ;
&       ifdef TRACE
        FOR _i := 0 TO _end_pos DO
            (*IF  (_i in _used_jrc_set)*)
            IF  ( gg12GetBit( _used_jrc_set, _i ))
            THEN
                t01int4 (ak_join, ' xxx    ==> ', _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, '    .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, '     .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
                    t01name (ak_join, '------------------');
                    t01int4 (ak_join, '_j          ', _j);
                    t01int4 (ak_join, 'curr_tab    ', _curr_tab);
                    t01int4 (ak_join, 'nxt_tab     ', _nxt_tab);
                    t01int4 (ak_join, 'offset      ', _offset);
&                   endif
                    FOR _i := 0 TO _end_pos DO
                        WITH dmli.d_joins.jrc_joinarr^[ _i ] DO
                            BEGIN
                            (*IF  (NOT (_i in _used_jrc_set))*)
                            IF  ( NOT gg12GetBit( _used_jrc_set, _i ))
                            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
                                        IF  ( eq_rec.eqr_cnt + 1 > eq_rec.eqr_capacity )
                                        THEN
                                            a685expand_eq_rec( acv, eq_rec );
                                        (*ENDIF*) 
                                        IF  ( eq_rec.eqr_cnt + 1 <= eq_rec.eqr_capacity )
                                        THEN
                                            BEGIN
                                            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 ];*)
                                                gg12SetBit( _used_jrc_set, _i, true );
                                                eq_rec.eqr_cnt :=
                                                      succ (eq_rec.eqr_cnt);
                                                END;
                                            (*ENDIF*) 
                                            END;
                                        (*ENDIF*) 
                                        END
                                    ELSE
                                        (*_used_jrc_set := _used_jrc_set + [ _i ];*)
                                        gg12SetBit( _used_jrc_set, _i, true );
                                    (*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)*)
            IF  ( gg12GetBit( _used_jrc_set, _i ))
            THEN
                t01int4 (ak_join, 'aaa     ==> ', _i);
            (*ENDIF*) 
        (*ENDFOR*) 
        a683_output (ak_join, dmli.d_joins);
&       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)*)
            IF  ( NOT gg12GetBit( _used_jrc_set, _i ))
                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
                (* don't remove entries with op <> op_eq and with expressions *)
                ak681pack_join_cond (dmli, series, _i);
            (*ENDIF*) 
        (*ENDFOR*) 
        END;
    (*ENDIF*) 
    END
ELSE
    a07_b_put_error (acv, e_no_more_memory, 1);
(*ENDIF*) 
gg12FinalizeBitArray( acv.a_transinf.tri_trans, _used_jrc_set );
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;
_j        := 0;
&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 jinfos    : tak68_joininfos;
            VAR mul_tabs  : tak68_mult_tabs;
            start_idx     : tsp00_Int2;
            dst_side      : 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;
      _ix_initial : tsp00_Int2;
      _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;
      _unknown_table_arr : tak681_unknown_table_arr_ptr;
      _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;
 
      _cast  : RECORD
            CASE integer OF
                1 :
                    (addr: tsp00_Addr);
                2 :
                    (ptr : tak681_unknown_table_arr_ptr);
                END;
            (*ENDCASE*) 
 
 
BEGIN
&ifdef TRACE
t01int4(ak_join, 'joinarr pos ', start_idx );
IF  dst_side = 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 >= mul_tabs.mt_capacity )
THEN
    a685expand_multab_rec( acv, mul_tabs );
(*ENDIF*) 
IF  ( mul_tabs.mt_pos <= mul_tabs.mt_capacity )
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 dst_side OF
        1 :
            _src := 2;
        2 :
            _src := 1;
        END;
    (*ENDCASE*) 
    _dst_tab := dmli.d_joins.jrc_joinarr^[ start_idx ].jo_recs[ dst_side ].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^[ start_idx ].jo_recs[ dst_side ].jop_multiplier;
    mul_tabs.mt_arr^[ mul_tabs.mt_pos ].mtr_joinno   := start_idx;
    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^[ start_idx ].
              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^[ start_idx ].
          jo_recs[ _src ].jop_inoutlen,
          'dest len    ', dmli.d_joins.jrc_joinarr^[ start_idx ].
          jo_recs[ dst_side ].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  ( jinfos.ji_use_operator_join ) OR
        ( dmli.d_joins.jrc_joinarr^[ start_idx ].
        jo_recs[ _src ].jop_inoutlen <= dmli.d_joins.jrc_joinarr^[ start_idx ].
        jo_recs[ dst_side ].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 ) OR
                ( ta_cluster_key in dmli.d_sparr.pbasep^.sbase.battributes )
            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
                mul_tabs.mt_arr^[ mul_tabs.mt_pos ].mtr_jointype := to_single_keyfield;
            (*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_arr := NIL;
        _cast.addr := gg941Allocate( acv.a_transinf.tri_trans,
              dmli.d_joins.jrc_cnt * sizeof(tak681_unknown_table_rec) );
        _unknown_table_arr := _cast.ptr;
&       ifdef trace
        t01addr( ak_join, '_unknown_tab', _cast.addr );
&       endif
        _unknown_table_pos := 1;
        _unknown_table_cnt := 0;
        IF  ( _unknown_table_arr <> NIL )
        THEN
            REPEAT
                (* 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 >= mul_tabs.mt_capacity )
                    THEN
                        a685expand_multab_rec( acv, mul_tabs );
                    (*ENDIF*) 
                    IF  mul_tabs.mt_pos < mul_tabs.mt_capacity
                    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
                    (* first REPEAT LOOP *)
                    (* if is_join_value = true --> *)
                    (* first execution of next WHILE fills _unknown_table_arr *)
                    _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
                _ix_initial := _ix;
                _reset_loop := false;
                WHILE ( _ix < dmli.d_joins.jrc_cnt ) AND ( acv.a_returncode = 0 ) DO
                    BEGIN
                    IF  ((_ix <> start_idx) 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  _ix_initial = _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
                                ( dmli.d_joins.jrc_joinarr^[ _ix ].
                                jo_recs[ _src ].jop_tableno <>
                                dmli.d_joins.jrc_joinarr^[ _ix ].
                                jo_recs[ _dst ].jop_tableno )
                                AND
                                ( jinfos.ji_use_operator_join OR
                                ( 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> *)
                                    (* extend join transition with any 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  := [ ];
                                    (* get better 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;
                                    (*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
                                        IF  NOT ( ta_cluster_key in dmli.d_sparr.pbasep^.sbase.battributes )
                                        THEN
                                            BEGIN
                                            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;
                                            END;
                                        (* exit while*)
                                        (*ENDIF*) 
                                        _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  ( _virt_mt_cnt >= mul_tabs.mt_capacity )
                                    THEN
                                        a685expand_multab_rec( acv, mul_tabs );
                                    (*ENDIF*) 
                                    IF  ( NOT ( dmli.d_joins.jrc_joinarr^[ _ix ].
                                        jo_recs[ _src ].jop_tableno in _new_tables ))
                                        AND
                                        ( _unknown_table_cnt < dmli.d_joins.jrc_cnt )
                                        AND
                                        ( _virt_mt_cnt < mul_tabs.mt_capacity )
                                    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 for *)
                                        (* every found unknown table         *)
                                        (* 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 if we found anything *)
                                END;
                            (*ENDIF*) 
                            ;
                            (* swap considered direction of join transition *)
                            _dst := succ (_dst);
                            _src := pred (_src);
                            END;
                        (*ENDWHILE*) 
                        END;
                    (*ENDIF*) 
                    ;
                    (* -- one join entry possibly 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  ( _ix_initial > 0 )
                            (* we found already a unknown table        *)
                            (* in a first walk through join conditions *)
                            AND
                            (* now we didn't found whole key *)
                            ( _ix = _ix_initial )
                        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;
                            _ix_initial  := 0;
                            END
                        ELSE
                            BEGIN
                            (* get next join condition *)
                            IF  ( NOT _reset_loop )
                            THEN
                                (* we have found a unknown table OR *)
                                (* known table with whole key      OR *)
                                (* we steped over a none-equi-join OR *)
                                (* we steped over any other equi-join *)
                                _ix := succ( _ix )
                            ELSE
                                (* we have found a known table and *)
                                (* there are further key columns   *)
                                BEGIN
                                _reset_loop := false;
                                _ix         := 0;
                                END;
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDWHILE*) 
            UNTIL
                (* i.e. UNTIL no input into _unknown_table_arr *)
                ( _unknown_table_pos > _unknown_table_cnt )
            (*ENDREPEAT*) 
        ELSE
            a07_b_put_error (acv, e_no_more_memory, 1);
        (*ENDIF*) 
        IF  ( _unknown_table_arr <> NIL )
        THEN
            BEGIN
            _cast.ptr := _unknown_table_arr;
&           ifdef trace
            t01addr( ak_join, '_unknown_tab', _cast.addr );
&           endif
            gg941Deallocate( acv.a_transinf.tri_trans, _cast.addr );
            END;
        (*ENDIF*) 
        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^[ start_idx ].jo_recs[ dst_side ].
                  jop_multiplier := cak68_only_field_multiplier;
            END
        ELSE
            BEGIN
            (* accept new entries into mult_tabs *)
            _jointype := to_mt_join;
            (* avoid wrong (something error case) multiplier *)
            FOR _ix := mul_tabs.mt_cnt + 1 TO mul_tabs.mt_pos DO
                BEGIN
                (* h.b. PTS 1106028 *)
                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 jinfos   : tak68_joininfos;
            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;
      _dst_side       : tsp00_Int2;
      _src_side       : tsp00_Int2;
      _ins_pos        : tsp00_Int2;
      _m              : tsp00_Int2;
      _old_sfieldcnt  : tsp00_Int2;
      _end_found      : boolean;
      _leftside_tab   : boolean;
      _dst_tab        : tsp00_Int2;
      _nxt_fieldno    : tsp00_Int2;
      _needed_tables  : 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;
_dst_tab := series[ ser_pos ].jos_source;
IF  ( mul_tabs.mt_pos <> 0 )
THEN
    (* decided for one of mult. transistions *)
    _needed_tables := mul_tabs.mt_arr^[ mul_tabs.mt_pos ].mtr_tab_seq
ELSE
    BEGIN
    IF  ( dmli.d_joins.jrc_joinarr^
        [ series[ ser_pos ].jos_joinno ].jo_recs[ 1 ].jop_tableno = _dst_tab )
    THEN
        BEGIN
        IF  (dmli.d_joins.jrc_joinarr^[ series[ ser_pos ].jos_joinno ].
            jo_recs[ 2 ].jop_tableno = cak68_join_value)
        THEN
            _needed_tables := [ ]
        ELSE
            _needed_tables := [ dmli.d_joins.jrc_joinarr^[ series[ ser_pos ].
                  jos_joinno ].jo_recs[ 2 ].jop_tableno ];
        (*ENDIF*) 
        END
    ELSE
        _needed_tables := [ dmli.d_joins.jrc_joinarr^
              [ series[ ser_pos ].jos_joinno ].jo_recs[ 1 ].jop_tableno ];
    (*ENDIF*) 
    END;
(*ENDIF*) 
ak681first_keyfield_no (acv, dmli, _col_buf, _dst_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, '_joinpred_po', _joinpred_pos);
&       endif
        IF  ( dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].jo_op = op_eq )
        THEN
            BEGIN
            _dst_side := 1;
            _src_side := 2;
            WHILE ( _dst_side <= 2 ) DO
                BEGIN
                IF  (( dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                    jo_recs[ _dst_side ].jop_tableno = _dst_tab )
                    AND
                    ( dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                    jo_recs[ _dst_side ].jop_fieldno = _nxt_fieldno )
                    AND
                    ( dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                    jo_recs[ _dst_side ].jop_cntstack = 1 )
                    AND
                    (* there could be more than one condition      *)
                    (* with different columns to dst_tab.dst_field *)
                    (jinfos.ji_use_operator_join OR
                    ( dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                    jo_recs[ _src_side ].jop_inoutlen <=
                    dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                    jo_recs[ _dst_side ].jop_inoutlen ))
                    AND
                    ( dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                    jo_recs[ _src_side ].jop_tableno <>
                    dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                    jo_recs[ _dst_side ].jop_tableno )
                    AND
                    (* strictly speaking *)
                    (* supposed to be given through jop_fieldno = _nxt_fieldno *)
                    ( jtkey in dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                    jo_recs[ _dst_side ].jop_propset ))
                THEN
                    (* <tab> = <dest tab> or <dest tab> = <tab> *)
                    BEGIN
                    IF  ( dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                        jo_recs[ _src_side ].jop_tableno = cak68_join_value )
                    THEN
                        _leftside_tab := true
                    ELSE
                        BEGIN
                        _leftside_tab :=
                              dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                              jo_recs[ _src_side ].jop_tableno in _needed_tables;
                        IF  ( _needed_tables = [ ] )
                        THEN
                            (* first and only join trans is <col>=value *)
                            BEGIN
                            _m := ser_pos;
                            WHILE ( NOT _leftside_tab ) AND ( _m > 1 ) DO
                                BEGIN
                                _m := pred (_m);
                                _leftside_tab :=
                                      ( series [ _m ].jos_source =
                                      dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                                      jo_recs[ _src_side ].jop_tableno );
                                _needed_tables :=
                                      [ series[ _m ].jos_source ];
                                END;
                            (*ENDWHILE*) 
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    IF  ( _leftside_tab )
                    THEN
                        (* <x-y. tab> = <x. tab> or <x. tab> = <x-y. tab> *)
                        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  ( series[ ser_pos ].jos_fieldcnt >= _old_sfieldcnt )
                            THEN
                                _end_found := true;
                            (*ENDIF*) 
                            IF  ( dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                                jo_recs[ _dst_side ].jop_inoutlen >
                                dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                                jo_recs[ _src_side ].jop_inoutlen )
                            THEN
                                (* src_len < dst_len *)
                                BEGIN
                                dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                                      jo_recs[ _src_side ].jop_inoutlen := dmli.d_joins.
                                      jrc_joinarr^[ _joinpred_pos ].
                                      jo_recs[ _dst_side ].jop_inoutlen;
                                END;
                            (*ENDIF*) 
                            END
                        ELSE
                            BEGIN
                            (* don't adjust jop_inoutlen for last key fields *)
                            _end_found := true;
                            END;
                        (*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;
                            (* don't search for further predicates *)
                            _joinpred_pos := dmli.d_joins.jrc_cnt;
                            END;
                        (*ENDIF*) 
                        _dst_side := 3; (* skip to next predicate *)
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                _dst_side := succ (_dst_side);
                _src_side := pred (_src_side);
                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*) 
sort_pos := sort_pos + series[ ser_pos ].jos_fieldcnt;
&ifdef TRACE
a683_output( ak_join, dmli.d_joins );
IF  ( series[ ser_pos ].jos_fieldcnt <> _old_sfieldcnt )
THEN
    g01abort( -7777, 'JOIN    ', 'WRONG FIELD COUNT       ', _old_sfieldcnt );
&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 jinfos       : tak68_joininfos;
            VAR mul_tabs     : tak68_mult_tabs;
            start_idx        : tsp00_Int2;
            dst_side         : tsp00_Int2;
            is_join_value    : boolean) : tak68_one_jointype;
 
VAR
      _dst_tabid      : tgg00_Surrogate;
      _index_scan_rec : tak_index_scan_record;
      _index_tree     : tgg00_FileId;
      _jointype       : tak68_one_jointype;
      _src            : tsp00_Int2;
      _dst_tab        : tsp00_Int2;
 
BEGIN
_jointype := to_eq_field;
(* set correct mt_pos *)
mul_tabs.mt_pos := mul_tabs.mt_cnt;
&ifdef trace
t01int4 (ak_join, 'start_idx   ', start_idx);
t01int4 (ak_join, 'dst_side    ', dst_side);
a683_one_join_entry( ak_join, dmli.d_joins, start_idx, true );
&endif
_dst_tab   := dmli.d_joins.jrc_joinarr^[ start_idx ].
      jo_recs[ dst_side ].jop_tableno;
_dst_tabid := dmli.d_tabarr^[ _dst_tab ].otreeid.fileTabId_gg00;
a24init_index_scan (acv, _dst_tabid, _index_scan_rec);
WHILE a24next_named_index( acv, _index_scan_rec ) DO
    BEGIN
    (* jo_recs[ dst_side ].jop_source is destination table         *)
    (* i.e. we would like to access jo_recs[ dst_side ].jop_source *)
    (* with index described in _index_scan_rec.isr_buf^.smindex.   *)
    (* indexdef [_index_scan_rec.isr_index]                        *)
    CASE dst_side OF
        1:
            _src := 2;
        2:
            _src := 1;
        END;
    (*ENDCASE*) 
    IF  ( mul_tabs.mt_pos >= mul_tabs.mt_capacity )
    THEN
        a685expand_multab_rec( acv, mul_tabs );
    (*ENDIF*) 
    ;
&   ifdef trace
    t01int4 (ak_join, 'jop_fieldno ', dmli.d_joins.jrc_joinarr^[ start_idx ].
          jo_recs[ dst_side ].jop_fieldno );
    t01int4 (ak_join, '1. inv field', _index_scan_rec.isr_buf^.smindex.
          indexdef[_index_scan_rec.isr_index].icolseq[ 1 ] );
&   endif
    IF  ( NOT _index_scan_rec.isr_buf^.smindex.
        indexdef[_index_scan_rec.isr_index].idisabled )
        AND
        (* run for first index column *)
        ( dmli.d_joins.jrc_joinarr^[ start_idx ].
        jo_recs[ dst_side ].jop_fieldno = _index_scan_rec.isr_buf^.
        smindex.indexdef[_index_scan_rec.isr_index].icolseq[ 1 ] )
        AND
        ( jinfos.ji_use_operator_join OR
        ( dmli.d_joins.jrc_joinarr^[ start_idx ].
        jo_recs[ _src ].jop_inoutlen <=
        dmli.d_joins.jrc_joinarr^[ start_idx ].
        jo_recs[ dst_side ].jop_inoutlen ) OR
        ( _index_scan_rec.isr_buf^.smindex.
        indexdef[_index_scan_rec.isr_index].icount = 1 ))
        AND
        ( mul_tabs.mt_pos < mul_tabs.mt_capacity )
    THEN
        BEGIN
        g04index_tree_build (dmli.d_tabarr^[ _dst_tab ].otreeid, _index_tree,
              _index_scan_rec.isr_buf^.
              smindex.indexdef[_index_scan_rec.isr_index].indexno);
        b01filestate( acv.a_transinf.tri_trans, _index_tree );
        ;
        IF  ( acv.a_transinf.tri_trans.trError_gg00 <> e_file_not_accessible )
        THEN
            BEGIN
            ak681ieval_inv_kind_ex( acv, dmli, jinfos, mul_tabs, start_idx,
                  dst_side, _index_scan_rec.isr_buf^.
                  smindex.indexdef[_index_scan_rec.isr_index],
                  _jointype, _dst_tab, is_join_value );
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
a24finish_index_scan (acv, _index_scan_rec);
a681ieval_inv_kind := _jointype;
&ifdef TRACE
a683trace_jointype(ak_join, 'return      ', _jointype);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681ieval_inv_kind_ex(
            VAR acv       : tak_all_command_glob;
            VAR dmli      : tak_dml_info;
            VAR jinfos    : tak68_joininfos;
            VAR mul_tabs  : tak68_mult_tabs;
            start_idx     : tsp00_Int2;
            dst_side      : tsp00_Int2;
            VAR m_inddef  : tak_multindex;
            VAR jointype  : tak68_one_jointype;
            dest_tab      : tsp00_Int2;
            is_join_value : boolean);
 
VAR
      _ix                : tsp00_Int2;
      _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;
      _unknown_table_arr : tak681_unknown_table_arr_ptr;
      _new_tables        : tak_joinset;
      _f_ok              : boolean;
      _known_table       : boolean;
      _reset_loop        : boolean;
 
      _cast  : RECORD
            CASE integer OF
                1 :
                    (addr: tsp00_Addr);
                2 :
                    (ptr : tak681_unknown_table_arr_ptr);
                END;
            (*ENDCASE*) 
 
 
BEGIN
CASE dst_side OF
    1:
        _src := 2;
    2:
        _src := 1;
    END;
(*ENDCASE*) 
(* create 'virtual' entry in mul_tabs,    *)
(* memory assured by a681ieval_inv_kind() *)
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^[ start_idx ].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^[ start_idx ].jo_recs[ dst_side ].jop_multiplier;
mul_tabs.mt_arr^[ mul_tabs.mt_pos ].mtr_joinno  := start_idx;
;
_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  (( NOT jinfos.ji_use_operator_join ) AND
        ( dmli.d_joins.jrc_joinarr^[ start_idx ].jo_recs[ _src ].
        jop_inoutlen >
        dmli.d_joins.jrc_joinarr^[ start_idx ].jo_recs[ dst_side ].
        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_arr := NIL;
    _cast.addr := gg941Allocate( acv.a_transinf.tri_trans,
          dmli.d_joins.jrc_cnt * sizeof(tak681_unknown_table_rec) );
    _unknown_table_arr := _cast.ptr;
&   ifdef trace
    t01addr( ak_join, '_unknown_tab', _cast.addr );
&   endif
    _unknown_table_cnt := 0;
    _unknown_table_pos := 1;
    IF  ( _unknown_table_arr <> NIL )
    THEN
        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 >= mul_tabs.mt_capacity )
                THEN
                    a685expand_multab_rec( acv, mul_tabs );
                (*ENDIF*) 
                IF  ( mul_tabs.mt_pos < mul_tabs.mt_capacity )
                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 <> start_idx )
                    AND
                    ( dmli.d_joins.jrc_joinarr^[ _ix ].jo_op = op_eq ))
                THEN
                    WITH dmli.d_joins.jrc_joinarr^[ _ix ] DO
                        BEGIN
                        (* 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
                        _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
                                ( jinfos.ji_use_operator_join OR
                                ( jo_recs[ _src ].jop_inoutlen <=
                                jo_recs[ _dst ].jop_inoutlen ))
                                AND
                                ( jo_recs[ _src ].jop_tableno <>
                                jo_recs[ _dst ].jop_tableno )
                                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  := [ ];
                                    (* get better 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;
                                    (*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  ( _virt_mt_cnt >= mul_tabs.mt_capacity )
                                    THEN
                                        a685expand_multab_rec( acv, mul_tabs );
                                    (*ENDIF*) 
                                    IF  ( NOT (jo_recs[ _src ].jop_tableno in
                                        _new_tables ))
                                        AND
                                        ( _unknown_table_cnt < dmli.d_joins.jrc_cnt )
                                        AND
                                        ( _virt_mt_cnt < mul_tabs.mt_capacity )
                                    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*) 
                (*ENDIF*) 
                ;
                (* -- 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*) 
    ELSE
        a07_b_put_error (acv, e_no_more_memory, 1);
    (*ENDIF*) 
    IF  ( _unknown_table_arr <> NIL )
    THEN
        BEGIN
        _cast.ptr := _unknown_table_arr;
&       ifdef trace
        t01addr( ak_join, '_unknown_tab', _cast.addr );
&       endif
        gg941Deallocate( acv.a_transinf.tri_trans, _cast.addr );
        END;
    (*ENDIF*) 
    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
            (* h.b. PTS 1106028 *)
            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;
 
(*------------------------------*) 
 
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
      _dst_tab       : tsp00_Int2;
      _index_no       : tsp00_Int2;
      _old_sfieldcnt  : tsp00_Int2;
      _joinpred_pos   : tsp00_Int2;
      _dst_side       : tsp00_Int2;
      _src_side       : tsp00_Int2;
      _ins_pos        : tsp00_Int2;
      _m              : tsp00_Int2;
      _nxt_fieldno    : tsp00_Int2;
      _joinpred             : tak_one_join;
      _index_scan_rec : tak_index_scan_record;
      _needed_tabs    : tak_joinset;
      _inv_tabid      : tgg00_Surrogate;
      _index_found    : boolean;
      _end_found      : boolean;
      _leftside_tab   : 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;
_dst_tab  := series[ ser_pos ].jos_source;
_index_no := series[ ser_pos ].jos_indexno;
&ifdef TRACE
t01int4 (ak_join, 'sort_pos    ', sort_pos);
t01int4 (ak_join, 'ser_pos     ', ser_pos);
t01int4 (ak_join, 'mt_pos      ', mul_tabs.mt_pos);
t01int4 (ak_join, '_old_fieldcn', _old_sfieldcnt);
t01int4 (ak_join, 'jcnt        ', dmli.d_joins.jrc_cnt);
a683_output (ak_join, dmli.d_joins);
&endif
IF  ( mul_tabs.mt_pos <> 0 )
THEN
    _needed_tabs := mul_tabs.mt_arr^[ mul_tabs.mt_pos ].mtr_tab_seq
ELSE
    BEGIN
    IF  ( dmli.d_joins.jrc_joinarr^
        [ series[ ser_pos ].jos_joinno ].jo_recs[ 1 ].jop_tableno = _dst_tab )
    THEN
        BEGIN
        IF  ( dmli.d_joins.jrc_joinarr^[ series[ ser_pos ].jos_joinno ].
            jo_recs[ 2 ].jop_tableno = cak68_join_value )
        THEN
            _needed_tabs := [ ]
        ELSE
            _needed_tabs := [ dmli.d_joins.jrc_joinarr^[ series[ ser_pos ].
                  jos_joinno ].jo_recs[ 2 ].jop_tableno ];
        (*ENDIF*) 
        END
    ELSE
        _needed_tabs := [ dmli.d_joins.jrc_joinarr^[ series[ ser_pos ].
              jos_joinno ].jo_recs[ 1 ].jop_tableno ];
    (*ENDIF*) 
    END;
(*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*) 
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
                _dst_side := 1;
                _src_side := 2;
                WHILE (_dst_side <= 2) DO
                    (* process both sides of predicate *)
                    BEGIN
                    IF  (( dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                        jo_recs[ _dst_side ].jop_tableno = _dst_tab)
                        AND
                        ( dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                        jo_recs[ _dst_side ].jop_fieldno = _nxt_fieldno )
                        AND
                        ( dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                        jo_recs[ _dst_side ].jop_cntstack = 1 )
                        AND
                        ( dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                        jo_recs[ _dst_side ].jop_tableno <>
                        dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                        jo_recs[ _src_side ].jop_tableno )
                        AND
                        ( jtmulti in dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                        jo_recs[ _dst_side ].jop_propset))
                    THEN
                        BEGIN
                        IF  ( dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                            jo_recs[ _src_side ].jop_tableno = cak68_join_value )
                        THEN
                            _leftside_tab := true
                        ELSE
                            BEGIN
                            _leftside_tab :=
                                  dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                                  jo_recs[ _src_side ].jop_tableno in _needed_tabs;
                            IF  ( _needed_tabs = [ ] )
                            THEN
                                (* first and only join trans is <col>=value *)
                                BEGIN
                                _m := ser_pos;
                                WHILE ( NOT _leftside_tab ) AND ( _m > 1 ) DO
                                    BEGIN
                                    _m := pred (_m);
                                    _leftside_tab := series [ _m ].jos_source =
                                          dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].jo_recs[ _src_side ].
                                          jop_tableno;
                                    _needed_tabs :=
                                          [ series[ _m ].jos_source ];
                                    END;
                                (*ENDWHILE*) 
                                END;
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        IF  ( _leftside_tab )
                        THEN
                            (* <x-y. tab> = <x. tab> or <x. tab> = <x-y. tab> *)
                            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[ _dst_side ].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[ _dst_side ].jop_startstack ].
                                                  eop := op_order_desc_ascii
                                        ELSE
                                            jinfos.ji_st_addr^
                                                  [ dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                                                  jo_recs[ _dst_side ].jop_startstack ].
                                                  eop := op_unique_desc_ascii;
                                        (*ENDIF*) 
                                    OTHERWISE
                                        jinfos.ji_st_addr^
                                              [ dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                                              jo_recs[ _dst_side ].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  (series[ ser_pos ].jos_fieldcnt >= _old_sfieldcnt)
                                THEN
                                    _end_found := true;
                                (*ENDIF*) 
                                IF  (dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                                    jo_recs[ _dst_side ].jop_inoutlen > dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                                    jo_recs[ _src_side ].jop_inoutlen)
                                THEN
                                    (* src_len < dst_len *)
                                    BEGIN
                                    dmli.d_joins.jrc_joinarr^[ _joinpred_pos ].
                                          jo_recs[ _src_side ].jop_inoutlen := dmli.d_joins.
                                          jrc_joinarr^[ _joinpred_pos ].
                                          jo_recs[ _dst_side ].jop_inoutlen;
                                    END;
                                (*ENDIF*) 
                                END
                            ELSE
                                BEGIN
                                (* don't adjust jop_inoutlen for last key fields *)
                                _end_found := true;
                                END;
                            (*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;
                                (* don't search for further predicates *)
                                _joinpred_pos := dmli.d_joins.jrc_cnt; (* exit while *)
                                END;
                            (*ENDIF*) 
                            _dst_side := 3; (* exit while *)
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    _dst_side := succ (_dst_side);
                    _src_side := pred (_src_side);
                    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*) 
    sort_pos := sort_pos + series[ ser_pos ].jos_fieldcnt;
&   ifdef TRACE
    t01int4 (ak_join, 'act fieldcnt', series[ ser_pos ].jos_fieldcnt);
    a683_output (ak_join, dmli.d_joins);
    IF  ( series[ ser_pos ].jos_fieldcnt <> _old_sfieldcnt )
    THEN
        g01abort( -6666, 'JOIN    ', 'WRONG FIELD COUNT       ', _old_sfieldcnt );
&   endif
    (*ENDIF*) 
    END;
(*ENDIF*) 
a24finish_index_scan (acv, _index_scan_rec);
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 (*  orig. position *)
            )
        THEN
            BEGIN
&           ifdef trace
            t01int4 (ak_join, 'series      ', _i);
            t01int4 (ak_join, 'joinno      ', series[ _i ].jos_joinno);
            t01sname (ak_join, '-->         ');
&           endif
            series[ _i ].jos_joinno  := _j;
&           ifdef TRACE
            t01int4 (ak_join, 'new joinno  ', _j);
&           endif
            _j := dmli.d_joins.jrc_cnt; (* exit loop over joinarr *)
            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
&           ifdef trace
            t01int4 (ak_join, 'mul_tab     ', _i);
            t01int4 (ak_join, 'joinno      ', mul_tabs.mt_arr^ [ _i ].mtr_joinno);
            t01sname (ak_join, '-->         ');
&           endif
            mul_tabs.mt_arr^ [ _i ].mtr_joinno  := _j;
&           ifdef TRACE
            t01int4 (ak_join, 'new joinno  ', _j);
&           endif
            _j := dmli.d_joins.jrc_cnt; (* exit loop over joinarr *)
            END;
        (*ENDIF*) 
        _j := succ( _j );
        END;
    (*ENDWHILE*) 
    END;
(*ENDFOR*) 
;
(* !!! tak68_eqfieldinfo.eqi_joinno, tak68_join_transition.jt_joinno !!! *)
(* !!!                      wasn't adjusted                          !!! *)
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 : tsp00_Addr (*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_arr  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)*)
            IF  ( NOT gg12GetBit( used_set, _k ))
            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)*)
            IF  ( NOT gg12GetBit( used_set, _k ))
            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
    (* loop over join sequence *)
    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
                (* loop over remaining join sequence *)
                BEGIN
                IF  ( series[ _j ].jos_joinno < series[ _i ].jos_joinno )
                    AND
                    ( series[ _j ].jos_joinno <> cak68_cartesian_product )
                THEN
                    series[ _j ].jos_joinno := series[ _j ].jos_joinno +
                          series[ _i ].jos_fieldcnt;
                (*ENDIF*) 
                END;
            (*ENDFOR*) 
            END;
        (*ENDIF*) 
        _sort_pos := _sort_pos + series[ _i ].jos_fieldcnt;
        series[ _i ].jos_joinno := cak68_cartesian_product;
        END;
    (*ENDIF*) 
(*ENDFOR*) 
;
&ifdef TRACE
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
    BEGIN
&   ifdef trace
    t01int4 (ak_join, 'cnt         ', cnt );
    t01int4 (ak_join, 'jrc_cnt     ', dmli.d_joins.jrc_cnt );
    t01int4 (ak_join, 'jrc_capacity', dmli.d_joins.jrc_capacity );
    t01int4 (ak_join, 'to_pos      ', to_pos );
    t01int4 (ak_join, 'from_pos    ', from_pos );
&   endif
    IF  ((dmli.d_joins.jrc_cnt + (from_pos - to_pos)) > dmli.d_joins.jrc_capacity)
    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,    
              dmli.d_joins.jrc_capacity * sizeof(tak_one_join),
              dmli.d_joins.jrc_capacity * sizeof(tak_one_join),
              @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,    
              dmli.d_joins.jrc_capacity * sizeof(tak_one_join),
              dmli.d_joins.jrc_capacity * sizeof(tak_one_join),
              @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,    
              dmli.d_joins.jrc_capacity * sizeof(tak_one_join),
              dmli.d_joins.jrc_capacity * sizeof(tak_one_join),
              @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*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
FUNCTION
      ak681all_multabs_in_succ (
            VAR mul_tab         : tak68_mul_tab_rec;
            newsuccession       : tak68_succession_ptr;
            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
_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 =
        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 =
            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 := true;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
    (*ENDIF*) 
    _xi := succ (_xi);
    END;
(*ENDWHILE*) 
&ifdef trace
t01int4 (ak_join, 'ji_acttabno ', jinfos.ji_acttabno );
t01bool( ak_join, '_pack_joinar', _pack_joinarr );
&endif
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;
(*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
      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 := a103GetColumn ( dmli.d_sparr.pbasep^.sbase,
          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     := a103GetColumn (dmli.d_sparr.pbasep^.sbase, 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;
            jtrans              : tak68_join_transitions; (* IN/OUT *)
            succession          : tak68_succession_ptr; (* 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;
      _jtrans_ptr           : tak68_join_transition_ptr;
      _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
        _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_ptr :=
                      a685get_join_trans( dmli, jtrans, src_table, dst_table );
                _jtrans_ptr^.jt_indexno  := mul_tabs.mt_arr^[ _l ].mtr_indexno;
                _jtrans_ptr^.jt_joinno   := mul_tabs.mt_arr^[ _l ].mtr_joinno;
                _jtrans_ptr^.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 *)
            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
IF  ( ak681init_context( acv, dmli, _context ) )
THEN
    BEGIN
    SAPDB_PascalForcedFill (sizeof (_ln), @_ln, 1, sizeof (_ln), bsp_c1);
    (* *** find best strategy to each table *** *)
    ak681best_join_strat( acv, dmli, config, table_stats, jtrans,
          sequence_info, jinfos, res_info, mul_tabs, _context.jir_best_jstrat^ );
    dmli.d_standard :=
          dmli.d_standard                               OR
          (dmli.d_outer_join AND g01outer_join_ordered) OR
          a80is_predefined_join_order( acv );
    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 )) )
    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;*)
                    SAPDB_PascalForcedMove (
                          dmli.d_cntfromtab * sizeof(tak68_succ),
                          dmli.d_cntfromtab * sizeof(tak68_succ),
                          @sequence_info.si_sequence^, 1,
                          @_context.jir_start_succession^, 1,
                          dmli.d_cntfromtab * sizeof(tak68_succ));
                    _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;*)
                        SAPDB_PascalForcedMove (
                              dmli.d_cntfromtab * sizeof(tak68_succ),
                              dmli.d_cntfromtab * sizeof(tak68_succ),
                              @_context.jir_start_succession^, 1,
                              @sequence_info.si_sequence^, 1,
                              dmli.d_cntfromtab * sizeof(tak68_succ));
                        (*  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
            BEGIN
            (*sequence_info.si_sequence := _context.jir_lowest_succession;*)
            SAPDB_PascalForcedMove (
                  dmli.d_cntfromtab * sizeof(tak68_succ),
                  dmli.d_cntfromtab * sizeof(tak68_succ),
                  @_context.jir_lowest_succession^, 1,
                  @sequence_info.si_sequence^, 1,
                  dmli.d_cntfromtab * sizeof(tak68_succ));
            END;
        (*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*) 
    ak681finialize_context( acv, _context );
    END
ELSE
    a07_b_put_error (acv, e_no_more_memory, 1);
(*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;
            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;
      _jtrans_ptr          : tak68_join_transition_ptr;
      _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;
 
      _cast  : RECORD
            CASE integer OF
                1 :
                    (addr: tsp00_Addr);
                2 :
                    (sptr : tak68_succession_ptr);
                END;
            (*ENDCASE*) 
 
 
BEGIN
&ifdef trace
t01name(ak_join, 'unprocessed sequen');
t01int4(ak_join, 'length      ', context.jir_max_tables - context.jir_i + 1);
&endif
_aux_l.si_sequence := NIL;
_cast.addr := gg941Allocate( acv.a_transinf.tri_trans,
      dmli.d_cntfromtab * sizeof(tak68_succ) );
_aux_l.si_sequence := _cast.sptr;
&ifdef trace
t01addr( ak_join, 'si_sequence ', _cast.addr );
&endif
context.jir_better_seq_exists := false;
_best_strat.bj_srctab := cak_is_undefined;
IF  ( ak681init_context( acv, dmli, _aux_c ) AND ( _aux_l.si_sequence <> NIL ))
THEN
    BEGIN
    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;
                ak681copy_context( dmli, context, _aux_c );
                (*_aux_l            := sequence_info;*)
                _aux_l.si_sum   := sequence_info.si_sum;
                _aux_l.si_pages := sequence_info.si_pages;
                SAPDB_PascalForcedMove (
                      dmli.d_cntfromtab * sizeof(tak68_succ),
                      dmli.d_cntfromtab * sizeof(tak68_succ),
                      @sequence_info.si_sequence^, 1,
                      @_aux_l.si_sequence^, 1,
                      dmli.d_cntfromtab * sizeof(tak68_succ));
                (* 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,
                          jinfos, 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;
                            _jtrans_ptr :=
                                  a685get_join_trans( dmli, jtrans,
                                  _seq_table, _nonseq_table );
                            (* look for best join transitions to remaining tables *)
                            IF  _jtrans_ptr^.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
                                BEGIN
                                (* single table transition *)
                                IF  ( _best_strat.bj_jtype >
                                    _jtrans_ptr^.jt_jointype )
                                    OR
                                    (( _best_strat.bj_jtype =
                                    _jtrans_ptr^.jt_jointype )
                                    AND
                                    ( _best_strat.bj_multiplier >
                                    _jtrans_ptr^.jt_multipl ))
                                THEN
                                    BEGIN
                                    _best_strat.bj_jtype      := _jtrans_ptr^.jt_jointype;
                                    _best_strat.bj_multiplier := _jtrans_ptr^.jt_multipl;
                                    _best_strat.bj_indexno    := _jtrans_ptr^.jt_indexno;
                                    _best_strat.bj_fieldcnt   := 1;
                                    _best_strat.bj_srctab     := _seq_table;
                                    _next_table    := _nonseq_table;
                                    _n             := _l;
                                    END;
                                (*ENDIF*) 
                                END;
                            (*ENDIF*) 
                            END;
                        (*ENDFOR*) 
                        END;
                    (*ENDFOR*) 
                    ;
                    (* all multiple table transition from sequence *)
                    (* to non-sequenced tables checked             *)
                    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;*)
                        SAPDB_PascalForcedMove (
                              dmli.d_cntfromtab * sizeof(tak68_succ),
                              dmli.d_cntfromtab * sizeof(tak68_succ),
                              @_aux_c.jir_lowest_succession^, 1,
                              @context.jir_lowest_succession^, 1,
                              dmli.d_cntfromtab * sizeof(tak68_succ));
                        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;*)
            _aux_l.si_sum   := sequence_info.si_sum;
            _aux_l.si_pages := sequence_info.si_pages;
            SAPDB_PascalForcedMove (
                  dmli.d_cntfromtab * sizeof(tak68_succ),
                  dmli.d_cntfromtab * sizeof(tak68_succ),
                  @sequence_info.si_sequence^, 1,
                  @_aux_l.si_sequence^, 1,
                  dmli.d_cntfromtab * sizeof(tak68_succ));
            ak681get_other_transition( acv, dmli, config, jtrans,
                  sequence_info, jinfos, 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*) 
    ak681finialize_context( acv, _aux_c );
&   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
ELSE
    a07_b_put_error (acv, e_no_more_memory, 1);
(*ENDIF*) 
IF  ( _aux_l.si_sequence <> NIL )
THEN
    BEGIN
    _cast.sptr := _aux_l.si_sequence;
&   ifdef trace
    t01addr( ak_join, 'si_sequence ', _cast.addr );
&   endif
    gg941Deallocate( acv.a_transinf.tri_trans, _cast.addr );
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681get_other_transition (
            VAR acv            : tak_all_command_glob;
            VAR dmli           : tak_dml_info;
            config             : tak_sysbufferaddress;
            jtrans             : tak68_join_transitions;
            VAR sequence_info  : tak68_sequence_info;
            VAR jinfos         : tak68_joininfos;
            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;
      _jtrans_ptr          : tak68_join_transition_ptr;
      _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,
                      jinfos.ji_use_operator_join);
                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
            BEGIN
            _jtrans_ptr :=
                  a685get_join_trans( dmli, jtrans, _seq_table, _nonseq_table );
            (* 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_ptr^.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*) 
            END;
        (*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 *)
            jtrans            : tak68_join_transitions; (* IN *)
            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 best_jstrat   : tak681_best_jstrat_arr (* IN/OUT *));
 
VAR
      _jtrans_ptr           : tak68_join_transition_ptr;
      _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 *)
&   ifdef trace
    IF  ( _dst_tab > dmli.d_cntfromtab )
    THEN
        g01abort (-8888, 'JOIN    ',
              'WRONG TABLE NO          ', _dst_tab);
&   endif
    (*ENDIF*) 
    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
            _jtrans_ptr :=
                  a685get_join_trans( dmli, jtrans, _src_tab, _dst_tab );
            IF  ( _jtrans_ptr^.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_ptr^.jt_jointype)
                    OR
                    (
                    (best_jstrat[ _dst_tab ].bjr_stratinfo.bj_jtype    =
                    _jtrans_ptr^.jt_jointype)
                    AND
                    ( best_jstrat[ _dst_tab ].bjr_stratinfo.bj_multiplier >
                    _jtrans_ptr^.jt_multipl)
                    )
                THEN
                    BEGIN
                    (* get better join transition *)
                    best_jstrat[ _dst_tab ].bjr_stratinfo.bj_jtype :=
                          _jtrans_ptr^.jt_jointype;
                    best_jstrat[ _dst_tab ].bjr_stratinfo.bj_multiplier :=
                          _jtrans_ptr^.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,
          jinfos.ji_use_operator_join );
    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_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_wholeIO_pages <
        table_stats[ _first_table ].ts_wholeIO_pages )
    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
&       ifdef trace
        IF  ( sequence_info.si_sequence^[ _j ].s_tableno > dmli.d_cntfromtab ) OR
            ( sequence_info.si_sequence^[ _i ].s_tableno > dmli.d_cntfromtab )
        THEN
            g01abort (-8888, 'JOIN    ',
                  'WRONG TABLE NO          ', 99999);
&       endif
        (*ENDIF*) 
        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;
            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;
      _jtrans_ptr          : tak68_join_transition_ptr;
      _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;
            _jtrans_ptr :=
                  a685get_join_trans( dmli, jtrans, _seq_table, _nonseq_table );
            IF  _jtrans_ptr^.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_ptr^.jt_jointype )
                    OR
                    (( _best_strat.bj_jtype = _jtrans_ptr^.jt_jointype )
                    AND
                    ( _best_strat.bj_multiplier > _jtrans_ptr^.jt_multipl ))
                THEN
                    BEGIN
                    _best_strat.bj_jtype      := _jtrans_ptr^.jt_jointype;
                    _best_strat.bj_multiplier := _jtrans_ptr^.jt_multipl;
                    _best_strat.bj_indexno    := _jtrans_ptr^.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;
            jtrans                : tak68_join_transitions;
            VAR sequence_info     : tak68_sequence_info;
            VAR jinfos            : tak68_joininfos;
            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
      _jtrans_ptr          : tak68_join_transition_ptr;
      _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
                _jtrans_ptr :=
                      a685get_join_trans( dmli, jtrans, _xi, _actual_table );
                IF  (_xi in context.jir_sequenced_tables)
                THEN
                    IF  ( _best_strat.bj_jtype > _jtrans_ptr^.jt_jointype)
                        OR
                        (
                        (_best_strat.bj_jtype = _jtrans_ptr^.jt_jointype)
                        AND
                        ( _best_strat.bj_multiplier > _jtrans_ptr^.jt_multipl)
                        )
                    THEN
                        BEGIN
                        _best_strat.bj_jtype      := _jtrans_ptr^.jt_jointype;
                        _best_strat.bj_multiplier := _jtrans_ptr^.jt_multipl;
                        _best_strat.bj_indexno    := _jtrans_ptr^.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, jinfos.ji_use_operator_join)
              <
              (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, jinfos, 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 jinfos         : tak68_joininfos;
            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;
      _jtrans_ptr           : tak68_join_transition_ptr;
      _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,
          jinfos.ji_use_operator_join );
    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;
                _jtrans_ptr :=
                      a685get_join_trans( dmli, jtrans, _seq_table, _nonseq_table );
                IF  _jtrans_ptr^.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, jinfos.ji_use_operator_join );
                        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_ptr^.jt_jointype)
                        AND
                        (context.
                        jir_best_jstrat^[ _nonseq_table ].bjr_stratinfo.bj_jtype =
                        _jtrans_ptr^.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_ptr^.
                              jt_jointype(*in*),
                              _jtrans_ptr^.
                              jt_multipl(*in*),
                              res_info, jinfos.ji_use_operator_join );
                        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_ptr^.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;
            jtrans                : tak68_join_transitions;
            VAR sequence_info     : tak68_sequence_info;
            VAR context           : tak681_jseq_info_record;
            VAR join_other_table  : boolean);
 
VAR
      _jtrans_ptr   : tak68_join_transition_ptr;
      _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;
    _jtrans_ptr :=
          a685get_join_trans( dmli, jtrans, _seq_table, _actual_table );
    IF  (_seq_table <> _actual_table)
        AND
        (_jtrans_ptr^.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_ptr^.jt_jointype)
            AND
            (_jtrans_ptr^.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_ptr^.jt_jointype > to_eq_field)
                  (* transition without access path and non-equal conditions *)
                  OR
                  (dmli.d_joins.jrc_joinarr^
                  [ _jtrans_ptr^.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_ptr^.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_ptr^.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_ptr^.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;
            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
        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 (table_stats[ _i ].ts_strategy, _pos, _ln.text);
        _ln.pos := _pos;
        _ln.pos := _ln.pos + 2;
        IF  table_stats[ _i ].ts_inv_only_strat
        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 (table_stats[ _i ].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 (table_stats[ _i ].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 (table_stats[ _i ].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 (table_stats[ _i ].ts_wholeIO_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    := ' 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 (table_stats[ _i ].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;
    (*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_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;
            succession : tak68_succession_ptr;
            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 dmli     : tak_dml_info;
            jtrans       : tak68_join_transitions;
            starttab     : tsp00_Int2;
            stoptab      : tsp00_Int2;
            table_cnt    : tsp00_Int2);
 
VAR
      _i              : tsp00_Int2;
      _j              : tsp00_Int2;
      _pos            : tsp00_Int2;
      _jtrans_ptr     : tak68_join_transition_ptr;
      _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
        _jtrans_ptr := a685get_join_trans( dmli, jtrans, _i, _j );
        CASE _jtrans_ptr^.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*)
            use_operator_join: boolean ) : tsp00_Longreal;
 
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 *),
      use_operator_join);
_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;
            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;
            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
&   ifdef TRACE
    t01real(ak_join, 'lowest_cost ', context.jir_lowest_cost, 6);
    t01real(ak_join, 'si_sum      ', sequence_info.si_sum, 6);
&   endif
    context.jir_lowest_cost       := sequence_info.si_sum;
    (*context.jir_lowest_succession := sequence_info.si_sequence;*)
    SAPDB_PascalForcedMove (
          dmli.d_cntfromtab * sizeof(tak68_succ),
          dmli.d_cntfromtab * sizeof(tak68_succ),
          @sequence_info.si_sequence^, 1,
          @context.jir_lowest_succession^, 1,
          dmli.d_cntfromtab * sizeof(tak68_succ));
    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
      _return        : boolean;
      _inv1PageCount : tsp00_Int4;
      _inv2PageCount : tsp00_Int4;
      _indexFileId   : tgg00_FileId;
 
BEGIN
(* returns true if index with no. invno1 is smaller than index with no. invno2 *)
g04index_tree_build_surr (tabid, _indexFileId, invno1);
bd03GetInvPageCount (acv.a_transinf.tri_trans, _indexFileId.fileTabId_gg00,
      _inv1PageCount);
IF  acv.a_transinf.tri_trans.trError_gg00 = e_ok
THEN
    BEGIN
    g04index_tree_build_surr (tabid, _indexFileId, invno2);
    bd03GetInvPageCount (acv.a_transinf.tri_trans, _indexFileId.fileTabId_gg00,
          _inv2PageCount);
    END;
(*ENDIF*) 
IF  acv.a_transinf.tri_trans.trError_gg00 = e_ok
THEN
    _return := _inv1PageCount < _inv2PageCount
ELSE
    _return := false;
(*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;
 
(*------------------------------*) 
 
PROCEDURE
      ak681tr_bstrat(
            debug       : tgg00_Debug;
            VAR bstrat  : tak681_best_jstrat);
 
BEGIN
t01p2int4 (debug, 'bj_srctab   ', bstrat.bjr_stratinfo.bj_srctab
      , 'bj_fieldcnt ', bstrat.bjr_stratinfo.bj_fieldcnt );
t01p2int4 (debug, 'bj_multip   ', bstrat.bjr_stratinfo.bj_multiplier
      , 'bj_indexno  ', bstrat.bjr_stratinfo.bj_indexno );
t01p2int4 (debug, 'bj_jtype    ', ord( bstrat.bjr_stratinfo.bj_jtype )
      , 'bjr_mtab_ind', bstrat.bjr_mtab_ind );
t01bool (debug, 'bjr_is_mt_jo', bstrat.bjr_is_mt_join );
t01real (debug, 'bjr_costs   ', bstrat.bjr_costs, 6 );
END;
 
&endif
(*------------------------------*) 
 
FUNCTION
      ak681init_context(
            VAR acv     : tak_all_command_glob;
            VAR dmli    : tak_dml_info;
            VAR context : tak681_jseq_info_record) : boolean;
 
VAR
 
      _cast  : RECORD
            CASE integer OF
                1 :
                    (addr: tsp00_Addr);
                2 :
                    (jptr : tak681_best_jstrat_arr_ptr);
                3 :
                    (sptr : tak68_succession_ptr);
                END;
            (*ENDCASE*) 
 
 
BEGIN
context.jir_best_jstrat       := NIL;
context.jir_lowest_succession := NIL;
context.jir_start_succession  := NIL;
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;
;
_cast.addr := gg941Allocate( acv.a_transinf.tri_trans,
      dmli.d_cntfromtab * sizeof(tak681_best_jstrat));
context.jir_best_jstrat       := _cast.jptr;
&ifdef trace
t01addr( ak_join, 'jir_best_jst', _cast.addr );
&endif
_cast.addr := gg941Allocate( acv.a_transinf.tri_trans,
      dmli.d_cntfromtab * sizeof(tak68_succ));
context.jir_lowest_succession  := _cast.sptr;
&ifdef trace
t01addr( ak_join, 'jir_lowest_s', _cast.addr );
&endif
_cast.addr := gg941Allocate( acv.a_transinf.tri_trans,
      dmli.d_cntfromtab * sizeof(tak68_succ));
context.jir_start_succession  := _cast.sptr;
&ifdef trace
t01addr( ak_join, 'jir_start_su', _cast.addr );
&endif
ak681init_context := ( context.jir_best_jstrat <> NIL ) AND
      ( context.jir_lowest_succession <> NIL ) AND
      ( context.jir_start_succession <> NIL );
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681finialize_context(
            VAR acv     : tak_all_command_glob;
            VAR context : tak681_jseq_info_record);
 
VAR
 
      _cast  : RECORD
            CASE integer OF
                1 :
                    (addr: tsp00_Addr);
                2 :
                    (jptr : tak681_best_jstrat_arr_ptr);
                3 :
                    (sptr : tak68_succession_ptr);
                END;
            (*ENDCASE*) 
 
 
BEGIN
IF  ( context.jir_best_jstrat <> NIL )
THEN
    BEGIN
    _cast.jptr := context.jir_best_jstrat;
&   ifdef trace
    t01addr( ak_join, 'jir_best_jst', _cast.addr );
&   endif
    gg941Deallocate( acv.a_transinf.tri_trans, _cast.addr );
    END;
(*ENDIF*) 
IF  ( context.jir_lowest_succession <> NIL )
THEN
    BEGIN
    _cast.sptr := context.jir_lowest_succession;
&   ifdef trace
    t01addr( ak_join, 'jir_lowest_s', _cast.addr );
&   endif
    gg941Deallocate( acv.a_transinf.tri_trans, _cast.addr );
    END;
(*ENDIF*) 
IF  ( context.jir_start_succession <> NIL )
THEN
    BEGIN
    _cast.sptr := context.jir_start_succession;
&   ifdef trace
    t01addr( ak_join, 'jir_start_su', _cast.addr );
&   endif
    gg941Deallocate( acv.a_transinf.tri_trans, _cast.addr );
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak681copy_context(
            VAR dmli  : tak_dml_info;
            VAR src   : tak681_jseq_info_record;
            VAR dst   : tak681_jseq_info_record);
 
BEGIN
dst.jir_sequenced_tables  := src.jir_sequenced_tables;
dst.jir_comp_sequences    := src.jir_comp_sequences;
dst.jir_i                 := src.jir_i;
dst.jir_non_best_trans    := src.jir_non_best_trans;
dst.jir_swap_cnt          := src.jir_swap_cnt;
dst.jir_last_swap_pos     := src.jir_last_swap_pos;
dst.jir_beststratcnt      := src.jir_beststratcnt;
dst.jir_max_tables        := src.jir_max_tables;
dst.jir_stop_sequence     := src.jir_stop_sequence;
dst.jir_better_seq_exists := src.jir_better_seq_exists;
dst.jir_filler            := src.jir_filler;
dst.jir_lowest_cost       := src.jir_lowest_cost;
SAPDB_PascalForcedMove (
      dmli.d_cntfromtab * sizeof(tak681_best_jstrat),
      dmli.d_cntfromtab * sizeof(tak681_best_jstrat),
      @src.jir_best_jstrat^, 1, @dst.jir_best_jstrat^, 1,
      dmli.d_cntfromtab * sizeof(tak681_best_jstrat));
SAPDB_PascalForcedMove (
      dmli.d_cntfromtab * sizeof(tak68_succ),
      dmli.d_cntfromtab * sizeof(tak68_succ),
      @src.jir_lowest_succession^, 1, @dst.jir_lowest_succession^, 1,
      dmli.d_cntfromtab * sizeof(tak68_succ));
SAPDB_PascalForcedMove (
      dmli.d_cntfromtab * sizeof(tak68_succ),
      dmli.d_cntfromtab * sizeof(tak68_succ),
      @src.jir_start_succession^, 1, @dst.jir_start_succession^, 1,
      dmli.d_cntfromtab * sizeof(tak68_succ));
END;
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
.PA 
