.nf
 
 
    ========== licence begin  GPL
    Copyright (C) 2000 SAP AG
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end
 
.fo
*****************************************************
Copyright by SAP AG, 2000
SAP Database Technology
 
Release :      Date : 2000-10-11
*****************************************************
modname : VAK80
changed : 2000-10-11
module  : Hint_Syntax
 
Author  : GertG
Created : 1999-10-13
Pretty  : 2001-09-04
*****************************************************
 
Purpose : Syntax analysis for Hints.
 
Define  :
 
        PROCEDURE
              a80_ahint_statement (
                    VAR acv : tak_all_command_glob;
                    subproc : tsp00_Int2;
                    putnode : tsp00_Int2);
 
        FUNCTION
              a80_hint_exists(
                    VAR acv        : tak_all_command_glob;
                    hint_type      : tsp00_Int2;
                    syntaxnode     : tsp00_Int4;
                    VAR hintnode   : tsp00_Int4) : boolean;
 
.CM *-END-* define --------------------------------------
***********************************************************
 
Use     :
 
        FROM
              Scanner : VAK01;
 
        PROCEDURE
              a01_next_symbol (VAR acv : tak_all_command_glob);
 
        PROCEDURE
              a01_call_put (
                    VAR acv  : tak_all_command_glob;
                    proc     : tak_procs;
                    subproc  : tsp_int2;
                    VAR curr_n : tsp_int2);
 
        PROCEDURE
              a01_put_node (
                    VAR acv    : tak_all_command_glob;
                    VAR curr_n : tsp_int2);
 
        FUNCTION
              a01_eqkey (
                    VAR a      : tak_keyword;
                    sqlmode    : tsp_sqlmode;
                    VAR b      : tsp_moveobj;
                    VAR scv    : tak_scanner_glob) : boolean;
&       IFDEF TRACE
 
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        PROCEDURE
              t01sname (
                    debug : tgg00_Debug;
                    nam : tsp00_Sname);
 
        PROCEDURE
              t01int4 (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    int      : tsp00_Int4);
 
        PROCEDURE
              t01bool (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    curr_bool: boolean);
&       ENDIF
 
.CM *-END-* use -----------------------------------------
***********************************************************
 
Synonym :
 
.CM *-END-* synonym -------------------------------------
***********************************************************
.CM -lll-
Code    :
 
 
(*------------------------------*) 
 
PROCEDURE
      a80_ahint_statement (
            VAR acv : tak_all_command_glob;
            subproc : tsp00_Int2;
            putnode : tsp00_Int2);
 
VAR
      _last_scv          : tak_scanner_glob;
      _tmp_scv           : tak_scanner_glob;
      _hint_n            : tsp00_Int2;
      _curr_n            : tsp00_Int2;
      _last_n            : tsp00_Int2;
      _first_n           : tsp00_Int2;
      _tmp_n             : tsp00_Int2;
      _keyword           : tak_keyword;
      _last_a_scv_index  : tsp00_Int2;
      _hint_syn_ok       : boolean;
      _restore_scv       : boolean;
      _put_node          : boolean;
      _hint_missing      : boolean;
 
BEGIN
&ifdef TRACE
t01int4( ak_syn, 'hint pos    ', acv.a_scv.sc_sypos );
t01int4( ak_syn, 'hint proc   ', subproc );
&endif
_last_a_scv_index := acv.a_scv_index;
_hint_syn_ok      := true;
_first_n          := 0;
a01_call_put( acv, a80, subproc, _hint_n );
(* use n_pos as node number of last putted node ! *)
acv.a_ap_tree^[ _hint_n ].n_pos := putnode;
(* tie new hint node *)
IF  ( acv.a_first_hint_node = csp_minint2 )
THEN
    (* this is the first hint node *)
    acv.a_first_hint_node := _hint_n
ELSE
    (* another hint node exists, tie this node *)
    BEGIN
    _last_n := acv.a_first_hint_node;
    WHILE ( acv.a_ap_tree^[ _last_n ].n_sa_level <> 0 ) DO
        _last_n := acv.a_ap_tree^[ _last_n ].n_sa_level;
    (*ENDWHILE*) 
    acv.a_ap_tree^[ _last_n ].n_sa_level := _hint_n;
    END;
(*ENDIF*) 
_last_scv  := acv.a_scv;
a01_next_symbol( acv );
(* scan comma seperated hint list *)
WHILE ( NOT (( _last_scv.sc_symb = s_asterisk ) AND
      ( acv.a_scv.sc_symb = s_divide ))
      AND
      ( acv.a_scv.sc_symb <> s_eof )) DO
    BEGIN
    _put_node     := false;
    _hint_missing := true;
    _keyword := 'ORDERED           ';
    IF  a01_eqkey( _keyword, acv.a_sqlmode,
        acv.a_cmd_part^.sp1p_buf, acv.a_scv )
    THEN
        BEGIN
        a01_call_put( acv, a80, cak_x_ordered_hint, _curr_n );
        _put_node     := true;
        _hint_missing := false;
&       ifdef trace
        t01sname( ak_syn, 'ORDERED     ' );
&       endif
        END;
    (*ENDIF*) 
    IF  ( _hint_missing )
    THEN
        BEGIN
        _keyword := 'KEYACCESS         ';
        IF  a01_eqkey( _keyword, acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv )
        THEN
            BEGIN
            a01_call_put( acv, a80, cak_x_keyaccess_hint, _curr_n );
            _put_node     := true;
            _hint_missing := false;
&           ifdef trace
            t01sname( ak_syn, 'KEYACCESS   ' );
&           endif
            END
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _hint_missing )
    THEN
        BEGIN
        _keyword := 'INDEXACCESS       ';
        IF  a01_eqkey( _keyword, acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv )
        THEN
            BEGIN
            (* 'INDEXACCESS[(INDEXNAME)]' *)
            a01_call_put( acv, a80, cak_x_indexaccess_hint, _curr_n );
            _put_node     := true;
            _hint_missing := false;
&           ifdef trace
            t01sname( ak_syn, 'INDEXACCESS ' );
&           endif
            _restore_scv := true;
            _tmp_scv     := acv.a_scv;
            a01_next_symbol( acv );
            IF  ( acv.a_scv.sc_symb = s_leftpar )
            THEN
                BEGIN
                a01_next_symbol( acv );
                IF  ( acv.a_scv.sc_symb = s_identifier )
                THEN
                    BEGIN
                    a01_put_node( acv, _tmp_n );
&                   ifdef trace
                    t01int4( ak_syn, '_tmp_n      ', _tmp_n );
&                   endif
                    a01_next_symbol( acv );
                    IF  ( acv.a_scv.sc_symb = s_rightpar )
                    THEN
                        (* tie index name node *)
                        BEGIN
                        acv.a_ap_tree^[ _curr_n ].n_sa_level := _tmp_n;
                        _restore_scv := false;
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            IF  _restore_scv
            THEN
                BEGIN
&               ifdef trace
                t01sname( ak_syn, 'restore scv ' );
&               endif
                acv.a_scv := _tmp_scv;
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _hint_missing )
    THEN
        BEGIN
        _keyword := 'KEYSCAN           ';
        IF  a01_eqkey( _keyword, acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv )
        THEN
            BEGIN
            a01_call_put( acv, a80, cak_x_keyscan_hint, _curr_n );
            _put_node     := true;
            _hint_missing := false;
&           ifdef trace
            t01sname( ak_syn, 'KEYSCAN     ' );
&           endif
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _hint_missing )
    THEN
        BEGIN
        _keyword := 'INDEXSCAN         ';
        IF  a01_eqkey( _keyword, acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv )
        THEN
            BEGIN
            a01_call_put( acv, a80, cak_x_indexscan_hint, _curr_n );
            _put_node     := true;
            _hint_missing := false;
&           ifdef trace
            t01sname( ak_syn, 'INDEXSCAN   ' );
&           endif
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _hint_missing )
    THEN
        BEGIN
        _keyword := 'BUILDRESULT       ';
        IF  a01_eqkey( _keyword, acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv )
        THEN
            BEGIN
            a01_call_put( acv, a80, cak_x_buildresult_hint, _curr_n );
            _put_node     := true;
            _hint_missing := false;
&           ifdef trace
            t01sname( ak_syn, 'BUILTRESULT ' );
&           endif
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _hint_missing )
    THEN
        BEGIN
        _keyword := 'ENABLE_MERGE      ';
        IF  a01_eqkey( _keyword, acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv )
        THEN
            BEGIN
            a01_call_put( acv, a80, cak_x_enablemerge_hint, _curr_n );
            _put_node     := true;
            _hint_missing := false;
&           ifdef trace
            t01sname( ak_syn, 'ENABLEMERGE ' );
&           endif
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _hint_missing )
    THEN
        BEGIN
        _keyword := 'DISABLE_INVONLY   ';
        IF  a01_eqkey( _keyword, acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv )
        THEN
            BEGIN
            a01_call_put( acv, a80, cak_x_disableinvonly_hint, _curr_n );
            _put_node     := true;
            _hint_missing := false;
&           ifdef trace
            t01sname( ak_syn, 'DISABLE_INVO' );
&           endif
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    ;
    IF  ( _hint_missing )
    THEN
        BEGIN
        _keyword := 'TRACE             ';
        IF  a01_eqkey( _keyword, acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv )
        THEN
            BEGIN
            a01_call_put( acv, a80, cak_x_trace_hint, _curr_n );
            _put_node     := true;
            _hint_missing := false;
&           ifdef trace
            t01sname( ak_syn, 'TRACE       ' );
&           endif
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _hint_missing )
    THEN
        BEGIN
        _keyword := 'L1_STRATEGY       ';
        IF  a01_eqkey( _keyword, acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv )
        THEN
            BEGIN
            a01_call_put( acv, a80, cak_x_L1_strat_hint, _curr_n );
            _put_node     := true;
            _hint_missing := false;
&           ifdef trace
            t01sname( ak_syn, 'L1_STRATEGY ' );
&           endif
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _hint_missing )
    THEN
        BEGIN
        _keyword := 'L2_STRATEGY       ';
        IF  a01_eqkey( _keyword, acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv )
        THEN
            BEGIN
            a01_call_put( acv, a80, cak_x_L2_strat_hint, _curr_n );
            _put_node     := true;
            _hint_missing := false;
&           ifdef trace
            t01sname( ak_syn, 'L2_STRATEGY ' );
&           endif
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _hint_missing )
    THEN
        BEGIN
        _keyword := 'L2_RANGE_STRATEGY ';
        IF  a01_eqkey( _keyword, acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv )
        THEN
            BEGIN
            a01_call_put( acv, a80, cak_x_L2_range_strat_hint, _curr_n );
            _put_node     := true;
            _hint_missing := false;
&           ifdef trace
            t01sname( ak_syn, 'L2_RANGE_STR' );
&           endif
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _hint_missing )
    THEN
        BEGIN
        _keyword := 'L2_MORE_STRATEGIES';
        IF  a01_eqkey( _keyword, acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv )
        THEN
            BEGIN
            a01_call_put( acv, a80, cak_x_L2_more_strat_hint, _curr_n );
            _put_node     := true;
            _hint_missing := false;
&           ifdef trace
            t01sname( ak_syn, 'L2_MORE_STRA' );
&           endif
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _hint_missing )
    THEN
        BEGIN
        _keyword := 'L2_STRAT_NO_OPTIM ';
        IF  a01_eqkey( _keyword, acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv )
        THEN
            BEGIN
            a01_call_put( acv, a80, cak_x_L2_strat_no_optim_hint, _curr_n );
            _put_node     := true;
            _hint_missing := false;
&           ifdef trace
            t01sname( ak_syn, 'L2_STR_NO_OP' );
&           endif
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _hint_missing )
    THEN
        BEGIN
        _keyword := 'IN_STRATEGY       ';
        IF  a01_eqkey( _keyword, acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv )
        THEN
            BEGIN
            a01_call_put( acv, a80, cak_x_in_strat_hint, _curr_n );
            _put_node     := true;
            _hint_missing := false;
&           ifdef trace
            t01sname( ak_syn, 'IN_STRATEGY ' );
&           endif
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  ( _hint_missing )
    THEN
        BEGIN
        _keyword := 'SUBQ_STRATEGY     ';
        IF  a01_eqkey( _keyword, acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv )
        THEN
            BEGIN
            a01_call_put( acv, a80, cak_x_subq_strat_hint, _curr_n );
            _put_node     := true;
            _hint_missing := false;
&           ifdef trace
            t01sname( ak_syn, 'SUBQ_STRAT  ' );
&           endif
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    ;
    (* tie new hint node *)
    IF  ( _put_node )
    THEN
        BEGIN
        IF  ( _first_n = 0 )
        THEN
            BEGIN
            _first_n := _curr_n;
            _last_n  := _curr_n;
            END
        ELSE
            BEGIN
            acv.a_ap_tree^[ _last_n ].n_lo_level := _curr_n;
            _last_n                              := _curr_n;
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    _last_scv := acv.a_scv;
    a01_next_symbol( acv );
    END;
(*ENDWHILE*) 
;
IF  ( NOT _hint_syn_ok )
THEN
    BEGIN
&   ifdef TRACE
    t01int4( ak_syn, 'hint syn err', acv.a_scv.sc_sypos );
&   endif
    acv.a_first_hint_node := csp_minint2;
    acv.a_scv_index       := _last_a_scv_index;
    END
ELSE
    BEGIN
    (* tie hint syntax tree *)
    acv.a_ap_tree^[ _hint_n ].n_lo_level := _first_n;
&   ifdef TRACE
    t01int4( ak_syn, 'first node  ', _first_n );
    t01int4( ak_syn, 'hint node   ', _hint_n );
&   endif
    END;
(*ENDIF*) 
a01_next_symbol( acv );
END;
 
(*------------------------------*) 
 
FUNCTION
      a80_hint_exists(
            VAR acv        : tak_all_command_glob;
            hint_type      : tsp00_Int2;
            syntaxnode     : tsp00_Int4;
            VAR hintnode   : tsp00_Int4) : boolean;
 
VAR
      _hint_n : tsp00_Int2;
      _tmp_n  : tsp00_Int2;
      _found  : boolean;
 
BEGIN
(* syntaxnode : select/insert/update/delete syntax node *)
_found := false;
IF  ( acv.a_first_hint_node <> csp_minint2 )
THEN
    BEGIN
&   ifdef TRACE
    t01int4(ak_sem, 'hint_type   ', hint_type);
    t01int4(ak_sem, 'syntaxnode  ', syntaxnode);
&   endif
    _hint_n := acv.a_first_hint_node;
    (* loop over all hint nodes *)
    REPEAT
        IF  ( acv.a_ap_tree^[ _hint_n ].n_pos = syntaxnode )
        THEN
            BEGIN
&           ifdef trace
            t01sname( ak_sem, 'hint start  ' );
&           endif
            _tmp_n := _hint_n;
            WHILE ( _tmp_n <> 0 ) AND NOT _found DO
                BEGIN
&               ifdef trace
                t01int4( ak_sem, 'check node  ', _tmp_n );
&               endif
                IF  ( acv.a_ap_tree^[ _tmp_n ].n_subproc = hint_type )
                THEN
                    BEGIN
                    _found   := true;
                    hintnode := _tmp_n;
                    END;
                (*ENDIF*) 
                _tmp_n := acv.a_ap_tree^[ _tmp_n ].n_lo_level;
                END;
            (*ENDWHILE*) 
            END;
        (*ENDIF*) 
        _hint_n := acv.a_ap_tree^[ _hint_n ].n_sa_level;
    UNTIL
        _found OR ( _hint_n = 0 );
    (*ENDREPEAT*) 
    END;
(*ENDIF*) 
;
&ifdef TRACE
t01bool(ak_sem, 'hint exists ', _found);
&endif
a80_hint_exists := _found;
END;
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
*-PRETTY-*  statements    :        182
*-PRETTY-*  lines of code :        489        PRETTYX 3.10 
*-PRETTY-*  lines in file :        616         1997-12-10 
.PA 
