.ad 8
.bm 8
.fm 4
.bt $Copyright (c) 2000-2005 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
 
 .nf
 
    ========== licence begin  GPL
    Copyright (c) 2000-2005 SAP AG
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end
.fo
 
 
.fo
.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
              a10get_sysinfo (
                    VAR acv      : tak_all_command_glob;
                    VAR syskey   : tgg00_SysInfoKey;
                    dstate       : tak_directory_state;
                    VAR syspoint : tak_sysbufferaddress;
                    VAR b_err    : tgg00_BasisError);
 
        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_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
              SAPDB_PascalOverlappingMove (
                    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);
&       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
&ifdef trace
t01int4 (ak_strat, 'extcolno    ', extcolno);
t01int4 (ak_strat, 'colpos      ', colpos);
&endif
oi_ptr.sys := acv.a_opt_info_ptr;
IF  oi_ptr.oi^.oi_start_node = startnode
THEN
    BEGIN
    pos := colpos;
    IF  pos > 0
    THEN
        IF  acv.a_cmd_part^.sp1p_buf[pos - 1] = '"'
        THEN
            pos := pos - oi_ptr.oi^.oi_char_size;
        (*ENDIF*) 
    (*ENDIF*) 
    found := false;
    ix    := 1;
    WHILE (ix <= oi_ptr.oi^.oi_count) AND NOT found DO
        IF  oi_ptr.oi^.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_ptr.oi^.oi_info[ix].ooi_pos = pos
        THEN
            BEGIN
            jx := ix;
            WHILE jx <= oi_ptr.oi^.oi_count DO
                IF  oi_ptr.oi^.oi_info[jx].ooi_pos <> pos
                THEN
                    jx := csp_maxint2
                ELSE
                    IF  (oi_ptr.oi^.oi_info[jx].ooi_extno = extcolno) AND
                        (oi_ptr.oi^.oi_info[jx].ooi_colno = colno)
                    THEN
                        BEGIN
                        (* entry already stored *)
                        ix := 0;
                        jx := csp_maxint2
                        END
                    ELSE
                        BEGIN
                        jx := jx + 1;
                        ix := jx
                        END;
                    (*ENDIF*) 
                (*ENDIF*) 
            (*ENDWHILE*) 
            END;
        (*ENDIF*) 
    (*ENDIF*) 
    IF  ix <> 0
    THEN
        BEGIN
        oi_ptr.oi^.oi_count := oi_ptr.oi^.oi_count + 1;
        IF  oi_ptr.oi^.oi_count > cak664max_opt_info
        THEN (* no optimization possible *)
            BEGIN
            ix := 0;
            a664dispose_opt_info (acv)
            END
        ELSE
            BEGIN
            IF  ix < oi_ptr.oi^.oi_count
            THEN
                FOR jx := oi_ptr.oi^.oi_count - 1 DOWNTO ix DO
                    oi_ptr.oi^.oi_info[jx + 1] := oi_ptr.oi^.oi_info[jx];
                (*ENDFOR*) 
&           ifdef trace
            (*ENDIF*) 
            t01int4 (ak_strat, 'stored      ', 1);
&           endif
            oi_ptr.oi^.oi_info[ix].ooi_extno := extcolno;
            oi_ptr.oi^.oi_info[ix].ooi_pos   := pos;
            oi_ptr.oi^.oi_info[ix].ooi_colno := colno;
            oi_ptr.oi^.oi_info[ix].ooi_len   := 0;
            IF  pos > 0
            THEN
                BEGIN
                acv.a_scv.sc_newpos := oi_ptr.oi^.oi_info[ix].ooi_pos;
                a01_next_symbol (acv);
                IF  oi_ptr.oi^.oi_info[ix].ooi_pos = colpos
                THEN
                    oi_ptr.oi^.oi_info[ix].ooi_len := acv.a_scv.sc_sylength
                ELSE
                    oi_ptr.oi^.oi_info[ix].ooi_len := acv.a_scv.sc_sylength +
                          2 * oi_ptr.oi^.oi_char_size;
                (*ENDIF*) 
                a01_next_symbol (acv);
                IF  acv.a_scv.sc_symb = s_point
                THEN
                    BEGIN
                    a01_next_symbol (acv);
                    oi_ptr.oi^.oi_info[ix].ooi_len := acv.a_scv.sc_sypos +
                          acv.a_scv.sc_sylength - oi_ptr.oi^.oi_info[ix].ooi_pos +
                          acv.a_scv.sc_double_quote
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(* main routine for optimization of the complex view *)
(*------------------------------*) 
 
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
      e               : tgg00_BasisError;
      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;
      pViewtext       : tak_sysbufferaddress;
      sysk            : tgg00_SysInfoKey;
      tree_info       : tak664tree_info;
      sel_list_info   : tak664sel_list_info;
 
BEGIN
select_segm := NIL;
view_segm   := NIL;
oi_ptr.sys  := NIL;
qual_len    := 0;
try_optimization := false;
IF  acv.a_opt_info_ptr <> NIL
THEN
    BEGIN
    oi_ptr.sys := acv.a_opt_info_ptr;
&   ifdef trace
    ak664trace_opt_info (acv);
    t01moveobj (ak_strat, acv.a_cmd_part^.sp1p_buf, 1, acv.a_cmd_part^.sp1p_buf_len);
&   endif
    IF  acv.a_pars_last_key.p_id[1] > chr(127)
    THEN
        ok := false
    ELSE
        BEGIN
        oi_ptr.oi^.oi_optimize := false;
        a06_systable_get (acv, d_fix, (* PTS 1109090 *)
              oi_ptr.oi^.oi_tabid, oi_ptr.oi^.oi_base_p, c_get_all, ok);
        IF  ok
        THEN
            IF  va_date_time_used in oi_ptr.oi^.oi_base_p^.sbase.bview_attributes
            THEN
                BEGIN
                ok             := false;
                sysk           := oi_ptr.oi^.oi_base_p^.syskey;
                sysk.sentrytyp := cak_eviewtext;
                a10get_sysinfo (acv, sysk, d_release, pViewtext, e);
                IF  e <> e_ok
                THEN
                    a07_b_put_error (acv, e, 1) 
                ELSE
                    ok := ord (acv.a_dt_format) = pViewtext^.sviewtext.vtcontext MOD 10;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END
ELSE
    ok := false;
(*ENDIF*) 
IF  ok (* PTS 1116891 *)
THEN
    BEGIN
    ix := 0;
    REPEAT
        IF  (acv.a_ap_tree^[ ix ].n_proc = a64) AND
            (acv.a_ap_tree^[ ix ].n_subproc = cak_x_left_outer_join) AND
            (acv.a_ap_tree^[ ix ].n_symb in [s_is_null, s_is_not_null])
        THEN
            ok := false;
        (*ENDIF*) 
        IF  (ni_skip_node in acv.a_ap_tree^[ ix ].n_special)
        THEN
            IF  (acv.a_ap_tree^[ ix ].n_pos = 0)
            THEN
                ix := acv.a_scv_index + 1 (* break loop *)
            ELSE
                ix := acv.a_ap_tree^[ ix ].n_pos
            (*ENDIF*) 
        ELSE
            ix := succ(ix);
        (*ENDIF*) 
    UNTIL
        NOT ok OR (ix > acv.a_scv_index);
    (*ENDREPEAT*) 
    END;
(*ENDIF*) 
IF  ok
THEN
    ak664check_select_stmt (acv, oi_ptr.oi^.oi_start_node,
          sel_list_info, qual_len)
ELSE
    WITH sel_list_info DO
        BEGIN
        sli_cnt  := 0;
        sli_aggr := false;
        sli_info[1].sli_pos := 0;
        sli_info[1].sli_len := 0;
        END;
    (*ENDWITH*) 
(*ENDIF*) 
IF  ok
THEN
    BEGIN
    select_segm := acv.a_cmd_segm;
    select_part := acv.a_cmd_part;
    oi_ptr.oi^.oi_optimize := true;
    a06_get_priv  (acv, oi_ptr.oi^.oi_base_p, oi_ptr.oi^.oi_priv);
    IF  r_sel in oi_ptr.oi^.oi_priv.priv_all_set
    THEN
        oi_ptr.oi^.oi_priv.priv_sel_set := a01fullset;
    (*ENDIF*) 
    FOR ix := 1 TO oi_ptr.oi^.oi_base_p^.sbase.bmaxcol DO
        IF  ix in oi_ptr.oi^.oi_priv.priv_sel_set
        THEN
            BEGIN
            a06extcolno (oi_ptr.oi^.oi_base_p^.sbase, ix, col_ptr);
            IF  NOT (ctinvisible in col_ptr^.ccolpropset)
            THEN
                oi_ptr.oi^.oi_maxcol := ix
            (*ENDIF*) 
            END;
        (*ENDIF*) 
    (*ENDFOR*) 
    new_cmd_segm := acv.a_cmd_segm;
    (* PTS 1128601 E.Z. *)
    (* PTS 1116567 E.Z. *)
    init_sqlmode   := acv.a_sqlmode;
    (* PTS 1124467 E.Z. *)
    init_dt_format := acv.a_dt_format;
    ak664get_view_definition (acv, oi_ptr.oi^.oi_tabid);
    view_segm        := acv.a_cmd_segm;
    init_ex_kind     := acv.a_ex_kind;
    acv.a_ex_kind    := only_syntax;
    IF  acv.a_returncode = 0
    THEN (* PTS 1116837 M.Ki. *)
        a35_asql_statement (acv);
    (*ENDIF*) 
    acv.a_ex_kind   := init_ex_kind;
    acv.a_sqlmode   := init_sqlmode;
    acv.a_dt_format := init_dt_format;
    qual_end_pos  := c_unknown_end_pos;
    offset        := 0;
    sel_col_index := 0;
    IF  acv.a_returncode = 0
    THEN
        BEGIN
        ak664analyze_syntax_tree (acv, tree_info,
              sel_list_info.sli_aggr, qual_len,
              oi_ptr.oi^.oi_optimize);
        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);
&       ifdef trace
        t01int4 (ak_strat, 'SelPartLen  ', select_part^.sp1p_buf_len);
        t01int4 (ak_strat, 'ViewPartLen ', view_segm^.sp1p_buf_len);
        t01int4 (ak_strat, 'Reserve     ', oi_ptr.oi^.oi_char_size * c_reserve);
&       endif
        acv.a_cmd_segm^.sp1c_prepare  := acv.a_initial_segment_header.sp1c_prepare;
        acv.a_cmd_segm^.sp1c_producer := sp1pr_view_optimizer;
        acv.a_cmd_segment_header      := acv.a_cmd_segm^.sp1s_segm_header;
        END
    ELSE
        WITH tree_info DO
            BEGIN
            ti_qual_found  := false;
            ti_select_node := 0;
            ;
            ti_from_start  := 0;
            ;
            ti_from_end    := 0;
            ;
            ti_qual_end    := 0;
            ;
            ti_end         := 0;
            ;
            END;
        (*ENDWITH*) 
    (*ENDIF*) 
    IF  acv.a_returncode <> 0
    THEN
        oi_ptr.oi^.oi_optimize := false
    ELSE
        BEGIN
        SAPDB_PascalMove ('VAK664',   1,    
              select_part^.sp1p_buf_size,
              acv.a_cmd_part^.sp1p_buf_size,
              @select_part^.sp1p_buf,
              1,
              @acv.a_cmd_part^.sp1p_buf,
              1,
              select_part^.sp1p_buf_len,
              acv.a_returncode);
        IF  acv.a_returncode <> 0
        THEN
            oi_ptr.oi^.oi_optimize := false
        ELSE
            acv.a_cmd_part^.sp1p_buf_len := select_part^.sp1p_buf_len
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    oi_ptr.oi^.oi_in_sel_list := true;
    oi_ptr.oi^.oi_index       := 1;
    prev_col_index := -1;
    WHILE (oi_ptr.oi^.oi_index <= oi_ptr.oi^.oi_count) AND
          oi_ptr.oi^.oi_optimize DO
        BEGIN
        IF  oi_ptr.oi^.oi_info[oi_ptr.oi^.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_ptr.oi^.oi_char_size
            END;
        (*ENDIF*) 
        IF  oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_colno <>
            cak664table_indicator
        THEN
            BEGIN
            IF  oi_ptr.oi^.oi_in_sel_list
            THEN
                sel_col_index := oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_extno;
            (*ENDIF*) 
            add_colname     := false;
            expand_asterisk := false;
            IF  oi_ptr.oi^.oi_in_sel_list AND
                (sel_col_index <= sel_list_info.sli_cnt)
            THEN
                IF  sel_list_info.sli_info[sel_col_index].sli_pos > 0
                THEN
                    expand_asterisk := true
                ELSE
                    add_colname :=
                          (sel_list_info.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,
                      sel_list_info.sli_info[sel_col_index].sli_pos,
                      sel_list_info.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,
                      sel_list_info.sli_info[sel_col_index].sli_len + 1,
                      offset)
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            oi_ptr.oi^.oi_in_sel_list := false;
            ak664substitute (acv, oi_ptr.oi^,
                  tree_info.ti_from_start,
                  tree_info.ti_from_end - tree_info.ti_from_start + 1,
                  view_segm, offset);
            IF  tree_info.ti_from_end <> tree_info.ti_end
            THEN
                BEGIN
                aux_pos   := oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_pos;
                aux_len   := oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_len;
                oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_pos
                      := oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_pos
                      + oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_len;
                oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_len   := 0;
                oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_colno := 1;
                ak664substitute (acv, oi_ptr.oi^,
                      tree_info.ti_from_end + 1,
                      tree_info.ti_qual_end - tree_info.ti_from_end,
                      view_segm, offset);
                IF  tree_info.ti_qual_end <> tree_info.ti_end
                THEN
                    BEGIN
                    oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_colno := 0;
                    ak664substitute (acv, oi_ptr.oi^,
                          tree_info.ti_qual_end + 1,
                          tree_info.ti_end - tree_info.ti_qual_end,
                          view_segm, offset);
                    END;
                (*ENDIF*) 
                oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_pos   := aux_pos;
                oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_len   := aux_len;
                oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_colno := 0;
                END;
            (*ENDIF*) 
            IF  qual_len > 0
            THEN
                BEGIN
                qual_end_pos :=
                      oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_pos
                      + oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_len
                      + qual_len - 1;
                ak664change_where (acv, oi_ptr.oi^.oi_optimize,
                      offset
                      + oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_pos
                      + oi_ptr.oi^.oi_info[oi_ptr.oi^.oi_index].ooi_len,
                      qual_len)
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        prev_col_index := sel_col_index;
        oi_ptr.oi^.oi_index       := oi_ptr.oi^.oi_index + 1
        END;
    (*ENDWHILE*) 
    try_optimization := oi_ptr.oi^.oi_optimize
    END;
(*ENDIF*) 
a664dispose_opt_info (acv);
IF  select_segm <> NIL
THEN
    IF  select_segm^.sp1c_producer in
        [sp1pr_kernel, sp1pr_view_optimizer, sp1pr_complex_view_handling]
    THEN
        a542release_packet (acv, select_segm);
    (*ENDIF*) 
(*ENDIF*) 
IF  view_segm <> NIL
THEN
    a542release_packet (acv, view_segm);
(*ENDIF*) 
IF  try_optimization AND acv.a_intern_explain
THEN
    IF  (acv.a_resname_addr[cak_extern_pos] <> NIL) AND
        (acv.a_resname_addr[cak_extern_pos]^.sresname.restreeid.fileRoot_gg00 <>
        NIL_PAGE_NO_GG00)
    THEN
        BEGIN
        b01empty_file (acv.a_transinf.tri_trans,
              acv.a_resname_addr[cak_extern_pos]^.sresname.restreeid);
        IF  acv.a_transinf.tri_trans.trError_gg00 <> e_ok
        THEN
            try_optimization := false;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
(*ENDIF*) 
IF  NOT try_optimization
THEN
    a542release_packet (acv, acv.a_cmd_segm);
&ifdef trace
(*ENDIF*) 
;
t01int4 (ak_strat, 'try_optimiza', ord (try_optimization));
IF  try_optimization
THEN
    BEGIN
    t01segment (ak_strat, acv.a_cmd_segm^);
    END;
&endif
(*ENDIF*) 
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
from_node := 0;
curr_n    := acv.a_ap_tree^[0].n_lo_level;
IF  (acv.a_ap_tree^[curr_n].n_proc = a63) AND
    (acv.a_ap_tree^[curr_n].n_subproc = cak_x_start_union)
THEN
    (* View containing UNION, EXCEPT, DIFFERENCE *)
    (* cannot be optimized yet                   *)
    try_optimization := false
ELSE
    curr_n := acv.a_ap_tree^[curr_n].n_lo_level;
(*ENDIF*) 
IF  try_optimization
THEN
    IF  (acv.a_ap_tree^[curr_n].n_proc = a63) AND
        (acv.a_ap_tree^[curr_n].n_subproc = cak_x_distinct)
    THEN
        BEGIN
        (* Views containing DISTINCT are not optimized *)
        try_optimization := false;
        curr_n           := acv.a_ap_tree^[curr_n].n_lo_level
        END;
    (*ENDIF*) 
(*ENDIF*) 
IF  try_optimization
THEN
    IF  (acv.a_ap_tree^[curr_n].n_proc = a60) AND
        (acv.a_ap_tree^[curr_n].n_subproc = cak_x_select_list)
    THEN
        BEGIN
        tree_info.ti_select_node := curr_n;
        tree_info.ti_select_node := acv.a_ap_tree^[tree_info.ti_select_node].n_lo_level;
        curr_n                   := acv.a_ap_tree^[curr_n].n_sa_level
        END
    ELSE
        BEGIN
&       ifdef trace
        a07ak_system_error (acv, 664, 1);
&       endif
        try_optimization := false;
        END;
    (*ENDIF*) 
(*ENDIF*) 
IF  try_optimization
THEN
    BEGIN
    aux_n := tree_info.ti_select_node;
    WHILE aux_n <> 0 DO
        BEGIN
        sel_col_node := acv.a_ap_tree^[aux_n].n_lo_level;
        IF  acv.a_ap_tree^[sel_col_node].n_symb = s_authid
        THEN
            sel_col_node := acv.a_ap_tree^[sel_col_node].n_sa_level;
        (*ENDIF*) 
        IF  acv.a_ap_tree^[sel_col_node].n_symb = s_tablename
        THEN
            sel_col_node := acv.a_ap_tree^[sel_col_node].n_sa_level;
        (*ENDIF*) 
        IF  acv.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 := acv.a_ap_tree^[aux_n].n_sa_level;
        (*ENDIF*) 
        END;
    (*ENDWHILE*) 
    IF  try_optimization
    THEN
        BEGIN
        IF  (acv.a_ap_tree^[curr_n].n_proc = a66) AND
            (acv.a_ap_tree^[curr_n].n_subproc = cak_x_given_sequence)
        THEN
            curr_n    := acv.a_ap_tree^[curr_n].n_sa_level;
        (*ENDIF*) 
        IF  (acv.a_ap_tree^[curr_n].n_proc = a63) AND
            (acv.a_ap_tree^[curr_n].n_subproc = cak_x_from_part)
        THEN
            BEGIN
            from_node := acv.a_ap_tree^[curr_n].n_lo_level;
            curr_n    := acv.a_ap_tree^[curr_n].n_sa_level;
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  from_node > 0
    THEN
        BEGIN
        aux_n                   := acv.a_ap_tree^[from_node].n_lo_level;
        tree_info.ti_from_start := acv.a_ap_tree^[aux_n ].n_pos;
        IF  acv.a_cmd_part^.sp1p_buf[tree_info.ti_from_start - 1] = '"'
        THEN
            IF  g01unicode
            THEN
                tree_info.ti_from_start := tree_info.ti_from_start - 2
            ELSE
                tree_info.ti_from_start := tree_info.ti_from_start - 1;
            (*ENDIF*) 
        (*ENDIF*) 
        tree_info.ti_end        := acv.a_cmd_part^.sp1p_buf_len;
        tree_info.ti_from_end   := tree_info.ti_end;
        tree_info.ti_qual_end   := tree_info.ti_end;
        tree_info.ti_qual_found := (acv.a_ap_tree^[curr_n].n_proc = a63) AND
              (acv.a_ap_tree^[curr_n].n_subproc = cak_x_search_condition);
        IF  tree_info.ti_qual_found
        THEN
            BEGIN
            acv.a_scv.sc_newpos := acv.a_ap_tree^[curr_n].n_pos;
            a01_next_symbol (acv);
            a01_get_keyword (acv, kw, dummy);
            IF  kw = cak_i_where
            THEN
                BEGIN
                a01_next_symbol (acv);
                tree_info.ti_from_end := acv.a_scv.sc_sypos - 1;
                IF  acv.a_cmd_part^.sp1p_buf[tree_info.ti_from_end] = '"'
                THEN
                    IF  g01unicode
                    THEN
                        tree_info.ti_from_end := tree_info.ti_from_end - 2
                    ELSE
                        tree_info.ti_from_end := tree_info.ti_from_end - 1;
                    (*ENDIF*) 
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            curr_n := acv.a_ap_tree^[curr_n].n_sa_level
            END;
        (*ENDIF*) 
        IF  curr_n <> 0
        THEN
            BEGIN
            tree_info.ti_qual_end := acv.a_ap_tree^[curr_n].n_pos - 1;
            IF  (acv.a_ap_tree^[curr_n].n_proc = a63) AND
                (acv.a_ap_tree^[curr_n].n_subproc = cak_x_group_by) AND
                ((qual_len > 0) OR aggr_function)
            THEN
                try_optimization := false;
            (*ENDIF*) 
            END
        (*ENDIF*) 
        END;
&   ifdef trace
    (*ENDIF*) 
    t01moveobj (ak_strat, acv.a_cmd_part^.sp1p_buf,
          tree_info.ti_from_start, tree_info.ti_end);
    t01int4 (ak_sem, 'from_end    ', tree_info.ti_from_end);
    t01int4 (ak_sem, 'qual_end    ', tree_info.ti_qual_end);
&   endif
    END;
(*ENDIF*) 
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
acv.a_scv.sc_newpos := pos;
a01_next_symbol (acv);
a01_get_keyword (acv, kw_index, res_kw);
IF  kw_index = cak_i_where
THEN
    BEGIN
    IF  g01unicode
    THEN
        char_size := 2
    ELSE
        char_size := 1;
    (*ENDIF*) 
    IF  acv.a_cmd_part^.sp1p_buf_size >= acv.a_cmd_part^.sp1p_buf_len + char_size
    THEN
        BEGIN
        pos := acv.a_scv.sc_sypos;
        ak664put_char (acv.a_cmd_part^.sp1p_buf, 'A', pos);
        ak664put_char (acv.a_cmd_part^.sp1p_buf, 'N', pos);
        ak664put_char (acv.a_cmd_part^.sp1p_buf, 'D', pos);
        ak664put_char (acv.a_cmd_part^.sp1p_buf, ' ', pos);
        ak664put_char (acv.a_cmd_part^.sp1p_buf, '(', pos);
&       ifdef trace
        t01int4 (ak_strat, 'ChangeWhere ', 1);
        t01int4 (ak_strat, 'BufferSize  ', acv.a_cmd_part^.sp1p_buf_size);
        t01int4 (ak_strat, 'BufferLength', acv.a_cmd_part^.sp1p_buf_len);
        t01int4 (ak_strat, 'SourcePos   ', acv.a_scv.sc_sypos + qual_len);
        t01int4 (ak_strat, 'DestPos     ', acv.a_scv.sc_sypos + qual_len + char_size);
        t01int4 (ak_strat, 'SyScPos     ', acv.a_scv.sc_sypos);
        t01int4 (ak_strat, 'QualLen     ', qual_len);
        t01int4 (ak_strat, 'CharSize    ', char_size);
        t01int4 (ak_strat, 'MoveSize    ', acv.a_cmd_part^.sp1p_buf_len
              - (acv.a_scv.sc_sypos + qual_len - 1));
&       endif
        SAPDB_PascalOverlappingMove ('VAK664',   2,    
              acv.a_cmd_part^.sp1p_buf_size,
              acv.a_cmd_part^.sp1p_buf_size,
              @acv.a_cmd_part^.sp1p_buf,
              acv.a_scv.sc_sypos + qual_len,
              @acv.a_cmd_part^.sp1p_buf,
              acv.a_scv.sc_sypos + qual_len + char_size,
              acv.a_cmd_part^.sp1p_buf_len - (acv.a_scv.sc_sypos + qual_len - 1),
              acv.a_returncode);
        pos := acv.a_scv.sc_sypos + qual_len;
        ak664put_char (acv.a_cmd_part^.sp1p_buf, ')', pos);
        acv.a_cmd_segment_header.sp1s_segm_len := acv.a_cmd_segment_header.sp1s_segm_len + char_size;
        acv.a_cmd_segm^.sp1s_segm_len          := acv.a_cmd_segment_header.sp1s_segm_len;
        acv.a_cmd_part^.sp1p_buf_len           := acv.a_cmd_part^.sp1p_buf_len  + char_size
        END
    ELSE
        BEGIN
        optimize := false;
&       ifdef trace
        t01int4 (ak_strat, 'ChangeWhere ', 2);
        t01int4 (ak_strat, 'Optim=false ', 0);
        t01int4 (ak_strat, 'BufLen      ', acv.a_cmd_part^.sp1p_buf_len);
        t01int4 (ak_strat, 'ScSyPos     ', acv.a_scv.sc_sypos);
        t01int4 (ak_strat, 'QualLen     ', qual_len);
        t01int4 (ak_strat, 'MoveSize    ', acv.a_cmd_part^.sp1p_buf_len
              - (acv.a_scv.sc_sypos + qual_len - 1));
&       endif
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
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
qual_len                := 0;
sel_list_info.sli_cnt   := 0;
sel_list_info.sli_aggr  := false;
sa_level                := 0;
curr_n                  := start_node;
&ifdef trace
t01int4 (ak_strat, 'curr_n      ', curr_n);
&endif
IF  acv.a_ap_tree^[curr_n].n_proc = a43
THEN (* EXPLAIN ... *)
    curr_n := acv.a_ap_tree^[curr_n].n_lo_level;
(*ENDIF*) 
curr_n := acv.a_ap_tree^[curr_n].n_lo_level;
IF  (acv.a_ap_tree^[curr_n].n_proc = a63) AND
    (acv.a_ap_tree^[curr_n].n_subproc = cak_x_distinct)
THEN
    curr_n := acv.a_ap_tree^[curr_n].n_lo_level;
(*ENDIF*) 
IF  acv.a_ap_tree^[curr_n].n_symb = s_identifier
THEN (* result table name *)
    curr_n := acv.a_ap_tree^[curr_n].n_sa_level;
(*ENDIF*) 
IF  (acv.a_ap_tree^[curr_n].n_proc = a60) AND
    (acv.a_ap_tree^[curr_n].n_subproc = cak_x_select_list)
THEN
    BEGIN
    sel_list_info.sli_aggr := acv.a_ap_tree^[curr_n].n_symb in [s_sum, s_count];
    sa_level := acv.a_ap_tree^[curr_n].n_sa_level;
    curr_n   := acv.a_ap_tree^[curr_n].n_lo_level
    END
ELSE
    curr_n := 0;
(*ENDIF*) 
WHILE curr_n <> 0 DO
    BEGIN
    sel_col_node          := acv.a_ap_tree^[curr_n].n_lo_level;
    sel_list_info.sli_cnt := sel_list_info.sli_cnt + 1;
    sel_list_info.sli_info[sel_list_info.sli_cnt].sli_len :=
          acv.a_ap_tree^[curr_n+1].n_pos + acv.a_ap_tree^[curr_n+1].n_length - 1;
    curr_n                := acv.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;
    IF  acv.a_ap_tree^[sel_col_node].n_symb = s_authid
    THEN
        BEGIN
        start_pos    := acv.a_ap_tree^[sel_col_node].n_pos;
        sel_col_node := acv.a_ap_tree^[sel_col_node].n_sa_level
        END;
    (*ENDIF*) 
    IF  acv.a_ap_tree^[sel_col_node].n_symb = s_tablename
    THEN
        BEGIN
        sel_col_node := acv.a_ap_tree^[sel_col_node].n_sa_level;
        IF  start_pos = 0
        THEN
            start_pos := acv.a_ap_tree^[sel_col_node].n_pos
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  acv.a_ap_tree^[sel_col_node].n_symb = s_asterisk
    THEN
        IF  start_pos = 0
        THEN
            BEGIN
            sel_list_info.sli_info[sel_list_info.sli_cnt].sli_pos :=
                  acv.a_ap_tree^[sel_col_node].n_pos;
            IF  g01unicode
            THEN
                sel_list_info.sli_info[sel_list_info.sli_cnt].sli_len := 2
            ELSE
                sel_list_info.sli_info[sel_list_info.sli_cnt].sli_len := 1
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            sel_list_info.sli_info[sel_list_info.sli_cnt].sli_pos
                  := start_pos;
            sel_list_info.sli_info[sel_list_info.sli_cnt].sli_len
                  := acv.a_ap_tree^[sel_col_node].n_pos - start_pos + 1
            END
        (*ENDIF*) 
    ELSE
        IF  acv.a_ap_tree^[sel_col_node].n_symb = s_columnname
        THEN
            sel_list_info.sli_info[sel_list_info.sli_cnt].sli_pos
                  := cak664add_colname
        ELSE
            IF  acv.a_ap_tree^[sel_col_node].n_symb = s_reference_name
            THEN
                sel_list_info.sli_info[sel_list_info.sli_cnt].sli_pos := 0
            ELSE
                BEGIN
                sel_list_info.sli_info[sel_list_info.sli_cnt].sli_pos := -1
                END;
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
IF  (acv.a_ap_tree^[sa_level].n_proc = a60) AND
    (acv.a_ap_tree^[sa_level].n_subproc = cak_x_single_select)
THEN
    sa_level := acv.a_ap_tree^[sa_level].n_sa_level;
(*ENDIF*) 
IF  (acv.a_ap_tree^[sa_level].n_proc = a63) AND
    (acv.a_ap_tree^[sa_level].n_subproc = cak_x_from_part)
THEN
    sa_level := acv.a_ap_tree^[sa_level].n_sa_level;
(*ENDIF*) 
IF  (acv.a_ap_tree^[sa_level].n_proc = a63) AND
    (acv.a_ap_tree^[sa_level].n_subproc = cak_x_search_condition)
THEN
    qual_len := acv.a_ap_tree^[sa_level+1].n_length;
&ifdef trace
(*ENDIF*) 
t01int4 (ak_strat, 'sli_aggr    ', ord (sel_list_info.sli_aggr));
FOR curr_n := 1 TO sel_list_info.sli_cnt DO
    t01p2int4 (ak_strat,
          'sli_pos     ', sel_list_info.sli_info[curr_n].sli_pos,
          'sli_len     ', sel_list_info.sli_info[curr_n].sli_len);
(*ENDFOR*) 
t01int4 (ak_strat, 'qual_len    ', qual_len)
&     endif
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
SAPDB_PascalOverlappingMove ('VAK664',   3,    
      acv.a_cmd_part^.sp1p_buf_size,
      acv.a_cmd_part^.sp1p_buf_size,
      @acv.a_cmd_part^.sp1p_buf,
      offset + asterisk_pos + asterisk_len,
      @acv.a_cmd_part^.sp1p_buf,
      offset + asterisk_pos,
      acv.a_cmd_part^.sp1p_buf_len - (offset + asterisk_pos + asterisk_len) + 1,
      acv.a_returncode);
acv.a_cmd_part^.sp1p_buf_len := acv.a_cmd_part^.sp1p_buf_len - asterisk_len;
ix      := 2;
col_cnt := 0;
WHILE ix <= o_info.oi_maxcol DO
    BEGIN
    IF  ix in o_info.oi_priv.priv_sel_set
    THEN
        BEGIN
        col_cnt   := col_cnt + 1;
&       ifdef trace
        t01int4 (ak_strat, 'oi_index    ', o_info.oi_index);
        t01int4 (ak_strat, 'ooi_extno   ', o_info.oi_info[o_info.oi_index].ooi_extno);
        t01int4 (ak_strat, 'ix          ', ix);
&       endif
        IF  o_info.oi_info[o_info.oi_index].ooi_extno <> ix - 1
        THEN
            BEGIN
            o_info.oi_optimize := false;
            ix                 := o_info.oi_maxcol + 1
            END
        ELSE
            BEGIN
            o_info.oi_info[o_info.oi_index].ooi_colno := ix;
            o_info.oi_info[o_info.oi_index].ooi_pos   := asterisk_pos;
            o_info.oi_info[o_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 < o_info.oi_maxcol, true,
                  asterisk_pos, offset);
            REPEAT
                o_info.oi_index := o_info.oi_index + 1;
            UNTIL
                o_info.oi_info[o_info.oi_index].ooi_extno <> ix - 1;
            (*ENDREPEAT*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    ix := ix + 1
    END;
(*ENDWHILE*) 
offset          := offset - asterisk_len;
o_info.oi_index := o_info.oi_index - 1
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak664get_view_definition (
            VAR acv     : tak_all_command_glob;
            VAR view_id : tgg00_Surrogate);
      (* receive the view definition for VIEW_ID *)
 
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);
      (* create a new tak664opt_info fill the attributes *)
 
VAR
      start_pos : tsp00_Int4;
      oi_ptr    : tak664opt_info_ptr;
 
BEGIN
IF  acv.a_optimize_info.o_do_optimize AND (acv.a_opt_info_ptr = NIL)
THEN
    BEGIN
    a10new (acv, sizeof (tak664opt_info), acv.a_opt_info_ptr);
    IF  acv.a_opt_info_ptr <> NIL
    THEN
        BEGIN
        oi_ptr.sys := acv.a_opt_info_ptr;
        IF  g01unicode
        THEN
            oi_ptr.oi^.oi_char_size := 2
        ELSE
            oi_ptr.oi^.oi_char_size := 1;
        (*ENDIF*) 
        oi_ptr.oi^.oi_tabid      := dmli.d_tabarr^[dmli.d_acttabindex].ofromtableid;
        oi_ptr.oi^.oi_sublevel   := dmli.d_subcount;
        oi_ptr.oi^.oi_start_node := dmli.d_act_node;
        oi_ptr.oi^.oi_cmd_no     := acv.a_max_intern_select - 1;
&       ifdef trace
        t01int4 (ak_strat, 'oi_start_nod', oi_ptr.oi^.oi_start_node);
        t01int4 (ak_strat, 'oi_sublevel ', oi_ptr.oi^.oi_sublevel);
&       endif
        oi_ptr.oi^.oi_count := 1;
        oi_ptr.oi^.oi_info[1].ooi_pos := acv.a_ap_tree^[table_node].n_pos;
        IF  acv.a_cmd_part^.sp1p_buf[oi_ptr.oi^.oi_info[1].ooi_pos-1] = '"'
        THEN
            oi_ptr.oi^.oi_info[1].ooi_pos := oi_ptr.oi^.oi_info[1].ooi_pos - oi_ptr.oi^.oi_char_size;
        (*ENDIF*) 
        start_pos := acv.a_ap_tree^[end_node].n_pos;
        IF  acv.a_cmd_part^.sp1p_buf[start_pos-1] = '"'
        THEN
            start_pos := start_pos - oi_ptr.oi^.oi_char_size;
        (*ENDIF*) 
        acv.a_scv.sc_newpos := start_pos;
        a01_next_symbol (acv);
        oi_ptr.oi^.oi_info[1].ooi_len := start_pos +
              2 * acv.a_scv.sc_double_quote +
              acv.a_scv.sc_sylength - oi_ptr.oi^.oi_info[1].ooi_pos;
        oi_ptr.oi^.oi_info[1].ooi_colno := cak664table_indicator;
        oi_ptr.oi^.oi_info[1].ooi_extno := 0
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak664sort (VAR o_info : tak664opt_info);
      (* sort the array oi_info of tak664one_opt_info contained in tak664opt_info o_info *)
 
VAR
      ix        : integer;
      jx        : integer;
      min       : tsp00_Int4;
      min_index : integer;
      aux       : tak664one_opt_info;
 
BEGIN
min_index := 0;
FOR ix := 1 TO o_info.oi_count - 1 DO
    BEGIN
    min := csp_maxint4;
    FOR jx := ix TO o_info.oi_count DO
        IF  o_info.oi_info[jx].ooi_pos < min
        THEN
            BEGIN
            min       := o_info.oi_info[jx].ooi_pos;
            min_index := jx
            END;
        (*ENDIF*) 
    (*ENDFOR*) 
    IF  min_index <> ix
    THEN
        BEGIN
        aux                       := o_info.oi_info[ix];
        o_info.oi_info[ix]        := o_info.oi_info[min_index];
        o_info.oi_info[min_index] := aux
        END;
    (*ENDIF*) 
    END;
(*ENDFOR*) 
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
IF  add_viewcolname
THEN
    BEGIN
&   ifdef trace
    t01int4 (ak_strat, 'colname_pos ', colname_pos);
&   endif
    a06extcolno (o_info.oi_base_p^.sbase,
          o_info.oi_info[o_info.oi_index].ooi_colno, col_ptr);
    col_len := ord (col_ptr^.ccolumnn_len);
    IF  add_comma
    THEN
        add := 4 * o_info.oi_char_size
    ELSE
        add := 3 * o_info.oi_char_size;
    (*ENDIF*) 
    (* h.b. PTS 1000899 *)
    IF  (acv.a_cmd_part^.sp1p_buf_len + col_len + add > acv.a_cmd_part^.sp1p_buf_size) OR
        (colname_pos + offset > acv.a_cmd_part^.sp1p_buf_len)
    THEN
        o_info.oi_optimize := false
    ELSE
        BEGIN
        colname_pos := offset + colname_pos;
        SAPDB_PascalOverlappingMove ('VAK664',   4,    
              acv.a_cmd_part^.sp1p_buf_size, acv.a_cmd_part^.sp1p_buf_size,
              @acv.a_cmd_part^.sp1p_buf, colname_pos, @acv.a_cmd_part^.sp1p_buf,
              colname_pos + col_len + add,
              acv.a_cmd_part^.sp1p_buf_len - colname_pos + 1,
              acv.a_returncode);
        ak664put_char (acv.a_cmd_part^.sp1p_buf, bsp_c1, colname_pos);
        ak664put_char (acv.a_cmd_part^.sp1p_buf, '"', colname_pos);
        SAPDB_PascalMove ('VAK664',   5,    
              sizeof (col_ptr^.ccolumnn), acv.a_cmd_part^.sp1p_buf_size,
              @col_ptr^.ccolumnn, 1,
              @acv.a_cmd_part^.sp1p_buf, colname_pos, col_len,
              acv.a_returncode);
        colname_pos := colname_pos + col_len;
        ak664put_char (acv.a_cmd_part^.sp1p_buf, '"', colname_pos);
        IF  add_comma
        THEN
            ak664put_char (acv.a_cmd_part^.sp1p_buf, ',', colname_pos);
        (*ENDIF*) 
        acv.a_cmd_part^.sp1p_buf_len := acv.a_cmd_part^.sp1p_buf_len + col_len + add
&             ifdef trace
              ;
        t01moveobj (ak_strat, acv.a_cmd_part^.sp1p_buf, 1, acv.a_cmd_part^.sp1p_buf_len);
&       endif
        END;
    (*ENDIF*) 
    END
ELSE
    BEGIN
    add := 0;
    col_len := 0;
    END;
(*ENDIF*) 
FOR ix := 2 TO o_info.oi_info[o_info.oi_index].ooi_colno - 1 DO
    first_sel_node := acv.a_ap_tree^[first_sel_node].n_sa_level;
(*ENDFOR*) 
&ifdef trace
t01int4 (ak_strat, 'node        ', first_sel_node);
t01int4 (ak_strat, 'start_pos   ',
      acv.a_ap_tree^[first_sel_node+1].n_pos);
t01int4 (ak_strat, 'length      ',
      acv.a_ap_tree^[first_sel_node+1].n_length);
t01int4 (ak_strat, 'oi_maxcol   ', o_info.oi_maxcol);
&endif
BEGIN
pos    := acv.a_ap_tree^[first_sel_node + 1].n_pos;
length := acv.a_ap_tree^[first_sel_node + 1].n_length;
IF  (acv.a_ap_tree^[first_sel_node + 2].n_symb = s_string_literal)
THEN
    BEGIN
    pos    := pred(pos);
    length := succ (length);
    END;
(*ENDIF*) 
END;
ak664substitute (acv, o_info, pos, length, view_segm, offset);
IF  add_viewcolname
THEN
    offset := offset + col_len + add
(*ENDIF*) 
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
old_pos   := o_info.oi_info[o_info.oi_index].ooi_pos;
old_len   := o_info.oi_info[o_info.oi_index].ooi_len;
is_column := o_info.oi_info[o_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, acv.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 * o_info.oi_char_size;
(*ENDIF*) 
IF  required_len > old_len
THEN
    IF  (acv.a_cmd_part^.sp1p_buf_len + required_len > acv.a_cmd_part^.sp1p_buf_size) OR
        (old_pos + offset - 1 > acv.a_cmd_part^.sp1p_buf_len) (* PTS 1113920 *)
    THEN
        o_info.oi_optimize := false
    ELSE
        SAPDB_PascalOverlappingMove ('VAK664',   6,    
              acv.a_cmd_part^.sp1p_buf_size, acv.a_cmd_part^.sp1p_buf_size,
              @acv.a_cmd_part^.sp1p_buf, old_pos + offset,
              @acv.a_cmd_part^.sp1p_buf, old_pos + offset + (required_len - old_len),
              acv.a_cmd_part^.sp1p_buf_len - (old_pos + offset) + 1,
              acv.a_returncode)
    (*ENDIF*) 
ELSE
    IF  required_len <> old_len
    THEN
        SAPDB_PascalOverlappingMove ('VAK664',   7,    
              acv.a_cmd_part^.sp1p_buf_size, acv.a_cmd_part^.sp1p_buf_size,
              @acv.a_cmd_part^.sp1p_buf, offset + old_pos + old_len,
              @acv.a_cmd_part^.sp1p_buf, offset + old_pos + required_len,
              acv.a_cmd_part^.sp1p_buf_len - (offset + old_pos + old_len) + 1,
              acv.a_returncode);
    (*ENDIF*) 
(*ENDIF*) 
IF  acv.a_returncode <> 0
THEN
    o_info.oi_optimize := false;
(*ENDIF*) 
IF  o_info.oi_optimize
THEN
    BEGIN
    pos := old_pos + offset;
    IF  is_column
    THEN
        ak664put_char (acv.a_cmd_part^.sp1p_buf, '(', pos);
    (*ENDIF*) 
    SAPDB_PascalMove ('VAK664',   8,    
          view_segm^.sp1p_buf_size,
          acv.a_cmd_part^.sp1p_buf_size, @view_segm^.sp1p_buf, new_pos,
          @acv.a_cmd_part^.sp1p_buf, pos, new_len,
          acv.a_returncode);
    pos := pos + new_len;
    IF  is_column
    THEN
        ak664put_char (acv.a_cmd_part^.sp1p_buf, ')', pos);
    (*ENDIF*) 
    offset       := offset + (required_len - old_len);
    acv.a_cmd_part^.sp1p_buf_len := acv.a_cmd_part^.sp1p_buf_len + (required_len - old_len);
&   ifdef trace
    t01moveobj (ak_strat, acv.a_cmd_part^.sp1p_buf, 1, acv.a_cmd_part^.sp1p_buf_len)
&         endif
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak664put_char (
            VAR moveobj : tsp00_MoveObj;
            c       : char;
            VAR pos : tsp00_Int4);
      (* insert char C at position POS into MOVEOBJ. take care of unicode *)
 
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);
      (* write content of the array oi_info to the trace *)
 
VAR
      ix     : integer;
      oi_ptr : tak664opt_info_ptr;
 
BEGIN
oi_ptr.sys := acv.a_opt_info_ptr;
FOR ix := 1 TO oi_ptr.oi^.oi_count DO
    BEGIN
    t01int4 (ak_strat, 'extno       ', oi_ptr.oi^.oi_info[ix].ooi_extno);
    t01int4 (ak_strat, 'colno       ', oi_ptr.oi^.oi_info[ix].ooi_colno);
    t01moveobj (ak_strat,
          acv.a_cmd_part^.sp1p_buf, oi_ptr.oi^.oi_info[ix].ooi_pos,
          oi_ptr.oi^.oi_info[ix].ooi_pos + oi_ptr.oi^.oi_info[ix].ooi_len - 1)
    END;
(*ENDFOR*) 
END;
 
&endif
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
.PA 
