.nf
 
 .nf
 
    ========== licence begin  GPL
    Copyright (c) 2000-2005 SAP AG
 
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end
.fo
 
 
.fo
*****************************************************
Copyright (c) 2000-2005 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
              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
              g04check_betw (
                    VAR mblock       : tgg00_MessBlock;
                    stpos            : tsp00_Int2;
                    VAR res_possible : boolean;
                    VAR to_eq_changed: boolean);
 
        PROCEDURE
              g04check_like (
                    VAR mblock       : tgg00_MessBlock;
                    stpos            : tsp00_Int2;
                    VAR to_eq_changed: boolean);
 
        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
              g04spec_null_check (
                    VAR mblock : tgg00_MessBlock;
                    VAR b_err : tgg00_BasisError);
 
        PROCEDURE
              g04read_subquery (
                    VAR trns        : tgg00_TransContext;
                    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_stpos_hint   : tsp00_Int2;
                    in_value_idx    : tsp00_Int2);
 
        PROCEDURE
              g04limitinvkeys (
                    VAR mblock    : tgg00_MessBlock (*ptocConst*);
                    VAR inv_strat : tgg07_StrInvInRange;
                    VAR startkey  : tgg00_Lkey;
                    VAR stopkey   : tgg00_Lkey;
                    in_stpos_hint : tsp00_Int2;
                    in_value_idx  : tsp00_Int2);
 
        PROCEDURE
              gg04one_subq_limitprimkey (
                    VAR mblock      : tgg00_MessBlock;
                    VAR subq_buf    : tgg00_Rec;
                    VAR keyarr      : tgg07_ColPosArr;
                    VAR one_key     : tgg00_Lkey;
                    VAR use_stopkey : boolean);
 
        PROCEDURE
              gg04one_subq_limitinvkey (
                    VAR mblock      : tgg00_MessBlock;
                    VAR subq_buf    : tgg00_Rec;
                    VAR inv_strat   : tgg07_StrInvInRange;
                    VAR one_key     : tgg00_Lkey;
                    is_startkey     : boolean);
 
        PROCEDURE
              g04smallest_greater_key_ex(
                    VAR key     : tgg00_Lkey;
                    max_length  : tsp00_Int2 );
 
        PROCEDURE
              g04greatest_smaller_key_ex(
                    VAR key     : tgg00_Lkey;
                    max_length  : tsp00_Int2 );
 
        PROCEDURE
              g04smallest_greater_key(
                    VAR key     : tgg00_Lkey );
 
        PROCEDURE
              g04greatest_smaller_key(
                    VAR key     : tgg00_Lkey );
 
        FUNCTION
              g04isnull_value (
                    VAR stackentry : tgg00_StackEntry;
                    VAR mblock : tgg00_MessBlock) : boolean;
 
        FUNCTION
              g04iseffective_value (
                    VAR stackentry : tgg00_StackEntry;
                    VAR mblock : tgg00_MessBlock) : 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;
              b01fullkey    : tsp00_Key;
 
      ------------------------------ 
 
        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);
 
        PROCEDURE
              b02prev_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
              SAPDB_PascalForcedFill (
                    size        : tsp00_Int4;
                    m           : tsp00_MoveObjPtr;
                    pos         : tsp00_Int4;
                    len         : tsp00_Int4;
                    fillchar    : char);
 
        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);
 
      ------------------------------ 
 
        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);
 
        FUNCTION
              s30lnr_defbyte (
                    str       : tsp00_MoveObjPtr;
                    defbyte   : char;
                    start_pos : tsp00_Int4;
                    length    : tsp00_Int4) : tsp00_Int4;
&       ifdef TRACE
 
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        PROCEDURE
              t01treeid (
                    debug      : tgg00_Debug;
                    nam        : tsp00_Sname;
                    VAR treeid : tgg00_FileId);
 
        PROCEDURE
              t01key (
                    debug   : tgg00_Debug;
                    nam     : tsp00_Sname;
                    VAR k   : tgg00_Lkey);
 
        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
              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
              vtracestack;
 
        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
 
.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.
 
G04CHECK_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.
 
G04LIMITINVKEYS
---------------------------------
 
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.
 
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_descending = true;  (* gg04subq_limitkey *)
 
 
(*------------------------------*) 
 
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_stpos_hint   : tsp00_Int2;
            in_value_idx    : tsp00_Int2);
 
VAR
      _dummy  : tsp00_Int2;
      _varpos : tsp00_Int2;
 
BEGIN
mblock.mb_trns^.trError_gg00 := e_ok;
gg04one_limitprimkey( mblock, startkeyarr, start_key, _dummy,
      in_stpos_hint, in_value_idx, c_start );
gg04one_limitprimkey( mblock, stopkeyarr, stop_key, _varpos,
      in_stpos_hint, in_value_idx, 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
(* PTS 1001813 E.Z. *)
IF  ( mblock.mb_trns^.trError_gg00 <> e_move_error )
THEN
    BEGIN
    t01key  (gg, 'START_KEY   ', start_key);
    t01key  (gg, 'STOP_KEY    ', 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
      g04limitinvkeys (
            VAR mblock    : tgg00_MessBlock;
            VAR inv_strat : tgg07_StrInvInRange;
            VAR startkey  : tgg00_Lkey;
            VAR stopkey   : tgg00_Lkey;
            in_stpos_hint : tsp00_Int2;
            in_value_idx  : tsp00_Int2);
 
BEGIN
mblock.mb_trns^.trError_gg00 := e_ok;
(* --- build startkey --- *)
gg04one_limitinvkey( mblock, inv_strat,
      startkey, in_stpos_hint, in_value_idx, c_start );
;
(* --- build stopkey --- *)
IF  ( isp_exact_match in inv_strat.siir_strat_props )
THEN
    BEGIN
    SAPDB_PascalMove ('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
    gg04one_limitinvkey( mblock, inv_strat,
          stopkey, in_stpos_hint, in_value_idx, c_stop );
    END;
(*ENDIF*) 
&ifdef TRACE
t01key (ak_strat, 'START-INDEX ', startkey);
t01key (ak_strat, 'STOP-INDEX  ', stopkey);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      gg04onevalue (
            VAR mblock     : tgg00_MessBlock;
            valpos         : tsp00_Int2;
            last_field     : boolean;
            descending     : boolean;
            maxlen         : tsp00_Int2;
            VAR key        : tgg00_Lkey);
 
VAR
      _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 ',   3,    
              sizeof (_msg_line), sizeof (_trace_line),
              @_msg_line, 1, @_trace_line, 1, sizeof(_msg_line), _move_err);
        g10mv ('VGG04 ',   4,    
              sizeof (_date), sizeof (_trace_line),
              @_date, 1, @_trace_line, 5, sizeof(_date), _move_err);
        g10mv ('VGG04 ',   5,    
              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 ',   6,    
              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);
        vtracestack;
        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
        END;
    (*ENDIF*) 
    IF  (_input_len > maxlen)
    THEN
        BEGIN
        _too_long  := true;
        _input_len := maxlen;
        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 ',   7,    
              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 ',   8,    
                      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 ',   9,    
                          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 ',  10,    
                          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 ',  11,    
                  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
      gg04subqvalue (
            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 ',  12,    
          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 ',  13,    
                  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 ',  14,    
                      sizeof( key.k ), @key.k, key.len + 1 + _input_len,
                      maxlen - _input_len, csp_unicode_blank, e )
            ELSE
                SAPDB_PascalFill('VGG04 ',  15,    
                      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 : tsp00_Int2;
      _startpos : tsp00_Int2;
      _stpos    : tsp00_Int2;
      _dummy    : boolean;
 
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           *)
                    (* ========================== *)
                    g04check_like( mblock, _stpos, _dummy );
                OTHERWISE
                    BEGIN
                    END;
                END;
            (*ENDCASE*) 
        (*ENDIF*) 
        _stpos:= succ( _stpos );
        END;
    (*ENDWHILE*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      gg04check_betw (
            VAR mblock           : tgg00_MessBlock;
            stpos                : tsp00_Int2;
            maxstpos             : tsp00_Int2;
            VAR finding_possible : boolean);
 
VAR
      _top_level : boolean;
      _res_poss  : boolean;
      _dummy     : boolean;
 
BEGIN
g04check_betw( mblock, stpos, _res_poss, _dummy );
IF  ( NOT _res_poss )
THEN
    BEGIN
    g04check_if_top_level (mblock.mb_st, succ (stpos),
          maxstpos, _top_level);
    IF  ( _top_level )
    THEN
        finding_possible := false;
    (*ENDIF*) 
    END
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04check_betw (
            VAR mblock       : tgg00_MessBlock;
            stpos            : tsp00_Int2;
            VAR res_possible : boolean;
            VAR to_eq_changed: boolean);
 
VAR
      _valpos1      : integer;
      _valpos2      : integer;
      _lc_result    : tsp00_LcompResult;
      _optimize_ptr : tsp00_MoveObjPtr;
 
BEGIN
res_possible  := true;
to_eq_changed := false;
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
        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 );
        IF  ( _lc_result = l_greater )
        THEN
            res_possible := false
        ELSE
            BEGIN
            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*) 
                to_eq_changed := true;
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END
    (*ENDIF*) 
    END;
&ifdef trace
(*ENDIF*) 
t01bool( gg, 'to_eq_change', to_eq_changed );
t01bool( gg, 'res_possible', res_possible );
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04check_like (
            VAR mblock       : tgg00_MessBlock;
            stpos            : tsp00_Int2;
            VAR to_eq_changed: boolean);
 
VAR
      _first             : tsp00_Int4;
      _j                 : tsp00_Int4;
      _k                 : tsp00_Int4;
      _def_byte_pos      : tsp00_Int4;
      _last              : tsp00_Int4;
      _offset            : tsp00_Int4;
      _restlen           : tsp00_Int4;
      _found_char        : char;
      _opt_ptr           : tsp00_MoveObjPtr;
      _rest_blanks       : boolean;
      _star_or_any_found : boolean;
 
BEGIN
(* st_column *)
(* st_dummy  *)
(* st_dummy  *)
(* st_value  *)
(* st_op,like  <-- stpos *)
to_eq_changed := false;
IF  ( mblock.mb_st^[ stpos - 2 ].etype = st_dummy ) AND
    ( mblock.mb_data^.mbp_buf[ mblock.mb_st^[ stpos - 2 ].epos ] <>
    csp_default_byte )
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
            BEGIN
            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*) 
            END
        ELSE
            BEGIN
            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*) 
            END;
        (*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*) 
            to_eq_changed := true;
            END
        ELSE
            BEGIN
            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
                    BEGIN
                    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*) 
                    END;
                (*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 ] := csp_undef_byte;
                                _k := succ(_k);
                                END;
                            (*ENDFOR*) 
                            END
                        (*ENDIF*) 
                        END
                    ELSE
                        BEGIN
                        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 ] := csp_undef_byte;
                                _k := succ(_k);
                                END;
                            (*ENDFOR*) 
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
&ifdef trace
(*ENDIF*) 
t01bool( gg, 'to_eq_change', to_eq_changed );
&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 ',  16,    
                          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 ',  17,    
                  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 ',  18,    
              sizeof (key.k), @key.k, key.len+2, maxlen-1, chr(255), e);
        key.len := key.len + maxlen;
        END
    (*ENDIF*) 
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      gg04one_limitprimkey (
            VAR mblock   : tgg00_MessBlock;
            VAR keyarr   : tgg07_ColPosArr;
            VAR one_key  : tgg00_Lkey;
            VAR varpos   : tsp00_Int2;
            in_stpos_hint: tsp00_Int2;
            in_value_idx : tsp00_Int2;
            is_startkey  : boolean);
 
VAR
      _fieldpos   : tsp00_Int2;
      _ix         : tsp00_Int2;
      _maxlen     : tsp00_Int2;
      _valpos     : tsp00_Int2;
      _last_field : boolean;
 
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
    _ix         := 0;
    varpos      := 0; (* means: no st_varkey found yet *)
    one_key.len := 0;
&   ifdef TRACE
    t01bool (gg, 'is startkey ', is_startkey);
    t01int4 (gg, 'in val idx  ', in_value_idx);
    t01int4 (gg, 'in st hint  ', in_stpos_hint);
&   endif
    WHILE ( _ix <= MAX_COLPOSARR_IDX_GG07 ) AND ( keyarr[ _ix ] <> 0 ) DO
        BEGIN
        _fieldpos := abs( keyarr[ _ix ] );
        gg04get_valpos( mblock, _valpos, keyarr[ _ix],
              in_stpos_hint, in_value_idx, NOT c_descending, is_startkey );
        ;
        IF  ( _ix < MAX_COLPOSARR_IDX_GG07 ) AND
            ( keyarr[ _ix + 1 ] <> 0 )
        THEN
            _last_field := false
        ELSE
            BEGIN
            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*) 
            END;
        (*ENDIF*) 
        IF  ( _last_field )
        THEN
            _maxlen := mxsp_key + 1 - varpos
        ELSE
            _maxlen := mblock.mb_st^[ _fieldpos ].elen_var;
        (*ENDIF*) 
        ;
        IF  (mblock.mb_st^[ _valpos ].etype = st_subquery)
        THEN
            BEGIN
            (* use SUBQ as range *)
            gg04onesubqvalue( mblock, one_key, _valpos,
                  _last_field, NOT c_descending, _maxlen, is_startkey );
            END
        ELSE
            gg04onevalue( mblock, _valpos, _last_field, NOT c_descending,
                  _maxlen, one_key );
        (*ENDIF*) 
        _ix := succ( _ix );
        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
      gg04one_subq_limitprimkey (
            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
mblock.mb_trns^.trError_gg00 := e_ok;
_ix         := 0;
_varpos     := 0; (* means: no st_varkey found yet *)
one_key.len := 0;
WHILE ( _ix <= MAX_COLPOSARR_IDX_GG07 ) AND ( keyarr[ _ix ] <> 0 ) DO
    BEGIN
    _fieldpos := abs( keyarr[ _ix ] );
    gg04get_valpos( mblock, _valpos, keyarr[ _ix],
          IS_UNDEFINED_GG07, -1 (* use IN as range *),
          NOT c_descending, NOT use_stopkey );
    ;
    IF  ( _ix < MAX_COLPOSARR_IDX_GG07 ) AND
        ( keyarr[ _ix + 1 ] <> 0 )
    THEN
        _last_field := false
    ELSE
        BEGIN
        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*) 
        END;
    (*ENDIF*) 
    IF  ( _last_field )
    THEN
        _maxlen := mxsp_key + 1 - _varpos
    ELSE
        _maxlen := mblock.mb_st^[ _fieldpos ].elen_var;
    (*ENDIF*) 
    IF  ( mblock.mb_st^[ _valpos ].etype = st_subquery )
    THEN
        BEGIN
        (* use one given SUBQ value *)
        gg04subqvalue( subq_buf, _last_field,
              NOT c_descending, _maxlen, one_key,
              mblock.mb_trns^.trError_gg00 );
        END
    ELSE
        BEGIN
        gg04onevalue( mblock, _valpos, _last_field, NOT c_descending,
              _maxlen, one_key );
        END;
    (*ENDIF*) 
    _ix := succ(_ix);
    END;
(*ENDWHILE*) 
IF  ( use_stopkey )
THEN
    BEGIN
    IF  (_varpos = 0)
    THEN
        BEGIN
        (* values for last fields missing;  *)
        SAPDB_PascalFill ('VGG04 ',  19,    
              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;
        (*ENDIF*) 
    (*ENDIF*) 
    ;
&   ifdef TRACE
    IF  ( use_stopkey )
    THEN
        t01key (gg, 'STOP_KEY    ', one_key)
    ELSE
        t01name (gg, 'USE NO STOP_KEY   ');
    (*ENDIF*) 
&   endif
    END
ELSE
    BEGIN
&   ifdef TRACE
    t01key  (gg, 'START_KEY   ', 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
      g04read_subquery (
            VAR trns        : tgg00_TransContext;
            VAR result      : tgg00_Rec;
            VAR subqtree_id : tgg00_FileId;
            VAR m_key       : tgg00_Lkey;
            VAR aux_error   : tgg00_BasisError;
            VAR ok          : boolean);
 
BEGIN
trns.trError_gg00 := e_ok;
ok := true;
&ifdef TRACE
t01name (ak_strat, 'b02next_record sub');
&endif
b02next_record (trns, subqtree_id, m_key, false, result);
IF  ( trns.trError_gg00 = e_key_not_found )
THEN
    trns.trError_gg00 := e_ok
ELSE
    IF  ( trns.trError_gg00 = e_no_next_record )
    THEN
        BEGIN
        aux_error := trns.trError_gg00;
        trns.trError_gg00    := e_ok;
        END;
    (*ENDIF*) 
(*ENDIF*) 
IF  ( trns.trError_gg00 = e_ok ) AND ( aux_error = e_ok )
THEN
    BEGIN
    g10mv ('VGG04 ',  20,    
          sizeof(result.mkey.k), sizeof(m_key.k),
          @result.mkey.k, 1,
          @m_key.k, 1, result.keylen, trns.trError_gg00);
    m_key.len := result.keylen;
    (* fill last 8 bytes of key with '\FF' to overstep same values *)
    SAPDB_PascalFill ('VGG04 ',  21,    
          sizeof(m_key.k), @m_key.k,
          m_key.len - (4 + RESCNT_MXGG04 ) + 1,
          ( 4 (* distinct handling *) + RESCNT_MXGG04 ),
          csp_undef_byte, trns.trError_gg00);
    IF  ( trns.trError_gg00 = e_move_error )
    THEN
        ok := false;
    (*ENDIF*) 
    END
ELSE
    ok := false;
(*ENDIF*) 
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;
 
(*------------------------------*) 
 
FUNCTION
      gg04is_IN_stack (
            VAR mblock      : tgg00_MessBlock;
            col_pos         : tsp00_Int2;
            VAR in_elemcnt  : tsp00_Int2) : boolean;
 
VAR
      _found  : boolean;
      _valpos : tsp00_Int2;
 
BEGIN
gg04is_IN_stack := false;
in_elemcnt      := IS_UNDEFINED_GG07;
IF  ( col_pos > 0 )
THEN
    BEGIN
    _found  := false;
    _valpos := col_pos + 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
            gg04is_IN_stack := true;
            in_elemcnt      := _valpos - col_pos - 1;
&           ifdef TRACE
            t01int4 (gg, 'IN! -cnt    ', in_elemcnt );
&           endif
            END
        (*ENDIF*) 
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      gg04onesubqvalue (
            VAR mblock     : tgg00_MessBlock;
            VAR one_key    : tgg00_Lkey;
            valpos         : tsp00_Int2;
            last_field     : boolean;
            descending     : boolean;
            maxlen         : tsp00_Int2;
            is_startkey    : boolean);
 
VAR
      _msg_line     : tsp00_C40;
      _date         : tsp00_Date;
      _time         : tsp00_Time;
      _trace_line   : tsp00_Line;
      _subqtree_id  : tgg00_FileId;
      _rec_buf      : tgg00_Rec;
      _search_key   : tgg00_Lkey;
      _ilen         : tsp00_Int4;
      _move_err     : tgg00_BasisError;
      _success      : boolean;
 
BEGIN
SAPDB_PascalMove ('VGG04 ',  22,    
      mblock.mb_data_size, sizeof( _subqtree_id ),
      @mblock.mb_data^.mbp_buf,
      mblock.mb_st^[ valpos ].epos,
      @_subqtree_id, 1, FILE_ID_MXGG00,
      mblock.mb_trns^.trError_gg00);
&ifdef trace
t01treeid( gg, 'subqtree_id ', _subqtree_id );
t01p2int4 (gg, '-maxlen     ', maxlen
      ,        '-key.len    ', one_key.len);
t01bool   (gg, '-last_field ', last_field);
&endif
_success := true;
IF  (( is_startkey ) AND ( NOT descending))
    OR
    (( NOT is_startkey ) AND ( descending))
THEN
    BEGIN
    _search_key.len := 0;
    b02next_record( mblock.mb_trns^, _subqtree_id, _search_key, false, _rec_buf );
    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
            _success:= false;
            mblock.mb_trns^.trError_gg00 := e_ok;
            END;
        (*ENDIF*) 
    (*ENDIF*) 
    END
ELSE
    BEGIN
    _search_key.len := KEY_MXSP00;
    _search_key.k   := b01fullkey;
    b02prev_record( mblock.mb_trns^, _subqtree_id, _search_key, false, _rec_buf );
    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_prev_record )
        THEN
            BEGIN
            _success:= false;
            mblock.mb_trns^.trError_gg00 := e_ok;
            END;
        (*ENDIF*) 
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  ( _success )
THEN
    gg04subqvalue( _rec_buf, last_field, descending, maxlen, one_key,
          mblock.mb_trns^.trError_gg00 )
ELSE
    BEGIN
    (* mark ilegal operations *)
    vdattime (_date, _time);
    _msg_line := 'G04                                     ';
    _move_err := e_ok;
    SAPDB_PascalMove ('VGG04 ',  23,    
          sizeof (_msg_line), sizeof (_trace_line),
          @_msg_line, 1, @_trace_line, 1, sizeof(_msg_line), _move_err);
    SAPDB_PascalMove ('VGG04 ',  24,    
          sizeof (_date), sizeof (_trace_line),
          @_date, 1, @_trace_line, 5, sizeof(_date), _move_err);
    SAPDB_PascalMove ('VGG04 ',  25,    
          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               ';
    SAPDB_PascalMove ('VGG04 ',  26,    
          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);
    vtracestack;
    mblock.mb_trns^.trError_gg00 := e_move_error;
&   ifdef trace
    g01abort (csp3_move_error, csp3_n_move, 'INCONSISTENT STRATEGY   ', valpos);
&   endif
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      gg04one_limitinvkey (
            VAR mblock      : tgg00_MessBlock;
            VAR inv_strat   : tgg07_StrInvInRange;
            VAR one_key     : tgg00_Lkey;
            in_stpos_hint   : tsp00_Int2;
            in_value_idx    : tsp00_Int2;
            is_startkey     : boolean);
 
VAR
      _arr_ptr          : ^tgg07_ColPosArr;
      _arr_ptr_rev      : ^tgg07_ColPosArr;
      _ix               : tsp00_Int2;
      _maxlen           : tsp00_Int2;
      _valpos           : tsp00_Int2;
      _entrycnt         : tsp00_Int2;
      _max_used_fields  : tsp00_Int2;
      _last_field       : boolean;
      _descending       : boolean;
 
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, 'max_used_fie', _max_used_fields );
&endif
IF  ( is_startkey )
THEN
    BEGIN
    _entrycnt   := inv_strat.siir_startcnt;
    _arr_ptr    := @inv_strat.siir_invstart;
    _arr_ptr_rev:= @inv_strat.siir_invstop;
    END
ELSE
    BEGIN
    _entrycnt   := inv_strat.siir_stopcnt;
    _arr_ptr    := @inv_strat.siir_invstop;
    _arr_ptr_rev:= @inv_strat.siir_invstart;
    END;
(*ENDIF*) 
one_key.len  := 0;
;
_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 <= _entrycnt - 1 )
    THEN
        BEGIN
        gg04get_valpos( mblock, _valpos, _arr_ptr^[ _ix],
              in_stpos_hint, in_value_idx, _descending, is_startkey );
        ;
        _maxlen := mblock.mb_st^[ abs( _arr_ptr^[ _ix ] ) ].elen_var;
        IF  ( mblock.mb_st^[ _valpos ].etype = st_subquery )
        THEN
            gg04onesubqvalue( mblock, one_key, _valpos,
                  _last_field, _descending, _maxlen,
                  is_startkey )
        ELSE
            gg04onevalue( mblock, _valpos, _last_field,
                  _descending, _maxlen, one_key );
        (*ENDIF*) 
        END
    ELSE
        gg04nil_value( _last_field, _descending,
              mblock.mb_st^[ abs( _arr_ptr_rev^[ _ix ] ) ].elen_var,
              is_startkey, one_key, mblock.mb_trns^.trError_gg00 );
    (*ENDIF*) 
    _ix := succ( _ix );
    END;
(*ENDWHILE*) 
IF  ( NOT is_startkey )
THEN
    BEGIN
    IF  ( _max_used_fields < inv_strat.siir_icount )
    THEN
        BEGIN (* values for last field(s) missing *)
        SAPDB_PascalFill('VGG04 ',  27,    
              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*) 
    END;
(*ENDIF*) 
;
&ifdef trace
IF  ( is_startkey )
THEN
    t01key(gg, 'START-KEY   ', one_key )
ELSE
    t01key(gg, 'STOP-KEY    ', one_key );
(*ENDIF*) 
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      gg04one_subq_limitinvkey (
            VAR mblock      : tgg00_MessBlock;
            VAR subq_buf    : tgg00_Rec;
            VAR inv_strat   : tgg07_StrInvInRange;
            VAR one_key     : tgg00_Lkey;
            is_startkey     : boolean);
 
VAR
      _arr_ptr          : ^tgg07_ColPosArr;
      _arr_ptr_rev      : ^tgg07_ColPosArr;
      _ix               : tsp00_Int2;
      _maxlen           : tsp00_Int2;
      _valpos           : tsp00_Int2;
      _entrycnt         : tsp00_Int2;
      _max_used_fields  : tsp00_Int2;
      _last_field       : boolean;
      _descending       : boolean;
 
BEGIN
mblock.mb_trns^.trError_gg00 := e_ok;
(* > 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, 'max_used_fie', _max_used_fields );
&endif
IF  ( is_startkey )
THEN
    BEGIN
    _entrycnt   := inv_strat.siir_startcnt;
    _arr_ptr    := @inv_strat.siir_invstart;
    _arr_ptr_rev:= @inv_strat.siir_invstop;
    END
ELSE
    BEGIN
    _entrycnt   := inv_strat.siir_stopcnt;
    _arr_ptr    := @inv_strat.siir_invstop;
    _arr_ptr_rev:= @inv_strat.siir_invstart;
    END;
(*ENDIF*) 
one_key.len  := 0;
;
_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 <= _entrycnt - 1 )
    THEN
        BEGIN
        gg04get_valpos( mblock, _valpos, _arr_ptr^[ _ix],
              IS_UNDEFINED_GG07, -1 (* use IN as range *),
              _descending, is_startkey );
        ;
        _maxlen := mblock.mb_st^[ abs( _arr_ptr^[ _ix ] ) ].elen_var;
        IF  ( mblock.mb_st^[ _valpos ].etype = st_subquery )
        THEN
            gg04subqvalue( subq_buf, _last_field, _descending,
                  _maxlen, one_key, mblock.mb_trns^.trError_gg00 )
        ELSE
            gg04onevalue( mblock, _valpos, _last_field,
                  _descending, _maxlen, one_key );
        (*ENDIF*) 
        END
    ELSE
        gg04nil_value( _last_field, _descending,
              mblock.mb_st^[ abs( _arr_ptr_rev^[ _ix ] ) ].elen_var,
              is_startkey, one_key, mblock.mb_trns^.trError_gg00 );
    (*ENDIF*) 
    _ix := succ( _ix );
    END;
(*ENDWHILE*) 
IF  ( NOT is_startkey )
THEN
    BEGIN
    IF  ( _max_used_fields < inv_strat.siir_icount )
    THEN
        BEGIN (* values for last field(s) missing *)
        SAPDB_PascalFill('VGG04 ',  28,    
              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*) 
    END;
(*ENDIF*) 
;
&ifdef trace
IF  ( is_startkey )
THEN
    t01key(gg, 'START-KEY   ', one_key )
ELSE
    t01key(gg, 'STOP-KEY    ', one_key );
(*ENDIF*) 
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04smallest_greater_key_ex(
            VAR key     : tgg00_Lkey;
            max_length  : tsp00_Int2);
 
BEGIN
IF  ( key.len < max_length )
THEN
    BEGIN
    key.len          := succ( key.len );
    key.k[ key.len ] := chr(0);
    END
ELSE
    BEGIN
    WHILE ( key.len > 1 ) AND ( key.k[ key.len ] = chr(255)) DO
        key.len := pred( key.len );
    (*ENDWHILE*) 
    IF  ( key.k[ key.len ] < chr(255))
    THEN
        key.k[ key.len ] := chr( succ( ord( key.k[ key.len ] )))
    ELSE
        key.len := max_length;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04smallest_greater_key(
            VAR key     : tgg00_Lkey );
 
BEGIN
g04smallest_greater_key_ex( key, MAX_KEYLEN_GG00 );
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04greatest_smaller_key_ex(
            VAR key     : tgg00_Lkey;
            max_length  : tsp00_Int2 );
 
BEGIN
IF  ( key.len > 0 )
THEN
    IF  ( key.k[ key.len ] = chr(0))
    THEN
        key.len := pred( key.len )
    ELSE
        BEGIN
        key.k[ key.len ] := chr( pred( ord( key.k[ key.len ] )));
        SAPDB_PascalForcedFill ( sizeof( key.k ), @key.k,
              key.len + 1, max_length - key.len, chr(255));
        key.len := max_length;
        END;
    (*ENDIF*) 
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      g04greatest_smaller_key(
            VAR key     : tgg00_Lkey );
 
BEGIN
g04greatest_smaller_key_ex( key, MAX_KEYLEN_GG00 );
END;
 
(*------------------------------*) 
 
PROCEDURE
      gg04get_valpos (
            VAR mblock      : tgg00_MessBlock;
            VAR valpos      : tsp00_Int2;
            fieldpos_code   : tsp00_Int2;
            in_stpos_hint   : tsp00_Int2;
            in_value_idx    : tsp00_Int2; (* only valid with given IN hint *)
            descending      : boolean;
            is_startkey     : boolean);
 
VAR
      _in_elemcnt : tsp00_Int2;
      _fieldpos   : tsp00_Int2;
 
BEGIN
&ifdef trace
t01int4 (gg, 'fieldpos_cod', fieldpos_code );
&endif
_in_elemcnt := 0;
_fieldpos   := abs( fieldpos_code );
valpos      := _fieldpos + 1;
IF  ( fieldpos_code > 0 )
    AND
    ((( in_stpos_hint <> IS_UNDEFINED_GG07 ) AND
    ( _fieldpos = in_stpos_hint )) OR
    gg04is_IN_stack( mblock, _fieldpos, _in_elemcnt ))
THEN
    BEGIN
    IF  (( in_value_idx > 0 ) AND
        ( in_stpos_hint <> IS_UNDEFINED_GG07 ) AND
        ( _fieldpos = in_stpos_hint ))
    THEN
        BEGIN
        (* value index valid only for given IN stack pos hint *)
        valpos := _fieldpos + in_value_idx;
&       ifdef trace
        t01int4 (gg, 'IN index    ', in_value_idx );
&       endif
        END
    ELSE
        (* non given in_value_idx or any other IN condition *)
        BEGIN
&       ifdef trace
        t01sname( gg, 'use IN range' );
&       endif
        IF  ( descending )
        THEN
            BEGIN
            IF  ( is_startkey )
            THEN
                (* get greatest value *)
                BEGIN
                valpos := _fieldpos + _in_elemcnt;
                (* 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
                (* 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;
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            IF  ( is_startkey )
            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 + _in_elemcnt;
                (* 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;
    (*ENDIF*) 
    END
ELSE
    BEGIN
    IF  ( fieldpos_code > 0 )
    THEN
        valpos := _fieldpos + 1
    ELSE
        (* second value of BETWEEN condition *)
        valpos := _fieldpos + 2;
    (*ENDIF*) 
    END;
(*ENDIF*) 
&ifdef trace
t01int4 (gg, 'valpos      ', valpos );
&endif
END;
 
(*------------------------------*) 
 
FUNCTION
      g04isnull_value (
            VAR stackentry : tgg00_StackEntry;
            VAR mblock : tgg00_MessBlock) : boolean;
 
VAR
      isnull       : boolean;
 
BEGIN
IF  stackentry.etype = st_value
THEN
    BEGIN
    IF  ( stackentry.ecol_tab[ 1 ] in
        [ cgg04_param_in_between_expr, cgg04_param_in_in_expr])
        OR
        ((stackentry.ecol_tab[ 1 ] = chr(0)) AND
        (stackentry.ecol_tab[ 2 ] <> chr(0)))
    THEN
        isnull := false
    ELSE
        BEGIN
        isnull := (mblock.mb_data^.mbp_buf[stackentry.epos] = csp_undef_byte);
        END;
    (*ENDIF*) 
    END
ELSE
    isnull := false;
(*ENDIF*) 
g04isnull_value := isnull;
END;
 
(*------------------------------*) 
 
FUNCTION
      g04iseffective_value (
            VAR stackentry : tgg00_StackEntry;
            VAR mblock : tgg00_MessBlock) : boolean;
 
VAR
      iseffective  : boolean;
 
BEGIN
IF  stackentry.etype = st_value
THEN
    BEGIN
    IF  ( stackentry.ecol_tab[ 1 ] in
        [ cgg04_param_in_between_expr, cgg04_param_in_in_expr])
        OR
        ((stackentry.ecol_tab[ 1 ] = chr(0)) AND
        (stackentry.ecol_tab[ 2 ] <> chr(0)))
    THEN
        iseffective := false
    ELSE
        iseffective := (mblock.mb_data^.mbp_buf[stackentry.epos] <> csp_default_byte);
    (*ENDIF*) 
    END
ELSE
    iseffective := false;
(*ENDIF*) 
g04iseffective_value := iseffective
END;
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
.PA 
