/*!
 * @file
 * @brief Realizes pascal stub a686_create_join_result().
 *
 *  Realizes pascal/C++ connector and creates join result by means
 * of Join_JoinOperator.
 *
 * @author GertG
 * @ingroup Join
 *
 * @par last changed by:
 * <br>
 * $Author: d024980 $ $DateTime: 2006/08/14 15:36:46 $
 */
/*!
 * @addtogroup SQLManager
*/
/*!
 * @defgroup Join Join Execution
 * @ingroup SQLManager
*/

/*

    ========== licence begin  GPL
    Copyright (c) 2002-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




*/

#include "SAPDBCommon/SAPDB_Types.hpp"
#include "SAPDBCommon/ErrorsAndMessages/SAPDBErr_Assertions.hpp"
#include "RunTime/RTE_Crash.hpp"
#include "SAPDBCommon/SAPDB_AutoPtr.hpp"
#include "SAPDBCommon/MemoryManagement/SAPDBMem_NewDestroy.hpp"
#include "Join/Join_JoinOperator.hpp"
#include "Join/Join_JoinOperator2.hpp"
#include "Join/Join_IResultSetOperator.hpp"
#include "Join/Join_ResultSetInserter.hpp"
#include "Join/Join_ResultSetHashInserter.hpp"
#include "Join/Join_ResultSetAppenderEx.hpp"
#include "Join/Join_ResultSetAppender.hpp"
#include "Join/Join_ResultSetOneResult.hpp"
#include "Join/Join_ResultSetDistinctOneResult.hpp"
#include "Join/Join_ResultSetDistinct.hpp"
#include "Join/Join_ResultSetAggregator.hpp"
#include "Join/Join_ResultSetAggregatorOneGroup.hpp"
#include "Join/Join_ResultSetAggregator2.hpp"
#include "SQLManager/SQLMan_Context.hpp"
#include "SQLManager/SQLMan_MessBlock.hpp"
#include "SQLManager/SQLMan_Strategy.hpp"
#include "RunTime/RTE_Message.hpp"
#include "Table/Table_TempHashTable.hpp"
#include "gsp03.h"
#include "gsp03_1.h"
#include "ggg00.h"
#include "ggg07.h"
#include "ggg04.h"
#include "vak001.h"
#include "gak68.h"
#include "hak682.h"
#include "hak686.h"
#include "hta01.h"
#include "heo51.h" // vdebug_break()
#include "hkb720.h"
#include "hkb05.h"
#include "hak07.h"
#include "hak071.h"
#include "hgg01_1.h"
#include "hbd01.h"
#include "hsp41.h"
#include "hak680.h"
#include "hak502.h"
#include "hbd73.h"

//! \if false
namespace {
    
inline    
Join_IResultSetOperator* 
    CreateResultSetOperator( 
            SQLMan_Context&         acv,
            tak_dml_info&           dmli,
            Join_StackListPtr&      rec_desc,
            tgg00_FileId&           res_tree, 
            const SAPDB_Int4&       rescnt, 
            const SAPDB_Int4&       rescnt_setop, 
            const SAPDB_Int4&       maxresult, 
            const pasbool           stamp_record_counter,
            IOperator&              top_operator);

inline
void
    GetStrategyInfo( 
            SQLMan_Context&         acv,
            tgg00_FileId&           result_id,
            SAPDB_Int4&             rescnt,
            SAPDB_Int4&             union_offs,
            pasbool&                stamp_record_counter);

inline
void
    GetResultDescription(
            SQLMan_Context&         acv,
            Join_StackListPtr&      res_rec_desc);

} // anonymous namespace
//! \endif


//! routine which generates result of a join
/*!
 * @param acv [in] global context
 * @param dmli [in] statement context
 * @param sequence [in] reference to join table sequence array
 * @param parsk [in] parskey to be used
 * @param jvrec [in] join view record
 * @param use_old_rescnt [in] delete 'CreateFile' flag of result file?
 * @param del_parsinfos [in] delete parse infos?
 * @param b_err [out] information code <tt>[e_ok, e_no_next_record]</tt> / error code
 */
externPascal void a686_create_join_result (
    tak_all_command_glob  VAR_VALUE_REF  acv,
    tak_dml_info          VAR_VALUE_REF  dmli,
    const tak68_sequence  VAR_VALUE_REF  sequence,
    const tak_parskey     VAR_VALUE_REF  parsk,
    const tak68_joinview_rec  VAR_VALUE_REF  jvrec,
    const pasbool                        use_old_rescnt,
    const pasbool                        del_parsinfos,
    const tgg07_opjoin_usage_Param       opjoin_usage,
    tgg00_BasisError      VAR_VALUE_REF  b_err )
{
    SQLMan_Context &_rContext = SQLMan_Context::AcvToContext(acv);

    if  ( !_rContext.IsErrorListEmpty() )
    {
        RTE_Message( _rContext.GetErrorList() );
        _rContext.ResetErrorList();
    }

    SAPDBTRACE_ROUTINE_DEBUG( "a686_create_join_result", Join_Trace, 1 );
#ifdef SAPDB_SLOW
    SAPDB_ULong _usedbytes1, _maxusedbytes, _ctrlbyted1, _usedbytes2, _ctrlbyted2;
    _rContext.GetAllocator().CalcStatistics(_usedbytes1, _maxusedbytes, _ctrlbyted1);
    vdebug_break( 77777 );
#endif
    b_err = e_ok;

    SAPDBTRACE_IF( Join_Trace, 5, 
            t01messblock( td_always, "orig mblock ", _rContext.a_mblock ));
    SAPDBERR_ASSERT_STATE( m_select == _rContext.GetMessBlock().MessType() && mm_with_join == _rContext.GetMessBlock().MessType2() );

    //get max result
    SAPDB_Int4 _maxresult;
    k720_maxresult_get( _rContext.GetMessBlock().DataPtr(), dmli.d_rowno, _maxresult, b_err );
    if  ( _maxresult <= 1 ) 
    {   
        if (( cgg04_subquery_one_record == dmli.d_rowno || 
             cgg04_at_least_one_record == dmli.d_rowno ) &&
            ! dmli.d_pseudo_ins_select /* insert value = <select>*/ )
            // EXISTS clause, don't warn about exceeding ROWNO record count
            _maxresult = -1;
        else
            _maxresult = 1;
        SAPDBTRACE_WRITELN( Join_Trace, 3, "special maxresult : " << _maxresult );
    }
    if  ( e_ok != b_err ) a07_b_put_error( _rContext, b_err, 1 );

    // get result description from join messblock
    Join_StackListPtr _res_rec_desc( _rContext.GetAllocator() ) ;
    GetResultDescription( _rContext, _res_rec_desc );

    //get messblock of last sequenced table into _rContext
    a682j_one_record( _rContext, dmli, dmli.d_cntfromtab, 
            sequence[dmli.d_cntfromtab-1].jos_source, 
            parsk, jvrec, use_old_rescnt, del_parsinfos );

    tgg00_FileId _result_id;
    SAPDB_Bool _restree_created = false; 
    pasbool _stamp_record_counter = false;
    SAPDB_Int4 _rescnt, _rescnt_start, _rescnt_start_setop;

    GetStrategyInfo( _rContext, _result_id, _rescnt_start, 
                _rescnt_start_setop, _stamp_record_counter );

    if ( _rContext.IsOk() )
    {
        // create result file
        if ( ! dmli.d_single && _result_id.fileHandling_gg00().includes( hsCreateFile_egg00 ) )
        {
            b01tcreate_file( _rContext.TransContext(), _result_id );
            if ( e_ok != _rContext.TransContext().trError_gg00 )
                a07_b_put_error( _rContext, _rContext.TransContext().trError_gg00, 1 );
            else
                _restree_created = true;
        }

        SAPDB_AutoPtr<IOperator> _TopJoinOp( _rContext.GetAllocator() );
        //initialize top join operator
        if  ( jopu_op_legacy == opjoin_usage )
        {
            b73cmd_count(ijoin_op_normal);
            _TopJoinOp.SetPtr( new( _rContext.GetAllocator() ) 
                    Join_JoinOperator( _rContext, dmli, parsk, jvrec, 
                    use_old_rescnt, del_parsinfos, sequence, 
                    dmli.d_cntfromtab ) );
        }
        else
        {
           // jopu_op_improved == opjoin_usage
            b73cmd_count(ijoin_op_improved);
            _TopJoinOp.SetPtr( new( _rContext.GetAllocator() ) 
                    Join_JoinOperator2( _rContext, dmli, parsk, jvrec, 
                    use_old_rescnt, del_parsinfos, sequence, 
                    dmli.d_cntfromtab ) );
        }

        if ( _rContext.IsOk() )
        {
            tgg00_Rec* _record;
            SAPDB_AutoPtr<Join_IResultSetOperator> 
                _ResultInserter( _rContext.GetAllocator() );

            if ( _ResultInserter.SetPtr( 
                    CreateResultSetOperator(_rContext, dmli, _res_rec_desc, 
                        _result_id, _rescnt_start, _rescnt_start_setop, 
                        _maxresult, _stamp_record_counter, *_TopJoinOp)) &&
                 _rContext.IsOk() )
            {
                _ResultInserter->Open();
                if ( _rContext.IsOk() )
                {
                    b_err = _TopJoinOp->Open();
                    while ( e_ok == b_err &&
                          e_ok == ( b_err = _TopJoinOp->Next( _record ) ) && 
                            _rContext.IsOk() )
                    {
                        b_err = _ResultInserter->Add( *_record );
                    }
                    _TopJoinOp->Close();

                }
                _ResultInserter->Close();
                _rescnt = _ResultInserter->ResultCount();
                SAPDBTRACE_WRITELN( Join_Trace, 3, "ResultCount(): " << _rescnt );
            }
        }
    }
    SAPDBTRACE_WRITELN( Join_Trace, 3, "b_err: " << SAPDBTrace::BasisError(b_err) );

    if ( _rContext.IsOk() && ( e_ok == b_err || e_no_next_record == b_err ))
    {
        if  ( 0 == _rescnt && _restree_created )
        {
            // what about first part of UNION , could we delete this file ?    
            b01destroy_file( _rContext.TransContext(), _result_id );
            a502empty_result( _rContext, dmli, _result_id );
        }
        _rContext.GetMessBlock().MessStructure().becomes( mbs_result );
        _rContext.GetMessBlock().MessType().becomes( m_return_result );
        _rContext.GetMessBlock().mb_qual()->mr_restree()   = _result_id;
        _rContext.GetMessBlock().mb_qual()->mr_res_build() = true;
        // set result count into messblock
        tsp00_NumError _res_err;
        s41p4int( _rContext.GetMessBlock().mb_qual()->mr_resnum(), 2, _rescnt, _res_err );
        _rContext.GetMessBlock().mb_qual()->mr_resnum()[ 0 ] = csp_defined_byte;
        _rContext.GetMessBlock().mb_qual()->mr_pagecnt() =
              _rContext.TransContext().trRteCommPtr_gg00->file_record_cnt;
        if  ( 0 == _rescnt || !dmli.d_single )
            _rContext.GetMessBlock().DataLength()  = 0;
        if ( dmli.d_single && 0 == _rescnt )
            a07_b_put_error( _rContext, e_no_next_record, 1 );
        if ( dmli.d_pseudo_ins_select /* insert values comes from a <select> clause */
             && _rContext.TransContext().trWarning_gg00.includes(warn12_rowno_used) )
            a07_b_put_error( _rContext, e_too_many_resultsets, 1 );
    }
    else
    {
        kb05ReturnErrorHandling( _rContext.TransContext(), false, m_select );
        _rContext.GetMessBlock().MessType().becomes( m_return_error );
        _rContext.GetMessBlock().MessStructure().becomes( mbs_nil );
        _rContext.GetMessBlock().QualLength() = 0;
        _rContext.GetMessBlock().DataLength() = 0;
        if  ( e_rollback_wanted == b_err || 
            acv.a_returncode == a07_return_code( e_rollback_wanted, _rContext.a_sqlmode))
        {
            _rContext.a_rollback_info.clear();
            _rContext.a_rollback_info.addElement( trans_rollback );
            _rContext.a_rollback_info.addElement( new_trans );
            _rContext.TransContext().trError_gg00 = e_work_rolled_back;
            a07_b_put_error( _rContext, e_work_rolled_back, 1 );
        }
        else
        {
            a07_b_put_error( _rContext, b_err, 1 );
        }
        if  ( del_parsinfos )
        {
            // delete parsinfo's that have not been
            // deleted by ak682_tmpbuf_to_mbuf()
            a680rollback_temp_jinfo( _rContext, dmli, parsk, jvrec.jv_tabid,
                  dmli.d_cntfromtab );
        }
        if  ( _restree_created )
            b01destroy_file( _rContext.TransContext(), _result_id );
    }
#ifdef SAPDB_SLOW
    _rContext.GetAllocator().CalcStatistics(_usedbytes2, _maxusedbytes, _ctrlbyted2);
    if ( ! _usedbytes1 == _usedbytes2 )
        RTE_Crash( SAPDBErr_Exception( __CONTEXT__, SAPDBERR_ASSERT_STATE_FAILED, "(join exec memory leek)"));
#endif
}


namespace {
//! Create operator which adds records to result set
/*!
 * @param acv [in] global context
 * @param dmli [in] statement context
 * @param rec_desc [in] pointer to result record description
 * @param result_id [in] name of result file
 * @param rescnt [in] amount of records exists in result generated by former 'MASS SELECT' command
 * @param rescnt_setop [in] amount of records exits in result generated by former part of a set operation
 * @param maxresult [in] maximal amount of result set
 * @param top_operator [in] join operator deliveres records
 * @return pointer to a Join_IResultSetOperator corresponding desired properties like distinctness and others
 */
inline 
Join_IResultSetOperator* 
    CreateResultSetOperator( 
            SQLMan_Context&         acv,
            tak_dml_info&           dmli,
            Join_StackListPtr&      rec_desc,
            tgg00_FileId&           result_id, 
            const SAPDB_Int4&       rescnt, 
            const SAPDB_Int4&       rescnt_setop, 
            const SAPDB_Int4&       maxresult, 
            const pasbool           stamp_record_counter,
            IOperator&              top_operator)
{
    SAPDBTRACE_ROUTINE_DEBUG( "CreateResultSetOperator", Join_Trace, 1 );
    SAPDBTRACE_WRITELN( Join_Trace, 3, "keylen: " << top_operator.GetKeyLength() << "\tselinto: " << dmli.d_single << "\tdistinct: " << dmli.d_distinct );
    SAPDBTRACE_WRITELN( Join_Trace, 3, "a_union_kind: " << acv.a_union_kind << "\ta_union_cnt: " << acv.a_union_cnt );
    SAPDBTRACE_WRITELN( Join_Trace, 3, "warning about ROWNO: " << (maxresult < 0) );

    bool _aggr_func = false, _one_result = ( RESCNT_MXGG04 == top_operator.GetKeyLength() ) ;
    Table_FixSizeEntry_FieldDescription _field_desc( acv.GetAllocator() );
    Table_FixSizeEntry_KeyNoList _key_desc( acv.GetAllocator() );
    _field_desc.Reserve(10); _key_desc.Reserve(5);
    bool _mem_ok = true;

    for ( SAPDB_Int4 _i = 1; _i <= (*rec_desc)[ 0 ].epos() - 1; ++_i )
    {
        if ( st_func == (*rec_desc)[ _i - 1 ].etype() )
            _aggr_func = true;
        else
        {
            if ( st_output == (*rec_desc)[ _i - 1 ].etype() )
            {
                if  ( op_o_output_later == (*rec_desc)[ _i - 1 ].eop_out() )
                    _one_result = true;

                _mem_ok = _mem_ok && _field_desc.InsertEnd( 
                        Table_OffsetLengthTuple( (*rec_desc)[ _i - 1 ].epos()-1, 
                                                 (*rec_desc)[ _i - 1 ].elen_var() ));
                if  ( (*rec_desc)[ _i - 1].epos() < 
                       cgg_rec_key_offset + top_operator.GetKeyLength() )
                    _mem_ok = _mem_ok && _key_desc.InsertEnd( _field_desc.GetSize() - 1 );
                if ( !_mem_ok )
                {
                    a07_b_put_error( acv, e_no_more_memory, 1 );
                    return 0;
                }
            }
        }
    }
#ifdef SAPDB_SLOW
    if ( Join_Trace.TracesLevel( 3 ) )
    {
        SAPDBTRACE_WRITELN( Join_Trace, 3, "_field_desc: " << _field_desc.GetSize() );
        for ( Table_FixSizeEntry_FieldDescription::Iterator _i = _field_desc.Begin(); _i != _field_desc.End(); ++_i )
        {
            SAPDBTRACE_WRITELN( Join_Trace, 3, "offs " << (*_i).Offset << " \tlen " << (*_i).Length );
        }
        SAPDBTRACE_WRITELN( Join_Trace, 3, "_key_desc: " << _key_desc.GetSize() );
        for ( Table_FixSizeEntry_KeyNoList::Iterator _j = _key_desc.Begin(); _j != _key_desc.End(); ++_j )
        {
            SAPDBTRACE_WRITELN( Join_Trace, 3, "field idx " << *_j );
        }
    }
#endif
    
    if ( _aggr_func )
    {
        Join_IResultSetOperator *_p = 0;
        if ( gg01_hashed_resultset )
        {
            _p = new( acv.GetAllocator() ) 
                Join_ResultSetAggregator2( acv, rec_desc, result_id, 
                        rescnt, maxresult, dmli.d_single, _one_result, 
                        _field_desc, _key_desc,
                        top_operator );
            if ( acv.IsOk() ) 
                return _p;
            else if ( a07_return_code( e_no_more_memory, acv.a_sqlmode ) == acv.ReturnCode())
            {
                // we can't construct Join_ResultSetAggregator2
                destroy( _p, acv.GetAllocator() );
                acv.a_returncode = 0;
                acv.a_ak_b_err = e_ok;
                RTE_Message( SAPDBErr_MessageList( 
                            "JOIN", __FILE__, __LINE__, 
                            SAPDBErr_MessageList::Info, csp3_ak_msg, 
                            "Join_ResultSetAggregator2 failed - fall back to Join_ResultSetAggregator", 0) );
            } else
                return 0; // any other error
        }
    
        if ( _one_result )
        {
            _p = new( acv.GetAllocator() ) 
                Join_ResultSetAggregatorOneGroup( acv, rec_desc, result_id, maxresult, top_operator, dmli.d_single );
            return _p;
        } else {
            _p = new( acv.GetAllocator() ) 
                Join_ResultSetAggregator( acv, rec_desc, result_id, rescnt, maxresult, top_operator );
            return _p;
        }
    }
    else
    {
        if ( dmli.d_single )
        {
            if ( dmli.d_distinct != no_distinct )
                return new( acv.GetAllocator() ) 
                    Join_ResultSetDistinctOneResult( acv, rec_desc, top_operator );
            else
                return new( acv.GetAllocator() ) 
                    Join_ResultSetOneResult( acv, rec_desc, top_operator );
        }
        else
        {
            if ( dmli.d_distinct != no_distinct )
            {
                // SELECT DISTINCT or distinct set operation
                if ( distinct_without_warning_byte == dmli.d_distinct )
                    a07_b_put_error( acv, e_not_implemented, 1 );
                if ( stamp_record_counter )
                    return new( acv.GetAllocator() ) 
                        // ROWNUM makes tuple distinct !
                        Join_ResultSetAppenderEx( acv, rec_desc, result_id, rescnt, maxresult );
                else
                    return new( acv.GetAllocator() ) 
                        Join_ResultSetDistinct( acv, rec_desc, result_id, rescnt, maxresult );
            }
            else
            {
                /*
                 * set operations not implemented with join selects with
                 * new C++ implementation
                 *
                if ( acv.a_union_kind != 0 || acv.a_union_cnt != 0 )
                {
                    // join is part of set operation
                    if ( acv.a_union_kind != 0 )
                    {
                        if ( acv.a_union_kind < cgg04_union_append )
                        {
                            return new( acv.GetAllocator() ) 
                                Join_ResultSetHashInserter( acv, result_id, rescnt, maxresult );
                        }
                        else
                        {
                            return new( acv.GetAllocator() ) 
                                Join_ResultSetAppenderEx( acv, result_id, rescnt, maxresult, rescnt_setop );
                        }
                    }
                    else
                    {
                        return new( acv.GetAllocator() ) 
                            Join_ResultSetAppenderEx( acv, result_id, rescnt, maxresult );
                    }
                }
                else
                */
                {
                    if ( top_operator.GetKeyLength() > RESCNT_MXGG04 )
                    {
                        return new( acv.GetAllocator() ) 
                            Join_ResultSetInserter( acv, rec_desc, result_id, rescnt, maxresult );
                    }
                    else
                    {
                        return new( acv.GetAllocator() ) 
                            Join_ResultSetAppender( acv, rec_desc, result_id, rescnt, maxresult );
                    }
                }
            }
        }
    }
}

//! extract some info from strategy info pool
/*!
 * @param acv [in] global context
 * @param result_id [out] name of result file
 * @param rescnt [out] amount of records exists in result generated by former 'MASS SELECT' command
 * @param union_offs [out] amount of records exits in result generated by former part of a set operation
 * @param stamp_record_counter [out] write record counter (ROWNUM) into record
 */
inline
void
    GetStrategyInfo( 
            SQLMan_Context&         acv,
            tgg00_FileId&           result_id,
            SAPDB_Int4&             rescnt,
            SAPDB_Int4&             union_offs,
            pasbool&                stamp_record_counter)
{
    SQLMan_Strategy *_pStrategy = acv.GetMessBlock().GetStrategyPtr();
    
    if ( _pStrategy )
    {
        result_id = _pStrategy->str_result_id;
        rescnt = _pStrategy->str_foundresults; // results already in result
        union_offs = _pStrategy->str_union_key_cnt_offs; // results already in result for set operations
        stamp_record_counter = _pStrategy->str_use_rowno; // write ROWNUM
    } 
    else
    {
        a07_b_put_error( acv, e_unknown_strategy, 1 );
        g01opmsg( sp3p_knldiag, sp3m_error, csp3_ak_msg,
              csp3_n_join, "MISSING STRATEGY INFO   ", 1 );
    }
}

//! extract result descption
/*!
 * @param acv [in] global context
 * @param res_rec_desc [out] pointer to result description
 */
inline
void
    GetResultDescription(
            SQLMan_Context&         acv,
            Join_StackListPtr&      res_rec_desc)
{
    SAPDBTRACE_ROUTINE_DEBUG( "GetResultDescription", Join_Trace, 1 );
    SAPDB_UInt2 _stackentry_cnt;
    if ( acv.GetMessBlock().HasResultOutputCols() )
    {
        _stackentry_cnt = acv.GetMessBlock().GetResOutputDescCount();
        res_rec_desc.SetPtr( (tgg00_StackList*) acv.GetAllocator().Allocate( _stackentry_cnt * sizeof( tgg00_StackEntry )) );
        if (  res_rec_desc.IsAssigned() )
            SAPDB_MemCopyNoCheck( res_rec_desc.GetPtr(), acv.GetMessBlock().StackEntryPtr( acv.GetMessBlock().ResQualPos() - 1 ), 
                    _stackentry_cnt * sizeof( tgg00_StackEntry ) );

    }
    else
    {
        SAPDBERR_ASSERT_STATE( acv.GetMessBlock().HasOutputCols() );
        _stackentry_cnt = acv.GetMessBlock().GetOutputDescCount();
        res_rec_desc.SetPtr( (tgg00_StackList*) acv.GetAllocator().Allocate( _stackentry_cnt * sizeof( tgg00_StackEntry )) );
        if (  res_rec_desc.IsAssigned() )
            SAPDB_MemCopyNoCheck( res_rec_desc.GetPtr(), acv.GetMessBlock().StackEntryPtr( acv.GetMessBlock().QualPos() - 1 ), 
                    _stackentry_cnt * sizeof( tgg00_StackEntry ) );
    }
    if ( ! res_rec_desc.IsAssigned() )
        a07_b_put_error( acv, e_no_more_memory, 1 );
#ifdef SAPDB_SLOW
    else
    {
        SAPDBTRACE_WRITELN( Join_Trace, 1, "result description: " );
        for ( SAPDB_Int4 _i = 1; _i < (*res_rec_desc)[0].epos(); ++_i)
        {
            SAPDBTRACE_IF ( Join_Trace, 1, t01stackentry( td_always, (*res_rec_desc)[_i-1], _i));
        }
    }
#endif
}

} // anonymous namespace

