.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
*****************************************************
Copyright (c) 2000-2004 SAP AG
SAP Database Technology
 
Release :      Date : 2000-11-27
*****************************************************
modname : VGG04
changed : 2001-03-12
module  : Select_Help_Procedures
 
Author  : ElkeZ
Created : 1985-02-06
*****************************************************
 
Purpose : Makes available procedures for forming keys and
          multiple indexes from strategy structures and
          for building temporary tree_ids
 
Define  :
 
        PROCEDURE
              g04between_keys (
                    VAR mblock       : tgg00_MessBlock;
                    VAR startlistkey : tgg00_Lkey;
                    VAR stoplistkey  : tgg00_Lkey;
                    colstackpos      : integer;
                    startpos         : integer;
                    stoppos          : integer);
 
        PROCEDURE
              g04build_temp_tree_id (
                    VAR curr : tgg00_FileId;
                    VAR t    : tgg00_TransContext);
 
        PROCEDURE
              g04check_if_top_level (
                    VAR mb_st     : tgg00_StackListPtr;
                    stpos         : integer;
                    maxstpos      : integer;
                    VAR top_level : boolean);
 
        PROCEDURE
              g04inbetween_change (
                    VAR mblock           : tgg00_MessBlock;
                    VAR finding_possible : boolean);
 
        PROCEDURE
              g04incheck (
                    VAR mblock : tgg00_MessBlock;
                    stpos      : integer);
 
        PROCEDURE
              g04init_select_fields (
                    VAR sel       : tgg00_SelectFieldsParam;
                    data_addr     : tsp00_MoveObjPtr;
                    data_size     : tsp00_Int4;
                    valarr_addr   : tgg00_ValueListPtr;
                    validx_max    : tsp00_Int4;
                    work_st_addr  : tgg00_StackListPtr;
                    work_st_max   : tsp00_Int2;
                    work_buf_addr : tsp00_MoveObjPtr;
                    work_buf_size : tsp00_Int4;
                    curr_sqlmode  : tsp00_SqlMode);
 
        FUNCTION
              g04inv_tfn (tfn : tgg00_Tfn) : boolean;
 
        PROCEDURE
              g04locate_col (
                    VAR st         : tgg00_StackEntry       (*ptocConst*);
                    rec_buf_ptr    : tgg00_RecPtr          (*ptocSynonym const tgg00_Rec**);
                    VAR varcol_pos : tgg00_VarColPosList;
                    VAR col_pos    : integer;
                    VAR col_len    : integer);
 
        PROCEDURE
              g04LocateOldVarCol (
                    st             : tgg00_StackEntry;
                    rec_buf_ptr    : tgg00_RecPtr;
                    VAR col_pos    : integer;
                    VAR col_len    : integer);
 
        FUNCTION
              g04calc_optimize_info_len (VAR mblock : tgg00_MessBlock): tsp00_Int2;
 
        PROCEDURE
              g04mblock_optimize_info (VAR mblock : tgg00_MessBlock);
 
        PROCEDURE
              g04onevalue (
                    VAR mblock     : tgg00_MessBlock (*ptocConst*);
                    valpos         : tsp00_Int2;
                    last_field     : boolean;
                    descending     : boolean;
                    maxlen         : tsp00_Int2;
                    VAR key        : tgg00_Lkey);
 
        PROCEDURE
              g04subqvalue (
                    VAR subq_buf : tgg00_Rec;
                    last_field   : boolean;
                    descending   : boolean;
                    maxlen       : tsp00_Int2;
                    VAR key      : tgg00_Lkey;
                    VAR e        : tgg00_BasisError);
 
        PROCEDURE
              g04spec_null_check (
                    VAR mblock : tgg00_MessBlock;
                    VAR b_err : tgg00_BasisError);
 
        PROCEDURE
              g04aggr_func (
                    VAR mblock     : tgg00_MessBlock;
                    VAR read_first : boolean;
                    VAR read_last  : boolean;
                    VAR optim      : boolean);
 
        PROCEDURE
              g04read_subquery (
                    VAR mblock      : tgg00_MessBlock;
                    VAR result      : tgg00_Rec;
                    VAR subqtree_id : tgg00_FileId;
                    VAR m_key       : tgg00_Lkey;
                    VAR aux_error   : tgg00_BasisError;
                    VAR ok          : boolean);
 
        PROCEDURE
              g04index_tree_build (
                    VAR file_id    : tgg00_FileId (*ptocConst*);
                    VAR index_tree : tgg00_FileId;
                    index_no       : tsp00_Int2);
 
        FUNCTION
              gg04IsPermStaticTfn (Tfn : tgg00_Tfn) : boolean;
 
        FUNCTION
              gg04IsStaticPage (PageType2 : tgg00_PageType2) : boolean;
              (* ptocExport hgg04_1.h *)
 
        PROCEDURE
              g04limitprimkeys (
                    VAR mblock      : tgg00_MessBlock (*ptocConst*);
                    VAR startkeyarr : tgg07_ColPosArr;
                    VAR start_key   : tgg00_Lkey;
                    VAR stopkeyarr  : tgg07_ColPosArr;
                    VAR stop_key    : tgg00_Lkey;
                    VAR use_stopkey : boolean;
                    in_stack        : tsp00_Int2;
                    in_cnt          : tsp00_Int2);
 
        PROCEDURE
              g04minv_key (
                    VAR mblock    : tgg00_MessBlock (*ptocConst*);
                    VAR subq_buf  : tgg00_Rec;
                    VAR inv_strat : tgg07_StrInvInRange;
                    VAR startkey  : tgg00_Lkey;
                    VAR stopkey   : tgg00_Lkey;
                    in_value_idx  : tsp00_Int2);
 
        PROCEDURE
              g04find_in_stack (
                    VAR mblock      : tgg00_MessBlock (*ptocConst*);
                    VAR keyarr      : tgg07_ColPosArr;
                    VAR in_stack    : tsp00_Int2;
                    VAR in_cnt      : tsp00_Int2);
 
        PROCEDURE
              gg04subq_limitkey (
                    VAR mblock      : tgg00_MessBlock;
                    VAR subq_buf    : tgg00_Rec;
                    VAR keyarr      : tgg07_ColPosArr;
                    VAR one_key     : tgg00_Lkey;
                    VAR use_stopkey : boolean);
 
.CM *-END-* define --------------------------------------
***********************************************************
 
Use     :
 
        FROM
              AK_semantic_scanner_tools : VAK05;
 
        PROCEDURE
              a05luc_space (
                    acv          : tsp00_Addr;
                    VAR buf1     : tsp00_MoveObj;
                    fieldpos1    : tsp00_Int4;
                    fieldlength1 : tsp00_Int4;
                    VAR buf2     : tsp00_MoveObj;
                    fieldpos2    : tsp00_Int4;
                    fieldlength2 : tsp00_Int4;
                    VAR l_result : tsp00_LcompResult);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_1 : VBD01;
 
        VAR
              b01niltree_id : tgg00_FileId;
 
      ------------------------------ 
 
        FROM
              filesysteminterface_2 : VBD02;
 
        PROCEDURE
              b02next_record (
                    VAR t           : tgg00_TransContext;
                    VAR file_id     : tgg00_FileId;
                    VAR rk          : tgg00_Lkey;
                    inclusive       : boolean;
                    VAR b           : tgg00_Rec);
 
      ------------------------------ 
 
        FROM
              Configuration_Parameter : VGG01;
 
        VAR
              g01nil_sel        : tgg00_SfpInitPart;
&       ifdef trace
 
        PROCEDURE
              g01abort (
                    msg_no     : tsp00_Int4;
                    msg_label  : tsp00_C8;
                    msg_text   : tsp00_C24;
                    bad_value  : tsp00_Int4);
&       endif
 
        PROCEDURE
              g01opmsg (
                    msg_prio  : tsp3_priority;
                    msg_type  : tsp3_msg_type;
                    msg_no    : tsp00_Int4;
                    msg_label : tsp00_C8;
                    msg_text  : tsp00_C24;
                    msg_value : tsp00_Int4);
 
      ------------------------------ 
 
        FROM
              GG_cpp_auxiliary_functions : VGG06;
 
        PROCEDURE
              gg06SetNilSession (VAR SessionNo : tgg91_SessionNo);
 
      ------------------------------ 
 
        FROM
              Kernel_move_and_fill : VGG101;
 
        PROCEDURE
              SAPDB_PascalFill (
                    mod_id      : tsp00_C6;
                    mod_num     : tsp00_Int4;
                    obj_upb     : tsp00_Int4;
                    obj         : tsp00_MoveObjPtr;
                    obj_pos     : tsp00_Int4;
                    length      : tsp00_Int4;
                    fillchar    : char;
                    VAR e       : tgg00_BasisError);
 
        PROCEDURE
              SAPDB_PascalUnicodeFill (
                    mod_id      : tsp00_C6;
                    mod_num     : tsp00_Int4;
                    obj_upb     : tsp00_Int4;
                    obj         : tsp00_MoveObjPtr;
                    obj_pos     : tsp00_Int4;
                    length      : tsp00_Int4;
                    fillchar    : tsp00_C2;
                    VAR e       : tgg00_BasisError);
 
        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
              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);
 
      ------------------------------ 
 
        FROM
              GG_edit_routines : VGG17;
 
        PROCEDURE
              g17int4to_line (
                    int       : tsp00_Int4;
                    with_zero : boolean;
                    int_len   : integer;
                    ln_pos    : integer;
                    VAR ln    : tsp00_Line);
 
      ------------------------------ 
 
        FROM
              Trace : VBD120;
 
        PROCEDURE
              b120InsertTrace (
                    VAR Trans  : tgg00_TransContext;
                    TraceLayer : tgg00_Debug;
                    TraceType  : tgg00_VtraceType;
                    BodyLen    : tsp00_Int2;
                    pEntry     : tsp00_Addr);
 
        PROCEDURE
              b120MessBlockTrace (
                    VAR Trans     : tgg00_TransContext;
                    TraceType     : tgg00_VtraceType;
                    VAR MessBlock : tgg00_MessBlock);
 
      ------------------------------ 
 
        FROM
              RTE-Extension-30 : VSP30;
 
        PROCEDURE
              s30luc (
                    VAR buf1     : tsp00_MoveObj;
                    fieldpos1    : tsp00_Int4;
                    fieldlength1 : tsp00_Int4;
                    VAR buf2     : tsp00_MoveObj;
                    fieldpos2    : tsp00_Int4;
                    fieldlength2 : tsp00_Int4;
                    VAR l_result : tsp00_LcompResult);
 
        PROCEDURE
              s30cmp (
                    VAR buf1     : tsp00_Key;
                    fieldpos1    : tsp00_Int4;
                    fieldlength1 : tsp00_Int4;
                    VAR buf2     : tsp00_Key;
                    fieldpos2    : tsp00_Int4;
                    fieldlength2 : tsp00_Int4;
                    VAR l_result : tsp00_LcompResult);
 
        FUNCTION
              s30lnr_defbyte (
                    str       : tsp00_MoveObjPtr;
                    defbyte   : char;
                    start_pos : tsp00_Int4;
                    length    : tsp00_Int4) : tsp00_Int4;
&       ifdef TRACE
 
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        PROCEDURE
              t01sname (
                    debug : tgg00_Debug;
                    nam   : tsp00_Sname);
 
        PROCEDURE
              t01qual (debug : tgg00_Debug; VAR part1 : tgg00_QualBuf);
 
        PROCEDURE
              t01bool (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    curr_bool: boolean);
 
        PROCEDURE
              t01bool2 (
                    debug     : tgg00_Debug;
                    nam1      : tsp00_Sname;
                    bool1     : boolean;
                    nam2      : tsp00_Sname;
                    bool2     : boolean);
 
        PROCEDURE
              t01buf (
                    debug    : tgg00_Debug;
                    VAR buf  : tsp00_Buf;
                    startpos : integer;
                    endpos   : integer);
 
        PROCEDURE
              t01int4 (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    int4     : tsp00_Int4);
 
        PROCEDURE
              t01lkey (
                    debug : tgg00_Debug;
                    VAR k : tgg00_Lkey);
 
        PROCEDURE
              t01name (debug : tgg00_Debug; nam  : tsp00_Name);
 
        PROCEDURE
              t01p2int4 (
                    debug : tgg00_Debug;
                    nam_1 : tsp00_Sname;
                    int_1 : tsp00_Int4;
                    nam_2 : tsp00_Sname;
                    int_2 : tsp00_Int4);
&       endif
 
      ------------------------------ 
 
        FROM
              Unicode-Utilities: VGG20;
 
        PROCEDURE
              g20unifill (
                    size      : tsp00_Int4;
                    m         : tsp00_MoveObjPtr;
                    pos       : tsp00_Int4;
                    len       : tsp00_Int4;
                    filluchar : tsp00_C2);
 
      ------------------------------ 
 
        FROM
              RTE_kernel : VEN101;
 
        PROCEDURE
              vdattime (
                    VAR date     : tsp00_Date;
                    VAR time     : tsp00_Time);
 
.CM *-END-* use -----------------------------------------
***********************************************************
 
Synonym :
 
        PROCEDURE
              a05luc_space;
 
              tak_acv_address tsp00_Addr
 
        PROCEDURE
              b120InsertTrace;
 
              tgg11_VtraceBodyPtr tsp00_Addr
 
        PROCEDURE
              s30cmp;
 
              tsp00_MoveObj tsp00_Key
 
.CM *-END-* synonym -------------------------------------
***********************************************************
 
Specification:
 
G04INBETWEEN_CHANGE
---------------------------------
 
In order to avoid unnecessary qualification checks, in this procedure
the lower and upper bounds of between conditions are compared.  If
lower bound > upper bound, the search is aborted; if
lower bound = upper bound, an equal condition is generated.
In the case of in conditions, any equal values are eliminated.
In the case of LIKE condition, an attempt is made to transform
them into simpler (equal or between) conditions.
 
G04INV_TFN
---------------------------------
 
Returns the value TRUE, if TFN sp[ecifies an inv file.
 
G04LOCATE_COL
---------------------------------
 
The column position COL_POS and the column length COL_LEN are
evaluated for the specified stack entry ST and the record in
the buffer REC_BUF, starting at the position REC_POS, with the length
REC_LEN and the key length KEY_LEN.
.br
The column position COL_POS points to the first byte of the column
(undef byte, not length byte). COL_POS = 1 signifies the first byte
of the buffer REC_BUF. If the column has been
redefined and is not contained in the record, COL_POS is set to
REC_POS + REC_LEN + LENGTH_BYTE(S) and COL_LEN is set to 0.
 
The column length COL_LEN indicates the length of the column,
including the undef byte without the length byte.  For fixed
columns, COL_LEN corresponds to the predefined length, regardless
of the column contents.  For variable columns whose undef byte
is set to UNDEF, COL_LEN=1.  COL_LEN is set to zero only in the
case of variable columns that are not contained in the record or
whose length is specified as zero.
 
  rec_pos = 3
     |       |1) | 2)          |  3)             |  4)     |  5)
     |       V   V             V                 V         V
     V       <-> <--->         <--->             <--->     <------->
 . . . . + . . . . | . . . . + . . . . | . . . . + . . . . | . . . . + .
----=================================================================----
|   |32 | 5 |key| key |  fix  | fix |4|  var  |3| var | 5 |longchar |
----=================================================================----
             <-------> key_len = 5                                rec_buf
     <----------------------- rec_len = 32 ------------------------>
 
   | I N P U T                           | O U T P U T
   | st.etype    | st_epos | st.elen_var | col_pos | col_len
---+-------------+---------+-------------+---------+---------
1) | fixkey      |    1    |      2      |    7    |    2
---+-------------+---------+-------------+---------+---------
2) | varkey      |    3    |     -.-     |    9    |    3
---+-------------+---------+-------------+---------+---------
3) | fixcol      |    5    |      3      |   16    |    3
---+-------------+---------+-------------+---------+---------
4) | varcol      |    8    |      2      |   25    |    3
---+-------------+---------+-------------+---------+---------
5) | varlongchar |    8    |   2     1   |   30    |    5
---+-------------+---------+-------------+---------+---------
6) | varcol      |    5    |      6      |   31    |    0
---+-------------+---------+-------------+---------+---------
7) | varlongchar |    5    |   7     3   |   32    |    0
 
     | rec_pos = 3                                        6) | | 7)
     V                                                       V V
 . . . . + . . . . | . . . . + . . . . | . . . . + . . . . | . . . . + .
----=======================================================--------------
|   |32 | 3 | key |  fix  |4|  var  |5|   var   |4|  var  |
----=======================================================--------------
     <---------------- rec_len = 27 --------------------->        rec_buf
 
 
 
.CM *-END-* specification -------------------------------
***********************************************************
 
Description:
 
G04INBETWEEN_CHANGE
---------------------------------
 
All the qualification stack entries are scanned.  In the case of a
between condition or a NOT-between condition, the two values (if
they are simple values and not field entries of arithmetic expressions)
are compared with one another.  If they are equal, an equal or
not-equal condition is formed; in the case of an invalid size
relation, finding_possible is set to false.
It must be noted that an invalid between in an
'OR' condition does not necessarily mean that the entire qualification
is invalid.  Rather, this between can be overwritten by a Boolean
stack entry (false).
In the case of an IN or NOT-IN condition, the values are compared,
sorted for the sake of simplicity and duplicates are removed.
The sorting cannot yet be exploited at the time of the qualification check
since it is not executed for all qualifications (e.g. single-record
selects, single-record updates, single-record deletes).
An attempt is made via CHECK_LIKE to simplify LIKE and NOT-LIKE
conditions.
These measures serve to minimize the number of queries that must
be executed for each primary record that is to be examined.
 
GG04CHECK_LIKE
---------------------------------
 
If a LIKE or NOT-LIKE condition is present that, based on the specified
value, can be transformed into an equal or between condition,
(sequence of st_fix/var-key/col, st_dummy, st_dummy, st_value),
an attempt is made to carry out this transformation.  The two st_dummy stack
entries are used for the recording of lower and upper bounds of the
between, if necessary.
A (not) equal condition can be formed if no dummy symbol
(star1 or any1) is contained in the value.
A (NOT) between condition can be formed if there is only one
dummy at the end of the value and if this is the dummy that stands
for a random number of characters (star1).
 
G04LIMITPRIMKEYS
---------------------------------
 
From a strategy descriptor for the primary keys (startkeyarr,
stopkeyarr), this procedure
constructs two keys, a start key and a stop key,
forming a range on the given primary index values.
ONE_LIMITKEY is called for each of the two keys.
If not enough values exist to form a complete stop key
(varpos = 0), the incomplete stop key is filled up with 'FF's.
If the use of a stop key is optional (input: use_stopkey = true)
then no-use (output: use_stopkey = false) is signalled to caller
if the stop key is too large( >= FF ) anyway.
 
G04ONE_LIMITKEY
---------------------------------
 
This procedure is
called by G04_LIMIT_KEYS to build one start key or stop key for the
primary key range.
First the number of valid key conditions that can be used is
determined (by searching keyarr from left to right up until the
first entry that is = 0).
Then G04_ONE_VALUE is subsequently called for all given conditions.
Every call is equipped with the parameters last_field and maxlen to
allow adjustment within a composite key.
 
G04MINV_KEY
---------------------------------
 
From a multiple index descriptor block of the type tstr_mindex
(for description, see VAK71 a71_mindex_arr), this procedure constructs
two keys, a start key and a stop key, forming a range on the given
multiple index values.
If siir_equals > 0 in mi_desc, then the values in the descriptor
form a complete EQUAL condition and the stop key is constructed
by simply copying the start key.
For building the keys, G04_ONE_VALUE is subsequently called for all
values stored in mi_desc (i.e. 'siir_startcnt' times for the start key and
'siir_stopcnt' times for the stop key).  For the key parts that are not
covered by a where condition, GG04NIL_VALUE takes care of the correct
fillers.
 
Every call of G04_ONE_VALUE or GG04NIL_VALUE is
equipped with the parameters descending, last_varcol, and maxlen to
allow the adjustment with length and fillers.
If not enough values exist to form a complete stop key (siir_stopcnt <
siir_icount), the incomplete stop key is filled up with 'FF's.
 
G04BETWEEN_KEYS
---------------------------------
 
From a single index strategy descriptor (startpos,stoppos),
this procedure constructs
two keys, a start key and a stop key, forming a range on the given
single index values.
G04_ONE_VALUE is used for constructing either a start key or a
stop key from a given condition. GG04NIL_VALUE creates bottom or
top values if one half of the index range should not be covered
by a condition (startpos=0 or stoppos=0).
 
G04ONE_VALUE
---------------------------------
 
This procedure add
one more value to the multiple index key currently under
construction.
This procedure determines the layout of a multiple index key.  It
functions similarly to K33_MULTINV_KEY and should be kept in
accordance with it.
This procedure should be used globally, wherever values for keys
have to be built from stack entries.
 
Rules for building a multiple key:
 
- all values that do not belong to the last multiple index field
are filled up to the inoutlen (parameter 'maxlen') of the field;
values in descending fields are then inverted (255 - x).
Undefined field values have the format 'FF000000..00' if ascending
and '00FFFF..FF' if descending.
 
- the last field is always truncated (whether fix or var) if
ascending, and it is always filled up to the inoutlen if descending;
values in descending fields are then inverted (255 - x).
If the last field value is undefined, it is appended to
the initial sequence with 'FF' (ascending) or '00FFFF..FF' (desc).
 
- if the value belongs to a field via an exclusive
condition ('>','<'), the value is incremented or decremented to
the next or previous value in the defined key order (procedure
INCRDECREMENT).
 
 
GG04INCRDECREMENT
---------------------------------
 
This procedure
increments or decrements a value to the next higher or lower value
in the given key order.
It takes care of truncation (where possible) and
fillers.
 
Note : A modification will take place in any case since
the conditions '> FFFF...FF' and '< 0000...00'
cannot occur : they have been filtered out by
G04INBETWEEN_CHANGE with 'find_possible=false'
 
GG04NIL_VALUE
---------------------------------
 
Co-procedure to G04_ONE_VALUE.  It is called when a key is being built
and one of its parts (generally the last part) has no
condition.  The top (maximum) or bottom (minimum) values for the
given field domain then must be used. The
procedure makes sure that all undefined values (FF...or 00... ] are
excluded, that descending indexes are handled properly, and that
keys are truncated where allowed.
This procedure should be used globally to ensure consistent treatment of
bottom and top values.
 
.CM *-END-* description ---------------------------------
***********************************************************
.CM -lll-
Code    :
 
 
CONST
      c_start      = true;  (* gg04nil_value *)
      c_stop       = false; (* gg04nil_value *)
      c_last_field = true;  (* g04onevalue   *)
      c_descending = true;  (* g04subq_limitkey *)
 
 
(*------------------------------*) 
 
PROCEDURE
      g04between_keys (
            VAR mblock       : tgg00_MessBlock;
            VAR startlistkey : tgg00_Lkey;
            VAR stoplistkey  : tgg00_Lkey;
            colstackpos      : integer;
            startpos         : integer;
            stoppos          : integer);
 
VAR
      _descending : boolean;
      _maxlen     : integer;
 
BEGIN
&ifdef TRACE
t01int4   (gg, '-colstackpos', colstackpos);
t01p2int4 (gg, '-startpos   ', startpos
      ,        '-stoppos    ', stoppos);
&endif
startlistkey.len := 0;
stoplistkey.len  := 0;
_maxlen           := mblock.mb_st^[ colstackpos ].elen_var;
_descending       := mblock.mb_st^[ colstackpos ].eop
      in [ op_order_desc, op_unique_desc ];
IF  _descending
THEN
    BEGIN
    IF  (startpos = 0)
    THEN
        gg04nil_value (c_last_field, _descending,
              _maxlen, c_stop, stoplistkey, mblock.mb_trns^.trError_gg00)
    ELSE
        g04onevalue (mblock, startpos, c_last_field, _descending,
              _maxlen, stoplistkey);
    (*ENDIF*) 
    IF  (stoppos = 0)
    THEN
        gg04nil_value (c_last_field, _descending,
              _maxlen, c_start, startlistkey, mblock.mb_trns^.trError_gg00)
    ELSE
        g04onevalue (mblock, stoppos, c_last_field, _descending,
              _maxlen, startlistkey);
    (*ENDIF*) 
    END
ELSE (* ascending *)
    BEGIN
    IF  (startpos = 0)
    THEN
        gg04nil_value (c_last_field, _descending,
              _maxlen, c_start, startlistkey, mblock.mb_trns^.trError_gg00)
    ELSE
        g04onevalue (mblock, startpos, c_last_field, _descending,
              _maxlen, startlistkey);
    (*ENDIF*) 
    IF  (stoppos = 0)
    THEN
        gg04nil_value (c_last_field, _descending,
              _maxlen, c_stop, stoplistkey, mblock.mb_trns^.trError_gg00)
    ELSE
        g04onevalue (mblock, stoppos, c_last_field, _descending,
              _maxlen, stoplistkey);
    (*ENDIF*) 
    END;
(*ENDIF*) 
&ifdef TRACE
t01name (gg, 'START_INDEX :     ');
t01lkey (gg, startlistkey);
t01name (gg, 'STOP_INDEX :      ');
t01lkey (gg, stoplistkey);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04build_temp_tree_id (
            VAR curr : tgg00_FileId;
            VAR t : tgg00_TransContext);
 
BEGIN
(* b01niltree_id initialized by b01setto_zero_full_and_null *)
curr := b01niltree_id;
WITH curr DO
    BEGIN
    (* really initialized by b01niltree_id *)
    fileLeafNodes_gg00  := cgg_nil_leafnodes;
    fileHandling_gg00   := fileHandling_gg00 + [hsNoLog_egg00, hsCreateFile_egg00];
    fileResultSite_gg00 := cgg_zero_c2;
    (* really initialized by b01niltree_id *)
    fileType_gg00       := [ftsTemp_egg00];
    fileTfn_gg00        := tfnTemp_egg00;
    (* really initialized by b01niltree_id *)
    fileBdUse_gg00      := [ ];
    fileZeroSite_gg00   := 0;
    gg06SetNilSession (fileSession_gg00); (* shared SQL *)
    fileTfnTemp_gg00    := ttfnNone_egg00
    END
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04check_if_top_level (
            VAR mb_st     : tgg00_StackListPtr;
            stpos         : integer;
            maxstpos      : integer;
            VAR top_level : boolean);
 
VAR
      i : integer;
 
BEGIN
top_level := true;
i := stpos;
WHILE (i <= maxstpos) AND top_level DO
    (* PTS 1117523 E.Z. *)
    IF  (mb_st^[i].etype = st_build_in_func) AND
        (mb_st^[i].eop_build_in = op_b_case_start)
    THEN
        i := i + mb_st^[i].epos + 1
    ELSE
        IF  mb_st^[ i ].eop in [ op_and, op_upd_view_and ]
        THEN
            i := succ(i)
        ELSE
            IF  mb_st^[ i ].etype = st_jump_false
            THEN
                i := i + mb_st^[ i ].epos
            ELSE
                IF  ((i <> maxstpos) OR (mb_st^[ i ].eop = op_or) OR
                    (mb_st^[ i ].eop = op_not))
                THEN
                    top_level := false
                ELSE
                    i:= succ(i)
                (*ENDIF*) 
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
(*ENDWHILE*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04inbetween_change (
            VAR mblock           : tgg00_MessBlock;
            VAR finding_possible : boolean);
 
BEGIN
finding_possible := true;
IF  ( mblock.mb_qual^.mqual_cnt > 0 )
THEN
    gg04change_stack( mblock, mblock.mb_qual^.mqual_pos,
          mblock.mb_qual^.mqual_cnt, finding_possible );
(*ENDIF*) 
IF  ( mblock.mb_qual^.minvqual_cnt > 0 )
THEN
    gg04change_stack( mblock, mblock.mb_qual^.minvqual_pos,
          mblock.mb_qual^.minvqual_cnt, finding_possible );
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04incheck (
            VAR mblock : tgg00_MessBlock;
            stpos      : integer);
 
VAR
      _highvalpos : integer;
      _valpos1    : integer;
      _valpos2    : integer;
      _ix         : tsp00_Int2;
      _lc_result  : tsp00_LcompResult;
      _helpstack  : tgg00_StackEntry;
      _parameter  : boolean;
 
BEGIN
(* stack was manipulated if we found equal IN values *)
(* one of these values becomes st_dummy              *)
_parameter   := false;
_highvalpos  := stpos - 1;
_valpos1     := stpos - mblock.mb_st^[ stpos ].elen_var;
_ix := _valpos1;
(* it's permit to move cgg_param_in_in_expression stack entries *)
(* because these stack entries contains stack entry offsets     *)
(* ecaol_tab[ 2 ] offset to expression                          *)
WHILE ( _ix <= _highvalpos ) AND ( NOT _parameter ) DO
    BEGIN
    IF  ( mblock.mb_data^.
        mbp_buf[ mblock.mb_st^[ _ix ].epos ] = csp_default_byte )
        OR
        (* constant param expression *)
        ( mblock.mb_st^[ _ix ].ecol_tab[ 1 ] = cgg04_param_in_in_expr )
    THEN
        (* first value is a parameter *)
        BEGIN
        _parameter := true;
&       ifdef trace
        t01int4( gg, 'IN parameter', _ix );
&       endif
        END;
    (*ENDIF*) 
    _ix := succ( _ix );
    END;
(*ENDWHILE*) 
IF  ( NOT _parameter )
THEN
    BEGIN
    mblock.mb_st^[ stpos ].ecol_tab[ 1 ]:= chr(1); (* g04_incheck done *)
    WHILE ( _valpos1 <= _highvalpos - 1 ) DO
        BEGIN
        IF  ( mblock.mb_data^.mbp_buf[ mblock.mb_st^[ _valpos1 ].epos ] =
            csp_undef_byte )
        THEN
            IF  ( mblock.mb_data^.mbp_buf[ mblock.mb_st^[ _highvalpos ].epos ] =
                csp_undef_byte )
            THEN
                BEGIN
                mblock.mb_st^[ _valpos1 ].etype := st_dummy;
                mblock.mb_st^[ stpos ].elen_var :=
                      pred( mblock.mb_st^[ stpos ].elen_var );
                END
            ELSE
                BEGIN
                (* SWAP NULL <--> highpos *)
                _helpstack                   := mblock.mb_st^[ _highvalpos ];
                mblock.mb_st^[ _highvalpos ] := mblock.mb_st^[ _valpos1 ];
                mblock.mb_st^[ _valpos1 ]    := _helpstack;
                END;
            (*ENDIF*) 
        (*ENDIF*) 
        IF  ( mblock.mb_st^[ _valpos1 ].etype <> st_dummy )
        THEN
            BEGIN
            _valpos2 := succ( _valpos1 );
            WHILE ( _valpos2 <= _highvalpos ) DO
                BEGIN
                s30luc (mblock.mb_data^.mbp_buf,
                      mblock.mb_st^[ _valpos1 ].epos,
                      mblock.mb_st^[ _valpos1 ].elen_var,
                      mblock.mb_data^.mbp_buf,
                      mblock.mb_st^[ _valpos2 ].epos,
                      mblock.mb_st^[ _valpos2 ].elen_var,
                      _lc_result );
                IF  ( _lc_result = l_greater )
                THEN
                    BEGIN
                    (* SWAP valpos1 <--> valpos2 *)
                    _helpstack                := mblock.mb_st^[ _valpos2 ];
                    mblock.mb_st^[ _valpos2 ] := mblock.mb_st^[ _valpos1 ];
                    mblock.mb_st^[ _valpos1 ] := _helpstack;
                    END
                ELSE
                    BEGIN
                    IF  ( _lc_result = l_equal )
                    THEN
                        BEGIN
                        mblock.mb_st^[ _valpos1 ].etype := st_dummy;
                        mblock.mb_st^[ stpos ].elen_var :=
                              pred( mblock.mb_st^[ stpos ].elen_var );
                        (* break through while loop *)
                        _valpos2   := succ( _highvalpos );
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                _valpos2 := succ( _valpos2 );
                END;
            (*ENDWHILE*) 
            END;
        (*ENDIF*) 
        _valpos1 := succ( _valpos1 );
        END;
    (*ENDWHILE*) 
    IF  ( mblock.mb_qual^.mst_optimize_pos > 0 ) AND
        ( stpos >= mblock.mb_qual^.mqual_pos ) AND
        ( stpos  < mblock.mb_qual^.mqual_pos + mblock.mb_qual^.mqual_cnt )
    THEN
        g04mblock_optimize_info( mblock );
    (*ENDIF*) 
    END;
&ifdef trace
(*ENDIF*) 
t01qual( gg, mblock.mb_qual^ );
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04init_select_fields (
            VAR sel       : tgg00_SelectFieldsParam;
            data_addr     : tsp00_MoveObjPtr;
            data_size     : tsp00_Int4;
            valarr_addr   : tgg00_ValueListPtr;
            validx_max    : tsp00_Int4;
            work_st_addr  : tgg00_StackListPtr;
            work_st_max   : tsp00_Int2;
            work_buf_addr : tsp00_MoveObjPtr;
            work_buf_size : tsp00_Int4;
            curr_sqlmode  : tsp00_SqlMode);
 
BEGIN
sel.sfp_init_part := g01nil_sel;
sel.sfp_data_addr     := data_addr;
sel.sfp_data_size     := data_size;
sel.sfp_valuearr_addr := valarr_addr;
sel.sfp_validx_max    := validx_max;
sel.sfp_work_st_addr  := work_st_addr;
sel.sfp_work_st_max   := work_st_max;
sel.sfp_work_st_size  := work_st_max * sizeof (tgg00_StackEntry);
sel.sfp_workbuf_addr  := work_buf_addr;
sel.sfp_workbuf_size  := work_buf_size;
sel.sfp_sqlmode       := curr_sqlmode;
END;
 
(*------------------------------*) 
 
FUNCTION
      g04inv_tfn (tfn : tgg00_Tfn) : boolean;
 
BEGIN
(* be aware of tgg00_Tfn type *)
g04inv_tfn := (tfn >= tfnOmsInv_egg00) AND (tfn <= tfnTempInv_egg00)
END;
 
(*------------------------------*) 
 
FUNCTION
      gg04IsPermStaticTfn (Tfn : tgg00_Tfn) : boolean;
 
BEGIN
gg04IsPermStaticTfn := (Tfn = tfnObj_egg00);
END;
 
(*------------------------------*) 
 
FUNCTION
      gg04IsStaticPage (PageType2 : tgg00_PageType2) : boolean;
 
BEGIN
gg04IsStaticPage :=
      (PageType2 = pt2Object_egg00    ) OR
      (PageType2 = pt2VarObject_egg00 )
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04limitprimkeys (
            VAR mblock      : tgg00_MessBlock;
            VAR startkeyarr : tgg07_ColPosArr;
            VAR start_key   : tgg00_Lkey;
            VAR stopkeyarr  : tgg07_ColPosArr;
            VAR stop_key    : tgg00_Lkey;
            VAR use_stopkey : boolean;
            in_stack        : tsp00_Int2;
            in_cnt          : tsp00_Int2);
 
VAR
      _dummy  : tsp00_Int2;
      _varpos : tsp00_Int2;
 
BEGIN
gg04one_limitkey( mblock, startkeyarr, start_key, _dummy, in_stack,
      in_cnt, c_start );
gg04one_limitkey( mblock, stopkeyarr, stop_key, _varpos, in_stack,
      in_cnt, c_stop );
IF  ( _varpos = 0 )
THEN
    BEGIN
    (* values for last fields missing;  *)
    SAPDB_PascalFill ('VGG04 ',   1,    
          sizeof( stop_key.k ), @stop_key.k, stop_key.len + 1,
          mxsp_key - stop_key.len, chr( 255 ), mblock.mb_trns^.trError_gg00);
    stop_key.len := mxsp_key;
    END;
(*ENDIF*) 
IF  ( use_stopkey )
THEN
    IF  ( stop_key.len = 0 )
    THEN
        use_stopkey := false
    ELSE
        IF  ( stop_key.k[ 1 ] = chr( 255 ))
        THEN
            BEGIN
            use_stopkey  := false;
            stop_key.len := 0
            END;
        (* PTS 1001813 E.Z. *)
        (*ENDIF*) 
    (*ENDIF*) 
(*ENDIF*) 
;
&ifdef TRACE
IF  ( mblock.mb_trns^.trError_gg00 <> e_move_error )
THEN
    BEGIN
    t01name (gg, 'START_KEY :       ');
    t01lkey (gg, start_key);
    t01name (gg, 'STOP_KEY :        ');
    t01lkey (gg, stop_key);
    IF  use_stopkey
    THEN
        t01name (gg, 'USE STOP_KEY      ');
    (*ENDIF*) 
    END;
&endif
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04locate_col (
            VAR st         : tgg00_StackEntry;
            rec_buf_ptr    : tgg00_RecPtr;
            VAR varcol_pos : tgg00_VarColPosList;
            VAR col_pos    : integer;
            VAR col_len    : integer);
 
VAR
      i        : integer;
      i2       : tsp_int_map_c2;
 
BEGIN
CASE st.etype OF
    st_fixkey:
        BEGIN
        col_pos := cgg_rec_key_offset + st.epos;
        col_len := st.elen_var
        END;
    st_varkey:
        BEGIN
        col_pos := cgg_rec_key_offset + st.epos;
        col_len := rec_buf_ptr^.recKeyLen_gg00 + 1 - st.epos
        END;
    st_fixcol:
        BEGIN
        col_pos := cgg_rec_key_offset + rec_buf_ptr^.recKeyLen_gg00 + st.epos;
        col_len := st.elen_var
        END;
    st_varcol:
        BEGIN
        col_pos := cgg_rec_key_offset + rec_buf_ptr^.recKeyLen_gg00 +
              rec_buf_ptr^.recVarcolOffset_gg00 + 1;
        IF  rec_buf_ptr^.recVarcolCnt_gg00 < st.ecolno
        THEN
            BEGIN
            col_len := 0;
            col_pos := 0
            END
        ELSE
            WITH varcol_pos DO
                BEGIN
                IF  vpl_last >= st.ecolno
                THEN
                    col_pos := vpl_pos_list [st.ecolno]
                ELSE
                    BEGIN
                    IF  vpl_last = -1
                    THEN
                        BEGIN
                        vpl_last         := 1;
                        vpl_pos_list [1] := col_pos
                        END;
                    (*ENDIF*) 
                    col_pos := vpl_pos_list[ vpl_last ];
                    FOR i := vpl_last TO st.ecolno - 1 DO
                        BEGIN
                        col_pos := col_pos + 1 + ord (rec_buf_ptr^.recBuf_gg00[ col_pos ]);
                        vpl_pos_list [i+1] := col_pos
                        END;
                    (*ENDFOR*) 
                    vpl_last := st.ecolno
                    END;
                (*ENDIF*) 
                col_len := ord (rec_buf_ptr^.recBuf_gg00[ col_pos ]);
                col_pos := col_pos + 1
                END
            (*ENDWITH*) 
        (*ENDIF*) 
        END;
    st_varlongchar:
        BEGIN
        col_pos := cgg_rec_key_offset + rec_buf_ptr^.recKeyLen_gg00 +
              rec_buf_ptr^.recVarcolOffset_gg00 + 1;
        (* skip var columns *)
        WITH varcol_pos DO
            BEGIN
            IF  vpl_last >= rec_buf_ptr^.recVarcolCnt_gg00 + 1
            THEN
                col_pos := vpl_pos_list [rec_buf_ptr^.recVarcolCnt_gg00 + 1]
            ELSE
                BEGIN
                IF  vpl_last = -1
                THEN
                    BEGIN
                    vpl_last         := 1;
                    vpl_pos_list [1] := col_pos
                    END;
                (*ENDIF*) 
                col_pos := vpl_pos_list [vpl_last];
                FOR i := vpl_last TO rec_buf_ptr^.recVarcolCnt_gg00 DO
                    BEGIN
                    col_pos := col_pos + 1 + ord (rec_buf_ptr^.recBuf_gg00[ col_pos ]);
                    vpl_pos_list [i+1] := col_pos
                    END;
                (*ENDFOR*) 
                vpl_last := rec_buf_ptr^.recVarcolCnt_gg00 + 1
                END
            (*ENDIF*) 
            END;
        (*ENDWITH*) 
        (* skip long var columns *)
        FOR i := 1 TO st.ecolno - 1 DO
            IF  col_pos < rec_buf_ptr^.recLen_gg00
            THEN
                BEGIN
                i2.map_c2 [ 1 ] := rec_buf_ptr^.recBuf_gg00[ col_pos ];
                i2.map_c2 [ 2 ] := rec_buf_ptr^.recBuf_gg00[ col_pos+1 ];
                col_pos := col_pos + 2 + i2.map_int
                END;
            (*ENDIF*) 
        (*ENDFOR*) 
        IF  col_pos < rec_buf_ptr^.recLen_gg00
        THEN
            BEGIN
            i2.map_c2 [ 1 ] := rec_buf_ptr^.recBuf_gg00[ col_pos ];
            i2.map_c2 [ 2 ] := rec_buf_ptr^.recBuf_gg00[ col_pos+1 ];
            col_len := i2.map_int;
            col_pos := col_pos + 2
            END
        ELSE
            col_len := 0
        (*ENDIF*) 
        END;
    st_object_col:
        BEGIN
        col_pos := st.epos;
        col_len := st.elen_var
        END;
    (* PTS 1116801 E.Z. *)
    st_column:
        IF  rec_buf_ptr^.recVarcolCnt_gg00 < st.ecolno
        THEN
            BEGIN
            col_len := 0;
            col_pos := 0
            END
        ELSE
            BEGIN
            col_pos := RSN_RECHEAD_MXGG00 + rec_buf_ptr^.columnoffset_gg00 [st.ecolno] + 1;
            col_len :=
                  rec_buf_ptr^.columnoffset_gg00 [st.ecolno + 1] -
                  rec_buf_ptr^.columnoffset_gg00 [st.ecolno    ];
            END;
        (*ENDIF*) 
    END
(*ENDCASE*) 
END;
 
(* PTS 1109644 *)
(*------------------------------*) 
 
PROCEDURE
      g04LocateOldVarCol (st : tgg00_StackEntry; (* must not be VAR !! *)
            rec_buf_ptr      : tgg00_RecPtr;
            VAR col_pos      : integer;
            VAR col_len      : integer);
 
VAR
      varcol_pos : tgg00_VarColPosList;
 
BEGIN
varcol_pos.vpl_last := -1;
IF  st.etype = st_old_varcol
THEN
    st.etype := st_varcol
ELSE
    st.etype := st_varlongchar;
(*ENDIF*) 
g04locate_col(st, rec_buf_ptr, varcol_pos, col_pos, col_len)
END;
 
(*------------------------------*) 
 
FUNCTION
      g04calc_optimize_info_len (VAR mblock : tgg00_MessBlock): tsp00_Int2;
 
VAR
      _len    : tsp00_Int2;
 
BEGIN
_len := mblock.mb_qual^.mqual_cnt;
IF  ( _len MOD ALIGNMENT_GG00 > 0 )
THEN
    _len := _len + ALIGNMENT_GG00 - ( _len MOD ALIGNMENT_GG00 );
(*ENDIF*) 
g04calc_optimize_info_len := _len;
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04mblock_optimize_info (VAR mblock : tgg00_MessBlock);
 
VAR
      _do_move    : boolean;
      _new_op     : boolean;
      _stop       : integer;
      _ix         : integer;
      _jx         : integer;
      _kx         : integer;
      _stackptr   : integer;
      _optimizeptr: integer;
      _param_cnt  : integer;
      _offset     : integer;
      _last_output: tsp00_Int4;
      _and_or_cnt : integer;
      _curr_op    : tgg00_StackOpType;
 
BEGIN
_offset := mblock.mb_qual^.mqual_cnt;
IF  ( _offset MOD ALIGNMENT_GG00 > 0 )
THEN
    _offset := _offset + ALIGNMENT_GG00 - ( _offset MOD ALIGNMENT_GG00 );
(*ENDIF*) 
IF  ( mblock.mb_qual^.mst_optimize_pos > 0 ) OR
    (( _offset > 0 ) AND
    ( _offset + 1 <= mblock.mb_data_size - mblock.mb_data_len ))
THEN
    (* optimize info fits into data part *)
    BEGIN
    IF  ( mblock.mb_qual^.mst_optimize_pos = 0 )
    THEN
        BEGIN
        mblock.mb_qual^.mst_optimize_pos := mblock.mb_data_len + 1;
        mblock.mb_data_len               := mblock.mb_data_len + _offset;
        END;
    (*ENDIF*) 
    ;
    (*** initialize optimization area with chr(0) ***)
    FOR _ix := 1 TO _offset DO
        mblock.mb_data^.
              mbp_buf[ mblock.mb_qual^.mst_optimize_pos + _ix - 1 ] := chr( 0 );
    (*ENDFOR*) 
    _stackptr   := mblock.mb_qual^.mqual_pos;
    _stop       := mblock.mb_qual^.mqual_pos + mblock.mb_qual^.mqual_cnt - 1;
    _do_move    := true;
    _param_cnt  := 0;
    _optimizeptr:= _stackptr - mblock.mb_qual^.mqual_pos + 1;
&   ifdef TRACE
    t01int4( gg, '_optimizeptr', _optimizeptr );
&   endif
    _and_or_cnt := 0;
    IF  ( mblock.mb_qual^.mst_addr^[ _stackptr ].etype = st_jump_output )
    THEN
        _last_output := _stackptr +
              mblock.mb_qual^.mst_addr^[ _stackptr ].epos - 2
    ELSE
        _last_output := 0;
    (*ENDIF*) 
&   ifdef trace
    t01int4( gg, 'last_output ', _last_output );
&   endif
    (*** build optimization info ***)
    WHILE ( _stackptr <= _stop ) DO
        BEGIN
        IF  ( _stackptr <= _last_output ) AND
            ( mblock.mb_qual^.mst_addr^[ _stackptr ].etype <= st_value )
        THEN
            BEGIN
            (* _stackptr points to column or value in output list *)
            _kx := _stackptr;
            (* skip over output columns without function *)
            WHILE ( _kx < _last_output)
                  AND
                  ( mblock.mb_qual^.mst_addr^[ _kx  ].etype <= st_value )
                  AND
                  ( mblock.mb_qual^.mst_addr^[ _kx  ].eop   = op_none  )
                  AND
                  ( mblock.mb_qual^.mst_addr^[ _kx + 1 ].etype = st_output )
                  AND
                  ( mblock.mb_qual^.mst_addr^[ _kx + 1 ].eop_out <>
                  op_o_output_hold ) DO
                BEGIN
                _kx := _kx + 2;
                END;
            (*ENDWHILE*) 
            IF  ( _kx <> _stackptr )
            THEN
                BEGIN
                (* mark output column, value, which wasn't *)
                (* combined with functions                 *)
                IF  ((_kx - _stackptr) DIV 2) <= 255
                THEN
                    BEGIN
                    mblock.mb_data^.
                          mbp_buf[ mblock.mb_qual^.mst_optimize_pos +
                          _stackptr - 1 ] := chr( 1 );
                    (* mark output col/val count *)
                    mblock.mb_data^.
                          mbp_buf[ mblock.mb_qual^.mst_optimize_pos +
                          _stackptr ] := chr(( _kx - _stackptr ) DIV 2 );
                    END;
                (*ENDIF*) 
                _stackptr := _kx;
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  ( _stackptr <= _stop )
        THEN
            BEGIN
            IF  ( mblock.mb_qual^.mst_addr^[ _stackptr ].etype = st_op )
                AND
                ( mblock.mb_qual^.mst_addr^[ _stackptr ].eop in
                [ op_and, op_not, op_or, op_upd_view_and ] )
            THEN
                mblock.mb_qual^.mst_addr^[ _stackptr ].epos := 0;
            (* PTS 1117523 E.Z. *)
            (*ENDIF*) 
            IF  (mblock.mb_qual^.mst_addr^[ _stackptr ].etype = st_build_in_func) AND
                (mblock.mb_qual^.mst_addr^[ _stackptr ].eop_build_in = op_b_case_start)
            THEN
                BEGIN
                IF  ( _param_cnt > 1 )
                THEN
                    BEGIN
                    (* remark absolute jumps with adjustment *)
                    mblock.mb_data^.
                          mbp_buf[ mblock.mb_qual^.mst_optimize_pos +
                          _optimizeptr - 1 ] := chr( _param_cnt );
                    mblock.mb_data^.
                          mbp_buf[ mblock.mb_qual^.mst_optimize_pos +
                          _optimizeptr ] := chr( ord( op_none ));
                    END;
                (*ENDIF*) 
                _param_cnt := 0;
                (* prepare _stackptr with jump adress *)
                _stackptr := _stackptr +
                      mblock.mb_qual^.mst_addr^[ _stackptr ].epos
                END
            ELSE
                IF  ( mblock.mb_qual^.mst_addr^[ _stackptr ].etype =
                    st_jump_absolute )
                THEN
                    BEGIN
                    IF  ( _param_cnt > 1 )
                    THEN
                        BEGIN
                        (* remark absolute jumps with adjustment *)
                        mblock.mb_data^.
                              mbp_buf[ mblock.mb_qual^.mst_optimize_pos +
                              _optimizeptr - 1 ] := chr( _param_cnt );
                        mblock.mb_data^.
                              mbp_buf[ mblock.mb_qual^.mst_optimize_pos +
                              _optimizeptr ] := chr( ord( op_none ));
                        END;
                    (*ENDIF*) 
                    _param_cnt := 0;
                    (* prepare _stackptr with jump adress *)
                    _stackptr := _stackptr +
                          mblock.mb_qual^.mst_addr^[ _stackptr ].epos
                    END
                ELSE
                    IF  ( mblock.mb_qual^.mst_addr^[ _stackptr ].etype <= st_value)
                        AND
                        ( _param_cnt < 255 )
                    THEN
                        BEGIN
                        IF  ( mblock.mb_qual^.mst_addr^[ _stackptr ].
                            etype <> st_get_subquery )
                        THEN
                            (* work for column or value *)
                            BEGIN
                            IF  ( _param_cnt = 0 )
                            THEN
                                BEGIN
                                _optimizeptr := _stackptr -
                                      mblock.mb_qual^.mqual_pos + 1;
                                END;
                            (*ENDIF*) 
                            _param_cnt := _param_cnt + 1;
                            IF  ( NOT gg04op_none( mblock.mb_qual^.
                                mst_addr^[ _stackptr ] ))
                            THEN
                                BEGIN
                                (* remark conditions             *)
                                (* parameter count and operation *)
                                IF  ( _param_cnt > 1 )
                                THEN
                                    BEGIN
                                    IF  ( _param_cnt = 2 )
                                        AND
                                        ( mblock.mb_qual^.
                                        mst_addr^[ _stackptr ].eop in
                                        [ op_eq, op_ne,op_ge, op_gt, op_le, op_lt ] )
                                        AND
                                        ( mblock.mb_qual^.
                                        mst_addr^[ _stackptr - 1].eop <>
                                        op_outer_join )
                                    THEN
                                        mblock.mb_data^.mbp_buf
                                              [ mblock.mb_qual^.mst_optimize_pos +
                                              _optimizeptr - 1 ] := chr( 1 )
                                    ELSE
                                        mblock.mb_data^.mbp_buf
                                              [ mblock.mb_qual^.mst_optimize_pos +
                                              _optimizeptr - 1 ] :=
                                              chr ( _param_cnt );
                                    (*ENDIF*) 
                                    mblock.mb_data^.mbp_buf
                                          [ mblock.mb_qual^.mst_optimize_pos +
                                          _optimizeptr ] :=
                                          chr( ord( mblock.mb_qual^.
                                          mst_addr^[ _stackptr].eop ));
                                    END;
                                (*ENDIF*) 
                                _param_cnt := 0;
                                END;
                            (*ENDIF*) 
                            END
                        ELSE
                            _param_cnt := 0;
                        (*ENDIF*) 
                        END
                    ELSE
                        (* no colunm or value or move > 255 *)
                        BEGIN
                        IF  ( _param_cnt > 1 )
                        THEN
                            BEGIN
                            IF  ( _param_cnt = 2 )
                                AND
                                ( mblock.mb_qual^.mst_addr^[ _stackptr ].etype = st_op)
                                AND
                                ( mblock.mb_qual^.mst_addr^[ _stackptr ].eop in
                                [ op_eq, op_ne, op_ge, op_gt, op_le, op_lt ] )
                                AND
                                ( mblock.mb_qual^.mst_addr^[_stackptr - 1 ].eop <>
                                op_outer_join )
                                AND
                                ( mblock.mb_qual^.mst_addr^[_stackptr - 2 ].eop <>
                                op_outer_join )
                            THEN
                                _param_cnt := 1;
                            (*ENDIF*) 
                            mblock.mb_data^.mbp_buf
                                  [ mblock.mb_qual^.mst_optimize_pos +
                                  _optimizeptr - 1] := chr( _param_cnt );
                            IF  ( mblock.mb_qual^.
                                mst_addr^[ _stackptr ].etype = st_op )
                            THEN
                                mblock.mb_data^.mbp_buf
                                      [ mblock.mb_qual^.mst_optimize_pos +
                                      _optimizeptr] :=
                                      chr( ord( mblock.mb_qual^.mst_addr^[ _stackptr ].eop ))
                            ELSE
                                mblock.mb_data^.mbp_buf
                                      [ mblock.mb_qual^.mst_optimize_pos +
                                      _optimizeptr ] := chr( ord (op_none ));
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        _new_op := false;
                        IF  ( mblock.mb_qual^.mst_addr^[ _stackptr ].etype = st_op )
                            AND
                            ( mblock.mb_qual^.mst_addr^[ _stackptr ].eop in
                            [ op_and, op_or ] )
                        THEN
                            IF  ( _and_or_cnt = 0 )
                            THEN
                                BEGIN
                                _and_or_cnt := 1;
                                _curr_op    := mblock.mb_qual^.
                                      mst_addr^[ _stackptr ].eop;
                                END
                            ELSE
                                IF  ( mblock.mb_qual^.
                                    mst_addr^[ _stackptr ].eop = _curr_op )
                                THEN
                                    _and_or_cnt := _and_or_cnt + 1
                                ELSE
                                    _new_op := true;
                                (*ENDIF*) 
                            (*ENDIF*) 
                        (*ENDIF*) 
                        IF  ( mblock.mb_qual^.mst_addr^[ _stackptr ].etype <> st_op )
                            OR
                            NOT ( mblock.mb_qual^.mst_addr^[ _stackptr ].eop in
                            [ op_and, op_or ] )
                            OR
                            (_stackptr = _stop )
                            OR
                            _new_op
                        THEN
                            BEGIN
                            IF  ( _and_or_cnt > 1 )
                            THEN
                                BEGIN
                                IF  ( mblock.mb_qual^.
                                    mst_addr^[ _stackptr ].etype <> st_op )
                                    OR
                                    NOT ( mblock.mb_qual^.
                                    mst_addr^[ _stackptr ].eop in [ op_and, op_or ] )
                                    OR
                                    _new_op
                                THEN
                                    _kx := 1
                                ELSE
                                    (* _stackptr = _stop *)
                                    _kx := 0;
                                (*ENDIF*) 
                                (* manipulate stack *)
                                FOR _jx := 1 TO _and_or_cnt - 1 DO
                                    BEGIN
&                                   ifdef TRACE
                                    (*t01int4(gg, 'manip index ', _stackptr-_jx-_kx);*)
                                    ;
&                                   endif
                                    mblock.mb_qual^.
                                          mst_addr^[ _stackptr - _jx - _kx].epos := _jx;
                                    END;
                                (*ENDFOR*) 
                                END;
                            (*ENDIF*) 
                            IF  ( _new_op )
                            THEN
                                BEGIN
                                _curr_op    := mblock.mb_qual^.
                                      mst_addr^[ _stackptr ].eop;
                                _and_or_cnt := 1;
                                END
                            ELSE
                                _and_or_cnt := 0
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        _param_cnt := 0;
                        END;
                    (*ENDIF*) 
                (*ENDIF*) 
            (*ENDIF*) 
            _stackptr := succ( _stackptr );
            END;
        (*ENDIF*) 
        END;
    (*ENDWHILE*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04minv_key (
            VAR mblock    : tgg00_MessBlock;
            VAR subq_buf  : tgg00_Rec;
            VAR inv_strat : tgg07_StrInvInRange;
            VAR startkey  : tgg00_Lkey;
            VAR stopkey   : tgg00_Lkey;
            in_value_idx  : tsp00_Int2);
 
VAR
      _descending      : boolean;
      _last_field      : boolean;
      _in_stack        : tsp00_Int2;
      _ix              : tsp00_Int2;
      _max_used_fields : tsp00_Int2;
      _valpos          : tsp00_Int2;
      _fieldpos        : tsp00_Int2;
      _fieldmaxlen     : tsp00_Int2;
      _lc_result       : tsp00_LcompResult;
 
BEGIN
(* > in_value_idx must contain every single "st_dummy" ! *)
(*   which determine duplicate IN values                 *)
(* ================================================ *)
(* _max_used_fields=max(siir_startcnt, siir_stopcnt)*)
(* specifies the number of index fields             *)
(* for which a condition is used in                 *)
(* strategey evaluation :                           *)
(* for all these fields the undef values            *)
(* must be skipped                                  *)
(* ================================================ *)
IF  ( inv_strat.siir_startcnt < inv_strat.siir_stopcnt )
THEN
    _max_used_fields := inv_strat.siir_stopcnt
ELSE
    _max_used_fields := inv_strat.siir_startcnt;
(*ENDIF*) 
&ifdef trace
t01int4( ak_strat, 'IN value idx', in_value_idx );
t01int4( ak_strat, 'stopcnt     ', inv_strat.siir_stopcnt );
t01int4( ak_strat, 'startcnt    ', inv_strat.siir_startcnt );
t01int4( ak_strat, 'max_used_fie', _max_used_fields );
&endif
startkey.len := 0;
stopkey.len  := 0;
IF  ( inv_strat.siir_IN_SUBQ_stpos = IS_UNDEFINED_GG07 )
THEN
    _in_stack := 0
ELSE
    _in_stack := inv_strat.siir_IN_SUBQ_stpos;
(*ENDIF*) 
(* --- build startkey --- *)
_ix := 0;
WHILE ( _ix <= _max_used_fields - 1 ) DO
    BEGIN
    _last_field  := (( _ix + 1 ) = inv_strat.siir_icount );
    _descending  := (( _ix + 1 ) in inv_strat.siir_invcoldesc );
&   ifdef trace
    t01bool( ak_strat, 'last field  ', _last_field );
    t01bool( ak_strat, 'descending  ', _descending );
&   endif
    IF  ( _ix <= inv_strat.siir_startcnt - 1 )
    THEN
        BEGIN
        _fieldpos    := abs( inv_strat.siir_invstart[ _ix ] );
        _fieldmaxlen := mblock.mb_st^[ _fieldpos ].elen_var;
        IF  ( mblock.mb_st^[ _fieldpos + 1 ].etype = st_subquery )
        THEN
            g04subqvalue( subq_buf, _last_field, _descending,
                  _fieldmaxlen, startkey, mblock.mb_trns^.trError_gg00 )
        ELSE
            BEGIN
            IF  ( _fieldpos = _in_stack )
            THEN
                BEGIN
                IF  ( in_value_idx > 0 )
                THEN
                    _valpos := _fieldpos + in_value_idx
                ELSE
                    BEGIN
                    IF  ( _descending )
                    THEN
                        (* get greatest value *)
                        BEGIN
                        _valpos := _fieldpos + inv_strat.siir_inelemcnt;
                        (* step forward to IN operator *)
                        WHILE ( mblock.mb_st^[ _valpos + 1 ].etype <> st_op ) DO
                            _valpos := succ( _valpos );
                        (*ENDWHILE*) 
&                       ifdef trace
                        t01int4( gg, 'max IN valpo', _valpos );
&                       endif
                        (* step backward to first none NULL value *)
                        WHILE (( mblock.mb_st^[ _valpos ].etype = st_dummy ) OR
                              ( mblock.mb_data^.mbp_buf[
                              mblock.mb_st^[ _valpos ].epos ] = csp_undef_byte ))
                              AND
                              ( _valpos > _fieldpos + 1 ) DO
                            _valpos := pred( _valpos );
                        (*ENDWHILE*) 
                        END
                    ELSE
                        BEGIN
                        (* get smallest value *)
                        _valpos := _fieldpos +  1;
                        WHILE ( mblock.mb_st^[ _valpos ].etype <> st_value ) AND
                              ( mblock.mb_st^[ _valpos + 1 ].etype <> st_op ) DO
                            _valpos := succ( _valpos );
                        (*ENDWHILE*) 
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                g04onevalue( mblock, _valpos, _last_field,
                      _descending, _fieldmaxlen, startkey );
                END
            ELSE
                BEGIN
                IF  ( inv_strat.siir_invstart[ _ix ] > 0 )
                THEN
                    _valpos :=  inv_strat.siir_invstart[ _ix ] + 1
                ELSE
                    _valpos := -inv_strat.siir_invstart[ _ix ] + 2;
                (*ENDIF*) 
                g04onevalue( mblock, _valpos, _last_field,
                      _descending, _fieldmaxlen, startkey );
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END
    ELSE
        gg04nil_value( _last_field, _descending,
              mblock.mb_st^[ abs( inv_strat.siir_invstop[ _ix ] ) ].elen_var,
              c_start, startkey, mblock.mb_trns^.trError_gg00 );
    (*ENDIF*) 
    _ix := succ( _ix );
    END;
(*ENDWHILE*) 
;
(* --- build stopkey --- *)
IF  ( isp_exact_match in inv_strat.siir_strat_props )
THEN
    BEGIN
    (* ======================== *)
    (* for every field of index *)
    (* a EQUAL-condition exists *)
    (* ======================== *)
    g10mv ('VGG04 ',   2,    
          sizeof (startkey.k), sizeof (stopkey.k),
          @startkey.k, 1,
          @stopkey.k, 1, startkey.len, mblock.mb_trns^.trError_gg00);
    stopkey.len := startkey.len;
    END
ELSE
    BEGIN
    _ix := 0;
    WHILE (_ix <= _max_used_fields - 1) DO
        BEGIN
        _last_field  := ((_ix + 1) = inv_strat.siir_icount);
        _descending  := ((_ix + 1) in inv_strat.siir_invcoldesc);
&       ifdef trace
        t01bool( ak_strat, 'last field  ', _last_field );
        t01bool( ak_strat, 'descending  ', _descending );
&       endif
        IF  ( _ix <= inv_strat.siir_stopcnt - 1 )
        THEN
            BEGIN
            _fieldpos := abs( inv_strat.siir_invstop[ _ix ] );
            _fieldmaxlen := mblock.mb_st^[ _fieldpos ].elen_var;
            IF  ( mblock.mb_st^[ _fieldpos + 1 ].etype = st_subquery )
            THEN
                g04subqvalue( subq_buf, _last_field, _descending,
                      _fieldmaxlen, stopkey, mblock.mb_trns^.trError_gg00 )
            ELSE
                BEGIN
                IF  ( _fieldpos = _in_stack )
                THEN
                    BEGIN
                    IF  ( in_value_idx > 0 )
                    THEN
                        _valpos := _fieldpos + in_value_idx
                    ELSE
                        BEGIN
                        IF  ( _descending )
                        THEN
                            (* get smallest value *)
                            BEGIN
                            _valpos := _fieldpos +  1;
                            WHILE ( mblock.mb_st^[ _valpos ].etype <> st_value ) AND
                                  ( mblock.mb_st^[ _valpos + 1 ].etype <> st_op ) DO
                                _valpos := succ( _valpos );
                            (*ENDWHILE*) 
                            END
                        ELSE
                            (* get greatest value *)
                            BEGIN
                            _valpos := _fieldpos + inv_strat.siir_inelemcnt;
                            (* step forward to IN operator *)
                            WHILE ( mblock.mb_st^[ _valpos + 1 ].etype <> st_op ) DO
                                _valpos := succ( _valpos );
                            (*ENDWHILE*) 
&                           ifdef trace
                            t01int4( gg, 'max IN valpo', _valpos );
&                           endif
                            (* step backward to first none NULL value *)
                            WHILE (( mblock.mb_st^[ _valpos ].etype = st_dummy ) OR
                                  ( mblock.mb_data^.mbp_buf[
                                  mblock.mb_st^[ _valpos ].epos ] = csp_undef_byte ))
                                  AND
                                  ( _valpos > _fieldpos + 1 ) DO
                                _valpos := pred( _valpos );
                            (*ENDWHILE*) 
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    g04onevalue( mblock, _valpos, _last_field,
                          _descending, _fieldmaxlen, stopkey );
                    END
                ELSE
                    BEGIN
                    IF  ( inv_strat.siir_invstop[ _ix ] > 0 )
                    THEN
                        _valpos :=  inv_strat.siir_invstop[ _ix ] + 1
                    ELSE
                        _valpos := -inv_strat.siir_invstop[ _ix ] + 2;
                    (*ENDIF*) 
                    g04onevalue( mblock, _valpos, _last_field,
                          _descending, _fieldmaxlen, stopkey );
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END
        ELSE
            gg04nil_value( _last_field, _descending,
                  mblock.mb_st^[ abs(inv_strat.siir_invstart[ _ix ]) ].elen_var,
                  c_stop, stopkey, mblock.mb_trns^.trError_gg00 );
        (*ENDIF*) 
        _ix := succ( _ix );
        END;
    (*ENDWHILE*) 
    END;
(*ENDIF*) 
IF  ( _max_used_fields < inv_strat.siir_icount )
THEN
    BEGIN (* values for last field(s) missing *)
    SAPDB_PascalFill('VGG04 ',   3,    
          sizeof( stopkey.k ), @stopkey.k, stopkey.len + 1,
          mxsp_key - stopkey.len, chr( 255 ), mblock.mb_trns^.trError_gg00 );
    stopkey.len := mxsp_key;
    END
ELSE
    IF  ( _max_used_fields = inv_strat.siir_stopcnt ) AND
        ( _max_used_fields = inv_strat.siir_startcnt ) AND
        (* we use IN as range operator *)
        ( in_value_idx = 0 )
    THEN
        BEGIN
        s30cmp( startkey.k, 1, startkey.len,
              stopkey.k, 1, stopkey.len,
              _lc_result );
        IF  ( _lc_result = l_equal )
        THEN
            BEGIN
&           ifdef trace
            t01sname( gg, 'INV EQUAL   ' );
&           endif
            inv_strat.siir_strat_props :=
                  inv_strat.siir_strat_props + [ isp_exact_match ];
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
(*ENDIF*) 
;
&ifdef TRACE
t01name (ak_strat, 'START-INDEX       ');
t01lkey (ak_strat, startkey);
t01name (ak_strat, 'STOP-INDEX        ');
t01lkey (ak_strat, stopkey);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04onevalue (
            VAR mblock     : tgg00_MessBlock;
            valpos         : tsp00_Int2;
            last_field     : boolean;
            descending     : boolean;
            maxlen         : tsp00_Int2;
            VAR key        : tgg00_Lkey);
 
VAR
      _found      : boolean;
      _too_long   : boolean;
      _pad_zero   : boolean;
      _ix         : tsp00_Int2;
      _input_len  : tsp00_Int2;
      _newlen     : tsp00_Int2;
      _vallen     : tsp00_Int2;
      _msg_line   : tsp00_C40;
      _trace_line : tsp00_Line;
      _move_err   : tgg00_BasisError;
      _date       : tsp00_Date;
      _time       : tsp00_Time;
      _ilen       : tsp00_Int4;
 
BEGIN
&ifdef TRACE
t01int4   (gg, '-valpos     ', valpos);
t01p2int4 (gg, '-maxlen     ', maxlen
      ,        '-key.len    ', key.len);
t01bool2  (gg, '-descending ', descending
      ,        '-last_field ', last_field);
&endif
_too_long := false;
IF  mblock.mb_trns^.trError_gg00 <> e_move_error
THEN
    BEGIN
    _input_len := mblock.mb_st^[ valpos ].elen_var;
&   ifdef TRACE
    t01int4   (gg, '-vallen     ', _input_len);
&   endif
    (* PTS 1001813 E.Z. *)
    IF  (maxlen < 2) OR (maxlen > mxsp_key - key.len) OR
        (* allow st_op because of BETWEEN --> EQ translation *)
        ( NOT (mblock.mb_st^[ valpos ].etype in [ st_value, st_dummy, st_op ]))
    THEN
        BEGIN
        (* mark ilegal move operations *)
        vdattime (_date, _time);
        _msg_line := 'G04                                     ';
        g10mv ('VGG04 ',   4,    
              sizeof (_msg_line), sizeof (_trace_line),
              @_msg_line, 1, @_trace_line, 1, sizeof(_msg_line), _move_err);
        g10mv ('VGG04 ',   5,    
              sizeof (_date), sizeof (_trace_line),
              @_date, 1, @_trace_line, 5, sizeof(_date), _move_err);
        g10mv ('VGG04 ',   6,    
              sizeof (_time), sizeof (_trace_line),
              @_time, 1, @_trace_line, 5+sizeof(_date)+1, sizeof(_time), _move_err);
        b120InsertTrace (mblock.mb_trns^, gg, gg_opmsg,
              5+sizeof(_date)+sizeof(_time), @_trace_line);
        _msg_line := '    maxlen         valpos               ';
        g10mv ('VGG04 ',   7,    
              sizeof (_msg_line), sizeof (_trace_line),
              @_msg_line, 1, @_trace_line, 1, sizeof(_msg_line), _move_err);
        g17int4to_line (maxlen, false, 5, 11, _trace_line);
        g17int4to_line (valpos, false, 5, 26, _trace_line);
        b120InsertTrace (mblock.mb_trns^, gg, gg_opmsg, 31, @_trace_line);
        _ilen := mblock.mb_data_len;
        b120MessBlockTrace (mblock.mb_trns^, ak_send, mblock);
        mblock.mb_data_len := _ilen;
        g01opmsg (sp3p_knldiag, sp3m_error, csp3_move_error,
              csp3_n_syserror, 'INCONSISTENT STRATEGY   ', valpos);
        mblock.mb_trns^.trError_gg00 := e_move_error;
&       ifdef trace
        g01abort (csp3_move_error, csp3_n_move, 'INCONSISTENT STRATEGY   ', valpos);
&       endif
        END;
    (*ENDIF*) 
    IF  (_input_len > maxlen)
    THEN
        BEGIN
        _input_len := 1 + s30lnr_defbyte (@mblock.mb_data^.mbp_buf,
              mblock.mb_data^.mbp_buf[ mblock.mb_st^[ valpos ].epos ],
              mblock.mb_st^[ valpos ].epos + 1, mblock.mb_st^[ valpos ].elen_var - 1);
&       ifdef TRACE
        t01int4   (gg, '-vallen  2  ', _input_len);
&       endif
        IF  (_input_len > maxlen)
        THEN
            BEGIN
            _too_long  := true;
            _input_len := maxlen;
            _found     := false;
            _ix        := valpos;
            (* check for smallest IN value *)
            WHILE (NOT _found) AND (_ix < mblock.mb_qual^.mfirst_free) DO
                IF  (mblock.mb_st^[ _ix ].eop   =  op_none) AND
                    (mblock.mb_st^[ _ix ].etype in [ st_value, st_dummy ])
                THEN
                    _ix    := succ (_ix)
                ELSE
                    _found := true;
                (*ENDIF*) 
            (*ENDWHILE*) 
            IF  (_ix < mblock.mb_qual^.mfirst_free)
            THEN
                IF  (mblock.mb_st^[ _ix ].etype = st_op) AND
                    (mblock.mb_st^[ _ix ].eop   = op_in)
                THEN
                    (* smallest IN value greater than maxlen *)
                    (* --> never found *)
                    _input_len := 0;
                (*ENDIF*) 
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  (_input_len = 0)
    THEN
        BEGIN
        key.k[ key.len + 1 ] := csp_undef_byte;
        _input_len   := 1;
        END
    ELSE
        (* get data from data part *)
        g10mv ('VGG04 ',   8,    
              mblock.mb_data_size, sizeof (key.k), @mblock.mb_data^.mbp_buf,
              mblock.mb_st^[ valpos ].epos,
              @key.k, key.len+1, _input_len, mblock.mb_trns^.trError_gg00);
    (*ENDIF*) 
    IF  (NOT last_field OR descending)
    THEN
        BEGIN
        IF  _input_len < maxlen
        THEN
            IF  key.k[ key.len + 1 ] = csp_undef_byte
            THEN
                (* "initialize" NULL values *)
                SAPDB_PascalFill ('VGG04 ',   9,    
                      sizeof (key.k), @key.k, key.len + 1 + _input_len,
                      maxlen - _input_len, csp_defined_byte, mblock.mb_trns^.trError_gg00)
            ELSE
                IF  key.k[ key.len + 1 ] = csp_unicode_def_byte
                THEN
                    (* fill rest of unicode fields with blank *)
                    SAPDB_PascalUnicodeFill ('VGG04 ',  10,    
                          sizeof(key.k), @key.k, key.len + 1 + _input_len,
                          maxlen - _input_len, csp_unicode_blank, mblock.mb_trns^.trError_gg00)
                ELSE
                    (* fill rest with define byte *)
                    SAPDB_PascalFill ('VGG04 ',  11,    
                          sizeof (key.k), @key.k, key.len + 1 + _input_len,
                          maxlen - _input_len, key.k[ key.len + 1 ], mblock.mb_trns^.trError_gg00);
                (*ENDIF*) 
            (*ENDIF*) 
        (*ENDIF*) 
        _newlen := key.len + maxlen;
        END
    ELSE (* last_varcol and not descending *)
        IF  (mblock.mb_qual^.mtree.fileTfn_gg00 <> tfnTemp_egg00) AND
            (mblock.mb_st^[ valpos ].eop <> op_eq_all)
        THEN
            IF  key.k[ key.len + 1 ] = csp_undef_byte
            THEN
                _newlen := key.len + 1
            ELSE
                _newlen := key.len + 1 +
                      s30lnr_defbyte (@key.k, key.k[ key.len + 1 ], key.len + 2,
                      _input_len - 1)
            (*ENDIF*) 
        ELSE
            _newlen := _input_len;
        (*ENDIF*) 
    (*ENDIF*) 
    IF  _too_long AND (mblock.mb_st^[ valpos ].eop = op_lt)
    THEN
        mblock.mb_st^[ valpos ].eop := op_le;
    (*ENDIF*) 
    IF  mblock.mb_st^[ valpos ].eop in [ op_gt, op_lt ]
    THEN
        gg04incrdecrement (mblock.mb_st^[ valpos ].eop, maxlen, key, _newlen,
              mblock.mb_trns^.trError_gg00)
    ELSE
        BEGIN
        _pad_zero := false;
        IF  NOT last_field
        THEN
            BEGIN
            _pad_zero := mblock.mb_st^[ valpos ].eop = op_ge;
            IF   (mblock.mb_st^[ valpos ].eop = op_none)
            THEN
                BEGIN
                _pad_zero := mblock.mb_st^[ valpos + 1 ].eop = op_between;
                IF  (mblock.mb_st^[ valpos + 1 ].eop = op_none)
                THEN
                    IF  (mblock.mb_st^[ valpos + 2 ].etype = st_dummy)
                    THEN
                        _pad_zero := mblock.mb_st^[ valpos + 3 ].eop = op_between
                    ELSE
                        IF  (mblock.mb_st^[ valpos + 2 ].etype = st_value)
                        THEN
                            _pad_zero := mblock.mb_st^[ valpos + 3 ].eop = op_like;
                        (*ENDIF*) 
                    (*ENDIF*) 
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
&       ifdef TRACE
        (*ENDIF*) 
        t01int4   (gg, 'pad_zero    ', ord(_pad_zero));
&       endif
        IF  _pad_zero
        THEN
            BEGIN
            _vallen := key.len + 1 +
                  s30lnr_defbyte (@key.k, key.k[ key.len+1 ], key.len+2, _newlen-key.len-1 );
            SAPDB_PascalFill ('VGG04 ',  12,    
                  sizeof (key.k), @key.k, _vallen + 1,
                  _newlen - _vallen, csp_defined_byte, mblock.mb_trns^.trError_gg00);
            END
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  descending AND (mblock.mb_trns^.trError_gg00 <> e_move_error)
    THEN
        BEGIN
        (* create an inverse value *)
        FOR _ix := key.len + 1 TO _newlen DO
            key.k[ _ix ]:= chr(255 - ord(key.k[ _ix ]));
        (*ENDFOR*) 
        FOR _ix := _newlen + 1 TO key.len + maxlen DO
            key.k[ _ix ]:= chr(255);
        (*ENDFOR*) 
        _newlen := key.len + maxlen;
        END;
    (*ENDIF*) 
    key.len := _newlen;
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04subqvalue (
            VAR subq_buf : tgg00_Rec;
            last_field   : boolean;
            descending   : boolean;
            maxlen       : tsp00_Int2;
            VAR key      : tgg00_Lkey;
            VAR e        : tgg00_BasisError);
 
VAR
      _ix         : tsp00_Int2;
      _input_len  : tsp00_Int2;
      _newlen     : tsp00_Int2;
      _vallen     : tsp00_Int2;
      _valpos     : tsp00_Int2;
 
BEGIN
_vallen := subq_buf.len - subq_buf.keylen - cgg_rec_key_offset;
_valpos := subq_buf.len - _vallen + 1;
&ifdef TRACE
t01buf    (gg, subq_buf.buf, 1, subq_buf.len);
t01int4   (gg, '-valpos     ', _valpos);
t01int4   (gg, '-vallen     ', _vallen);
t01p2int4 (gg, '-maxlen     ', maxlen
      ,        '-key.len    ', key.len);
t01bool2  (gg, '-descending ', descending
      ,        '-last_field ', last_field);
&endif
IF  ( _vallen > maxlen )
THEN
    BEGIN
    _vallen := 1 + s30lnr_defbyte( @subq_buf.buf, subq_buf.buf[ _valpos ],
          _valpos + 1, _vallen - 1 );
&   ifdef TRACE
    t01int4   (gg, '-vallen  2  ', _vallen);
&   endif
    END;
(*ENDIF*) 
IF  ( _vallen = 0 ) OR ( _vallen > maxlen )
THEN
    BEGIN
    key.k[ key.len + 1 ] := csp_undef_byte;
    _input_len           := 1;
    END
ELSE
    BEGIN
    _input_len := _vallen;
    g10mv('VGG04 ',  13,    
          sizeof( subq_buf ), sizeof( key.k ),
          @subq_buf, _valpos,
          @key.k, key.len + 1, _input_len, e );
    END;
(*ENDIF*) 
IF  ( NOT last_field OR descending )
THEN
    BEGIN
    IF  ( _input_len < maxlen )
    THEN
        IF  key.k[ key.len + 1 ] = csp_undef_byte
        THEN
            SAPDB_PascalFill('VGG04 ',  14,    
                  sizeof( key.k ), @key.k, key.len + 1 + _input_len,
                  maxlen - _input_len, csp_defined_byte, e )
        ELSE
            IF  ( key.k[ key.len + 1 ] = csp_unicode_def_byte )
            THEN
                SAPDB_PascalUnicodeFill('VGG04 ',  15,    
                      sizeof( key.k ), @key.k, key.len + 1 + _input_len,
                      maxlen - _input_len, csp_unicode_blank, e )
            ELSE
                SAPDB_PascalFill('VGG04 ',  16,    
                      sizeof( key.k ), @key.k, key.len + 1 + _input_len,
                      maxlen - _input_len, key.k[ key.len + 1 ], e );
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    _newlen := key.len + maxlen;
    END
ELSE (* last_varcol and not descending *)
    IF  ( key.k[ key.len + 1 ] = csp_undef_byte )
    THEN
        _newlen := key.len + 1
    ELSE
        _newlen := key.len + 1 +
              s30lnr_defbyte( @key.k, key.k[ key.len + 1 ],
              key.len + 2, _input_len - 1 );
    (*ENDIF*) 
(*ENDIF*) 
IF  ( descending AND ( e <> e_move_error ))
THEN
    FOR _ix := key.len + 1 TO _newlen DO
        key.k[ _ix ]:= chr( 255 - ord( key.k[ _ix ] ));
    (*ENDFOR*) 
(*ENDIF*) 
key.len := _newlen;
END;
 
(*------------------------------*) 
 
PROCEDURE
      gg04change_stack (
            VAR mblock           : tgg00_MessBlock;
            VAR qual_pos         : tsp00_Int2;
            VAR qual_cnt         : tsp00_Int2;
            VAR finding_possible : boolean);
 
VAR
      _maxstpos : integer;
      _startpos : integer;
      _stpos    : integer;
 
BEGIN
IF  ( qual_cnt > 0 )
THEN
    BEGIN
    IF  ( mblock.mb_st^[ qual_pos ].etype = st_jump_output )
    THEN
        _startpos := qual_pos + mblock.mb_st^[ qual_pos ].epos - 1
    ELSE
        _startpos := qual_pos;
    (*ENDIF*) 
    _maxstpos := qual_pos + qual_cnt - 1; (*inclusive*)
    _stpos    := _startpos;
    WHILE _stpos <= _maxstpos DO
        BEGIN
        WHILE (
              ( NOT( mblock.mb_st^[ _stpos ].eop in
              [ op_between, op_not_between,
              op_in, op_not_in,
              op_lt,
              op_like,op_not_like ] ) OR
              (mblock.mb_st^[ _stpos ].etype in [ st_dummy, st_bool,
              st_build_in_func, st_func ] ))
              AND
              ( _stpos <= _maxstpos )
              ) DO
            _stpos := succ( _stpos );
        (*ENDWHILE*) 
        IF  ( _stpos <= _maxstpos )
        THEN
            CASE mblock.mb_st^[ _stpos ].eop OF
                op_between, op_not_between :
                    gg04check_betw( mblock, _stpos, _maxstpos,
                          finding_possible );
                op_lt :
                    (* op_gt not necessary, because > 'ff..ff *)
                    (* not possible                           *)
                    gg04check_lt( mblock, _stpos, _maxstpos,
                          finding_possible );
                op_in, op_not_in :
                    IF  ( mblock.mb_st^[ _stpos ].ecol_tab[ 1 ] = chr( 0 ))
                    THEN
                        g04incheck( mblock, _stpos );
                    (*ENDIF*) 
                op_like, op_not_like :
                    (* ========================== *)
                    (* modify   'like'-stackentry *)
                    (* to 'equal' or 'between' if *)
                    (* possible.                  *)
                    (* ==> VKB71 faster           *)
                    (* ========================== *)
                    gg04check_like( mblock, _stpos );
                OTHERWISE
                    BEGIN
                    END;
                END;
            (*ENDCASE*) 
        (*ENDIF*) 
        _stpos:= succ( _stpos );
        END;
    (*ENDWHILE*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      gg04check_betw (
            VAR mblock           : tgg00_MessBlock;
            stpos                : integer;
            maxstpos             : integer;
            VAR finding_possible : boolean);
 
VAR
      _top_level    : boolean;
      _valpos1      : integer;
      _valpos2      : integer;
      _lc_result    : tsp00_LcompResult;
      _optimize_ptr : tsp00_MoveObjPtr;
 
BEGIN
IF  mblock.mb_st^[ stpos ].etype = st_value
THEN
    BEGIN
    _valpos2:= stpos;
    _valpos1:= stpos - 1;
    IF  ((mblock.mb_st^[ _valpos1 ].etype = st_value) AND
        (mblock.mb_st^[ _valpos1 ].eop = op_none))
    THEN
        BEGIN
        IF  mblock.mb_data^.mbp_buf[ mblock.mb_st^[ _valpos1 ].epos ] = csp_undef_byte
        THEN
            IF  mblock.mb_data^.mbp_buf[ mblock.mb_st^[ _valpos2 ].epos ] = csp_undef_byte
            THEN
                _lc_result := l_equal
            ELSE
                _lc_result := l_greater
            (*ENDIF*) 
        ELSE
            a05luc_space( mblock.mb_trns^.trAcvPtr_gg00,
                  mblock.mb_data^.mbp_buf, mblock.mb_st^[ _valpos1 ].epos,
                  mblock.mb_st^[ _valpos1 ].elen_var, mblock.mb_data^.mbp_buf,
                  mblock.mb_st^[ _valpos2 ].epos,
                  mblock.mb_st^[ _valpos2 ].elen_var,
                  _lc_result);
        (*ENDIF*) 
        IF  _lc_result = l_greater
        THEN
            BEGIN
            g04check_if_top_level (mblock.mb_st, succ (stpos),
                  maxstpos, _top_level);
            IF  _top_level
            THEN
                finding_possible := false;
            (*   mblock.mb_st^[ stpos - 2 ].etype := st_dummy; *)
            (*   mblock.mb_st^[ stpos - 1 ].etype := st_dummy; *)
            (*   WITH mblock.mb_st^[ stpos ] DO                *)
            (*       BEGIN                                 *)
            (*       etype     := st_bool;                 *)
            (*       eop       := op_none;                 *)
            (*       epos      := 0;                       *)
            (*       eval4_var := 0                        *)
            (*       END                                   *)
            (*ENDIF*) 
            END
        ELSE
            IF  _lc_result = l_equal
            THEN
                BEGIN
                mblock.mb_st^[ _valpos2 ].etype := st_op;
                IF  mblock.mb_st^[ _valpos2 ].eop = op_between
                THEN
                    mblock.mb_st^[ _valpos2 ].eop := op_eq
                ELSE
                    mblock.mb_st^[ _valpos2 ].eop := op_ne;
                (*ENDIF*) 
                IF  (mblock.mb_qual^.mst_optimize_pos > 0) AND
                    (_valpos1 >= mblock.mb_qual^.mqual_pos) AND
                    (_valpos1 < mblock.mb_qual^.mqual_pos +
                    mblock.mb_qual^.mqual_cnt)
                THEN
                    BEGIN
                    _optimize_ptr := @mblock.mb_data^.
                          mbp_buf[ mblock.mb_qual^.mst_optimize_pos ];
                    _optimize_ptr^[_valpos1 - mblock.mb_qual^.mqual_pos] := chr(0);
                    _optimize_ptr^[_valpos2 - mblock.mb_qual^.mqual_pos] := chr(0);
                    END;
                (*ENDIF*) 
                END
            (*ENDIF*) 
        (*ENDIF*) 
        END
    (*ENDIF*) 
    END
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      gg04check_like (
            VAR mblock : tgg00_MessBlock;
            stpos : integer);
 
VAR
      _rest_blanks       : boolean;
      _star_or_any_found : boolean;
      _first             : integer;
      _j                 : integer;
      _k                 : integer;
      _def_byte_pos      : integer;
      _last              : integer;
      _offset            : integer;
      _restlen           : integer;
      _found_char        : char;
      _opt_ptr           : tsp00_MoveObjPtr;
 
BEGIN
(* st_column *)
(* st_dummy  *)
(* st_dummy  *)
(* st_value  *)
(* st_op,like  <-- stpos *)
IF  mblock.mb_st^[ stpos - 2 ].etype = st_dummy
THEN
    BEGIN
    (* ============================= *)
    (* stackentry found which may be *)
    (* elligible for optimization    *)
    (* ============================= *)
    _first := mblock.mb_st^[ stpos - 1 ].epos + 1;
    _last  := _first + mblock.mb_st^[ stpos - 1 ].elen_var - 2;
    IF  (_last >= _first)
    THEN
        BEGIN
        _k                 := _first;
        _star_or_any_found := false;
        IF  mblock.mb_data^.mbp_buf [_first-1] = csp_unicode_def_byte
        THEN
            WHILE (_k <= _last) AND NOT _star_or_any_found DO
                IF  ((mblock.mb_data^.mbp_buf [_k+1] = csp_star1) OR
                    ( mblock.mb_data^.mbp_buf [_k+1] = csp_any1)  OR
                    ( mblock.mb_data^.mbp_buf [_k+1] = csp_cclass))
                    AND (mblock.mb_data^.mbp_buf[ _k ] = csp_unicode_mark)
                THEN
                    BEGIN
                    _star_or_any_found := true;
                    _found_char        := mblock.mb_data^.mbp_buf [_k+1];
                    END
                ELSE
                    _k := _k+2
                (*ENDIF*) 
            (*ENDWHILE*) 
        ELSE
            WHILE (_k <= _last) AND NOT _star_or_any_found DO
                IF  (mblock.mb_data^.mbp_buf[ _k ] = csp_star1) OR
                    (mblock.mb_data^.mbp_buf[ _k ] = csp_any1) OR
                    (mblock.mb_data^.mbp_buf[ _k ] = csp_cclass)
                THEN
                    BEGIN
                    _star_or_any_found := true;
                    _found_char        := mblock.mb_data^.mbp_buf [_k];
                    END
                ELSE
                    _k := succ (_k);
                (*ENDIF*) 
            (*ENDWHILE*) 
        (*ENDIF*) 
        IF  NOT _star_or_any_found
        THEN
            BEGIN
            (* ============================= *)
            (* transform to EQUAL-condition  *)
            (* ============================= *)
            IF  mblock.mb_st^[ stpos ].eop = op_like
            THEN
                mblock.mb_st^[ stpos ].eop := op_eq
            ELSE
                mblock.mb_st^[ stpos ].eop := op_ne;
            (*ENDIF*) 
            END
        ELSE
            IF  _found_char = csp_star1
            THEN
                BEGIN
                _j           := _k + 1;
                _rest_blanks := true;
                IF  mblock.mb_data^.mbp_buf [_first-1]
                    = csp_unicode_def_byte
                THEN
                    BEGIN
                    _j := succ(_j);
                    WHILE (_j <= _last) AND _rest_blanks DO
                        IF  (mblock.mb_data^.mbp_buf [_j  ] <> csp_unicode_mark) OR
                            (mblock.mb_data^.mbp_buf [_j+1] <> csp_ascii_blank)
                        THEN
                            _rest_blanks := false
                        ELSE
                            _j := _j + 2
                        (*ENDIF*) 
                    (*ENDWHILE*) 
                    END
                ELSE
                    WHILE (_j <= _last) AND _rest_blanks DO
                        IF  (mblock.mb_data^.mbp_buf[ _j ] <>
                            mblock.mb_data^.mbp_buf[ _first - 1 ])
                        THEN
                            _rest_blanks := false
                        ELSE
                            _j := succ (_j);
                        (*ENDIF*) 
                    (*ENDWHILE*) 
                (*ENDIF*) 
                IF  _rest_blanks
                THEN
                    BEGIN
                    (* ============================== *)
                    (* transform to BETWEEN-condition *)
                    (* ============================== *)
                    IF  mblock.mb_st^[ stpos ].eop = op_like
                    THEN
                        mblock.mb_st^[ stpos ].eop := op_between
                    ELSE
                        mblock.mb_st^[ stpos ].eop := op_not_between;
                    (*ENDIF*) 
                    mblock.mb_st^[ stpos - 1 ].etype := st_dummy;
                    mblock.mb_st^[ stpos - 2 ].etype := st_value;
                    mblock.mb_st^[ stpos - 2 ].eop   := op_none;
                    mblock.mb_st^[ stpos - 3 ].etype := st_value;
                    mblock.mb_st^[ stpos - 3 ].eop   := op_none;
                    IF  (mblock.mb_qual^.mst_optimize_pos > 0) AND
                        (stpos >= mblock.mb_qual^.mqual_pos) AND
                        (stpos < mblock.mb_qual^.mqual_pos +
                        mblock.mb_qual^.mqual_cnt)
                    THEN
                        BEGIN
                        _opt_ptr :=
                              @mblock.mb_data^.mbp_buf[mblock.mb_qual^.mst_optimize_pos];
                        _opt_ptr^[stpos - 4 - mblock.mb_qual^.mqual_pos+1] :=
                              chr(3);
                        _opt_ptr^[stpos - 3 - mblock.mb_qual^.mqual_pos+1] :=
                              chr (ord (op_none))
                        END;
                    (*ENDIF*) 
                    _restlen := _last - _k + 1;
                    _offset  := _k - _first + 1;
                    _def_byte_pos := mblock.mb_st^[ stpos - 3 ].epos;
                    _k := mblock.mb_st^[ stpos - 3 ].epos + _offset;
                    IF  mblock.mb_data^.mbp_buf [_first-1]
                        = csp_unicode_def_byte
                    THEN
                        BEGIN
                        IF  (mblock.mb_data^.mbp_buf[ _k   ] <> csp_unicode_mark) OR
                            (mblock.mb_data^.mbp_buf[ _k+1 ] <> csp_ascii_blank)
                        THEN
                            BEGIN
                            g20unifill (mblock.mb_data_size, @mblock.mb_data^.mbp_buf, _k,
                                  _restlen, csp_unicode_blank);
                            _k := mblock.mb_st^[ stpos - 2 ].epos + _offset;
                            FOR _j := 1 TO _restlen DO
                                BEGIN
                                mblock.mb_data^.mbp_buf[ _k ] := chr(255);
                                _k := succ(_k);
                                END;
                            (*ENDFOR*) 
                            END
                        (*ENDIF*) 
                        END
                    ELSE
                        IF  (mblock.mb_data^.mbp_buf[ _k ] <>
                            mblock.mb_data^.mbp_buf[ _def_byte_pos ])
                        THEN
                            BEGIN
                            (* ============================== *)
                            (* parse-then-execute case;       *)
                            (* bottom- and top-values for be- *)
                            (* tween are not yet in stack     *)
                            (* ============================== *)
                            FOR _j := 1 TO _restlen DO
                                BEGIN
                                mblock.mb_data^.mbp_buf[ _k ] :=
                                      mblock.mb_data^.mbp_buf[ _def_byte_pos ];
                                _k := succ(_k);
                                END;
                            (*ENDFOR*) 
                            _k := mblock.mb_st^[ stpos - 2 ].epos + _offset;
                            FOR _j := 1 TO _restlen DO
                                BEGIN
                                mblock.mb_data^.mbp_buf[ _k ] := chr(255);
                                _k := succ(_k);
                                END;
                            (*ENDFOR*) 
                            END;
                        (*ENDIF*) 
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      gg04check_lt (
            VAR mblock           : tgg00_MessBlock;
            stpos                : integer;
            maxstpos             : integer;
            VAR finding_possible : boolean);
 
VAR
      _all_minmax : boolean;
      _top_level  : boolean;
      _pos        : integer;
 
BEGIN
IF  ( mblock.mb_st^[ stpos ].etype = st_value )
THEN
    BEGIN
    _pos        := mblock.mb_st^[ stpos ].epos;
    _all_minmax := true;
    WHILE (_pos <= mblock.mb_st^[ stpos ].epos + mblock.mb_st^[ stpos ].elen_var - 1) AND _all_minmax DO
        IF  mblock.mb_data^.mbp_buf[ _pos ] = chr(0)
        THEN
            _pos := succ(_pos)
        ELSE
            _all_minmax := false;
        (*ENDIF*) 
    (*ENDWHILE*) 
    IF  _all_minmax
    THEN
        BEGIN
        stpos := succ(stpos);
        g04check_if_top_level (mblock.mb_st, stpos, maxstpos, _top_level);
        IF  _top_level
        THEN
            finding_possible := false;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      gg04incrdecrement (
            eop        : tgg00_StackOpType;
            maxlen     : tsp00_Int2;
            VAR key    : tgg00_Lkey;
            VAR newlen : tsp00_Int2;
            VAR e      : tgg00_BasisError);
 
VAR
      _modified : boolean;
      _pos      : integer;
 
BEGIN
IF  e <> e_move_error
THEN
    BEGIN
    _modified := false;
    (* keys are non interpreted bit structures (from BD's point of view) !*)
    (* take a greater key means take a greater bit sequence !*)
    (* take a smaller key means take a smaller bit sequence !*)
    CASE eop OF
        op_gt :
            (* start key *)
            BEGIN
            IF  (key.k[ key.len + 1 ] > csp_defined_byte (* x'00' *)
                )
            THEN
                (* ASCII   x'20' *)
                (* EBCDIC  x'40' *)
                (* UNICODE x'01' *)
                newlen := key.len + 1 +
                      s30lnr_defbyte (@key.k, key.k[ key.len+1 ], key.len+2, newlen - key.len - 1);
            (*ENDIF*) 
            IF  (newlen < key.len + maxlen)
            THEN
                BEGIN
                (* field has not its full length *)
                _modified   := true;
                newlen     := newlen + 1;
                key.k [newlen] := chr(0);
                END
            ELSE
                BEGIN
                (* field has its full length *)
                _pos := newlen;
                WHILE (_pos > key.len) AND NOT _modified DO
                    BEGIN
                    IF  ( ord(key.k[ _pos ]) < 255 )
                    THEN
                        BEGIN
                        (* increment position found *)
                        _modified := true; (* break through while loop *)
                        key.k[ _pos ] := chr( ord(key.k[ _pos ]) + 1 );
                        newlen   := _pos
                        END
                    ELSE
                        _pos := pred(_pos)
                    (*ENDIF*) 
                    END;
                (*ENDWHILE*) 
                END;
            (*ENDIF*) 
            END;
        op_lt :
            BEGIN
            (* stop key *)
            _pos := newlen;
            WHILE (_pos > key.len) AND NOT _modified DO
                IF  (ord(key.k[ _pos ]) > 0)
                THEN
                    BEGIN
                    _modified := true;
                    key.k[ _pos ] := chr( ord(key.k[ _pos ]) - 1 );
                    SAPDB_PascalFill ('VGG04 ',  17,    
                          sizeof (key.k), @key.k, _pos+1,
                          key.len+maxlen-_pos, chr(255), e);
                    newlen := key.len + maxlen;
                    END
                ELSE
                    _pos := pred(_pos);
                (*ENDIF*) 
            (*ENDWHILE*) 
            END;
        END;
    (*ENDCASE*) 
    END;
(* ======================================================= *)
(* note : A modification will take place in any case as the*)
(*        condition '> FFFF...FF' is impossible (NULL is   *)
(*        shown as FF00...00) and the condition '< 00...00'*)
(*        can not occur : it has been filtered out by      *)
(*        g04inbetween_change with 'find_possible=false'   *)
(* ======================================================= *)
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      gg04nil_value (
            last_field : boolean;
            descending : boolean;
            maxlen     : tsp00_Int2;
            start      : boolean;
            VAR key    : tgg00_Lkey;
            VAR e      : tgg00_BasisError);
 
BEGIN
&ifdef TRACE
t01p2int4 (gg, '-maxlen     ', maxlen
      ,        '-key.len    ', key.len);
t01bool2  (gg, '-descending ', descending
      ,        '-last_field ', last_field);
t01bool   (gg, '-start      ', start);
&endif
IF  e <> e_move_error
THEN
    IF  start
    THEN (* startkey is being built *)
        BEGIN
        IF  descending
        THEN
            key.k[ key.len+1 ] := chr(1) (* skip undefined fields *)
        ELSE
            key.k[ key.len+1 ] := chr(0);
        (*ENDIF*) 
        IF  last_field
        THEN
            key.len := succ(key.len)
        ELSE
            BEGIN
            SAPDB_PascalFill ('VGG04 ',  18,    
                  sizeof (key.k), @key.k, key.len+2, maxlen-1, chr(0), e);
            key.len := key.len + maxlen;
            END;
        (*ENDIF*) 
        END
    ELSE (* stopkey is being built *)
        BEGIN
        IF  descending
        THEN
            key.k[ key.len+1 ] := chr(255)
        ELSE
            key.k[ key.len+1 ] := chr(254); (* skip undefined fields *)
        (*ENDIF*) 
        SAPDB_PascalFill ('VGG04 ',  19,    
              sizeof (key.k), @key.k, key.len+2, maxlen-1, chr(255), e);
        key.len := key.len + maxlen;
        END
    (*ENDIF*) 
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      gg04one_limitkey (
            VAR mblock   : tgg00_MessBlock;
            VAR keyarr   : tgg07_ColPosArr;
            VAR one_key  : tgg00_Lkey;
            VAR varpos   : tsp00_Int2;
            in_stack     : tsp00_Int2;
            in_value_idx : tsp00_Int2;
            is_startkey  : boolean);
 
VAR
      _last_field : boolean;
      _fieldpos   : tsp00_Int2;
      _iy         : tsp00_Int2;
      _maxlen     : tsp00_Int2;
      _valpos     : tsp00_Int2;
 
BEGIN
(* > precondition: at most one equal condition on column     *)
(* > range bounds are optimized, worse bounds are eliminated *)
(* > in_value_idx must contain every single "st_dummy" !     *)
(*   which determine duplicate IN values                     *)
IF  ( mblock.mb_trns^.trError_gg00 <> e_move_error )
THEN
    BEGIN
    one_key.len := 0;
    varpos      := 0; (* means: no st_varkey found yet *)
    _iy         := 0;
&   ifdef TRACE
    t01bool (gg, 'is startkey ', is_startkey);
    t01int4 (gg, 'in stack    ', in_stack);
    t01int4 (gg, 'in val idx  ', in_value_idx);
&   endif
    _iy := 0;
    WHILE ( _iy <= MAX_COLPOSARR_IDX_GG07 ) AND ( keyarr[ _iy ] <> 0 ) DO
        BEGIN
        _fieldpos := abs( keyarr[ _iy ] );
        IF  ( _fieldpos = in_stack )
        THEN
            BEGIN
            IF  ( in_value_idx > 0 )
            THEN
                _valpos := _fieldpos + in_value_idx
            ELSE
                (* negative in_value_idx *)
                BEGIN
                IF  ( is_startkey )
                THEN
                    BEGIN
                    _valpos := _fieldpos +  1;
                    WHILE ( mblock.mb_st^[ _valpos ].etype <> st_value ) AND
                          ( mblock.mb_st^[ _valpos + 1 ].etype <> st_op ) DO
                        _valpos := succ( _valpos );
                    (*ENDWHILE*) 
                    END
                ELSE
                    BEGIN
                    _valpos := _fieldpos - in_value_idx;
                    (* step forward to IN operator *)
                    WHILE ( mblock.mb_st^[ _valpos + 1 ].etype <> st_op ) DO
                        _valpos := succ( _valpos );
                    (*ENDWHILE*) 
&                   ifdef trace
                    t01int4 (gg, 'max IN valpo', _valpos);
&                   endif
                    (* step backward to first none NULL value *)
                    WHILE (( mblock.mb_st^[ _valpos ].etype = st_dummy ) OR
                          ( mblock.mb_data^.mbp_buf[
                          mblock.mb_st^[ _valpos ].epos ] = csp_undef_byte )) AND
                          ( _valpos > _fieldpos + 1 ) DO
                        _valpos := pred( _valpos );
                    (*ENDWHILE*) 
                    END
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END
        ELSE
            IF  ( keyarr[ _iy ] > 0 )
            THEN
                _valpos := _fieldpos + 1
            ELSE
                (* second value of BETWEEN condition *)
                _valpos := _fieldpos + 2;
            (*ENDIF*) 
        (*ENDIF*) 
        IF  ( _iy < MAX_COLPOSARR_IDX_GG07 ) AND
            ( keyarr[ _iy + 1 ] <> 0 )
        THEN
            _last_field := false
        ELSE
            IF  ( mblock.mb_st^[ _fieldpos ].etype in
                [ st_varkey, st_varprimkey ] )
                OR
                (( mblock.mb_st^[ _fieldpos ].etype = st_varinv ) AND
                ( mblock.mb_st^[ _fieldpos ].ecol_tab[ 1 ] = VARKEY_GG07 ))
                OR
                (( mblock.mb_st^[ _fieldpos ].etype = st_fixinv ) AND
                ( mblock.mb_st^[ _fieldpos ].ecol_tab[ 1 ] = VARKEY_GG07 ))
            THEN
                BEGIN
                _last_field := true;
                varpos      := one_key.len + 1;
                END
            ELSE
                _last_field := false;
            (*ENDIF*) 
        (*ENDIF*) 
        IF  ( _last_field )
        THEN
            _maxlen := mxsp_key + 1 - varpos
        ELSE
            _maxlen := mblock.mb_st^[ _fieldpos ].elen_var;
        (*ENDIF*) 
        g04onevalue( mblock, _valpos, _last_field, NOT c_descending,
              _maxlen, one_key );
        _iy := succ( _iy );
        END;
    (*ENDWHILE*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
FUNCTION
      gg04op_none (VAR st : tgg00_StackEntry) : boolean;
 
BEGIN
gg04op_none :=
      ( st.eop in [ op_none, op_order_asc, op_unique ] )
      OR
      (( st.eop in [ op_order_desc, op_unique_desc ] ) AND
      ( st.etype <> st_fixinv ) AND ( st.etype <> st_varinv ))
END;
 
(*------------------------------*) 
 
PROCEDURE
      gg04subq_limitkey (
            VAR mblock      : tgg00_MessBlock;
            VAR subq_buf    : tgg00_Rec;
            VAR keyarr      : tgg07_ColPosArr;
            VAR one_key     : tgg00_Lkey;
            VAR use_stopkey : boolean);
 
VAR
      _last_field : boolean;
      _ix         : tsp00_Int2;
      _fieldpos   : tsp00_Int2;
      _maxlen     : tsp00_Int2;
      _varpos     : tsp00_Int2;
      _valpos     : tsp00_Int2;
 
BEGIN
_ix         := 0;
_varpos     := 0; (* means: no st_varkey found yet *)
one_key.len := 0;
WHILE _ix <= MAX_COLPOSARR_IDX_GG07 DO
    BEGIN
    _fieldpos := abs(keyarr[ _ix ]);
    IF  (_fieldpos <> 0)
    THEN
        BEGIN
        _last_field := false;
        IF  (mblock.mb_st^[ _fieldpos ].etype in
            [ st_varkey, st_varprimkey ])                 OR
            ((mblock.mb_st^[ _fieldpos ].etype = st_varinv) AND
            (mblock.mb_st^[ _fieldpos ].elen_var = 0))            OR
            ((mblock.mb_st^[ _fieldpos ].etype = st_fixinv) AND
            (ord(mblock.mb_st^[ _fieldpos ].ecol_tab[ 1 ]) = 255))
        THEN
            BEGIN
            _last_field := true;
            _varpos     := one_key.len + 1;
            END;
        (*ENDIF*) 
        IF  _last_field
        THEN
            _maxlen := mxsp_key - _varpos
        ELSE
            _maxlen := mblock.mb_st^[ _fieldpos ].elen_var;
        (*ENDIF*) 
        IF  (mblock.mb_st^[ _fieldpos + 1 ].etype = st_subquery)
        THEN
            g04subqvalue (subq_buf, _last_field,
                  NOT c_descending, _maxlen, one_key,
                  mblock.mb_trns^.trError_gg00)
        ELSE
            BEGIN
            IF  (keyarr[ _ix ] > 0)
            THEN
                _valpos := _fieldpos + 1
            ELSE
                _valpos := _fieldpos + 2;
            (*ENDIF*) 
            g04onevalue (mblock, _valpos, _last_field, false,
                  _maxlen, one_key);
            END
        (*ENDIF*) 
        END
    ELSE
        _ix := MAX_COLPOSARR_IDX_GG07;
    (*ENDIF*) 
    _ix := succ(_ix);
    END;
(*ENDWHILE*) 
IF  use_stopkey
THEN
    BEGIN
    IF  (_varpos = 0)
    THEN
        BEGIN
        (* values for last fields missing;  *)
        SAPDB_PascalFill ('VGG04 ',  20,    
              sizeof (one_key.k), @one_key.k, one_key.len + 1,
              mxsp_key - one_key.len, chr(255), mblock.mb_trns^.trError_gg00);
        one_key.len := mxsp_key;
        END;
    (*ENDIF*) 
    IF  one_key.len = 0
    THEN
        use_stopkey := false
    ELSE
        IF  one_key.k[ 1 ] = chr(255)
        THEN
            BEGIN
            use_stopkey  := false;
            one_key.len  := 0
            END;
&       ifdef TRACE
        (*ENDIF*) 
    (*ENDIF*) 
    IF  use_stopkey
    THEN
        BEGIN
        t01name (gg, 'STOP_KEY :        ');
        t01lkey (gg, one_key);
        END
    ELSE
        t01name (gg, 'USE NO STOP_KEY   ');
    (*ENDIF*) 
&   endif
    END
ELSE
    BEGIN
&   ifdef TRACE
    t01name (gg, 'START_KEY :       ');
    t01lkey (gg, one_key);
&   endif
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04spec_null_check (
            VAR mblock : tgg00_MessBlock;
            VAR b_err : tgg00_BasisError);
 
VAR
      _start : tsp00_Int2;
      _stop  : tsp00_Int2;
 
BEGIN
b_err  := e_ok;
_start := mblock.mb_qual^.mqual_pos;
IF  _start > 0
THEN
    BEGIN
    IF  mblock.mb_st^[ _start ].etype = st_jump_output
    THEN
        _start := _start + mblock.mb_st^[ _start ].epos - 1;
    (*ENDIF*) 
    _stop := mblock.mb_qual^.mqual_pos + mblock.mb_qual^.mqual_cnt - 1;
    WHILE (_start <= _stop) AND (b_err = e_ok) DO
        BEGIN
        IF  (mblock.mb_st^[ _start ].etype = st_value)
        THEN
            IF  (mblock.mb_st^[ _start ].ecol_tab[ 1 ] = chr(0))
                AND (mblock.mb_data^.mbp_buf[ mblock.mb_st^[ _start ].epos]  = csp_oflw_byte)
            THEN
                b_err := e_special_null;
            (*ENDIF*) 
        (*ENDIF*) 
        _start := succ(_start);
        END;
    (*ENDWHILE*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04aggr_func (
            VAR mblock     : tgg00_MessBlock;
            VAR read_first : boolean;
            VAR read_last  : boolean;
            VAR optim      : boolean);
 
VAR
      ix               : tsp00_Int2;
      stop             : tsp00_Int2;
      field_found      : boolean;
      funct_found      : boolean;
      value_found      : boolean;
      check_null_found : boolean;
 
BEGIN
optim            := true;
field_found      := false;
funct_found      := false;
value_found      := false;
check_null_found := false;
ix               := mblock.mb_qual^.mqual_pos;
IF  (mblock.mb_st^[ mblock.mb_qual^.mqual_pos ].etype = st_jump_output)
THEN
    BEGIN
    ix   := succ(ix);
    stop := mblock.mb_qual^.mqual_pos + mblock.mb_st^[ mblock.mb_qual^.mqual_pos ].epos - 2;
    END
ELSE
    optim := false;
(*ENDIF*) 
WHILE (ix <= stop) AND optim DO
    BEGIN
    CASE mblock.mb_st^[ ix ].etype OF
        st_fixkey,
        st_varkey :
            IF  NOT field_found
            THEN
                BEGIN
                field_found := true;
                IF  (mblock.mb_st^[ ix ].epos <> 1)
                THEN
                    optim := false;
                (*ENDIF*) 
                END
            ELSE
                optim := false;
            (*ENDIF*) 
        st_func :
            IF  (NOT funct_found) AND field_found
            THEN
                BEGIN
                funct_found := true;
                CASE mblock.mb_st^[ ix ].eop_func OF
                    op_f_min :
                        read_first := true;
                    op_f_max :
                        read_last  := true;
                    op_f_none :
                        IF  field_found
                        THEN
                            optim := false;
                        (*ENDIF*) 
                    OTHERWISE
                        optim := false;
                    END;
                (*ENDCASE*) 
                END
            ELSE
                IF  (mblock.mb_st^[ ix ].eop_func <> op_f_none)
                THEN
                    IF  (mblock.mb_st^[ ix ].eop_func = op_f_check_null)
                        AND NOT check_null_found
                    THEN
                        check_null_found := true
                    ELSE
                        optim := false;
                    (*ENDIF*) 
                (*ENDIF*) 
            (*ENDIF*) 
        st_output :
            IF  field_found AND funct_found
            THEN
                BEGIN
                field_found := false;
                funct_found := false;
                END
            ELSE
                IF  value_found
                THEN
                    value_found := false
                ELSE
                    IF  (NOT check_null_found) AND
                        NOT (mblock.mb_st^[ ix ].eop_out =
                        op_o_output_later)
                    THEN
                        optim := false;
                    (*ENDIF*) 
                (*ENDIF*) 
            (*ENDIF*) 
        st_value :
            IF  NOT (mblock.mb_st^[ ix + 1 ].etype IN
                [ st_value, st_result, st_output])
            THEN
                optim := false
            ELSE
                value_found := true;
            (*ENDIF*) 
        st_result :
            BEGIN
            END;
        OTHERWISE
            optim := false;
        END;
    (*ENDCASE*) 
&   IFDEF TRACE
    t01int4 (ak_sem, ' STACK ENT >', ix);
    t01int4 (ak_sem, ' optim     >', ord(optim));
&   ENDIF
    ix := succ(ix);
    END;
(*ENDWHILE*) 
optim := optim AND (read_first OR read_last);
&IFDEF TRACE
t01int4 (ak_sem, ' optim     >', ord(optim));
&ENDIF
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04read_subquery (
            VAR mblock      : tgg00_MessBlock;
            VAR result      : tgg00_Rec;
            VAR subqtree_id : tgg00_FileId;
            VAR m_key       : tgg00_Lkey;
            VAR aux_error   : tgg00_BasisError;
            VAR ok          : boolean);
 
BEGIN
ok := true;
&ifdef TRACE
t01name (ak_strat, 'b02next_record sub');
&endif
b02next_record (mblock.mb_trns^, subqtree_id, m_key,
      false, result);
IF  (mblock.mb_trns^.trError_gg00 = e_key_not_found)
THEN
    mblock.mb_trns^.trError_gg00 := e_ok
ELSE
    IF  (mblock.mb_trns^.trError_gg00 = e_no_next_record)
    THEN
        BEGIN
        aux_error := mblock.mb_trns^.trError_gg00;
        mblock.mb_trns^.trError_gg00    := e_ok;
        END;
    (*ENDIF*) 
(*ENDIF*) 
IF  (mblock.mb_trns^.trError_gg00 = e_ok) AND
    (aux_error = e_ok)
THEN
    BEGIN
    g10mv ('VGG04 ',  21,    
          sizeof(result.mkey.k), sizeof(m_key.k),
          @result.mkey.k, 1,
          @m_key.k, 1, result.keylen, mblock.mb_trns^.trError_gg00);
    m_key.len := result.keylen;
    SAPDB_PascalFill ('VGG04 ',  22,    
          sizeof(m_key.k), @m_key.k,
          m_key.len - 7, 8, csp_undef_byte, mblock.mb_trns^.trError_gg00);
    IF  mblock.mb_trns^.trError_gg00 = e_move_error
    THEN
        ok := false;
    (*ENDIF*) 
    END
ELSE
    ok := false;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04find_in_stack (
            VAR mblock      : tgg00_MessBlock;
            VAR keyarr      : tgg07_ColPosArr;
            VAR in_stack    : tsp00_Int2;
            VAR in_cnt      : tsp00_Int2);
 
VAR
      found  : boolean;
      ix     : tsp00_Int2;
      valpos : tsp00_Int2;
 
BEGIN
ix := 0;
WHILE (ix <= MAX_COLPOSARR_IDX_GG07) DO
    BEGIN
    IF  (keyarr[ ix ] > 0)
    THEN
        BEGIN
        (* Before constructing the key, we have to check,       *)
        (* if the given keyarr describes an IN qualification.   *)
        (* Then we have to set in_stack and in_cnt, so that the *)
        (* keys will describe a range.                          *)
        found  := false;
        valpos := keyarr[ ix ] + 1;
        WHILE (NOT found) AND (valpos < mblock.mb_qual^.mfirst_free) DO
            IF  (mblock.mb_st^[ valpos ].eop   =  op_none) AND
                (mblock.mb_st^[ valpos ].etype in [ st_value, st_dummy ])
            THEN
                valpos := succ (valpos)
            ELSE
                found  := true;
            (*ENDIF*) 
        (*ENDWHILE*) 
        IF  valpos < mblock.mb_qual^.mfirst_free
        THEN
            IF  (mblock.mb_st^[ valpos ].etype    = st_op) AND
                (mblock.mb_st^[ valpos ].eop      = op_in)
            THEN
                BEGIN
                in_stack := keyarr[ ix ];
                in_cnt   := valpos - in_stack - 1;
                ix       := MAX_COLPOSARR_IDX_GG07;
&               ifdef TRACE
                t01p2int4 (gg, 'IN! -stack  ', in_stack
                      ,        '    -cnt    ', in_cnt);
&               endif
                END
            (*ENDIF*) 
        (*ENDIF*) 
        END
    ELSE
        IF  (keyarr[ ix ] = 0)
        THEN
            ix := MAX_COLPOSARR_IDX_GG07;
        (*ENDIF*) 
    (*ENDIF*) 
    ix := succ(ix);
    END;
(*ENDWHILE*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04index_tree_build (
            VAR file_id    : tgg00_FileId;
            VAR index_tree : tgg00_FileId;
            index_no       : tsp00_Int2);
 
BEGIN
index_tree                           := file_id;
index_tree.fileRoot_gg00             := NIL_PAGE_NO_GG00;
index_tree.fileRootCheck_gg00        := ROOT_CHECK_GG00;
index_tree.fileVersion_gg00.ci2_gg00 := cgg_dummy_file_version;
index_tree.fileTfnNo_gg00[ 1 ]       := chr( index_no );
index_tree.fileTfn_gg00              := tfnMulti_egg00;
END;
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
.PA 
