.ad 8
.bm 8
.fm 4
.bt $Copyright (c) 2000-2005 SAP AG$$Page %$
.tm 12
.hm 6
.hs 3
.TT 1 $SQL$Project Distributed Database System$VAK62$
.tt 2 $$$
.TT 3 $ElkeZ$Single_Select$$2000-11-14$
***********************************************************
.nf
 
 .nf

    ========== licence begin  GPL
    Copyright (c) 2000-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end
.fo

 
.fo
.nf
.sp
MODULE  : Single_Select
=========
.sp
Purpose : Syntax and semantics of select direct, ordered select
.CM *-END-* purpose -------------------------------------
.sp
.cp 3
Define  :
 
        PROCEDURE
              a62_direct_ordered_select (
                    VAR acv    : tak_all_command_glob;
                    start_node : tsp00_Int2);
 
.CM *-END-* define --------------------------------------
.sp;.cp 3
Use     :
 
        FROM
              Scanner : VAK01;
 
        VAR
              a01sysnullkey : tgg00_SysInfoKey;
              a01_zero_res_name  : tsp00_KnlIdentifier;
 
      ------------------------------ 
 
        FROM
              AK_universal_semantic_tools : VAK06;
 
        PROCEDURE
              a06finish_curr_retpart (
                    VAR acv   : tak_all_command_glob;
                    part_kind : tsp1_part_kind;
                    arg_count : tsp00_Int2);
 
        PROCEDURE
              a06a_mblock_init (
                    VAR acv      : tak_all_command_glob;
                    mtype        : tgg00_MessType;
                    m2type       : tgg00_MessType2;
                    VAR tree     : tgg00_FileId);
 
      ------------------------------ 
 
        FROM
              AK_error_handling : VAK07;
 
        PROCEDURE
              a07_b_put_error (
                    VAR acv : tak_all_command_glob;
                    b_err   : tgg00_BasisError;
                    err_code : tsp00_Int4);
 
        PROCEDURE
              a07ak_system_error (
                    VAR acv  : tak_all_command_glob;
                    modul_no : integer;
                    id       : integer);
 
      ------------------------------ 
 
        FROM
              Systeminfo_cache : VAK10;
 
        PROCEDURE
              a10get_sysinfo (
                    VAR acv      : tak_all_command_glob;
                    VAR syskey   : tgg00_SysInfoKey;
                    dstate       : tak_directory_state;
                    VAR syspoint : tak_sysbufferaddress;
                    VAR b_err    : tgg00_BasisError);
 
        PROCEDURE
              a10_key_del  (
                    VAR acv    : tak_all_command_glob;
                    VAR syskey : tgg00_SysInfoKey);
 
        PROCEDURE
              a10del_sysinfo (
                    VAR acv     : tak_all_command_glob;
                    VAR syskey  : tgg00_SysInfoKey;
                    VAR b_err   : tgg00_BasisError);
 
      ------------------------------ 
 
        FROM
              Executing_dispatcher : VAK501;
 
        PROCEDURE
              a501do_execute (
                    VAR acv                 : tak_all_command_glob;
                    VAR dmli                : tak_dml_info;
                    VAR parsk               : tak_parskey;
                    output_during_execution : boolean);
 
      ------------------------------ 
 
        FROM
              Long-Support-Getval: VAK508;
 
        PROCEDURE
              a508_lget_long_columns (
                    VAR acv             : tak_all_command_glob;
                    VAR change_rec      : tak_changerecord;
                    VAR lcol_lock       : boolean;
                    rec_cnt             : integer;
                    rec_len             : integer;
                    startpos            : integer);
 
        FUNCTION
              a508_lcol_found (
                    VAR acv        : tak_all_command_glob;
                    VAR change_rec : tak_changerecord) : boolean;
 
      ------------------------------ 
 
        FROM
              DML_Help_Procedures : VAK54;
 
        PROCEDURE
              a54_dml_init (
                    VAR dmli : tak_dml_info;
                    in_union : boolean);
 
        PROCEDURE
              a54_get_pparsp_pinfop (
                    VAR acv   : tak_all_command_glob;
                    VAR sparr : tak_syspointerarr;
                    mtype     : tgg00_MessType);
 
        PROCEDURE
              a54_select_last_part (
                    VAR acv              : tak_all_command_glob;
                    VAR dmli             : tak_dml_info;
                    VAR user_result_tree : tgg00_FileId;
                    last_pars_part       : boolean);
 
        PROCEDURE
              a54_view_put_into (
                    VAR acv  : tak_all_command_glob;
                    VAR dmli : tak_dml_info);
 
        PROCEDURE
              a54_fixedpos (
                    VAR acv  : tak_all_command_glob;
                    VAR dmli : tak_dml_info);
 
        PROCEDURE
              a54_loc_temp_locks (
                    VAR acv   : tak_all_command_glob;
                    globstate : tgg00_HandlingSet;
                    VAR sparr : tak_syspointerarr);
 
      ------------------------------ 
 
        FROM
              DML_Parts : VAK55;
 
        PROCEDURE
              a55_build_key (
                    VAR acv  : tak_all_command_glob;
                    VAR dmli : tak_dml_info;
                    VAR dfa  : tak_dfarr;
                    keynode  : integer);
 
      ------------------------------ 
 
        FROM
              AK_Delete : VAK58;
 
        PROCEDURE
              a58_current_of (
                    VAR acv  : tak_all_command_glob;
                    VAR dmli : tak_dml_info;
                    curr_n   : integer);
 
      ------------------------------ 
 
        FROM
              Select_Syntax : VAK60;
 
        PROCEDURE
              a60_p_info_output (
                    VAR acv   : tak_all_command_glob;
                    VAR sparr : tak_syspointerarr);
 
        PROCEDURE
              a60_columnnames_return (
                    VAR acv   : tak_all_command_glob;
                    pcolnamep : tak_sysbufferaddress);
 
        PROCEDURE
              a60_change_results (
                    VAR acv        : tak_all_command_glob;
                    VAR data       : tsp00_MoveObj;
                    VAR change_rec : tak_changerecord;
                    startpos       : integer;
                    curr_resreclen : integer);
 
        PROCEDURE
              a60_get_longinfobuffer (
                    VAR acv   : tak_all_command_glob;
                    VAR sparr : tak_syspointerarr;
                    col_cnt   : integer;
                    resultno  : tsp00_Int4);
 
        PROCEDURE
              a60rescount (
                    VAR acv  : tak_all_command_glob;
                    rescount : tsp00_Int4);
 
        PROCEDURE
              a60_put_result (
                    VAR acv    : tak_all_command_glob;
                    VAR mblock : tgg00_MessBlock;
                    spos       : integer);
 
      ------------------------------ 
 
        FROM
              Select_List : VAK61;
 
        PROCEDURE
              a61_check_val_params (
                    VAR acv  : tak_all_command_glob;
                    VAR dmli : tak_dml_info;
                    sel_node : integer;
                    par_node : integer);
 
      ------------------------------ 
 
        FROM
              Execute_Where_Part : VAK65;
 
        PROCEDURE
              a65_search_condition (
                    VAR acv        : tak_all_command_glob;
                    VAR dmli       : tak_dml_info;
                    VAR first_node : integer);
 
      ------------------------------ 
 
        FROM
              Execute_Select_Expression : VAK660;
 
        PROCEDURE
              a660_search_one_table (
                    VAR acv        : tak_all_command_glob;
                    VAR dmli       : tak_dml_info;
                    table_node     : integer;
                    all            : boolean;
                    check_teresult : boolean;
                    lock_spec      : tak_lockenum;
                    wanted_priv    : tak00_PrivR);
 
        PROCEDURE
              a660_new_pparsp (
                    VAR acv        : tak_all_command_glob;
                    VAR sparr      : tak_syspointerarr;
                    first_parsinfo : boolean;
                    complicate     : boolean);
 
        PROCEDURE
              a660_prefix_delete (
                    VAR acv       : tak_all_command_glob;
                    VAR parsk     : tak_parskey;
                    VAR del_cnt   : integer;
                    prefix_length : integer);
 
        PROCEDURE
              a660_lock (
                    VAR acv        : tak_all_command_glob;
                    lock_node      : integer;
                    VAR lock_state : tgg00_HandlingSet);
 
      ------------------------------ 
 
        FROM
              Subquery_handling : VAK661;
 
        PROCEDURE
              a661_sub_build (
                    VAR acv            : tak_all_command_glob;
                    VAR dmli           : tak_dml_info;
                    sub_n              : integer;
                    filled_part2_bytes : integer;
                    VAR sr_rec         : tak71_strat_rec);
 
      ------------------------------ 
 
        FROM
              Resultname_handling : VAK663;
 
        PROCEDURE
              a663_del_result (
                    VAR acv          : tak_all_command_glob;
                    VAR resname_rec  : tak_resname_record;
                    do_cdel          : boolean;
                    del_resname_rec  : boolean);
 
        PROCEDURE
              a663_make_res_buf (
                    VAR acv      : tak_all_command_glob;
                    VAR dmli     : tak_dml_info;
                    VAR res_name : tsp00_KnlIdentifier;
                    VAR res_tree : tgg00_FileId);
 
      ------------------------------ 
 
        FROM
              Part2_Select_Expression : VAK67;
 
        PROCEDURE
              a67_bextcolindex (
                    VAR d_esparr : tak_syspointerarr;
                    outcolno : integer);
 
      ------------------------------ 
 
        FROM
              Resulttable : VAK73;
 
        PROCEDURE
              a73_ex_describe (
                    VAR acv           : tak_all_command_glob;
                    VAR dmli          : tak_dml_info;
                    start_fieldno     : integer;
                    count_in_var_part : boolean);
 
      ------------------------------ 
 
        FROM
              Kernel_move_and_fill : VGG101;
 
        PROCEDURE
              SAPDB_PascalForcedMove (
                    size1    : tsp00_Int4;
                    size2    : tsp00_Int4;
                    val1     : tsp00_MoveObjPtr;
                    p1       : tsp00_Int4;
                    val2     : tsp00_MoveObjPtr;
                    p2       : tsp00_Int4;
                    cnt      : tsp00_Int4);
 
        PROCEDURE
              g10mv (
                    mod_id      : tsp00_C6;            
                    mod_num     : tsp00_Int4;
                    source_upb  : tsp00_Int4;          
                    dest_upb    : tsp00_Int4;
                    source      : tsp00_MoveObjPtr;       
                    src_pos     : tsp00_Int4;
                    destin      : tsp00_MoveObjPtr;       
                    dest_pos    : tsp00_Int4;
                    length      : tsp00_Int4;
                    VAR e       : tgg00_BasisError);
 
        PROCEDURE
              s10mv (
                    source_upb  : tsp00_Int4;       
                    destin_upb  : tsp00_Int4;
                    source      : tsp00_MoveObjPtr;    
                    source_pos  : tsp00_Int4;
                    destin      : tsp00_MoveObjPtr;    
                    destin_pos  : tsp00_Int4;
                    length      : tsp00_Int4);
 
&       IFDEF TRACE
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        PROCEDURE
              t01int4 (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    int      : tsp00_Int4);
&       ENDIF
 
.CM *-END-* use -----------------------------------------
.sp;.cp 3
Synonym :
 
.CM *-END-* synonym -------------------------------------
.sp;.cp 3
Author  : ElkeZ
.sp
.cp 3
Created : 1985-02-21
.sp
.cp 3
.sp
.cp 3
Release :      Date : 2000-11-14
.sp
***********************************************************
.sp
.cp 10
.fo
.oc _/1
Specification:
.CM *-END-* specification -------------------------------
.sp 2
***********************************************************
.sp
.cp 10
.fo
.oc _/1
Description:
.sp 2
A62_A_D_O_SELECT_STATEMENT
.sp
This procedure is called by VAK35 if a SELECT DIRECT or an ordered select
(SELECT FIRST/LAST/NEXT/PREV) has been recognized.  Kw_index specifies
the type of select.  This procedure analyzes the syntax of the entire
command.
.br
The first node is assigned according to the select type and a local
variable that contains the message type to be used is also assigned
immediately.
.br
The select list is processed via A60_SELECT_LIST;
allow_functions = tf_no_func indicates that no SET functions are allowed
and rowno_allowed indicates that entering ROWNO is not allowed.
.br
If the command is only parsed (mainly precompiler), the INTO clause must
be present so that the output values can be assigned to
application-program variables.  For ad-hoc queries, the INTO can be
omitted.  However, the warning3 is issued.
.br
If INTO was specified A02_L_APARAMETER_LIST is used to read the parameter
list.
.br
One table name must follow FROM.
.br
Either ADIRECT_SELECT_REST or AORDER_SELECT_REST is called, depending
on the message type.
.br
For all SELECTs, including single-record selects, it is permissible to
specify a LOCK option (WITH LOCK .. ].  A60_AWAIT_OPTION is called for
this purpose.
.br
A01_IS_END_SYMBOL is used to check whether there are still
superfluous entries on the end of the command.
.sp 2
ADIRECT_SELECT_REST
.sp
This procedure is called by A60_A_D_O_SELECT_STATEMENT.
.br
For a SELECT DIRECT, a key must be specified.  This key entry is
syntactically analyzed by A55_AKEY_SPEC_LIST.
.br
Afterwards, if a search condition still remains, it is processed via
A63_ASEARCH_CONDITION.  Neither SET functions nor a ROWNO are
allowed to occur.
.sp 2
AORDER_SELECT_REST
.sp
For ordered selects, in addition to the key entry and search condition,
it is also permissible to specify an inversion.  This means that the
main 'sorting' criterion for a NEXT or PREV and FIRST or LAST is no
longer the primary key but, instead, is a secondary key.
.br
If only INDEX was specified, APOS_CLAUSE is called and, in the case of
INDEXNAME (multiple inversion specified) APOS_MULTIINDEX_CLAUSE is called.
In both cases, key_allowed (key entry still valid) can become false
because, for a SELECT FIRST/LAST, only the name of the inversion was
specified but no values for it.  Since there were definition problems
as to which inversion the key entry should be valid for (only for the
first inversion list that is handled or for all of them) and there were
also implementation problems, the key entry would have to be prevented
in such a case.
.br
The key entry and the search condition are again processed via
A55_AKEY_SPEC_LIST or A63_ASEARCH_CONDITION.  Since all parts are optional,
care must only be taken when the parse tree is built that put_node or
curr_n, as the case may be, is correctly assigned in all combinations.
.sp 2
APOS_CLAUSE
.sp
This procedure is called by AORDER_SELECT_REST if the entry of INDEX
was found.
.br
The name of a table column must follow since INDEX represents the
symbol for a single index.
.br
A value designating the inversion list at which the search is to begin
must be specified for this index in the case of SELECT NEXT/PREV and
can be specified in the case of FIRST/LAST.
.sp 2
APOS_MULTIINDEX_CLAUSE
.sp
This procedure is called by AORDER_SELECT_REST if the entry of
INDEXNAME was found.
.br
The name of a named (usually multicolumn) index must follow since
INDEXNAME represents the symbol for a named index.
.br
A value designating the inversion list at which the search is to begin
must be specified for this index in the case of SELECT NEXT/PREV and
can be specified in the case of FIRST/LAST.
This is performed following the key word VALUES.  The values must be
enclosed in parentheses.  This is checked via A03_L_AVALUE_LIST.
.sp 2
A62_DIRECT_ORDERED_SELECT
.sp
This procedure is called by VAK35 if a SELECT DIRECT or ordered select
is to be executed.
.br
The indication for a subquery in the command is n_sa_level <> 0, i.e. a
subtree is attached to the parse tree that concatenates the individual
SELECTs (compare VAK60 and A60_ASUB_QUERY).  These subqueries must
be handled separately.
.br
Simple SELECTs are processed via D-SELECT (SELECT DIRECT) or O_SELECT
(ordered SELECT).
.sp 2
D_SELECT
.sp
This procedure processes SELECT DIRECTs both with and without
subqueries in the search condition (called via SUBQUERY).
.br
INIT_DIRORDERED_SELECT is used to search for the table specified in the
from part, to initialize the mess buffer and, if necessary, to provide
a parse buffer or buffer for storing long infos in the cache.
.br
Atsubquery must be false since, for example, no information
on the necessary conversion of the result record
would otherwise be made available in VAK61.
.br
INTERN_BUILD_KEY is used to process the key entry that must be present
for SELECT DIRECT and to transfer the key value to the beginning of
part2 of the mess buffer.
.br
For SELECT DIRECT with subquery, if the user has requested the output of
the long infos, a system-information record is created that contains the
column descriptions of the output columns.  After the SELECT DIRECT
has been executed (parsed and executed separately), an internal
DESCRIBE is carried out which fetches the information required for the
long infos from the sysinfo record.  This record is then deleted.
.br
A61_CHECK_VAL_PARMS is used to process the select list of the command,
enter the output-column information in the long-info buffer or
sysinfo record, if necessary, and to assign atch, the record with
information on the necessary conversions.
.br
If a search condition is pending, it is processed with
A65_SEARCH_CONDITION.  In the case of separate parsing and execution,
a field-information record must be created beforehand in the parse
buffer that guarantees that the next value begin at a fixed position.
This is necessary
since, when the search condition is processed, a stack entry pointing
to the value and specifying a fixed position is created for each
value (compare VAK53, FIELDVALUES, type gotopos).
.br
If the table specified was a view, its qualification is copied next to
the qualification of the search condition after the
special parse-field information gotopos (see VAK53) has been generated,
if necessary.
.br
SINGLE_SELECT_REST is used to process the LOCK option.  The command
is stored (if it was only to be parsed).  Otherwise, it is executed
and the result is entered in the SQL_PACKET converted.
.sp 2
INTERN_BUILD_KEY
.sp
This procedure is called for a key specification for a SELECT DIRECT.
.br
Actually, only A55_BUILD_KEY is called.  However, since it operates on
dmli variables for the privilege check (for historical reasons), these
data must be transferred there from atarr.
.sp 2
O_SELECT
.sp
This procedure processes ordered SELECTs both with and without
subqueries in the search condition (called by SUBQUERY).
.br
INIT_DIRORDERED_SELECT is used to search for the table specified in the
from part, to initialize the mess buffer and, if necessary, to provide
a parse buffer or buffer for storing long infos in the cache.
.br
Atsubquery must be false since, for example, no information
on the necessary conversion of the result record
would otherwise be made available in VAK61.
.br
For SELECTs with subquery, if the user has requested the output of the
long infos, a system-information record is created that contains the
column descriptions of the output columns.  After the SELECT
has been executed (parsed and executed separately), an internal
DESCRIBE is carried out which fetches the information required for the
long infos from the sysinfo record.  This record is then deleted.
.br
A61_CHECK_VAL_PARMS is used to process the select list of the command,
enter the output-column information in the long-info buffer or
sysinfo record, if necessary, and to assign atch, the record with
information on the necessary conversions.
.br
If a search condition is pending, it is processed with
A65_SEARCH_CONDITION.  Unlike D_SELECT, no special field information is
created because the operation is still taking place at the beginning of
part2 of the mess buffer.
.br
If the table specified was a view, its qualification is copied next to
the qualification of the search condition after the
special parse-field information gotopos (see VAK53) has been generated,
if necessary.
.br
In the meantime, variables have been assigned that indicate for the
subsequent strategy search which SELECT variant was pending (with or
without key entry, with or without search condition, etc ].  An attempt
is then made to find a strategy that identifies the desired record as
quickly as possible.  Since some users input information in the
search condition only, and this information would have been more
suitable in the INDEX or key part (equal conditions for inverted
columns, start keys), the search condition must be examined to find
the entries that could be taken from it to expedite the search procedure.
This search procedure is described below in PHASE I-III.
.br
SINGLE_SELECT_REST is used at the end to process the LOCK option.  The
command is stored (if it was only to be parsed).  Otherwise, it is executed
and the result is entered in the SQL_PACKET converted.
.sp;.nf
PHASE I :
=========
.fo
This procedure processes a parse tree.
All necessary information is extracted from the parse tree and stored
in a module-local descriptor block (type selord_desc) which represents
the first part of the interface to phase II
(see comments next to type definition for explanation).
.br
If a search condition was specified, A724TOP_LEVEL_CONDITIONS is
called to analyze the where predicates and to store a description of
those that could be useful in 'zstrat' (which is the second part of
the interface to phase II).
.sp;.nf
PHASE II :
==========
input: selo_desc : selord_type, zstrat : strat_zw_rec
.fo
It attempts to use an index for processing a command. If an index was
specified by the user with an INDEX or INDEXNAME clause, this index
must be used in any case; if not, the procedure still tries to
use an index by searching the search condition for a complete EQUAL
condition on any of the existing (single or multiple) indices.
No attempt is made to use a range condition (<,>,BETW,. ] on an index,
as this would involve using a BD merge for evaluation, which is too
expensive.
.br
The first case is processed by procedures
SINDEX_COL_DESCRIPTION,
MINDEX_COL DESCRIPTION,
second case by
FIND_EQUAL_INDEX.
In both cases, the complete column descriptions for the index involved
have been established (in the form of stack entries) in mess_buffer.
.sp 1
Layout of stack entries for column descriptions:
.sp
.nf
- mcol_pos :  Description of single index values (secondary
              start key and stop key)
              to be used for evaluation of select_row command:
                  etype       = st_value
                  eop         = op_order_asc/op_order_desc
                  epos        = 1
                  elen_var    = 1 (first and only field)
                  ecol_tab(1) = single index no.
                  ecol_tab(2) = inoutlen of field
- mmult_pos : Sequence of descriptions (mmult_cnt entries) of
              multiple index values to be used for evaluation
              of select_row command. Order of entries corres-
              ponds to order of fields in the index definition
              and to the order in which the values are stored in
              part2 of mess_buffer.
              Each entry is of the form:
                  etype       = st_value
                  eop         = op_order_asc/op_order_desc
                  epos        = 1
                  elen_var    = field number within index
                  ecol_tab(1) = multiple index no.
                  ecol_tab(2) = inoutlen of field
.fo
.sp;.nf
PHASE III
=========
input: case of no index:
         - sindex_no = 0; mindex_no = 0
       case of single index:
         - sindex_no <> 0; mindex_no = 0     (* index number      *)
         - inoutlen                          (* length of column  *)
         - single_desc                       (* col is descending *)
         - 1 st_varcol stackentry at mcol_pos
       case of multiple index:
         - sindex_no = 0; mindex_no <> 0
         - n st_varcol stackentries at mmult_pos
.fo;.sp
This phase stores the values that will be used as primary start key,
primary stop key, index start key and index stop key in part2 of
the mess buffer.
The variable x_kind is used in all cases as an indicator of whether a
lower bound (x_low) or an upper bound (x_high) on a range has to be
built. This is convenient since a couple of different cases are equivalent
(e.g. start key/next and stop key/prev) and can be bundled in processing.
Processing of values is performed by the procedures
KEY_FROM_TREE,
KEY_FROM_ZSTRAT, NIL_KEY, SINDEX_TREE, SINDEX_ZSTRAT, MINDEX_TREE,
MINDEX_ZSTRAT and NIL_SMINDEX.
.sp
The layout of the mess buffer after phase III is as follows:
.sp
.nf
----|-------|--|------|---|-----|--|---|-----|---|-----|--|---|-----|--
 .. | start |..| stop |len|value|..|len|value|len|value|..|len|value|
 .. | key   | .| key  |1  |  1  |  | i |  i  |i+1| i+1 |  | n |  n  |
____|_______|__|______|___|_____|__|___|_____|___|_____|__|___|_____|__
     |          |     |<- STARTINDEX as    -> <- STOPINDEX as     ->|
     |          |         described at           described at
     |          |         mcol_pos/mmult_pos     mcol_pos/mmult_pos
     |          |     |<---- all field values with len in front --->|
     |          |
     |          |_________ mst_addr^[ mstrat_pos+1 ].epos
     |____________________ mst_addr^[ mstrat_pos ].epos
.fo
.sp 2
INIT_DIRORDERED_SELECT
.sp
INIT_DIRORDERED_SELECT is used to search for the table specified in the
from part, to initialize the mess buffer and, if necessary, to provide
a parse buffer or buffer for storing long infos in the cache.
.br
Variables are initialized that are important for the processing of the
select list (atoutcolno, atinoutpos, atkeylen, atch,
atuse_order) and those that are relevant for building the parse
information (dm_like, dm_movebefore, dm_pargeslen, dm_range,
dm_maxlen) and for processing the search condition.
.br
The table specified is fetched via A66_SEARCH_TABLE, i.e. pointers
to it are transferred to sparr.
.br
Single-record selects for result sets, join views or complicated views
are always forbidden, along with those for views that have been defined
with DISTINCT, except in cases where a SELECT DIRECT is involved.
.br
The mess buffer is initialized.  Msubquery means that subquery
conditions are to be taken into account.  This leads to the call of a
separate procedure in KB.  This is the opposite of the meaning of
msubquery for set selects where there is space in the strategy
information for the subquery entry.
.br
For subqueries, the parse information must be build with a different
mechanism than that for simple SELECTs.
This is necessary
since, in the case of subquery
selects, a command number has already been assigned via a previous
A54_GET_PPARS_PINFOP, the P-ID = 0 has already been used and no buffer
has to be created for the parse information returned to the user.
The subcntlevel specifies the number contained in all subquery result
files that can be deleted after this SELECT has been processed.
.br
If separate parsing and execution was not requested, the user can
request long infos that give him a more detailed description of the
output columns.  For this purpose, a buffer must be made available
via A60_GET_LONGINFOBUFFER.
.sp 2
BUILD_STRAT_DESCRIPTOR
.sp
This procedure
builds a stack entry of the type st_strat to denote the positions of
primary keys for select ordered within part2 of mess_buffer.
It is called twice: first for start key, and then for stop key.
.sp 2
KEY_FROM_TREE
.sp
This procedure
processes the 'KEY keyfield= ..' clause of the select ordered
command. It extracts the given values from the parse_tree and
assembles them to form a primary start key for the search in KB.
In the case of parse-only, the necessary parse infos are collected.
.sp 2
KEY_FROM_ZSTRAT
.sp
This procedure is
equivalent to KEY_FROM_TREE except that it extracts the primary-key values
from the where condition (i.e. from z_strat_rec) instead of the
'KEY' clause. It is
called a maximum of twice (if no KEY clause exists but
lower and upper bounds for key are available in search condition) to
construct primary start key and stop key.
.br
'x_kind' determines whether the current call has to build a
lower range value or an upper range value (necessary, for example, to
SAPDB_PascalFill key gaps properly with '00' or 'FF').
.br
The length of the assembled key is stored in the corresponding
'st_strat' stack entry.
.br
In the case of parse-only, the necessary parse information are assembled
(A55_COPY_DESCRIBE).
.sp 2
NIL_KEY
.sp
This procedure is
called if neither a 'KEY' clause nor useful where conditions for the
primary keys are found.
It assembles a 'Top'(FF) or 'Bottom'(00) key.
.br
Instead of assembling a NIL stop key, a 'use no stop key' signal is
sent to KB by assigning the value 0 to the key length.
.sp 2
FIND_EQUAL_INDEX
.sp
This procedure
is called when a select-ordered command has no 'INDEX' or 'INDEXNAME'
clause.
.br
It tries to determine from the where part an index that may still be
used to optimize the search. Only Equal conditions for an indexed field
are elligible (range conditions would lead to a BD merge, which is too
expensive).
.br
First z_strat_rec.z_feq is searched for an equal condition on a single
index. IF one exists, it is taken (without considering any multiple
indices) and a stack entry describing the index field (mcol_pos) is
built. If not, the system information for any indices on the table is
fetched and
A71_MINDEX_ARR is called with 'one_specific=false' and
'only_equal=true'. It returns a descriptor block mindex_arr
that takes into account equal conditions only.
If mindex_arr contains an element with smir_equals  > 0  , it is taken
and descriptor stack entries (mmult_pos) are built.
.sp 2
MI_STACKENTRIES
.sp
This procedure is used to enter a description of a multiple index in
the stack entries beginning at position mmult_pos.
.sp 2
SINDEX_COL_DESCRIPTION
.sp
This procedure is
called if an 'INDEX' clause was specified.
.br
It gets the system information
on the specified column/index, checks column attributes and constructs
a stack entry describing the index field.
.sp 2
MINDEX_COL_DESCRIPTION
.sp
This procedure is
called if an 'INDEXNAME' clause was specified.
It has the same function as
SINDEX_COL_DESCRIPTION.  In addition, A71_MINDEX_ARR is called with
'one_specific=true' and 'only_equal=false' to get a description of
the available where conditions on the specified index for the further
processing.
.sp 2
GET_EMINDEX
.sp
This procedure
gets system information on the indices of the specified table.
.sp 2
SINDEX_TREE
.sp
This procedure
extracts a single index value from a parse tree and stores it with a
length field in part2 of the mess buffer.
.sp 2
MINDEX_TREE
.sp
This procedure
extracts multiple index values from a parse tree and stores them with
a length field in part2 of the mess_buffer. If an 'INDEXNAME' clause was
specified without values, 'top'(FF) or 'bottom'(00) values are
stored instead. (Note: a descending index field has inverted top and
bottom values).
.sp 2
SINDEX_ZSTRAT
.sp
This procedure
extracts a condition value for a given single index ('sindex_no')
from a where part (via st_value stack entries referenced by zstrat) if
it exists (procedure SMINDEX_VALUE).
It builds a nil entry (procedure
NIL_SMINDEX) if no value could be extracted.
It builds a parse description if value will be furnished only at
execution time (procedure A55_COPY_DESCRIBE).
.br
The input variable x_kind (x_low, x_high) determines whether a lower
or upper bound of the index range is constructed.
.sp 2
MINDEX_ZSTRAT
.sp
This procedure has the
same function as SINDEX_ZSTRAT for a multiple index.
There is a
FOR loop on all participating columns.
.br
x_kind has to be determined
individually for each column depending on its ordering type (ascending,
descending).
.sp 2
SMINDEX_VALUE
.sp
This procedure is a
primitive to transfer exactly one index value from the
where condition of a command (position, length described by a stack
entry of type st_value) to the proper position in part2 of
the mess_buffer.
.br
The value is copied identically (i.e. not truncated or filled); all
adjustment in length takes place in VKB71.
.br
In the
parse-only mode, parse information about this value (i.e. its length)
is recorded in dm_move_before.
.br
All index-value entries (note: every field value for a multiple index)
are preceeded by their lengths.
.sp 2
NIL_SMINDEX
.sp
This procedure is a
primitive to describe a non-existent value for one of the index keys.
There are two cases:
.br
no_use = true
.br
It will only be called for the stop key of a single index. It
stores a value of the length 0 and thereby signals to KB that bd_use_info
will not contain 'secondary stop key'.
.sp
no_use = false
.br
This
will be called in all other cases (i.e. start keys and multiple indices).
It stores a bottom value ('00', length 1) or a top value ('FF', length 1),
depending on the value of x_kind (x_low, x_high).
.sp 2
SINGLE_SELECT_REST
.sp
This procedure is called at the end of D_SELECT and O_SELECT.  It is used
at the end to process the LOCK option.  The command is stored (if it
was to be parsed only).  Otherwise, it is executed and the result is
entered in the SQL_PACKET converted.
.br
The supplementary lock-mode information specified by the user is kept
in dm_lockstate.  At the time of execution, this information is added
to the current transaction states and afterwards removed.
.br
In the entire procedure up to this point, part2.len was always correct
for the info part of part2 of the mess buffer.  The 4 additional
bytes must be calculated in and the command must be executed or stored
(parsing) via A54_SELECT_LAST_PART.
.br
If the command was executed and if it was desired by the user (info_output),
the long infos for the output columns must be transferred to part1 of
the SQL_PACKET (A60_P_INFO_OUTPUT).  The maximum of 2 long-info
buffers are deleted via A10_TABLE_CACHE_DELETE.
.br
If a result was found, it must be converted
(A60_CHANGE_RESULTS) and moved to part2 of the SQL_PACKET if
it still fits there (A60_PUT_RESULT).
.sp 2
SUBQUERY
.sp
This procedure is called if a SELECT DIRECT or an ordered
SELECT contains subqueries.
.br
At first, these subqueries are only parsed so that not too much work
has been done before it is determined, for example, that a column name
has been written incorrectly or a privilege does not exist.
.br
A parse-information record is created (A54_GET_PPARSP_PINFOP). The levels
of the subqueries are numbered so that their file names can be formed
correctly and so that all subqueries on one level can also be deleted with
prefix_delete.
.br
A66_SUB_BUILD is used to parse all subqueries and to store their
information records.  The SELECT DIRECT or the
ordered select is then also parsed (D_SELECT and O_SELECT, respectively).
.br
If the execution of the command was desired by the user, the entire
command, including all subqueries, is processed via A50_DO_EXECUTE.
.br
If the command was successful or if it led to the error 100, the entire
set of long infos must still be given to the user, if applicable.  Since
these infos could not also be generated during internal parsing, they are
also contained in a system-information record (column description) for
single-record selects.  This record is completed via A67_BEXTCOLINDEX.
A73_EX_DESCRIBE is used to store a long info for each output column
in part1 of the SQL_PACKET after the result count.
.br
If no long info is requested, the 'result-set name' of the single-record
select is stored in part1 before the result count as a sequence of
binary zeros.
.br
The result is then converted (A60_CHANGE_RESULTS) and shifted
to the SQL_PACKET via A60_PUT_RESULT (or stored in the mess buffer
in the case of FETCH REST).
.br
Since, for this separation of parsing and execution, column descriptions
were created and entries were made in the result-set array that actually
should not have existed, they must be deleted.  The parse-information
records created for internal purposes must also be deleted.
.CM *-END-* description ---------------------------------
.sp 2
***********************************************************
.sp
.cp 10
.nf
.oc _/1
Structure:
 
.CM *-END-* structure -----------------------------------
.sp 2
**********************************************************
.sp
.cp 10
.nf
.oc _/1
.CM -lll-
Code    :
 
 
CONST
      c_output_during_execution= true (* a501do_execute *);
      c_in_union            = true (* a54_dml_init *);
      c_last_pars_part      = true (* a54_select_last_part *);
      c_subquery_select     = true (* ak62_d_select *);
      (*                              ak62_o_select *)
      c_first_parsinfo      = true (* a660_new_pparsp *);
      c_complicate          = true (* a660_new_pparsp *);
      c_all                 = true (* a660_search_one_table *);
      c_check_teresult      = true (* a660_search_one_table *);
      c_do_cdel             = true (* a663_del_result *);
      c_del_resname_rec     = true (* a663_del_result *);
      c_subquery            = true (* a73_ex_describe *);
 
 
(*------------------------------*) 
 
PROCEDURE
      ak62_d_select (
            VAR acv                       : tak_all_command_glob;
            VAR dmli                      : tak_dml_info;
            start_node                    : tsp00_Int2;
            subquery_select               : boolean;
            with_subquery_and_info_output : boolean);
 
VAR
      last_node : integer;
      par_node  : integer;
      sel_node  : integer;
      res_name  : tsp00_KnlIdentifier;
      dummy_id  : tgg00_FileId;
      dfa       : tak_dfarr;
 
BEGIN
WITH acv, dmli DO
    BEGIN
    sel_node := a_ap_tree^[ start_node ].n_lo_level;
    par_node := a_ap_tree^[ sel_node ].n_sa_level;
    WITH a_ap_tree^[ par_node ] DO
        IF  ((n_proc = a60) AND (n_subproc = cak_x_single_select))
        THEN
            last_node := n_sa_level
        ELSE
            last_node := par_node;
        (*ENDIF*) 
    (*ENDWITH*) 
    ak62init_dirordered_select (acv, dmli, last_node, subquery_select,
          mm_direct);
    IF  a_returncode = 0
    THEN
        BEGIN
        (* PTS 1111575 E.Z. *)
        last_node := a_ap_tree^[ last_node ].n_sa_level;
        d_pars_kind := fp_val_varcol_with_len;
        IF  (a_ap_tree^[ last_node ].n_proc = a55) AND
            (a_ap_tree^[ last_node ].n_subproc = cak_x_keyspec_list)
        THEN
            a55_build_key (acv, dmli, dfa, last_node)
        ELSE
            a58_current_of (acv, dmli, last_node);
        (*ENDIF*) 
        WITH acv.a_mblock, mb_data^ DO
            (* PTS 1111575 E.Z. *)
            mbp_keylen := mb_data_len - cgg_rec_key_offset;
        (*ENDWITH*) 
        (* PTS 1111575 E.Z. *)
        IF  ((a_returncode = 0) AND
            with_subquery_and_info_output
            AND NOT d_only_sem_check)
        THEN
            BEGIN
            d_single := false;
            res_name := a01_zero_res_name;
            a663_make_res_buf (acv, dmli, res_name, dummy_id);
            dmli.d_global_pos_result := dmli.d_pos_result;
&           ifdef trace
            t01int4 (ak_sem, 'd_global_pos', dmli.d_global_pos_result);
&           endif
            END;
        (*ENDIF*) 
        IF  a_returncode = 0
        THEN
            BEGIN
            IF  a_ex_kind = only_parsing
            THEN
                a54_fixedpos (acv, dmli);
            (*ENDIF*) 
            a61_check_val_params (acv, dmli, sel_node, par_node);
            last_node := a_ap_tree^[ last_node ].n_sa_level;
            IF  last_node <> 0
            THEN
                IF  ((a_ap_tree^[ last_node ].n_proc = a63) AND
                    (a_ap_tree^[ last_node ].n_subproc =
                    cak_x_search_condition))
                THEN
                    BEGIN
                    sel_node := a_ap_tree^[ last_node ].n_lo_level;
                    last_node := a_ap_tree^[ last_node ].n_sa_level;
                    IF  a_ex_kind = only_parsing
                    THEN
                        a54_fixedpos (acv, dmli);
                    (* PTS 1111575 E.Z. *)
                    (*ENDIF*) 
                    a65_search_condition (acv, dmli, sel_node)
                    END;
                (*ENDIF*) 
            (*ENDIF*) 
            IF  (a_returncode = 0)
            THEN
                WITH a_mblock, mb_qual^, dmli.d_tabarr[ dmli.d_acttabindex ] DO
                    BEGIN
                    IF  oview AND oviewqual
                    THEN
                        BEGIN
                        IF  a_ex_kind = only_parsing
                        THEN
                            a54_fixedpos (acv, dmli);
                        (*ENDIF*) 
                        a54_view_put_into (acv, dmli)
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDWITH*) 
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        ak62single_select_rest (acv, dmli);
        END;
    (* PTS 1111575 E.Z. *)
    (*ENDIF*) 
    END
(*ENDWITH*) 
END;
 
(* PTS 1111575 E.Z. *)
(*------------------------------*) 
 
PROCEDURE
      ak62init_dirordered_select (
            VAR acv         : tak_all_command_glob;
            VAR dmli        : tak_dml_info;
            table_spec_node : integer;
            subquery_select : boolean;
            mtype           : tgg00_MessType2);
 
VAR
      honly_sem_check : boolean;
      h_handling      : tgg00_HandlingSet;
      table_node      : integer;
 
BEGIN
WITH acv, dmli DO
    BEGIN
    IF  ((a_ex_kind = only_parsing) AND subquery_select)
    THEN
        a_ptr3 := d_sparr.pinfop;
    (*ENDIF*) 
    h_handling := d_unchanged_globstate;
    IF  subquery_select
    THEN
        honly_sem_check := d_only_sem_check
    ELSE
        honly_sem_check := false;
    (*ENDIF*) 
    a54_dml_init (dmli, NOT c_in_union);
    (* PTS 1111575 E.Z. *)
    d_only_sem_check      := honly_sem_check;
    d_globstate          := h_handling;
    d_unchanged_globstate := h_handling;
    IF  hsIntentExcl_egg00 in d_globstate
    THEN
        d_globstate := d_globstate -
              [ hsConsistentLock_egg00, hsWithoutLock_egg00 ];
    (*ENDIF*) 
    d_acttabindex := 1;
    d_cntfromtab := 1;
    d_single := true;
    d_inoutpos := cgg_rec_key_offset + RESCNT_MXGG04 + 1;
    d_keylen := RESCNT_MXGG04; (*  neccessary for bufpos during p_long_info, VAK61 *)
    d_rowno := cgg04_no_rowno_predicate;
    table_node := a_ap_tree^[ table_spec_node ].n_lo_level;
    a660_search_one_table (acv, dmli, table_node, c_all,
          NOT c_check_teresult, no_lock, r_sel);
    IF  a_returncode = 0
    THEN
        BEGIN
        WITH d_sparr, pbasep^.sbase, d_tabarr[ 1 ] DO
            IF  ((btablekind in [tcatalog_table,
                tresult, tview, tcomplexview, tdb2view]) OR
                (bv_tablekind = tcatalog_table) OR
                ((btablekind = tonebase) AND
                (bv_distinct <> no_distinct) AND (mtype <> mm_direct)))
            THEN
                a07_b_put_error (acv, e_missing_basetable,
                      a_ap_tree^[ table_node ].n_pos);
            (*ENDIF*) 
        (*ENDWITH*) 
        IF  a_returncode = 0
        THEN
            BEGIN
            (* h.b. PTS 1119078 *)
            IF  hsConsistentLock_egg00 in d_globstate
            THEN
                BEGIN
                d_globstate := d_globstate - [ hsConsistentLock_egg00 ];
                IF  (hsPermLock_egg00 in d_globstate) OR
                    (hsTempLock_egg00 in d_globstate)
                THEN
                    BEGIN
                    IF  NOT (hsIntentExcl_egg00 in d_globstate)
                    THEN
                        d_globstate := d_globstate
                              + [ hsWithoutLock_egg00 ]
                    (*ENDIF*) 
                    END
                ELSE
                    d_globstate := d_globstate
                          + [ hsCollisionTest_egg00 ];
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            a06a_mblock_init (acv, m_select_row, mtype, d_tabarr[ 1 ].otreeid);
            IF  subquery_select
            THEN
                BEGIN
                d_use_sub := true;
                a_mblock.mb_qual^.msubquery := true;
                END;
            (*ENDIF*) 
            IF  a_ex_kind = only_parsing
            THEN
                BEGIN
                IF  subquery_select
                THEN
                    BEGIN
                    (* *** union in subquery ! *** *)
                    a_pars_last_key.p_kind := m_select_row;
                    a660_new_pparsp (acv, d_sparr,
                          NOT c_first_parsinfo, c_complicate);
                    WITH a_ptr2^.scomplexrec DO
                        BEGIN
                        comparr[ compcnt ].centryinfo   :=
                              comparr[ compcnt ].centryinfo + [ ci_lastpars ];
                        comparr[ compcnt ].cqual_jv_upd := acv.a_qualified_jv_upd
                        END;
                    (*ENDWITH*) 
                    IF  a_returncode = 0
                    THEN
                        d_sparr.pparsp^.sparsinfo.p_subcntlevel := 1;
                    (*ENDIF*) 
                    d_sparr.pinfop := a_ptr3
                    END
                ELSE
                    a54_get_pparsp_pinfop (acv, d_sparr, m_select_row);
                (*ENDIF*) 
                (* PTS 1111575 E.Z. *)
                d_sparr.pparsp^.sparsinfo.p_tabid :=
                      d_sparr.pbasep^.syskey.stableid;
                END;
            (* PTS 1111575 E.Z. *)
            (*ENDIF*) 
            IF  ((a_returncode = 0) AND a_info_output)
            THEN
                a60_get_longinfobuffer (acv, d_sparr, MAX_COL_PER_TAB_GG00,
                      cak_into_res_fid);
            (*ENDIF*) 
            END
        (*ENDIF*) 
        END
    (*ENDIF*) 
    END
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak62single_select_rest (
            VAR acv  : tak_all_command_glob;
            VAR dmli : tak_dml_info);
 
VAR
      lcol_lock  : boolean;
      dummy_tree : tgg00_FileId;
 
BEGIN
WITH acv, dmli DO
    BEGIN
    d_reuse := false;
    (* PTS 1111575 E.Z. *)
    IF  ((a_returncode = 0) AND NOT d_only_sem_check)
    THEN
        (* PTS 1112770 E.Z. *)
        BEGIN
        d_single := true;
        a54_select_last_part (acv, dmli, dummy_tree,
              c_last_pars_part);
        END;
    (*ENDIF*) 
    IF  a_info_output
    THEN
        BEGIN
        (* PTS 1112770 E.Z. *)
        IF  d_sparr.pinfop <> NIL
        THEN
            BEGIN
            a60_p_info_output (acv, d_sparr);
            a10_key_del (acv, d_sparr.pinfop^.syskey);
&           ifdef trace
            d_sparr.pinfop := NIL;
&           endif
            a_shortinfo_key := cgg_zero_id;
            END;
        (*ENDIF*) 
        IF  d_sparr.pcolnamep <> NIL
        THEN
            BEGIN
            IF  (
                (acv.a_comp_type = at_xci)
                OR (acv.a_comp_type = at_odbc)
                )                      AND
                (acv.a_returncode = 0) AND
                (acv.a_ex_kind = only_parsing)
            THEN
                a60_columnnames_return (acv, d_sparr.pcolnamep);
            (*ENDIF*) 
            a10_key_del (acv, d_sparr.pcolnamep^.syskey);
&           ifdef trace
            d_sparr.pcolnamep := NIL
&                 endif
            END
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  (a_ex_kind <> only_parsing)
        (* PTS 1111575 E.Z. *)
    THEN
        BEGIN
        IF  a_returncode = 0
        THEN
            BEGIN
            a60rescount (acv, 1);
            a60_change_results (acv, a_mblock.mb_data^.mbp_buf,
                  d_change, 0, a_mblock.mb_data_len);
            a60_put_result (acv,
                  a_mblock, cgg_rec_key_offset + RESCNT_MXGG04);
            IF  (d_change.cr_colcount > 0) AND
                (a_returncode = 0)
            THEN
                IF  a508_lcol_found (acv, d_change)
                THEN
                    BEGIN
                    lcol_lock := true;
                    (* PTS 1116801 E.Z. *)
                    a508_lget_long_columns (acv, d_change, lcol_lock, 1,
                          mxsp_long_desc, - (cgg_rec_key_offset + RESCNT_MXGG04));
                    END;
                (*ENDIF*) 
            (*ENDIF*) 
            IF  a_returncode = 0
            THEN
                a06finish_curr_retpart (acv, sp1pk_data, 1)
            (*ENDIF*) 
            END
        (*ENDIF*) 
        END
    (*ENDIF*) 
    END
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak62subquery (
            VAR acv    : tak_all_command_glob;
            VAR dmli   : tak_dml_info;
            start_node : tsp00_Int2;
            mtype      : tgg00_MessType;
            mmtype     : tgg00_MessType2);
 
VAR
      m_acv_info_output : boolean;
      h_handling        : tgg00_HandlingSet;
      mcommand          : tak_commandkind;
      low_first         : integer;
      sr_rec            : tak71_strat_rec;
 
BEGIN
WITH acv, dmli DO
    BEGIN
    a_ex_kind := only_parsing;
    m_acv_info_output := a_info_output;
    h_handling := d_unchanged_globstate;
    a54_dml_init (dmli, NOT c_in_union);
    d_unchanged_globstate := h_handling;
    d_globstate          := h_handling;
    d_subquery := true;
    d_use_sub := true;
    a_info_output := false;
    mcommand := a_command_kind;
    IF  a_command_kind = complex_view_command
    THEN
        a_command_kind := sub_in_complex_command
    ELSE
        IF  a_command_kind <> sub_in_complex_command
        THEN
            a_command_kind := subquery_command;
        (*ENDIF*) 
    (*ENDIF*) 
    IF  ((hsTempLock_egg00 in d_globstate) OR
        (hsPermLock_egg00 in d_globstate))
        AND
        (a_isolation_info <> temp_lock_rec_get)
    THEN
        a_isolation_info := temp_lock_rec_needed;
    (*ENDIF*) 
    a54_get_pparsp_pinfop (acv, d_sparr, mtype);
    a_mblock.mb_data_len         := cgg_rec_key_offset;
    a_mblock.mb_data^.mbp_reclen := 0;
    a_mblock.mb_data^.mbp_keylen := 0;
    sr_rec.sr_reverse_access := false;
    low_first              := 1;
    a661_sub_build (acv, dmli,
          a_ap_tree^[start_node].n_sa_level,
          cgg_rec_key_offset, sr_rec);
    IF  (a_returncode = 0) AND (a_main_returncode <> 0)
    THEN
        BEGIN
        a_returncode := a_main_returncode;
        a_errorpos   := a_main_errorpos;
        END;
    (*ENDIF*) 
    d_subquery := false;
    IF  (a_returncode = 0) AND
        ( a_intern_select_cnt = a_max_intern_select )
    THEN
        BEGIN
        d_subcount := 0;
        IF  mmtype = mm_direct
        THEN
            ak62_d_select (acv, dmli, start_node,
                  c_subquery_select, m_acv_info_output)
        ELSE
            BEGIN
            a07ak_system_error( acv, 62, 2 );
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    a_command_kind := mcommand;
    IF  ((a_returncode = 0) AND
        (a_isolation_info = temp_lock_rec_get))
    THEN
        a54_loc_temp_locks (acv, d_globstate, d_sparr);
    (*ENDIF*) 
    END
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a62_direct_ordered_select (
            VAR acv    : tak_all_command_glob;
            start_node : tsp00_Int2);
 
VAR
      with_pos_of_select : boolean;
      m_acv_info_output  : boolean;
      lcol_lock          : boolean;
      b_err              : tgg00_BasisError;
      lock_node          : integer;
      aux_return         : tsp00_Int2;
      aux_errorpos       : tsp00_Int4;
      mcntbuf            : integer;
      del_cnt            : integer;
      parsk              : tak_parskey;
      sysk               : tgg00_SysInfoKey;
      dmli               : tak_dml_info;
 
BEGIN
acv.a_ptr1           := NIL;
acv.a_p_arr1.pbasep  := NIL;
acv.a_p_arr1.pcount  := 0;
(* PTS 1111575 E.Z. *)
dmli.d_unchanged_globstate := acv.a_transinf.tri_global_state;
lock_node := acv.a_ap_tree^[ start_node ].n_lo_level;
REPEAT
    lock_node := acv.a_ap_tree^[ lock_node ].n_sa_level
UNTIL
    ((lock_node = 0) OR
    ((acv.a_ap_tree^[ lock_node ].n_proc = a60) AND
    (acv.a_ap_tree^[ lock_node ].n_subproc in
    [ cak_x_lock_exclusive, cak_x_lock_share,
    cak_x_lock_nowait, cak_x_lock_optimistic, cak_x_lock_ignore ])) OR
    ((acv.a_ap_tree^[ lock_node ].n_proc = a51) AND
    (acv.a_ap_tree^[ lock_node ].n_subproc = cak_i_isolation)));
(*ENDREPEAT*) 
IF  lock_node <> 0
THEN
    BEGIN
    dmli.d_with_lock_clause := true;
    a660_lock (acv, lock_node, dmli.d_unchanged_globstate);
    END;
(*ENDIF*) 
WITH acv, dmli DO
    BEGIN
    d_only_sem_check := false;
    m_acv_info_output := a_info_output;
    with_pos_of_select := (acv.a_ap_tree^[ 0 ].n_lo_level <> start_node);
    IF  with_pos_of_select
    THEN
        BEGIN
        sysk := a01sysnullkey;
        WITH sysk, parsk DO
            BEGIN
            sauthid[ 1 ] := cak_tempinfo_byte;
            p_count   := a_pars_last_key.p_count;
            p_id[ 1 ] := a_first_parsid;
            p_kind    := m_fetch;
            p_no      := 0;
            sentrytyp := cak_eshortinfo;
            s10mv (sizeof(parsk), sizeof(sauthid),
                  @parsk, 1, @sauthid, 2, mxak_parskey);
            END;
        (*ENDWITH*) 
        a10get_sysinfo (acv, sysk, d_fix, d_sparr.pinfop, b_err);
        IF  b_err <> e_ok
        THEN
            a07_b_put_error (acv, b_err, 1);
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    WITH acv.a_ap_tree^[ start_node ] DO
        IF  n_subproc = cak_x_select_direct
        THEN
            IF  n_sa_level <> 0
            THEN
                ak62subquery (acv, dmli, start_node,
                      m_select_row, mm_direct)
            ELSE
                BEGIN
                ak62_d_select (acv, dmli, start_node, with_pos_of_select,
                      with_pos_of_select AND a_info_output);
                END
            (*ENDIF*) 
        ELSE
            BEGIN
            a07ak_system_error( acv, 62, 1 );
            END;
        (*ENDIF*) 
    (*ENDWITH*) 
    (* end of subquery or end of 'POS OF <ergname>' *)
    IF  ( a_init_ex_kind <> only_parsing ) AND
        ( a_ex_kind      =  only_parsing ) AND
        ( a_intern_select_cnt = a_max_intern_select )
    THEN
        BEGIN
        IF  a_returncode = 0
        THEN
            BEGIN
            WITH a_resname_addr[ d_pos_result ]^.sresname DO
                BEGIN
                mcntbuf       := resmaxlinkage;
                resmaxlinkage := 0
                END;
            (*ENDWITH*) 
            parsk           := a_pars_last_key;
            parsk.p_id[ 1 ] := a_first_parskey;
            parsk.p_kind    := m_complex;
            parsk.p_no      := 0;
            a_ex_kind         := only_executing;
            a501do_execute (acv, dmli, parsk,
                  NOT c_output_during_execution);
            WITH a_resname_addr[ d_pos_result ]^.sresname DO
                resmaxlinkage := mcntbuf;
            (*ENDWITH*) 
            END;
        (*ENDIF*) 
        aux_return   := acv.a_returncode;
        aux_errorpos := acv.a_errorpos;
        IF  a_returncode in [ 0, 100 ]
        THEN
            IF  m_acv_info_output
            THEN
                BEGIN
                a_returncode := 0;
                a67_bextcolindex (d_esparr, d_outcolno);
                a73_ex_describe (acv, dmli, 1, NOT c_subquery);
                IF  ((a_returncode <> 0) AND (aux_return in [ 0, 100 ]))
                THEN
                    BEGIN
                    aux_return   := acv.a_returncode;
                    aux_errorpos := acv.a_errorpos;
                    END;
&               ifdef trace
                (*ENDIF*) 
                t01int4 (ak_sem, 'd_global_pos', dmli.d_global_pos_result);
                t01int4 (ak_sem, 'd_pos_result', dmli.d_pos_result);
&               endif
                WITH a_resname_addr [ cak_intern_pos ]^.sresname DO
                    IF  (resmaxlinkage > 0)
                    THEN
                        a663_del_result (acv,
                              a_resname_addr [ cak_intern_pos ]^.sresname,
                              c_do_cdel, NOT c_del_resname_rec);
                    (*ENDIF*) 
                (*ENDWITH*) 
                END
            ELSE
                BEGIN
                (* is done in vak507 *)
                END;
            (*ENDIF*) 
        (*ENDIF*) 
        IF  aux_return = 0
        THEN
            BEGIN
            a60_change_results (acv, a_mblock.mb_data^.mbp_buf,
                  d_change, 0, a_mblock.mb_data_len);
            a60_put_result (acv,
                  a_mblock, cgg_rec_key_offset + RESCNT_MXGG04);
            IF  (d_change.cr_colcount > 0) AND
                (a_returncode = 0)
            THEN
                IF  a508_lcol_found (acv, d_change)
                THEN
                    BEGIN
                    lcol_lock := true;
                    (* PTS 1116801 E.Z. *)
                    a508_lget_long_columns (acv, d_change, lcol_lock, 1,
                          mxsp_long_desc, - (cgg_rec_key_offset + RESCNT_MXGG04));
                    END;
                (*ENDIF*) 
            (*ENDIF*) 
            IF  a_returncode = 0
            THEN
                a06finish_curr_retpart (acv, sp1pk_data, 1)
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  NOT (a_returncode in [ 0, 100 ])
        THEN
            BEGIN
            aux_return   := acv.a_returncode;
            aux_errorpos := acv.a_errorpos;
            END;
        (*ENDIF*) 
        a_returncode := 0;
        IF  m_acv_info_output
        THEN
            BEGIN
            a10del_sysinfo (acv,
                  d_esparr.pbasep^.syskey, b_err);
&           ifdef trace
            d_esparr.pbasep := NIL;
&           endif
            IF  ((b_err <> e_ok) AND
                ( b_err <> e_sysinfo_not_found))
            THEN
                a07_b_put_error (acv, b_err, 1);
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        a660_prefix_delete (acv, parsk, del_cnt, cak_complete_prefix);
        IF  ((aux_return <> 0) AND (a_returncode in [ 0, 100 ]))
        THEN
            BEGIN
            acv.a_returncode := aux_return;
            acv.a_errorpos   := aux_errorpos;
            END
        (*ENDIF*) 
        END
    ELSE
        (* PTS 1112770 E.Z. *)
        BEGIN
        IF  (( a_init_ex_kind = only_parsing ) AND
            (  d_esparr.pbasep <> NIL )        AND
            m_acv_info_output)
        THEN
            BEGIN
            aux_return   := acv.a_returncode;
            aux_errorpos := acv.a_errorpos;
            a_returncode := 0;
            a10del_sysinfo (acv,
                  d_esparr.pbasep^.syskey, b_err);
&           ifdef trace
            d_esparr.pbasep := NIL;
&           endif
            IF  ((b_err <> e_ok) AND
                ( b_err <> e_sysinfo_not_found))
            THEN
                a07_b_put_error (acv, b_err, 1);
            (*ENDIF*) 
            IF  ((aux_return <> 0) AND (a_returncode in [ 0, 100 ]))
            THEN
                BEGIN
                acv.a_returncode := aux_return;
                acv.a_errorpos   := aux_errorpos;
                END
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  a_intern_select_cnt < a_max_intern_select
        THEN
            BEGIN
            parsk           := a_pars_last_key;
            a660_prefix_delete (acv, parsk, del_cnt, cak_complete_prefix);
            END
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    a_ex_kind     := a_init_ex_kind;
    a_info_output := m_acv_info_output;
    END
(*ENDWITH*) 
END;
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
.PA 
