.ad 8
.bm 8
.fm 4
.bt $Copyright (c) 2000-2004 SAP AG$$Page %$
.tm 12
.hm 6
.hs 3
.tt 1 $SQL$Project Distributed Database System$VAK664$
.tt 2 $$$
.TT 3 $ThomasA$Complex_View_Optimization$$1999-02-17$
***********************************************************
.nf
 
 
    ========== licence begin  GPL
    Copyright (c) 2000-2004 SAP AG
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end
 
.fo
.nf
.sp
MODULE  : Complex_View_Optimization
=========
.sp
Purpose :
.CM *-END-* purpose -------------------------------------
.sp
.cp 3
Define  :
 
        PROCEDURE
              a664col_info (
                    VAR acv  : tak_all_command_glob;
                    extcolno : integer;
                    colno    : integer;
                    colpos   : integer;
                    startnode: integer);
 
        PROCEDURE
              a664complex_view_optimize (
                    VAR acv              : tak_all_command_glob;
                    VAR try_optimization : boolean);
 
        PROCEDURE
              a664dispose_opt_info (VAR acv : tak_all_command_glob);
 
        PROCEDURE
              a664new_optimize_info (
                    VAR acv    : tak_all_command_glob;
                    VAR dmli   : tak_dml_info;
                    table_node : integer;
                    end_node   : integer);
 
.CM *-END-* define --------------------------------------
.sp;.cp 3
Use     :
 
        FROM
              Scanner : VAK01;
 
        VAR
              a01fullset : tak_columnset;
 
        PROCEDURE
              a01_get_keyword (
                    VAR acv   : tak_all_command_glob;
                    VAR index : integer;
                    VAR reserved : boolean);
 
        PROCEDURE
              a01_next_symbol (VAR acv : tak_all_command_glob);
 
      ------------------------------ 
 
        FROM
              AK_universal_semantic_tools : VAK06;
 
        PROCEDURE
              a06extcolno (
                    VAR baserec  : tak_baserecord;
                    extcolno     : integer;
                    VAR col_ptr  : tak00_colinfo_ptr);
 
        PROCEDURE
              a06_get_priv  (
                    VAR acv     : tak_all_command_glob;
                    VAR brec    : tak_sysbufferaddress;
                    VAR priv    : tak_privilege);
 
        PROCEDURE
              a06_systable_get (
                    VAR acv      : tak_all_command_glob;
                    dstate       : tak_directory_state;
                    VAR tableid  : tgg00_Surrogate;
                    VAR base_ptr : tak_sysbufferaddress;
                    get_all      : boolean;
                    VAR ok       : boolean);
 
      ------------------------------ 
 
        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
              Systeminfo_cache : VAK10;
 
        PROCEDURE
              a10dispose (
                    VAR acv : tak_all_command_glob;
                    VAR p : tak_sysbufferaddress);
 
        PROCEDURE
              a10new (
                    VAR acv  : tak_all_command_glob;
                    obj_size : tsp00_Int4;
                    VAR p    : tak_sysbufferaddress);
 
      ------------------------------ 
 
        FROM
              AK_distributor : VAK35;
 
        PROCEDURE
              a35_asql_statement (VAR acv : tak_all_command_glob);
 
      ------------------------------ 
 
        FROM
              DML_Help_Procedures : VAK542;
 
        PROCEDURE
              a542internal_packet (
                    VAR acv                 : tak_all_command_glob;
                    release_internal_packet : boolean;
                    required_len            : tsp00_Int4);
 
        PROCEDURE
              a542next_intern_sql_cmd (
                    VAR acv        : tak_all_command_glob;
                    release_packet : boolean;
                    VAR tree       : tgg00_FileId;
                    VAR key_int    : tsp00_Int2);
 
        PROCEDURE
              a542release_packet (
                    VAR acv  : tak_all_command_glob;
                    segm_ptr : tsp1_segment_ptr);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_1 : VBD01;
 
        PROCEDURE
              b01empty_file (
                    VAR t       : tgg00_TransContext;
                    VAR file_id : tgg00_FileId);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_2 : VBD07;
 
        PROCEDURE
              b07cget_record (
                    VAR t       : tgg00_TransContext;
                    VAR file_id : tgg00_FileId;
                    VAR rk      : tgg00_Lkey;
                    VAR b       : tgg00_Rec);
 
      ------------------------------ 
 
        FROM
              Configuration_Parameter : VGG01;
 
        VAR
              g01unicode        : boolean;
 
      ------------------------------ 
 
        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_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
              g10mv (
                    mod_id      : tsp00_C6;
                    mod_num     : tsp00_Int4;
                    source_upb  : tsp00_Int4;
                    dest_upb    : tsp00_Int4;
                    source      : tsp00_MoveObjPtr;
                    src_pos     : tsp00_Int4;
                    destin      : tsp00_MoveObjPtr;
                    dest_pos    : tsp00_Int4;
                    length      : tsp00_Int4;
                    VAR e       : tgg00_BasisError);
 
        PROCEDURE
              s10mv (
                    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);
&       ifdef trace
 
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        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
              t01segment (
                    debug       : tgg00_Debug;
                    VAR segm    : tsp1_segment);
 
        PROCEDURE
              t01moveobj (
                    debug       : tgg00_Debug;
                    VAR moveobj : tsp00_MoveObj;
                    startpos    : tsp00_Int4;
                    endpos      : tsp00_Int4);
&       endif
 
.CM *-END-* use -----------------------------------------
.sp;.cp 3
Synonym :
 
.CM *-END-* synonym -------------------------------------
.sp;.cp 3
Author  : ThomasA
.sp
.cp 3
Created : 1992-02-14
.sp
.cp 3
.sp
.cp 3
Release :      Date : 1999-02-17
.sp
***********************************************************
.sp
.cp 10
.fo
.oc _/1
Specification:
 
 
.CM *-END-* specification -------------------------------
.sp 2
***********************************************************
.sp
.cp 10
.fo
.oc _/1
Description:
 
.sp 2
.CM *-END-* description ---------------------------------
.sp 2
***********************************************************
.sp
.cp 10
.nf
.oc _/1
Structure:
 
.CM *-END-* structure -----------------------------------
.sp 2
**********************************************************
.sp
.cp 10
.nf
.oc _/1
.CM -lll-
Code    :
 
 
CONST
      cak664add_comma       = true;
      cak664add_colname     = -2;
      cak664max_opt_info    = 512;
      cak664table_indicator = -1;
      cak664release_packet  = true;
 
TYPE
 
      tak664one_opt_info = RECORD
            ooi_pos   : tsp00_Int4;
            ooi_len   : tsp00_Int2;
            ooi_extno : tsp00_Int2;
            ooi_colno : tsp00_Int2;
            ooi_fill1 : tsp00_Int2;
            ooi_fill2 : tsp00_Int4
      END;
 
 
      tak664opt_info = RECORD
            oi_tabid       : tgg00_Surrogate;
            oi_base_p      : tak_sysbufferaddress;
            oi_priv        : tak_privilege;
            oi_cmd_no      : integer;
            oi_count       : integer;
            oi_index       : integer;
            oi_maxcol      : integer;
            oi_sublevel    : integer;
            oi_start_node  : integer;
            oi_in_sel_list : boolean;
            oi_optimize    : boolean;
            oi_char_size   : integer;
            oi_info  : ARRAY[1..cak664max_opt_info] OF tak664one_opt_info;
      END;
 
 
      tak664sel_list_info = RECORD
            sli_cnt  : integer;
            sli_aggr : boolean;
            sli_info : ARRAY[0..MAX_COL_PER_TAB_GG00] OF RECORD
                  sli_pos : tsp00_Int4;
                  sli_len : tsp00_Int4;
            END;
 
      END;
 
 
      tak664tree_info = RECORD
            ti_qual_found  : boolean;
            ti_select_node : tsp00_Int4;
            ti_from_start  : tsp00_Int4;
            ti_from_end    : tsp00_Int4;
            ti_qual_end    : tsp00_Int4;
            ti_end         : tsp00_Int4;
      END;
 
 
      tak664opt_info_ptr = RECORD
            CASE boolean OF
                true :
                    (oi : ^tak664opt_info);
                false :
                    (sys : tak_sysbufferaddress);
                END;
            (*ENDCASE*) 
 
 
 
(*------------------------------*) 
 
PROCEDURE
      a664col_info (
            VAR acv  : tak_all_command_glob;
            extcolno : integer;
            colno    : integer;
            colpos   : integer;
            startnode: integer);
 
VAR
      found  : boolean;
      ix     : integer;
      jx     : integer;
      pos    : tsp00_Int4;
      oi_ptr : tak664opt_info_ptr;
 
BEGIN
WITH acv, a_scv DO
    BEGIN
&   ifdef trace
    t01int4 (ak_strat, 'extcolno    ', extcolno);
    t01int4 (ak_strat, 'colpos      ', colpos);
&   endif
    oi_ptr.sys := a_opt_info_ptr;
    WITH oi_ptr.oi^ DO
        IF  oi_start_node = startnode
        THEN
            BEGIN
            pos := colpos;
            IF  pos > 0
            THEN
                IF  a_cmd_part^.sp1p_buf[pos - 1] = '"'
                THEN
                    pos := pos - oi_char_size;
                (*ENDIF*) 
            (*ENDIF*) 
            found := false;
            ix    := 1;
            WHILE (ix <= oi_count) AND NOT found DO
                IF  oi_info[ix].ooi_pos < pos
                THEN
                    ix := ix + 1
                ELSE
                    found := true;
                (*ENDIF*) 
            (*ENDWHILE*) 
            IF  found
            THEN (* entry with same position found *)
                IF  oi_info[ix].ooi_pos = pos
                THEN
                    BEGIN
                    jx := ix;
                    WHILE jx <= oi_count DO
                        WITH oi_info[jx] DO
                            IF  ooi_pos <> pos
                            THEN
                                jx := csp_maxint2
                            ELSE
                                IF  (ooi_extno = extcolno) AND
                                    (ooi_colno = colno)
                                THEN
                                    BEGIN
                                    (* entry already stored *)
                                    ix := 0;
                                    jx := csp_maxint2
                                    END
                                ELSE
                                    BEGIN
                                    jx := jx + 1;
                                    ix := jx
                                    END;
                                (*ENDIF*) 
                            (*ENDIF*) 
                        (*ENDWITH*) 
                    (*ENDWHILE*) 
                    END;
                (*ENDIF*) 
            (*ENDIF*) 
            IF  ix <> 0
            THEN
                BEGIN
                oi_count := oi_count + 1;
                IF  oi_count > cak664max_opt_info
                THEN (* no optimization possible *)
                    BEGIN
                    ix := 0;
                    a664dispose_opt_info (acv)
                    END
                ELSE
                    BEGIN
                    IF  ix < oi_count
                    THEN
                        FOR jx := oi_count - 1 DOWNTO ix DO
                            oi_info[jx + 1] := oi_info[jx];
                        (*ENDFOR*) 
                    (*ENDIF*) 
                    WITH oi_info[ix] DO
                        BEGIN
&                       ifdef trace
                        t01int4 (ak_sem, 'stored      ', 1);
&                       endif
                        ooi_extno := extcolno;
                        ooi_pos   := pos;
                        ooi_colno := colno;
                        ooi_len   := 0;
                        IF  pos > 0
                        THEN
                            BEGIN
                            sc_newpos := ooi_pos;
                            a01_next_symbol (acv);
                            IF  ooi_pos = colpos
                            THEN
                                ooi_len := sc_sylength
                            ELSE
                                ooi_len := sc_sylength +
                                      2 * oi_char_size;
                            (*ENDIF*) 
                            a01_next_symbol (acv);
                            IF  sc_symb = s_point
                            THEN
                                BEGIN
                                a01_next_symbol (acv);
                                ooi_len := sc_sypos +
                                      sc_sylength - ooi_pos +
                                      a_scv.sc_double_quote
                                END;
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDWITH*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
    (*ENDWITH*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a664complex_view_optimize (
            VAR acv              : tak_all_command_glob;
            VAR try_optimization : boolean);
 
CONST
      c_get_all         = true;
      c_unknown_end_pos = csp_maxint4;
      c_reserve         = 256;
 
VAR
      ok              : boolean;
      add_colname     : boolean;
      expand_asterisk : boolean;
      init_ex_kind    : tak_execution_kind;
      init_sqlmode    : tsp00_SqlMode;
      init_dt_format  : tgg00_DateTimeFormat;
      ix              : integer;
      col_ptr         : tak00_colinfo_ptr;
      offset          : tsp00_Int4;
      sel_col_index   : integer;
      prev_col_index  : integer;
      qual_len        : tsp00_Int4;
      qual_end_pos    : tsp00_Int4;
      aux_pos         : tsp00_Int4;
      aux_len         : tsp00_Int4;
      select_segm     : tsp1_segment_ptr;
      select_part     : tsp1_part_ptr;
      view_segm       : tsp1_segment_ptr;
      new_cmd_segm    : tsp1_segment_ptr;
      oi_ptr          : tak664opt_info_ptr;
      tree_info       : tak664tree_info;
      sel_list_info   : tak664sel_list_info;
 
BEGIN
WITH acv DO
    BEGIN
    select_segm := NIL;
    view_segm   := NIL;
    try_optimization := false;
    IF  a_opt_info_ptr <> NIL
    THEN
        BEGIN
        oi_ptr.sys := a_opt_info_ptr;
&       ifdef trace
        ak664trace_opt_info (acv);
        t01moveobj (ak_strat, a_cmd_part^.sp1p_buf, 1, a_cmd_part^.sp1p_buf_len);
&       endif
        IF  a_pars_last_key.p_id[1] > chr(127)
        THEN
            ok := false
        ELSE
            WITH oi_ptr.oi^ DO
                BEGIN
                oi_optimize := false;
                a06_systable_get (acv, d_fix, (* PTS 1109090 *)
                      oi_tabid, oi_base_p, c_get_all, ok)
                END;
            (*ENDWITH*) 
        (*ENDIF*) 
        END
    ELSE
        ok := false;
    (*ENDIF*) 
    IF  ok (* PTS 1116891 *)
    THEN
        BEGIN
        ix := 0;
        REPEAT
            IF  (a_ap_tree^[ ix ].n_proc = a64) AND
                (a_ap_tree^[ ix ].n_subproc = cak_x_left_outer_join) AND
                (a_ap_tree^[ ix ].n_symb in [s_is_null, s_is_not_null])
            THEN
                ok := false;
            (*ENDIF*) 
            IF  (ni_skip_node in a_ap_tree^[ ix ].n_special)
            THEN
                IF  (a_ap_tree^[ ix ].n_pos = 0)
                THEN
                    ix := a_scv_index + 1 (* break loop *)
                ELSE
                    ix := a_ap_tree^[ ix ].n_pos
                (*ENDIF*) 
            ELSE
                ix := succ(ix);
            (*ENDIF*) 
        UNTIL
            NOT ok OR (ix > a_scv_index);
        (*ENDREPEAT*) 
        END;
    (*ENDIF*) 
    IF  ok
    THEN
        ak664check_select_stmt (acv, oi_ptr.oi^.oi_start_node,
              sel_list_info, qual_len);
    (*ENDIF*) 
    IF  ok
    THEN
        BEGIN
        select_segm := a_cmd_segm;
        select_part := a_cmd_part;
        WITH oi_ptr.oi^ DO
            BEGIN
            oi_optimize := true;
            a06_get_priv  (acv, oi_base_p, oi_priv);
            IF  r_sel in oi_priv.priv_all_set
            THEN
                oi_priv.priv_sel_set := a01fullset;
            (*ENDIF*) 
            FOR ix := 1 TO oi_base_p^.sbase.bmaxcol DO
                IF  ix in oi_priv.priv_sel_set
                THEN
                    BEGIN
                    a06extcolno (oi_base_p^.sbase, ix, col_ptr);
                    IF  NOT (ctinvisible in col_ptr^.ccolpropset)
                    THEN
                        oi_maxcol := ix
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
            (*ENDFOR*) 
            END;
        (*ENDWITH*) 
        new_cmd_segm := a_cmd_segm;
        (* PTS 1128603E.Z. *)
        (* PTS 1116567 E.Z. *)
        init_sqlmode   := acv.a_sqlmode;
        (* PTS 1124461 + 1124467 E.Z. *)
        init_dt_format := acv.a_dt_format;
        ak664get_view_definition (acv, oi_ptr.oi^.oi_tabid);
        view_segm        := a_cmd_segm;
        init_ex_kind     := a_ex_kind;
        a_ex_kind        := only_syntax;
        IF  a_returncode = 0
        THEN (* PTS 1116837 M.Ki. *)
            a35_asql_statement (acv);
        (*ENDIF*) 
        a_ex_kind   := init_ex_kind;
        a_sqlmode   := init_sqlmode;
        a_dt_format := init_dt_format;
        IF  a_returncode = 0
        THEN
            BEGIN
            ak664analyze_syntax_tree (acv, tree_info,
                  sel_list_info.sli_aggr, qual_len,
                  oi_ptr.oi^.oi_optimize);
            offset        := 0;
            sel_col_index := 0;
            qual_end_pos  := c_unknown_end_pos;
            ak664sort (oi_ptr.oi^);
            a542internal_packet (acv, NOT cak664release_packet,
                  select_part^.sp1p_buf_len +
                  view_segm^.sp1p_buf_len +
                  oi_ptr.oi^.oi_char_size * c_reserve);
            a_cmd_segm^.sp1c_prepare := a_initial_segment_header.sp1c_prepare;
            a_cmd_segment_header     := a_cmd_segm^.sp1s_segm_header;
            END;
        (*ENDIF*) 
        WITH oi_ptr.oi^, tree_info, sel_list_info DO
            BEGIN
            IF  a_returncode <> 0
            THEN
                oi_optimize := false
            ELSE
                BEGIN
                g10mv ('VAK664',   1,    
                      select_part^.sp1p_buf_size,
                      a_cmd_part^.sp1p_buf_size,
                      @select_part^.sp1p_buf, 1,
                      @a_cmd_part^.sp1p_buf,  1, select_part^.sp1p_buf_len,
                      a_returncode);
                IF  a_returncode <> 0
                THEN
                    oi_optimize := false
                ELSE
                    a_cmd_part^.sp1p_buf_len := select_part^.sp1p_buf_len
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            oi_in_sel_list := true;
            oi_index       := 1;
            prev_col_index := -1;
            WHILE (oi_index <= oi_count) AND oi_optimize DO
                BEGIN
                IF  oi_info[oi_index].ooi_pos > qual_end_pos
                THEN (* consider inserted closing bracket of qual *)
                    BEGIN
                    qual_end_pos := c_unknown_end_pos;
                    offset       := offset + oi_char_size
                    END;
                (*ENDIF*) 
                IF  oi_info[oi_index].ooi_colno <>
                    cak664table_indicator
                THEN
                    BEGIN
                    IF  oi_in_sel_list
                    THEN
                        sel_col_index := oi_info[oi_index].ooi_extno;
                    (*ENDIF*) 
                    add_colname     := false;
                    expand_asterisk := false;
                    IF  oi_in_sel_list
                        AND
                        (sel_col_index <= sli_cnt)
                    THEN
                        IF  sli_info[sel_col_index].sli_pos > 0
                        THEN
                            expand_asterisk := true
                        ELSE
                            add_colname :=
                                  (sli_info[sel_col_index].sli_pos =
                                  cak664add_colname)
                                  AND
                                  (sel_col_index <> prev_col_index);
                        (*ENDIF*) 
                    (*ENDIF*) 
                    IF  expand_asterisk
                    THEN
                        ak664expand_asterisk (acv, oi_ptr.oi^,
                              tree_info.ti_select_node,
                              sli_info[sel_col_index].sli_pos,
                              sli_info[sel_col_index].sli_len,
                              view_segm, offset)
                    ELSE
                        ak664subst_column (acv, oi_ptr.oi^,
                              tree_info.ti_select_node,
                              view_segm, NOT cak664add_comma,
                              add_colname,
                              sli_info[sel_col_index].sli_len + 1,
                              offset)
                    (*ENDIF*) 
                    END
                ELSE
                    WITH oi_info[oi_index], tree_info DO
                        BEGIN
                        oi_in_sel_list := false;
                        ak664substitute (acv, oi_ptr.oi^,
                              ti_from_start, ti_from_end - ti_from_start + 1,
                              view_segm, offset);
                        IF  ti_from_end <> ti_end
                        THEN
                            BEGIN
                            aux_pos   := ooi_pos;
                            aux_len   := ooi_len;
                            ooi_pos   := ooi_pos + ooi_len;
                            ooi_len   := 0;
                            ooi_colno := 1;
                            ak664substitute (acv, oi_ptr.oi^,
                                  ti_from_end + 1,
                                  ti_qual_end - ti_from_end,
                                  view_segm, offset);
                            IF  ti_qual_end <> ti_end
                            THEN
                                BEGIN
                                ooi_colno := 0;
                                ak664substitute (acv, oi_ptr.oi^,
                                      ti_qual_end + 1,
                                      ti_end - ti_qual_end,
                                      view_segm, offset);
                                END;
                            (*ENDIF*) 
                            ooi_pos   := aux_pos;
                            ooi_colno := 0;
                            ooi_len   := aux_len
                            END;
                        (*ENDIF*) 
                        IF  qual_len > 0
                        THEN
                            BEGIN
                            qual_end_pos :=
                                  ooi_pos + ooi_len + qual_len - 1;
                            ak664change_where (acv, oi_ptr.oi^.oi_optimize,
                                  offset + ooi_pos + ooi_len,
                                  qual_len)
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDWITH*) 
                (*ENDIF*) 
                prev_col_index := sel_col_index;
                oi_index       := oi_index + 1
                END;
            (*ENDWHILE*) 
            END;
        (*ENDWITH*) 
        try_optimization := oi_ptr.oi^.oi_optimize
        END;
    (*ENDIF*) 
    a664dispose_opt_info (acv);
    IF  select_segm <> NIL
    THEN
        IF  select_segm^.sp1c_producer = sp1pr_kernel
        THEN
            a542release_packet (acv, select_segm);
        (*ENDIF*) 
    (*ENDIF*) 
    IF  view_segm <> NIL
    THEN
        a542release_packet (acv, view_segm);
    (*ENDIF*) 
    IF  try_optimization AND a_intern_explain
    THEN
        IF  (a_resname_addr[cak_extern_pos] <> NIL) AND
            (a_resname_addr[cak_extern_pos]^.sresname.restreeid.fileRoot_gg00 <>
            NIL_PAGE_NO_GG00)
        THEN
            BEGIN
            b01empty_file (a_transinf.tri_trans,
                  a_resname_addr[cak_extern_pos]^.sresname.restreeid);
            IF  a_transinf.tri_trans.trError_gg00 <> e_ok
            THEN
                try_optimization := false
            (*ENDIF*) 
            END;
        (*ENDIF*) 
    (*ENDIF*) 
    IF  NOT try_optimization
    THEN
        a542release_packet (acv, a_cmd_segm);
&   ifdef trace
    (*ENDIF*) 
    ;
    t01int4 (ak_strat, 'try_optimiza', ord (try_optimization));
    IF  try_optimization
    THEN
        BEGIN
        t01segment (ak_strat, a_cmd_segm^);
        END;
&   endif
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a664dispose_opt_info (VAR acv : tak_all_command_glob);
 
BEGIN
IF  acv.a_opt_info_ptr <> NIL
THEN
    a10dispose (acv, acv.a_opt_info_ptr)
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak664analyze_syntax_tree (
            VAR acv              : tak_all_command_glob;
            VAR tree_info        : tak664tree_info;
            aggr_function        : boolean;
            qual_len             : tsp00_Int4;
            VAR try_optimization : boolean);
 
VAR
      dummy        : boolean;
      kw           : integer;
      aux_n        : integer;
      curr_n       : integer;
      from_node    : integer;
      sel_col_node : integer;
 
BEGIN
WITH acv, tree_info DO
    BEGIN
    from_node := 0;
    curr_n    := a_ap_tree^[0].n_lo_level;
    WITH a_ap_tree^[curr_n] DO
        IF  (n_proc = a63) AND (n_subproc = cak_x_start_union)
        THEN
            (* View containing UNION, EXCEPT, DIFFERENCE *)
            (* cannot be optimized yet                   *)
            try_optimization := false
        ELSE
            curr_n := n_lo_level;
        (*ENDIF*) 
    (*ENDWITH*) 
    IF  try_optimization
    THEN
        WITH a_ap_tree^[curr_n] DO
            IF  (n_proc = a63) AND (n_subproc = cak_x_distinct)
            THEN
                BEGIN
                (* Views containing DISTINCT are not optimized *)
                try_optimization := false;
                curr_n           := n_lo_level
                END;
            (*ENDIF*) 
        (*ENDWITH*) 
    (*ENDIF*) 
    IF  try_optimization
    THEN
        WITH a_ap_tree^[curr_n] DO
            IF  (n_proc = a60) AND (n_subproc = cak_x_select_list)
            THEN
                BEGIN
                ti_select_node := curr_n;
                ti_select_node := a_ap_tree^[ti_select_node].n_lo_level;
                curr_n         := n_sa_level
                END
            ELSE
                BEGIN
&               ifdef trace
                a07ak_system_error (acv, 664, 1);
&               endif
                try_optimization := false
                END;
            (*ENDIF*) 
        (*ENDWITH*) 
    (*ENDIF*) 
    IF  try_optimization
    THEN
        BEGIN
        aux_n := ti_select_node;
        WHILE aux_n <> 0 DO
            BEGIN
            sel_col_node := a_ap_tree^[aux_n].n_lo_level;
            WITH a_ap_tree^[sel_col_node] DO
                IF  n_symb = s_authid
                THEN
                    sel_col_node := n_sa_level;
                (*ENDIF*) 
            (*ENDWITH*) 
            WITH a_ap_tree^[sel_col_node] DO
                IF  n_symb = s_tablename
                THEN
                    sel_col_node := n_sa_level;
                (*ENDIF*) 
            (*ENDWITH*) 
            IF  a_ap_tree^[sel_col_node].n_symb = s_asterisk
            THEN
                BEGIN
                (* view defined by select * is not optimized *)
                aux_n            := 0;
                try_optimization := false
                END
            ELSE
                aux_n := a_ap_tree^[aux_n].n_sa_level;
            (*ENDIF*) 
            END;
        (*ENDWHILE*) 
        IF  try_optimization
        THEN
            BEGIN
            WITH a_ap_tree^[curr_n] DO
                IF  (n_proc = a66) AND (n_subproc = cak_x_given_sequence)
                THEN
                    curr_n    := n_sa_level;
                (*ENDIF*) 
            (*ENDWITH*) 
            WITH a_ap_tree^[curr_n] DO
                IF  (n_proc = a63) AND (n_subproc = cak_x_from_part)
                THEN
                    BEGIN
                    curr_n    := n_sa_level;
                    from_node := n_lo_level;
                    END;
                (*ENDIF*) 
            (*ENDWITH*) 
            END;
        (*ENDIF*) 
        IF  from_node > 0
        THEN
            BEGIN
            aux_n         := a_ap_tree^[from_node].n_lo_level;
            ti_from_start := a_ap_tree^[aux_n ].n_pos;
            IF  a_cmd_part^.sp1p_buf[ti_from_start - 1] = '"'
            THEN
                IF  g01unicode
                THEN
                    ti_from_start := ti_from_start - 2
                ELSE
                    ti_from_start := ti_from_start - 1;
                (*ENDIF*) 
            (*ENDIF*) 
            ti_end      := a_cmd_part^.sp1p_buf_len;
            ti_from_end := ti_end;
            ti_qual_end := ti_end;
            WITH a_ap_tree^[curr_n] DO
                BEGIN
                ti_qual_found := (n_proc = a63) AND
                      (n_subproc = cak_x_search_condition);
                IF  ti_qual_found
                THEN
                    BEGIN
                    a_scv.sc_newpos := n_pos;
                    a01_next_symbol (acv);
                    a01_get_keyword (acv, kw, dummy);
                    IF  kw = cak_i_where
                    THEN
                        BEGIN
                        a01_next_symbol (acv);
                        ti_from_end := a_scv.sc_sypos - 1;
                        IF  a_cmd_part^.sp1p_buf[ti_from_end] = '"'
                        THEN
                            IF  g01unicode
                            THEN
                                ti_from_end := ti_from_end - 2
                            ELSE
                                ti_from_end := ti_from_end - 1;
                            (*ENDIF*) 
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    curr_n := n_sa_level
                    END
                (*ENDIF*) 
                END;
            (*ENDWITH*) 
            IF  curr_n <> 0
            THEN
                BEGIN
                ti_qual_end := a_ap_tree^[curr_n].n_pos - 1;
                WITH a_ap_tree^[curr_n] DO
                    IF  (n_proc = a63) AND (n_subproc = cak_x_group_by)
                        AND
                        ((qual_len > 0) OR aggr_function)
                    THEN
                        try_optimization := false;
                    (*ENDIF*) 
                (*ENDWITH*) 
                END
            (*ENDIF*) 
            END;
&       ifdef trace
        (*ENDIF*) 
        t01moveobj (ak_strat, a_cmd_part^.sp1p_buf,
              ti_from_start, ti_end);
        t01int4 (ak_sem, 'from_end    ', ti_from_end);
        t01int4 (ak_sem, 'qual_end    ', ti_qual_end);
&       endif
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak664change_where (
            VAR acv      : tak_all_command_glob;
            VAR optimize : boolean;
            pos          : tsp00_Int4;
            qual_len     : tsp00_Int4);
 
VAR
      res_kw    : boolean;
      kw_index  : integer;
      char_size : integer;
 
BEGIN
WITH acv DO
    BEGIN
    a_scv.sc_newpos := pos;
    a01_next_symbol (acv);
    a01_get_keyword (acv, kw_index, res_kw);
    IF  kw_index = cak_i_where
    THEN
        IF  g01unicode
        THEN
            char_size := 2
        ELSE
            char_size := 1;
        (*ENDIF*) 
    (*ENDIF*) 
    IF  acv.a_cmd_part^.sp1p_buf_size >= acv.a_cmd_part^.sp1p_buf_len + char_size
    THEN
        WITH a_scv, a_cmd_part^ DO
            BEGIN
            pos := sc_sypos;
            ak664put_char (sp1p_buf, 'A', pos);
            ak664put_char (sp1p_buf, 'N', pos);
            ak664put_char (sp1p_buf, 'D', pos);
            ak664put_char (sp1p_buf, ' ', pos);
            ak664put_char (sp1p_buf, '(', pos);
            SAPDB_PascalOverlappingMove ('VAK664',   2,    
                  sp1p_buf_size, sp1p_buf_size,
                  @sp1p_buf, sc_sypos + qual_len, @sp1p_buf,
                  sc_sypos + qual_len + char_size,
                  sp1p_buf_len - (sc_sypos + qual_len - 1),
                  a_returncode);
            pos := sc_sypos + qual_len;
            ak664put_char (sp1p_buf, ')', pos);
            a_cmd_segment_header.sp1s_segm_len := a_cmd_segment_header.sp1s_segm_len
                  + char_size;
            a_cmd_segm^.sp1s_segm_len := a_cmd_segment_header.sp1s_segm_len;
            sp1p_buf_len  := sp1p_buf_len  + char_size
            END
        (*ENDWITH*) 
    ELSE
        optimize := false;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak664check_select_stmt (
            VAR acv              : tak_all_command_glob;
            start_node           : integer;
            VAR sel_list_info    : tak664sel_list_info;
            VAR qual_len         : tsp00_Int4);
 
VAR
      curr_n       : integer;
      sel_col_node : integer;
      sa_level     : integer;
      start_pos    : tsp00_Int4;
 
BEGIN
WITH acv, sel_list_info DO
    BEGIN
    qual_len  := 0;
    sli_cnt   := 0;
    sli_aggr  := false;
    sa_level  := 0;
    curr_n    := start_node;
&   ifdef trace
    t01int4 (ak_strat, 'curr_n      ', curr_n);
&   endif
    WITH a_ap_tree^[curr_n] DO
        IF  n_proc = a43
        THEN (* EXPLAIN ... *)
            curr_n := n_lo_level;
        (*ENDIF*) 
    (*ENDWITH*) 
    curr_n := a_ap_tree^[curr_n].n_lo_level;
    WITH a_ap_tree^[curr_n] DO
        IF  (n_proc = a63) AND (n_subproc = cak_x_distinct)
        THEN
            curr_n := n_lo_level;
        (*ENDIF*) 
    (*ENDWITH*) 
    WITH a_ap_tree^[curr_n] DO
        IF  n_symb = s_identifier
        THEN (* result table name *)
            curr_n := n_sa_level;
        (*ENDIF*) 
    (*ENDWITH*) 
    WITH a_ap_tree^[curr_n] DO
        IF  (n_proc = a60) AND (n_subproc = cak_x_select_list)
        THEN
            BEGIN
            sli_aggr := n_symb in [s_sum, s_count];
            curr_n   := a_ap_tree^[curr_n].n_lo_level;
            sa_level := n_sa_level
            END
        ELSE
            curr_n := 0;
        (*ENDIF*) 
    (*ENDWITH*) 
    WHILE curr_n <> 0 DO
        BEGIN
        sel_col_node := a_ap_tree^[curr_n].n_lo_level;
        sli_cnt      := sli_cnt + 1;
        WITH a_ap_tree^[curr_n+1] DO
            sli_info[sli_cnt].sli_len := n_pos + n_length - 1;
        (*ENDWITH*) 
        curr_n := a_ap_tree^[curr_n].n_sa_level;
&       ifdef trace
        t01int4 (ak_strat, 'curr_n      ', curr_n);
        t01int4 (ak_strat, 'sel_col_node', sel_col_node);
&       endif
        start_pos := 0;
        WITH a_ap_tree^[sel_col_node] DO
            IF  n_symb = s_authid
            THEN
                BEGIN
                sel_col_node := n_sa_level;
                start_pos    := n_pos
                END;
            (*ENDIF*) 
        (*ENDWITH*) 
        WITH a_ap_tree^[sel_col_node] DO
            IF  n_symb = s_tablename
            THEN
                BEGIN
                sel_col_node := n_sa_level;
                IF  start_pos = 0
                THEN
                    start_pos := n_pos
                (*ENDIF*) 
                END;
            (*ENDIF*) 
        (*ENDWITH*) 
        WITH a_ap_tree^[sel_col_node] DO
            IF  n_symb = s_asterisk
            THEN
                IF  start_pos = 0
                THEN
                    BEGIN
                    sli_info[sli_cnt].sli_pos :=
                          a_ap_tree^[sel_col_node].n_pos;
                    IF  g01unicode
                    THEN
                        sli_info[sli_cnt].sli_len := 2
                    ELSE
                        sli_info[sli_cnt].sli_len := 1
                    (*ENDIF*) 
                    END
                ELSE
                    BEGIN
                    sli_info[sli_cnt].sli_pos := start_pos;
                    sli_info[sli_cnt].sli_len := n_pos - start_pos + 1
                    END
                (*ENDIF*) 
            ELSE
                IF  a_ap_tree^[sel_col_node].n_symb = s_columnname
                THEN
                    sli_info[sli_cnt].sli_pos := cak664add_colname
                ELSE
                    IF  a_ap_tree^[sel_col_node].n_symb =
                        s_reference_name
                    THEN
                        sli_info[sli_cnt].sli_pos := 0
                    ELSE
                        BEGIN
                        sli_info[sli_cnt].sli_pos := -1
                        END;
                    (*ENDIF*) 
                (*ENDIF*) 
            (*ENDIF*) 
        (*ENDWITH*) 
        END;
    (*ENDWHILE*) 
    WITH a_ap_tree^[sa_level] DO
        IF  (n_proc = a60) AND (n_subproc = cak_x_single_select)
        THEN
            sa_level := n_sa_level;
        (*ENDIF*) 
    (*ENDWITH*) 
    WITH a_ap_tree^[sa_level] DO
        IF  (n_proc = a63) AND (n_subproc = cak_x_from_part)
        THEN
            sa_level := n_sa_level;
        (*ENDIF*) 
    (*ENDWITH*) 
    WITH a_ap_tree^[sa_level] DO
        IF  (n_proc = a63) AND (n_subproc = cak_x_search_condition)
        THEN
            qual_len := a_ap_tree^[sa_level+1].n_length;
&       ifdef trace
        (*ENDIF*) 
    (*ENDWITH*) 
    t01int4 (ak_strat, 'sli_aggr    ', ord (sli_aggr));
    FOR curr_n := 1 TO sli_cnt DO
        t01p2int4 (ak_strat, 'sli_pos     ', sli_info[curr_n].sli_pos,
              'sli_len     ', sli_info[curr_n].sli_len);
    (*ENDFOR*) 
    t01int4 (ak_strat, 'qual_len    ', qual_len)
&         endif
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak664expand_asterisk (
            VAR acv        : tak_all_command_glob;
            VAR o_info     : tak664opt_info;
            first_sel_node : integer;
            asterisk_pos   : tsp00_Int4;
            asterisk_len   : tsp00_Int4;
            view_segm      : tsp1_segment_ptr;
            VAR offset     : tsp00_Int4);
 
VAR
      ix      : integer;
      col_cnt : integer;
 
BEGIN
WITH o_info DO
    BEGIN
    WITH acv.a_cmd_part^ DO
        BEGIN
        SAPDB_PascalOverlappingMove ('VAK664',   3,    
              sp1p_buf_size, sp1p_buf_size,
              @sp1p_buf, offset + asterisk_pos + asterisk_len,
              @sp1p_buf, offset + asterisk_pos,
              sp1p_buf_len - (offset + asterisk_pos + asterisk_len) + 1,
              acv.a_returncode);
        sp1p_buf_len := sp1p_buf_len - asterisk_len
        END;
    (*ENDWITH*) 
    ix      := 2;
    col_cnt := 0;
    WHILE ix <= oi_maxcol DO
        BEGIN
        IF  ix in oi_priv.priv_sel_set
        THEN
            WITH oi_info[oi_index] DO
                BEGIN
                col_cnt   := col_cnt + 1;
&               ifdef trace
                t01int4 (ak_strat, 'oi_index    ', oi_index);
                t01int4 (ak_strat, 'ooi_extno   ', ooi_extno);
                t01int4 (ak_strat, 'ix          ', ix);
&               endif
                IF  ooi_extno <> ix - 1
                THEN
                    BEGIN
                    oi_optimize := false;
                    ix          := oi_maxcol + 1
                    END
                ELSE
                    BEGIN
                    oi_info[oi_index].ooi_colno := ix;
                    oi_info[oi_index].ooi_pos   := asterisk_pos;
                    oi_info[oi_index].ooi_len   := 0;
&                   ifdef trace
                    t01int4 (ak_strat, 'asterisk_pos', asterisk_pos);
                    t01int4 (ak_strat, 'asterisk_len', asterisk_len);
&                   endif
                    ak664subst_column (acv, o_info, first_sel_node,
                          view_segm, ix < oi_maxcol, true,
                          asterisk_pos, offset);
                    REPEAT
                        oi_index := oi_index + 1;
                    UNTIL
                        oi_info[oi_index].ooi_extno <> ix - 1;
                    (*ENDREPEAT*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDWITH*) 
        (*ENDIF*) 
        ix := ix + 1
        END;
    (*ENDWHILE*) 
    offset   := offset - asterisk_len;
    oi_index := oi_index - 1
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak664get_view_definition (
            VAR acv     : tak_all_command_glob;
            VAR view_id : tgg00_Surrogate);
 
VAR
 
      k : RECORD
            CASE boolean OF
                true :
                    (dummy        : tsp00_Int2;
                    klen          : tsp00_Int2;
                    varcol_offset : tsp00_Int2;
                    varcol_cnt    : tsp00_Int2;
                    tabid         : tgg00_Surrogate);
                false :
                    (lk : tgg00_Lkey);
                END;
            (*ENDCASE*) 
 
 
      rec_buf : RECORD
            CASE boolean OF
                true :
                    (rec : tgg00_Rec);
                false :
                    (reclen       : tsp00_Int2;
                    keylen        : tsp00_Int2;
                    varcol_offset : tsp00_Int2;
                    varcol_cnt    : tsp00_Int2;
                    viewid        : tgg00_Surrogate;
                    cmd_id        : tsp00_Int2);
                END;
            (*ENDCASE*) 
 
 
BEGIN
k.klen  := SURROGATE_MXGG00;
k.tabid := view_id;
b07cget_record (acv.a_transinf.tri_trans,
      acv.a_intern_cmd_tree, k.lk, rec_buf.rec);
IF  acv.a_transinf.tri_trans.trError_gg00 = e_ok
THEN
    BEGIN
    rec_buf.cmd_id := rec_buf.cmd_id - 1;
    a542next_intern_sql_cmd (acv, NOT cak664release_packet,
          acv.a_intern_cmd_tree, rec_buf.cmd_id);
    END
ELSE
    a07_b_put_error (acv, acv.a_transinf.tri_trans.trError_gg00, 1)
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a664new_optimize_info (
            VAR acv    : tak_all_command_glob;
            VAR dmli   : tak_dml_info;
            table_node : integer;
            end_node   : integer);
 
VAR
      start_pos : tsp00_Int4;
      oi_ptr    : tak664opt_info_ptr;
 
BEGIN
WITH acv DO
    IF  a_optimize_info.o_do_optimize AND (a_opt_info_ptr = NIL)
    THEN
        BEGIN
        a10new (acv, sizeof (tak664opt_info), a_opt_info_ptr);
        IF  a_opt_info_ptr <> NIL
        THEN
            BEGIN
            oi_ptr.sys := a_opt_info_ptr;
            WITH oi_ptr.oi^, dmli, d_tabarr[d_acttabindex] DO
                BEGIN
                IF  g01unicode
                THEN
                    oi_char_size := 2
                ELSE
                    oi_char_size := 1;
                (*ENDIF*) 
                oi_tabid      := ofromtableid;
                oi_sublevel   := d_subcount;
                oi_start_node := d_act_node;
                oi_cmd_no     := a_max_intern_select - 1;
&               ifdef trace
                t01int4 (ak_strat, 'oi_start_nod', oi_start_node);
                t01int4 (ak_strat, 'oi_sublevel ', oi_sublevel);
&               endif
                oi_count := 1;
                WITH oi_info[1] DO
                    BEGIN
                    ooi_pos := a_ap_tree^[table_node].n_pos;
                    IF  a_cmd_part^.sp1p_buf[ooi_pos-1] = '"'
                    THEN
                        ooi_pos := ooi_pos - oi_char_size;
                    (*ENDIF*) 
                    start_pos := a_ap_tree^[end_node].n_pos;
                    IF  a_cmd_part^.sp1p_buf[start_pos-1] = '"'
                    THEN
                        start_pos := start_pos - oi_char_size;
                    (*ENDIF*) 
                    a_scv.sc_newpos := start_pos;
                    a01_next_symbol (acv);
                    ooi_len := start_pos +
                          2 * a_scv.sc_double_quote +
                          a_scv.sc_sylength - ooi_pos;
                    ooi_colno := cak664table_indicator;
                    ooi_extno := 0
                    END;
                (*ENDWITH*) 
                END;
            (*ENDWITH*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak664sort (VAR o_info : tak664opt_info);
 
VAR
      ix        : integer;
      jx        : integer;
      min       : tsp00_Int4;
      min_index : integer;
      aux       : tak664one_opt_info;
 
BEGIN
WITH o_info DO
    FOR ix := 1 TO oi_count - 1 DO
        BEGIN
        min := csp_maxint4;
        FOR jx := ix TO oi_count DO
            IF  oi_info[jx].ooi_pos < min
            THEN
                BEGIN
                min       := oi_info[jx].ooi_pos;
                min_index := jx
                END;
            (*ENDIF*) 
        (*ENDFOR*) 
        IF  min_index <> ix
        THEN
            BEGIN
            aux                := oi_info[ix];
            oi_info[ix]        := oi_info[min_index];
            oi_info[min_index] := aux
            END;
        (*ENDIF*) 
        END;
    (*ENDFOR*) 
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak664subst_column (
            VAR acv         : tak_all_command_glob;
            VAR o_info      : tak664opt_info;
            first_sel_node  : integer;
            view_segm       : tsp1_segment_ptr;
            add_comma       : boolean;
            add_viewcolname : boolean;
            colname_pos     : tsp00_Int4;
            VAR offset      : tsp00_Int4);
 
VAR
      add      : integer;
      col_ptr  : tak00_colinfo_ptr;
      ix       : integer;
      pos      : tsp00_Int4;
      length   : tsp00_Int4;
      col_len  : tsp00_Int4;
 
BEGIN
WITH acv, o_info DO
    BEGIN
    IF  add_viewcolname
    THEN
        BEGIN
&       ifdef trace
        t01int4 (ak_strat, 'colname_pos ', colname_pos);
&       endif
        a06extcolno (oi_base_p^.sbase,
              oi_info[oi_index].ooi_colno, col_ptr);
        WITH a_cmd_part^, col_ptr^ DO
            BEGIN
            col_len := ord (ccolumnn_len);
            IF  add_comma
            THEN
                add := 4 * oi_char_size
            ELSE
                add := 3 * oi_char_size;
            (*ENDIF*) 
            (* h.b. PTS 1000899 *)
            IF  (sp1p_buf_len + col_len + add > sp1p_buf_size) OR
                (colname_pos + offset > sp1p_buf_len)
            THEN
                o_info.oi_optimize := false
            ELSE
                BEGIN
                colname_pos := offset + colname_pos;
                SAPDB_PascalOverlappingMove ('VAK664',   4,    
                      sp1p_buf_size, sp1p_buf_size,
                      @sp1p_buf, colname_pos, @sp1p_buf,
                      colname_pos + col_len + add,
                      sp1p_buf_len - colname_pos + 1,
                      acv.a_returncode);
                ak664put_char (sp1p_buf, bsp_c1, colname_pos);
                ak664put_char (sp1p_buf, '"', colname_pos);
                g10mv ('VAK664',   5,    
                      sizeof (ccolumnn), sp1p_buf_size,
                      @ccolumnn, 1,
                      @sp1p_buf, colname_pos, col_len,
                      acv.a_returncode);
                colname_pos := colname_pos + col_len;
                ak664put_char (sp1p_buf, '"', colname_pos);
                IF  add_comma
                THEN
                    ak664put_char (sp1p_buf, ',', colname_pos);
                (*ENDIF*) 
                sp1p_buf_len := sp1p_buf_len + col_len + add
&                     ifdef trace
                      ;
                t01moveobj (ak_strat, sp1p_buf, 1, sp1p_buf_len);
&               endif
                END;
            (*ENDIF*) 
            END;
        (*ENDWITH*) 
        END;
    (*ENDIF*) 
    FOR ix := 2 TO oi_info[oi_index].ooi_colno - 1 DO
        first_sel_node := a_ap_tree^[first_sel_node].n_sa_level;
    (*ENDFOR*) 
&   ifdef trace
    t01int4 (ak_strat, 'node        ', first_sel_node);
    t01int4 (ak_strat, 'start_pos   ',
          a_ap_tree^[first_sel_node+1].n_pos);
    t01int4 (ak_strat, 'length      ',
          a_ap_tree^[first_sel_node+1].n_length);
    t01int4 (ak_strat, 'oi_maxcol   ', oi_maxcol);
&   endif
    WITH a_ap_tree^[first_sel_node + 1] DO
        BEGIN
        pos    := n_pos;
        length := n_length;
        IF  (a_ap_tree^[first_sel_node + 2].n_symb = s_string_literal)
        THEN
            BEGIN
            pos    := pred(pos);
            length := succ (length);
            END;
        (*ENDIF*) 
        END;
    (*ENDWITH*) 
    ak664substitute (acv, o_info, pos, length, view_segm, offset);
    IF  add_viewcolname
    THEN
        offset := offset + col_len + add
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak664substitute (
            VAR acv         : tak_all_command_glob;
            VAR o_info      : tak664opt_info;
            new_pos         : tsp00_Int4;
            new_len         : tsp00_Int4;
            view_segm       : tsp1_segment_ptr;
            VAR offset      : tsp00_Int4);
 
VAR
      is_column     : boolean;
      old_pos       : tsp00_Int4;
      old_len       : tsp00_Int4;
      pos           : tsp00_Int4;
      required_len  : tsp00_Int4;
&     ifdef trace
      aux : integer;
&     endif
 
BEGIN
WITH acv, o_info DO
    BEGIN
    old_pos   := oi_info[oi_index].ooi_pos;
    old_len   := oi_info[oi_index].ooi_len;
    is_column := oi_info[oi_index].ooi_colno > 0;
&   ifdef trace
    t01int4    (ak_strat, 'offset      ', offset);
    aux := offset + old_pos + old_len - 1;
    IF  aux < offset + old_pos
    THEN
        aux := offset + old_pos;
    (*ENDIF*) 
    t01moveobj (ak_strat, a_cmd_part^.sp1p_buf, offset + old_pos, aux);
    t01moveobj (ak_strat, view_segm^.sp1p_buf,
          new_pos, new_pos+new_len-1);
&   endif
    required_len := new_len;
    IF  is_column
    THEN (* reserve space for brackets *)
        required_len := required_len + 2 * oi_char_size;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
WITH acv, a_cmd_part^ DO
    IF  required_len > old_len
    THEN
        IF  (sp1p_buf_len + required_len > sp1p_buf_size) OR
            (old_pos + offset - 1 > sp1p_buf_len) (* PTS 1113920 *)
        THEN
            o_info.oi_optimize := false
        ELSE
            SAPDB_PascalOverlappingMove ('VAK664',   6,    
                  sp1p_buf_size, sp1p_buf_size,
                  @a_cmd_part^.sp1p_buf, old_pos + offset, @a_cmd_part^.sp1p_buf,
                  old_pos + offset + (required_len - old_len),
                  sp1p_buf_len - (old_pos + offset) + 1,
                  acv.a_returncode)
        (*ENDIF*) 
    ELSE
        IF  required_len <> old_len
        THEN
            SAPDB_PascalOverlappingMove ('VAK664',   7,    
                  sp1p_buf_size, sp1p_buf_size,
                  @a_cmd_part^.sp1p_buf, offset + old_pos + old_len,
                  @a_cmd_part^.sp1p_buf, offset + old_pos + required_len,
                  sp1p_buf_len - (offset + old_pos + old_len) + 1,
                  acv.a_returncode);
        (*ENDIF*) 
    (*ENDIF*) 
(*ENDWITH*) 
IF  acv.a_returncode <> 0
THEN
    o_info.oi_optimize := false;
(*ENDIF*) 
WITH o_info, acv, a_cmd_part^ DO
    IF  oi_optimize
    THEN
        BEGIN
        pos := old_pos + offset;
        IF  is_column
        THEN
            ak664put_char (sp1p_buf, '(', pos);
        (*ENDIF*) 
        g10mv ('VAK664',   8,    
              view_segm^.sp1p_buf_size,
              sp1p_buf_size, @view_segm^.sp1p_buf, new_pos,
              @sp1p_buf, pos, new_len,
              acv.a_returncode);
        pos := pos + new_len;
        IF  is_column
        THEN
            ak664put_char (sp1p_buf, ')', pos);
        (*ENDIF*) 
        offset       := offset + (required_len - old_len);
        sp1p_buf_len := sp1p_buf_len + (required_len - old_len);
&       ifdef trace
        t01moveobj (ak_strat, sp1p_buf, 1, sp1p_buf_len)
&             endif
        END;
    (*ENDIF*) 
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak664put_char (
            VAR moveobj : tsp00_MoveObj;
            c       : char;
            VAR pos : tsp00_Int4);
 
BEGIN
IF  g01unicode
THEN
    BEGIN
    moveobj[pos] := csp_unicode_mark;
    pos := pos + 1
    END;
(*ENDIF*) 
moveobj[pos] := c;
pos := pos + 1
END;
 
&ifdef trace
(*------------------------------*) 
 
PROCEDURE
      ak664trace_opt_info (VAR acv : tak_all_command_glob);
 
VAR
      ix     : integer;
      oi_ptr : tak664opt_info_ptr;
 
BEGIN
oi_ptr.sys := acv.a_opt_info_ptr;
WITH oi_ptr.oi^ DO
    BEGIN
    FOR ix := 1 TO oi_count DO
        WITH oi_info[ix] DO
            BEGIN
            t01int4 (ak_strat, 'extno       ', ooi_extno);
            t01int4 (ak_strat, 'colno       ', ooi_colno);
            t01moveobj (ak_strat,
                  acv.a_cmd_part^.sp1p_buf, ooi_pos, ooi_pos + ooi_len - 1)
            END;
        (*ENDWITH*) 
    (*ENDFOR*) 
    END;
(*ENDWITH*) 
END;
 
&endif
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
.PA 
