.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$VAK60$
.tt 2 $$$
.TT 3 $ElkeZ$Select_Syntax$$$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  : Select_Syntax
=========
.sp
Purpose : Syntax analysis for select, explain, declare.
          Conversion routines for output, help procedures
          for single-record selects and fetches
.CM *-END-* purpose -------------------------------------
.sp
.cp 3
Define  :
 
        PROCEDURE
              a60_aselect_statement (
                    VAR acv      : tak_all_command_glob;
                    VAR put_node : tsp00_Int2);
 
        PROCEDURE
              a60_aexplain_statement (
                    VAR acv      : tak_all_command_glob;
                    VAR put_node : tsp00_Int2);
 
        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_put_result (
                    VAR acv    : tak_all_command_glob;
                    VAR mblock : tgg00_MessBlock;
                    spos       : integer);
 
        PROCEDURE
              a60_get_longinfobuffer (
                    VAR acv   : tak_all_command_glob;
                    VAR sparr : tak_syspointerarr;
                    col_cnt   : integer;
                    resultno  : tsp00_Int4);
 
        PROCEDURE
              a60_adeclare (
                    VAR acv      : tak_all_command_glob;
                    VAR put_node : tsp00_Int2);
 
        PROCEDURE
              a60_aquery_spec (
                    VAR acv       : tak_all_command_glob;
                    stamp_allowed : boolean;
                    from_select   : boolean; (* PTS 1138343 D.T. *)
                    VAR put_node  : tsp00_Int2;
                    VAR last_node : tsp00_Int2;
                    last_n        : tsp00_Int2;(* PTS 1138343 D.T. *)
                    fromselnode_built : boolean); (* PTS 1138343 D.T. *)
 
        PROCEDURE
              a60_asub_query (
                    VAR acv         : tak_all_command_glob;
                    VAR put_node    : tsp00_Int2;
                    list_cnt        : integer;
                    one_valsubquery : boolean);
 
        PROCEDURE
              a60rescount (
                    VAR acv  : tak_all_command_glob;
                    rescount : tsp00_Int4);
 
        PROCEDURE
              a60resnum (
                    VAR acv     : tak_all_command_glob;
                    VAR moveobj : tsp00_MoveObj;
                    startpos    : integer);
 
.CM *-END-* define --------------------------------------
.sp;.cp 3
Use     :
 
        FROM
              Scanner : VAK01;
 
        VAR
              a01kw                : tak_keywordtab;
              a01sysnullkey        : tgg00_SysInfoKey;
              a01_il_b_identifier  : tsp00_KnlIdentifier;
 
        PROCEDURE
              a01info_call_put (
                    VAR acv    : tak_all_command_glob;
                    proc       : tak_procs;
                    subproc    : tsp00_Int2;
                    VAR curr_n : tsp00_Int2;
                    VAR info_n : tsp00_Int2);
 
        PROCEDURE
              a01_next_symbol (VAR acv : tak_all_command_glob);
 
        PROCEDURE
              a01_get_keyword (
                    VAR acv      : tak_all_command_glob;
                    VAR index    : integer;
                    VAR reserved : boolean);
 
        PROCEDURE
              a01_put_node (
                    VAR acv    : tak_all_command_glob;
                    VAR curr_n : tsp00_Int2);
 
        PROCEDURE
              a01_call_put (
                    VAR acv    : tak_all_command_glob;
                    proc       : tak_procs;
                    subproc    : tsp00_Int2;
                    VAR curr_n : tsp00_Int2);
 
        PROCEDURE
              a01_is_end_symbol (VAR acv : tak_all_command_glob);
 
        FUNCTION
              a01_eqkey (
                    VAR a      : tak_keyword;
                    sqlmode    : tsp00_SqlMode;
                    VAR b      : tsp00_MoveObj;
                    VAR scv    : tak_scanner_glob) : boolean;
 
        FUNCTION
              a01mandatory_keyword (
                    VAR acv          : tak_all_command_glob;
                    required_keyword : integer) : boolean;
 
        PROCEDURE
              a01_force_symbol (
                    VAR acv         : tak_all_command_glob;
                    expected_symbol : tak_sc_symbol;
                    VAR node1       : tsp00_Int2;
                    VAR node2       : tsp00_Int2);
 
        FUNCTION
              a01_odbc_end_ok (
                    VAR acv : tak_all_command_glob;
                    partype : tak_odbc_partype) : boolean;
 
        PROCEDURE
              a01_is_odbc_syntax (
                    VAR acv      : tak_all_command_glob;
                    VAR partype  : tak_odbc_partype;
                    VAR functype : tak_odbc_functiontype);
 
      ------------------------------ 
 
        FROM
              AK_syntax_tools : VAK02;
 
        PROCEDURE
              a02_aparameter_name (
                    VAR acv       : tak_all_command_glob;
                    VAR put_node  : tsp00_Int2;
                    VAR last_node : tsp00_Int2);
 
        PROCEDURE
              a02_atablename (
                    VAR acv       : tak_all_command_glob;
                    VAR put_node  : tsp00_Int2;
                    VAR last_node : tsp00_Int2);
 
        PROCEDURE
              a02_aresulttablename (
                    VAR acv       : tak_all_command_glob;
                    VAR put_node  : tsp00_Int2;
                    VAR last_node : tsp00_Int2);
 
        PROCEDURE
              a02_l_aparameter_list (
                    VAR acv       : tak_all_command_glob;
                    VAR put_node  : tsp00_Int2;
                    VAR last_node : tsp00_Int2);
 
        PROCEDURE
              a02_l_acolumn_list (
                    VAR acv       : tak_all_command_glob;
                    VAR put_node  : tsp00_Int2;
                    VAR last_node : tsp00_Int2);
 
        PROCEDURE
              a02_acolumnspec (
                    VAR acv        : tak_all_command_glob;
                    table_required : boolean;
                    VAR put_node   : tsp00_Int2;
                    VAR last_node  : tsp00_Int2);
 
        PROCEDURE
              a02_ls_acolumnspec_list (
                    VAR acv        : tak_all_command_glob;
                    table_required : boolean;
                    VAR put_node   : tsp00_Int2;
                    VAR last_node  : tsp00_Int2);
 
        PROCEDURE
              a02_put_identifier (
                    VAR acv       : tak_all_command_glob;
                    VAR put_node  : tsp00_Int2;
                    VAR last_node : tsp00_Int2);
 
        PROCEDURE
              a02_aparameter_name (VAR acv : tak_all_command_glob;
                    VAR put_node      : tsp00_Int2;
                    VAR last_node     : tsp00_Int2);
 
      ------------------------------ 
 
        FROM
              AK_syntax_values_tools : VAK03;
 
        PROCEDURE
              a03_aunsigned_integer (
                    VAR acv       : tak_all_command_glob;
                    VAR put_node  : tsp00_Int2;
                    VAR last_node : tsp00_Int2);
 
        PROCEDURE
              a03_avalue_spec (VAR acv : tak_all_command_glob;
                    null_allowed    : boolean;
                    stamp_allowed   : boolean;
                    default_allowed : boolean;
                    sysdba_allowed  : boolean;
                    VAR put_node    : tsp00_Int2;
                    VAR last_node   : tsp00_Int2);
 
      ------------------------------ 
 
        FROM
              Hint_Handling : VAK80;
 
        PROCEDURE
              a80_ahint_statement (
                    VAR acv : tak_all_command_glob;
                    subproc : tsp00_Int2;
                    putnode : tsp00_Int2);
 
      ------------------------------ 
 
        FROM
              AK_universal_semantic_tools : VAK06;
 
        PROCEDURE
              a06init_curr_retpart (VAR acv : tak_all_command_glob);
 
        PROCEDURE
              a06finish_curr_retpart (
                    VAR acv   : tak_all_command_glob;
                    part_kind : tsp1_part_kind;
                    arg_count : tsp00_Int2);
 
        PROCEDURE
              a06retpart_move (
                    VAR acv     : tak_all_command_glob;
                    moveobj_ptr : tsp00_MoveObjPtr;
                    move_len    : tsp00_Int4);
 
      ------------------------------ 
 
        FROM
              AK_error_handling : VAK07;
 
        PROCEDURE
              a07_hex_uni_error (
                    VAR acv     : tak_all_command_glob;
                    uni_err     : tsp8_uni_error;
                    err_code    : tsp00_Int4;
                    to_unicode  : boolean;
                    bytestr     : tsp00_MoveObjPtr;
                    len         : tsp00_Int4 );
 
        PROCEDURE
              a07_error (
                    VAR acv   : tak_all_command_glob;
                    errorcode : tgg00_BasisError;
                    VAR nod1  : tsp00_Int2;
                    VAR nod2  : tsp00_Int2);
 
        PROCEDURE
              a07_b_put_error (
                    VAR acv  : tak_all_command_glob;
                    b_err    : tgg00_BasisError;
                    err_code : tsp00_Int4);
 
        PROCEDURE
              a07_kw_put_error (
                    VAR acv  : tak_all_command_glob;
                    b_err    : tgg00_BasisError;
                    err_code : tsp00_Int4;
                    kw       : integer);
 
      ------------------------------ 
 
        FROM
              Systeminfo_cache : VAK10;
 
        PROCEDURE
              a10_nil_get_sysinfo (
                    VAR acv      : tak_all_command_glob;
                    VAR syskey   : tgg00_SysInfoKey;
                    dstate       : tak_directory_state;
                    syslen       : tsp00_Int4;
                    VAR syspoint : tak_sysbufferaddress;
                    VAR b_err    : tgg00_BasisError);
 
      ------------------------------ 
 
        FROM
              AK_Domain : VAK12;
 
        FUNCTION
              a12dbfunc_exist (VAR acv : tak_all_command_glob;
                    VAR owner       : tsp00_KnlIdentifier;
                    VAR dbfunc_name : tsp00_KnlIdentifier;
                    dstate          : tak_directory_state;
                    VAR method_buf  : tak_sysbufferaddress) : boolean;
 
      ------------------------------ 
 
        FROM
              DBProc_DDL_Syntax : VAK201;
 
        PROCEDURE
              a201call_proc (VAR acv : tak_all_command_glob;
                    expected_odbc_terminator : tak_odbc_partype;
                    resultNameNode           : integer;
                    VAR put_node             : tsp00_Int2);
 
      ------------------------------ 
 
        FROM
              AK_show_syntax : VAK41;
 
        PROCEDURE
              a41show_result_name (
                    VAR acv      : tak_all_command_glob;
                    VAR put_node : tsp00_Int2);
 
      ------------------------------ 
 
        FROM
              DML_Parts : VAK55;
 
        PROCEDURE
              a55_aselectinto_key_spec_list (
                    VAR acv       : tak_all_command_glob;
                    VAR put_node  : tsp00_Int2;
                    VAR last_node : tsp00_Int2);
 
      ------------------------------ 
 
        FROM
              Where_Part : VAK63;
 
        PROCEDURE
              a63_avalue_expression (
                    VAR acv       : tak_all_command_glob;
                    VAR put_node  : tsp00_Int2;
                    VAR last_node : tsp00_Int2);
 
        PROCEDURE
              a63_asearch_condition (
                    VAR acv       : tak_all_command_glob;
                    VAR put_node  : tsp00_Int2;
                    VAR last_node : tsp00_Int2);
 
      ------------------------------ 
 
        FROM
              Deal-With-User-Commands : VAK92;
 
        PROCEDURE
              a92find_return_part (
                    VAR acv      : tak_all_command_glob;
                    part_kind    : tsp1_part_kind;
                    VAR part_ptr : tsp1_part_ptr);
 
      ------------------------------ 
 
        FROM
              Configuration_Parameter : VGG01;
 
        VAR
              g01glob           : tgg00_KernelGlobals;
              g01unicode        : boolean;
 
        FUNCTION
              g01userstackoverflow : boolean;
 
      ------------------------------ 
 
        FROM
              Check-Date-Time : VGG03;
 
        VAR
              g03dictionary : tsp6_dictionaries;
 
        PROCEDURE
              g03dchange_format_date (
                    VAR sdata : tsp00_MoveObj;
                    VAR ddata : tsp00_MoveObj;
                    spos      : tsp00_Int4;
                    dpos      : tsp00_Int4;
                    format    : tgg00_DateTimeFormat;
                    VAR e     : tgg00_BasisError);
 
        PROCEDURE
              g03tchange_format_time (
                    VAR sdate : tsp00_MoveObj;
                    VAR ddate : tsp00_MoveObj;
                    spos      : tsp00_Int4;
                    dpos      : tsp00_Int4;
                    format    : tgg00_DateTimeFormat;
                    VAR e     : tgg00_BasisError);
 
        PROCEDURE
              g03tschange_format_timestamp (
                    VAR sdate : tsp00_MoveObj;
                    VAR ddate : tsp00_MoveObj;
                    spos      : tsp00_Int4;
                    dpos      : tsp00_Int4;
                    format    : tgg00_DateTimeFormat;
                    language  : tsp00_C3;
                    VAR e     : tgg00_BasisError);
 
        FUNCTION
              g03date_error_to_b_err (date_e : tsp6_date_error)
                    : tgg00_BasisError;
 
      ------------------------------ 
 
        FROM
              Kernel_move_and_fill : VGG101;
 
        PROCEDURE
              SAPDB_PascalMove  (
                    mod_id         : tsp00_C6;
                    mod_intern_num : tsp00_Int4;
                    size1          : tsp00_Int4;
                    size2          : tsp00_Int4;
                    val1           : tsp00_MoveObjPtr;
                    p1             : tsp00_Int4;
                    val2           : tsp00_MoveObjPtr;
                    p2             : tsp00_Int4;
                    cnt            : tsp00_Int4;
                    VAR e          : tgg00_BasisError);
 
        PROCEDURE
              SAPDB_PascalFill  (
                    mod_id         : tsp00_C6;
                    mod_intern_num : tsp00_Int4;
                    size           : tsp00_Int4;
                    m              : tsp00_MoveObjPtr;
                    pos            : tsp00_Int4;
                    len            : tsp00_Int4;
                    fillchar       : char;
                    VAR e          : tgg00_BasisError);
 
        PROCEDURE
              SAPDB_PascalUnicodeFill  (
                    mod_id         : tsp00_C6;
                    mod_intern_num : tsp00_Int4;
                    size           : tsp00_Int4;
                    m              : tsp00_MoveObjPtr;
                    pos            : tsp00_Int4;
                    len            : tsp00_Int4;
                    filluchar      : tsp00_C2;
                    VAR e          : tgg00_BasisError);
 
        PROCEDURE
              SAPDB_PascalOverlappingMove (
                    mod_id      : tsp00_C6;
                    mod_num     : tsp00_Int4;
                    source_upb  : tsp00_Int4;
                    dest_upb    : tsp00_Int4;
                    source      : tsp00_MoveObjPtr;
                    src_pos     : tsp00_Int4;
                    destin      : tsp00_MoveObjPtr;
                    dest_pos    : tsp00_Int4;
                    length      : tsp00_Int4;
                    VAR e       : tgg00_BasisError);
 
      ------------------------------ 
 
        FROM
              RTE-Extension-30 : VSP30;
 
        FUNCTION
              s30lnr_defbyte (
                    str       : tsp00_MoveObjPtr;
                    defbyte   : char;
                    start_pos : tsp00_Int4;
                    length    : tsp00_Int4) : tsp00_Int4;
 
        PROCEDURE
              s30cmp (
                    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
              PUT-Conversions : VSP41;
 
        PROCEDURE
              s41p4int (
                    VAR buf : tsp00_ResNum;
                    pos     : tsp00_Int4;
                    source  : tsp00_Int4;
                    VAR res : tsp00_NumError);
 
      ------------------------------ 
 
        FROM
              Number-Arithmetic : VSP51;
 
        PROCEDURE
              s51div (
                    VAR left       : tsp00_MoveObj;
                    lpos           : tsp00_Int4;
                    llen           : integer;
                    VAR right      : tsp00_MoveObj;
                    rpos           : tsp00_Int4;
                    rlen           : integer;
                    VAR result     : tsp00_MoveObj;
                    respos         : tsp00_Int4;
                    reslen         : integer;
                    resfrac        : integer;
                    VAR resbytelen : integer;
                    VAR ret        : tsp00_NumError);
 
      ------------------------------ 
 
        FROM
              date_time_formatting : VSP78;
 
        PROCEDURE
              s78d2c_to_char (
                    VAR dictionary : tsp6_dictionary;
                    ts_addr      : tsp00_MoveObjPtr;
                    format_addr  : tsp00_MoveObjPtr;
                    format_len   : integer;
                    dest_size    : integer;
                    dest_addr    : tsp00_MoveObjPtr;
                    VAR dest_pos : integer;
                    dest_len     : integer;
                    VAR e        : tsp6_date_error);
 
      ------------------------------ 
 
        FROM
              RTE-Extension-80 : VSP80;
 
        PROCEDURE
              s80uni_trans
                    (src_ptr        : tsp00_MoveObjPtr;
                    src_len         : tsp00_Int4;
                    src_codeset     : tsp00_Int2;
                    dest_ptr        : tsp00_MoveObjPtr;
                    VAR dest_len    : tsp00_Int4;
                    dest_codeset    : tsp00_Int2;
                    trans_options   : tsp8_uni_opt_set;
                    VAR rc          : tsp8_uni_error;
                    VAR err_char_no : tsp00_Int4);
&       IFDEF TRACE
 
      ------------------------------ 
 
        FROM
              Test_Procedures : VTA01;
 
        PROCEDURE
              t01bool (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    curr_bool: boolean);
 
        PROCEDURE
              t01moveobj (
                    debug       : tgg00_Debug;
                    VAR moveobj : tsp00_MoveObj;
                    startpos    : tsp00_Int4;
                    endpos      : tsp00_Int4);
 
        PROCEDURE
              t01buf (
                    level : tgg00_Debug;
                    VAR b : tak_colnamesbuf;
                    start : integer;
                    stop  : integer);
 
        PROCEDURE
              t01name (
                    level : tgg00_Debug;
                    nam : tsp00_Name);
 
        PROCEDURE
              t01int4 (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    int      : tsp00_Int4);
 
        PROCEDURE
              t01aptree (
                    layer         : tgg00_Debug;
                    VAR a_ap_tree : tak_ap_max_tree;
                    node_cnt      : integer;
                    hint_node     : tsp00_Int2);
&       ENDIF
 
.CM *-END-* use -----------------------------------------
.sp;.cp 3
Synonym :
 
        PROCEDURE
              s41p4int;
 
              tsp00_MoveObj tsp00_ResNum
 
        PROCEDURE
              t01buf;
 
              tsp00_Buf tak_colnamesbuf
 
        PROCEDURE
              t01aptree;
 
              tsp00_MoveObj tak_ap_max_tree
 
.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
A60_ASELECT_STATEMENT
.sp
Only the first node is created that designates a set select. Then
ASEL_EXPLAIN is called.
.sp 2
A60_AEXPLAIN_STATEMENT
.sp
The command EXPLAIN is not possible when parsing and exection are
separate.  However, it must be possible to parse an EXPLAIN (internally)
if a complicated view was found for this command and this view must first
be built beforehand.  Within the kernel, parsing and execution are
carried out separately.
.br
The specified result-set name, in parentheses when appropriate, is
syntactically analyzed via A41SHOW_RESULT_NAME.
.br
Then a normal set select must be initiated so that analysis takes
place via ASEL_EXPLAIN.
.sp 2
ASEL_EXPLAIN
.sp
This procedure is called both by A60_ASELECT_STATEMENT and
A60_AEXPLAIN_STATEMENT if a set select is to be analyzed syntactically.
.br
A query is issued as to whether DISTINCT was specified or ALL (the
default; no node is created for it).  If DISTINCT was specified, a
'FOR UPDATE' entry is invalid (may_for_update = false). Since the record
in the primary file that formed the record contained in the result
and can therefore be modified
would depend on the kernel, this combination is not allowed.
.br
An examination is performed to find out if a result-set name has been
specified.  Since the syntax '<result-table name> ( ...' resembles that
of various functions ( 'SUBSTR ( ...' ), the following identifier
(if it is not in double quotation signs, which is not valid for
functions) must be examined to determine whether it is the same as
a function name.  If it is not but a key word (as result-set name) is
specified, this is an error.
.br
For this syntax analysis, the entry indicating the point up to which
the command has already been read (scv) is stored in scvh so that
reading can continue from this identifier after the result-set name
has been decided upon (the reading of the open parenthesis that
was too early for the further processing is forgotten). In scv there
exists an entry sc_pack, which tells wheather a quote in a string is
to be deleted or not (e.g. 'Hello''World' will become the string Hello'World).
While looking forward, we must set this entry to false, since otherwise
there is no correct backtrack.
.br
Allow_functions is set to tf_unknown in order to show that
SET functions (SUM, MIN, etc ] are allowed for the subsequent
analysis (select list).
.br
Rowno_allowed indicates that the ROWNO can be specified;
rowno_found indicates whether it has already been specified.
.br
If a result-set name is specified (res), it is read with
A02_ARESULTTABLENAME.  The select list is processed with AK60SELECT_LIST
and then the closing parenthesis is expected.  The other parts of the
set select (FROM, WHERE, GROUP BY, UNION, etc ] are analyzed by
ASELECT_EXPRESSION.
.br
If no result-set name was specified, the select list is read and then
checked to determine whether INTO was specified, i.e. a single-record
select must be carried out.
.br
If INTO was specified, the rest of the command (no GROUP BY, no HAVING,
no ORDER BY, no FOR UPDATE, no FOR REUSE allowed) is analyzed in
ASELECT_SINGLE_SPEC.  In the rest of the command, no set functions
must occur (allow_functions = tf_no_func).
.br
If no INTO was specified, the rest of the command parts are analyzed
with ASELECT_EXPRESSION.  A01_IS_END_SYMBOL is used to check whether
there have been excess entries.
.sp 2
A60_ADECLARE
.sp
If, from programs, first a DECLARE CURSOR is performed and then an OPEN,
this has as a result in the kernel that, at the time of the program
OPEN, the kernel receives the DECLARE COMMAND.  This command is slightly
different syntactically from a normal SELECT; however, it must be
processed in exactly the same way, i.e. it leads to the same node in
the syntax tree.
.br
It is different from ASEL_EXPLAIN in that a result-set name must be
specified (the cursor) and no INTO must be used.
.sp 2
ASELECT_SINGLE_SPEC
.sp
This procedure is called when the select list has been processed and an
INTO has been found.
.br
The parameter list is read (A02_L_APARMETER_LIST) and the
tables contained
in the from part are entered in the node tree via
ATABLE_SPEC_LIST.  The search condition, if present, is processed
via A63_ASEARCH_CONDITION (rowno_allowed = false, allow_functions
= tf_no_func).
.br
Special_expr specifies whether an expression is contained in the command
that makes it complicated (e.g. arithmetic over two tables).  The
command must then, in addition to the join, be divided into several
KB requests.  This is indicated in the node of the search condition by
s_sum.
.br
AK60AWAIT_OPTION is used to check whether the user wishes, for this
SELECT, to override the lock mode selected at the time of the CONNECT with
WITH LOCK ..
.sp 2
ASELECT_EXPRESSION
.sp
ATABLE_EXPRESSION is used to analyze the part of the set select that
includes the from part, the search condition, GROUP BY and HAVING.
These parts can also occur several times within UNION.
.br
The parts ORDER BY, FOR UPDATE, the LOCK option and the FOR REUSE, which
are subsequently analyzed, are allowed only once for each set select
(at the very end).
.br
For the ORDER-BY analysis, ASORT_SPEC (see that section) is called once
for each sorting field specified; for the LOCK option (as in
ASELECT_SINGLE_SPEC) the procedure AWAIT_OPTION is called.
.br
At the very end, another check is run to determine whether the command
contains excess entries (A01_IS_END_SYMBOL).
.sp 2
A60_AQUERY_SPEC
.sp
This procedure is called for the syntax analysis of CREATE VIEW,
INSERT..SELECT, for subqueries (and, later, for UNIONS, etc ].
.br
A complete subselect is analyzed from the key word SELECT to HAVING.
Unlike ASEL_EXPLAIN, no result-set name must be specified (within
a subquery, an INSERT..SELECT or in the second SELECT of a UNION).
.br
.br
As in ASELECT_EXPRESSION, the rest of the SELECT is processed via
ATABLE_EXPRESSION.
.sp 2
AK60SELECT_LIST
.sp
In this procedure, the entire select list is processed in such a way
that SELECT_COLUMN is called for each select column.
.br
At the end, rowno_found is to specify whether ROWNO was specified in
any of the output columns.  However, ROWNO must not be used twice
in one expression (if rowno_found, ROWNO is no longer allowed).
For this reason, a local variable must be used (s_rowno_found)
that records in the meantime whether a ROWNO has already occurred
somewhere.
.br
Allow_functions should specify at the end whether a SET function or
even a SET function with arithmetic has been found.  The procedure is
similar to that with the ROWNO in that allow_functions is
reinitialized for each loop run (with tf_unknown or tf_no_func) and
the most complicated case (with arithmetic as most complicated,
then simple SET function, then normal select column) is stored.
In the case of SET functions, this leads to the entry of s_count in the
select-list
node; in the case of SET functions with arithmetic, this leads to s_sum.
For processing, this makes it possible to immediately recognize
complicated SELECTs that have to be divided among several KB calls
in the select-list node before the list has been processed.
.sp 2
SELECT_COLUMN
.sp
This procedure, which is called by AK60SELECT_LIST, analyzes one select
column.
.br
This procedure is explained in the Structure section.
.br
What is special about the processing is that each select column (except
'*' and STAMP) processing
is placed in A63_AVALUE_EXPRESSION, including the simple
entries of a table column.
.br
Attention must also be given to the buffering in scvh and scvh1 where
information is stored concerning the point up to which the command
has already been read.  Processing can then be continued with scv.
If a decision must be made whether to call A63_AVALUE_EXPRESSION or
A02_ATABLENAME, scvh or scvh1 are jumped back to, since these procedures
assume that they must also read the part that they are to analyze.
For this reason, before the procedures are called, the position is changed
to the beginning of the select column or after the '=' that is after a
reference name.
.sp 2
A60_ASUB_QUERY
.sp
This procedure is called in VAK63 in the search condition if the key word
SELECT has been found.
.br
A60_AQUERY_SPEC is used to syntactically analyze the SELECT subcommand.
An ORDER-BY clause is appended to this command (in a subquery ORDER
BY is not allowed
syntactically and, for this reason, certainly not already present) which
causes sorting to be performed after the first output column (generally,
only one output column is allowed).  This is expedient for the execution
of the above-lying SELECT since '=' or '<' is then easy to query without
having to go through the entire subquery result.
.br
In addition, a subtree is generated in the parse tree that concatenates
the SELECTs.  This subtree begins at the node of the first SELECT in
the command and there at n_sa_level (the actual select is attached
at n_lo_level).
.br
There is one node per subquery, each with the entry a63, x_subquery.
N_sa_level points to subqueries that are attached on the same level
(start from the same search condition); n_lo_level points to subqueries
that start from the search condition of the current SELECT.
.br
The value -1 in n_lo_level or n_sa_level indicates that no further node
is attached there but that this is where the next node would have
been attached.
.br
A new node (new_node) is generated for which n_lo_level is set to -1.
This node is inserted in the subtree at the suitable serverdb
(for -1).  The subquery is analyzed syntactically.  A60_ASUB_QUERY
can again be called recursively, which then appends n_lo_level to the
node that has just been installed, etc.
.br
If the subquery has been analyzed, the node number of the node that
contains the select entry of the subquery is entered in n_pos,
n_lo_level is set to 0 if further nodes are not already attached
there and n_sa_level is set to -1 so that additional subqueries of
the same search condition can be attached there.
.br
The result can then have the following layout:
.nf;.sp 2
----------   -------------
| SELECT |---|select_list|
----------   -------------
    |              |
    |        -------------
    |        | FROM-part |
    |        -------------
    |              |
    |        -------------   -----   -----------
    |        |search-cond|---|AND|---|predicate|
    |        -------------   -----   -----------
    |                          |          |
    |                          |          |
    |                          |      --------
    |  -----------------------------> |SELECT|---...
    |  |                       |      --------
    |  |                       |
    |  |                  -----------
    |  |                  |predicate|
    |  |                  -----------
    |  |                       |
    |  |                    --------
    |  |            ------> |SELECT|---...
    |  |            |       --------   ...
    |  |            |                  ...
 ------|---   ------|---              -----------
 |subquery|---|subquery|              |predicate|
 ----------   ----------              -----------
                  |                        |
                  |                    --------
                  |   ---------------> |SELECT|---...
                  |   |                --------
              --------|-
              |subquery|
              ----------
.sp;.fo
Descending lines stand for n_sa_level, lines pointing to the right stand
for n_lo_level, and ascending lines stand for n_pos.  This presentation
corresponds to the trace output in VAK99 (see that section).
.sp
Via this second subtree (pointers to SELECTs), it is relatively easy
to find the lowest SELECT which, in the case of simple subqueries,
must be processed first and, in the case of correlated subqueries, to
find the associated SELECTs together on one level.
.sp 2
ATABLE_EXPRESSION
.sp
This procedure is called by ASELECT_EXPRESSION and A60_AQUERY_SPEC.
It analyzes the parts of a SELECT from the FROM part to HAVING.
.br
The old value of allow_functions is stored so that is can be reused
for HAVING.  The value itself is set to tf_no_func in order to indicate
that no SET functions are allowed in the search condition.
Group_n <> 0 is used to indicate the presence of GROUP BY.
.br
If the table names in the from part are enclosed in angle brackets, this
means that the user has preset the processing sequence of the tables
for a join.  These brackets are
an undocumented test feature.  In this case,
a special, supplementary node is incorporated.
.br
After the from part has been processed, a check is run to determine the
number of tables that were specified there.  If there is more than one,
FOR UPDATE must no longer be specified (may_for_update := false).
.br
The search condition is analyzed and, if it contained a complicated
expression, s_sum is entered in the search-condition node in order to
be able to recognize this complicated case as quickly as possible when
processing.
.br
If GROUP BY is specified, no further FOR UPDATE must be performed.  Each
grouping column is analyzed via a call by AGROUP_SPEC.
.br
Before the HAVING, the old allow_functions value that was stored is
reentered in order to avoid falsification for the outside.
.br
HAVING must be specified only if GROUP BY (group_n = 0 ) was specified
or if a SET function (with or without arithmetic) is located in the
select list or in very stupid SAGSIS-cases.
.sp 2
ASORT_SPEC
.sp
This procedure is called once for each entry in the ORDER-BY part
(ASELECT_EXPRESSION).
.br
It is determined whether an integer (specifies the number of the output
column according to which sorting is to be performed.  This is necessary
if the output contains expressions according to which sorting is to
be performed ] or a column name has been specified.  The key words
ASC and DESC are also processed here and each results in an extra node.
.sp 2
AGROUP_SPEC
.sp
This procedure is called by ATABLE_EXPRESSION after GROUP BY, once for
each entry.
.br
No expressions are valid for grouping entries; only column names are
allowed.
.sp 2
AK60AWAIT_OPTION
.sp
For all SELECTs (including SELECT DIRECT and ordered select), it is
possible to override the lock mode activated at the time of the CONNECT
by specifying WITH LOCK ... .  It is possible to specify
(WAIT) or (NOWAIT) and SHARE or EXCLUSIVE; (WAIT) SHARE corresponds
to the default value.
.br
This option is useful when, despite a LOCK EXPLICIT, a record that has
been found is to be locked immediately. In some cases this locking
cannot wait until the next
LOCK command since, in the meantime, another user could have changed
the (unlocked) record.  In addition, one less command is needed
and the associated communication overhead is avoided.
.sp 2
A60_GET_LONGINFOBUFFER
.sp
This procedure is called by VAK62 (SELECT DIRECT, ordered select), VAK66
(set select) and VAK73 (FETCH, DESCRIBE).  It is used if the user has
requested an exact information record for the output columns
(name, data type and length, position in the output buffer).
.br
Space in the cache is requested for a buffer that can receive these
long infos; its address is stored in sparr.pinfop and the buffer is
initialized.  The second pointer that can take on an address of a
long-info buffer (pparsp) is assigned NIL so that it is clear that it is
not yet in use.  It does not have to be used until more that 166 long infos
must be built (compare VAK61).
.sp 2
A60_P_INFO_OUTPUT
.sp
This procedure is called by VAK62, VAK67, and VAK73 if the long infos
stored in the long-info buffer(s) (pparsp and pinfop) are to be
transferred to the corresponding part
of the SQL_PACKET at the end of a command.
.br
If pparsp <> NIL, i.e. there are more than 166 long infos, first this buffer
must be copied and then pinfop.  The number of long infos is
given as argument_count of the part.
The entire part is converted in A04_INFO_BYTESWAP
(names of the output columns) and byte-swapped (the long info contains
int2) if necessary.
.sp 2
A60_CHANGE_RESULTS
.sp
This procedure is called by VAK50, VAK62, and VAK74, among others, if a
result record must still be converted.  Atch, a record
containing the (fixed) position beginning at which a field must be
converted and the length of this field,
is used.  Atcolcount designates the number of fields to be changed; not
every output field is contained in atch.
.sp 2
A60_PUT_RESULT
.sp
This procedure is called by VAK50, VAK62 and VAK73, among others, if the
mess_block contains a result record that is to be transferred
to the SQL_PACKET.
.br
For old programs the following is true:
Since, under certain circumstances, long
infos are located in the SQL_PACKET and they and the result
record could not fit in the result segment together, a check is run.
If necessary, the result record is buffered in the mess buffer
beginning at position 1, to be given to the user via a subsequent
FETCH REST.  If the very next command is not the FETCH REST, the result
record is lost.  However, this concerns only the dialog components and
not the applications programmers.
.sp 2
A60_RESTABLE_GET
.sp
This procedure is called by VAK73 (FETCH, DESCRIBE), among others, if
the system information records (column descriptions) of a result
set are needed.  They are of a different type from the descriptions
of permanent tables (eresult instead of etable) and are always found
locally only.
.br
If all system-information records are desired (get_all) and not just the
existence of the result set is to be checked, the maximum of 4
system-information records are fetched in a loop and their pointers are
entered in sparr.
.sp 2
.CM *-END-* description ---------------------------------
.sp 2
***********************************************************
.sp
.cp 10
.nf
.oc _/1
Structure:
 
 
(*------------------------------*) 
 
PROCEDURE
      select_column;
 
BEGIN
IF  the_symbol_is_an_'*'
THEN
    insertion_of_a_corresponding_node
ELSE
    BEGIN
    read_2nd_symbol;
    IF  2nd_symbol_is_a_'.'
    THEN
        BEGIN
        read_3rd_symbol;
        IF  3rd_symbol_is_an_'*'
        THEN
            tablename.*_was_found
        ELSE
            BEGIN
            read_4th_symbol;
            IF  4th_symbol_is_a_'.'
            THEN
                BEGIN
                read_5th_symbol;
                IF  5th_symbol_is_an_'*'
                THEN
                    userid.tablename.*_was_found
                ELSE
                    userid.tablename.columnname_was_found
                (*ENDIF*) 
                END
            ELSE
                tablename.columnname_was_found
            (*ENDIF*) 
            END
        (*ENDIF*) 
        END
    ELSE (* no 1st dot found *)
        IF  2nd_symbol_is_an_'='
        THEN (* specify reference name *)
            BEGIN
            read_3rd_symbol;
            IF  3rd_symbol_=_'STAMP'
            THEN
                node_entry
            ELSE
                reference_name_=_<column_spec>_was_found
            (*ENDIF*) 
            END
        ELSE
            IF  2nd_symbol_is_neither_'.'_nor_'='
            THEN
                IF  1st_symbol_=_'STAMP'
                THEN
                    node_entry
                ELSE
                    any_other_expression_was_found
                (*ENDIF*) 
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    END
(*ENDIF*) 
END;
 
.CM *-END-* structure -----------------------------------
.sp 2
**********************************************************
.sp
.cp 10
.nf
.oc _/1
.CM -lll-
Code    :
 
 
CONST
      c_table_required      = true (* a02_acolumnspec  *);
      (*                              a02_ls_acolumnspec_list *)
      c_is_single_select    = true (* ak60atab_expr    *);
      c_stamp_allowed       = true (* a60_aquery_spec  *);
      (*                              ak60select_list  *)
      c_null_allowed        = true (* a03_avalue_spec *);
      c_default_allowed     = true (* a03_avalue_spec *);
      c_sysuser_allowed     = true (* a03_avalue_spec *);
      c_may_for_update      = true (* ak60aupdate_of   *);
      c_outer_level         = true (* ak60union_select *);
      c_trans_to_uni        = true (* a07_hex_uni_err  *);
      c_for_union           = true;
      c_unicode_wid         = 2    (* a07_hex_uni_err  *);
 
TYPE
      ak60parts_allowed = (
            ak60is_not_allowed,
            ak60is_allowed,
            ak60is_needed,
            ak60was_found);
 
      ak60syntax_helptype = PACKED RECORD
            sh_subcount           : tsp00_Int2;
            sh_into_allowed       : ak60parts_allowed;
            sh_for_update_allowed : boolean;
            sh_stamp_allowed      : boolean;
            sh_is_query_spec      : boolean;
            sh_is_fromsel         : boolean; (* PTS 1138343 D.T. *)
      END;
 
 
TYPE
      ak60all_or_not = (is_unknown, is_all, is_distinct, is_mixture);
 
 
(*------------------------------*) 
 
PROCEDURE
      ak60agroup_by (
            VAR acv            : tak_all_command_glob;
            VAR curr_n         : tsp00_Int2;
            VAR may_for_update : boolean);
 
VAR
      last_n         : tsp00_Int2;
 
BEGIN
WITH acv, a_scv DO
    BEGIN
    IF  a_precomp_info_byte = csp1_p_mselect_found
    THEN
        a_precomp_info_byte := csp1_p_mass_select_found;
    (*ENDIF*) 
    a01_call_put (acv, a63, cak_x_group_by,
          a_ap_tree^[ curr_n ].n_sa_level);
    curr_n := a_ap_tree^[ curr_n ].n_sa_level;
    a01_next_symbol (acv);
    IF  a01mandatory_keyword (acv, cak_i_by)
    THEN
        BEGIN
        may_for_update := false;
        ak60agroup_spec (acv, a_ap_tree^[ curr_n ].n_lo_level, last_n);
        WHILE ((sc_symb = s_comma) AND (a_returncode = 0)) DO
            BEGIN
            a01_next_symbol (acv);
            ak60agroup_spec (acv,
                  a_ap_tree^[ last_n ].n_sa_level, last_n)
            END
        (*ENDWHILE*) 
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60agroup_spec (
            VAR acv       : tak_all_command_glob;
            VAR put_node  : tsp00_Int2;
            VAR last_node : tsp00_Int2);
 
VAR
      curr_n              : tsp00_Int2;
      oneval_subq_allowed : boolean;
 
BEGIN
WITH acv, a_scv DO
    IF  a_returncode = 0
    THEN
        BEGIN
        a01_call_put (acv, a63, cak_x_sort_spec, put_node);
        curr_n := put_node;
        last_node := put_node;
        (* PTS 1116169 E.Z. *)
        oneval_subq_allowed := a_oneval_subq_allowed;
        a_oneval_subq_allowed := false;
        IF  (a_sqlmode = sqlm_internal) OR (a_sqlmode = sqlm_oracle)
        THEN
            a63_avalue_expression (acv,
                  a_ap_tree^[ curr_n ].n_lo_level, curr_n)
        ELSE
            a02_acolumnspec (acv, NOT c_table_required,
                  a_ap_tree^[ curr_n ].n_lo_level, curr_n);
        (*ENDIF*) 
        a_oneval_subq_allowed := oneval_subq_allowed;
        END
    (*ENDIF*) 
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60arest_select_expression (
            VAR acv            : tak_all_command_glob;
            VAR put_node       : tsp00_Int2;
            VAR may_for_update : boolean);
 
VAR
      curr_n              : tsp00_Int2;
      temp_n              : tsp00_Int2;
      last_n              : tsp00_Int2;
      order_by_allowed    : boolean;
      fetch_only_allowed  : boolean;
      limit_allowed       : boolean;
      optimize_allowed    : boolean;
      update_allowed      : boolean;
      reuse_allowed       : boolean;
      with_allowed        : boolean;
      order_by_count      : integer;
      fetch_only_count    : integer;
      optimize_count      : integer;
      update_count        : integer;
      reuse_count         : integer;
      with_count          : integer;
      key_index           : integer;
      subkey_index        : integer;
      key_reserved        : boolean;
      continue_parse      : boolean;
      bool_temp           : boolean;
      scvh                : tak_scanner_glob;
 
BEGIN
curr_n := 0;
WITH acv, a_scv DO
    IF  a_returncode = 0
    THEN
        BEGIN
        order_by_allowed    := true; (* works with all modes *)
        fetch_only_allowed  := (a_sqlmode = sqlm_db2);
        limit_allowed       := (a_sqlmode in [ sqlm_internal, sqlm_oracle]) AND
              a_limit_allowed AND NOT a_limit_found;
        optimize_allowed    := (a_sqlmode = sqlm_db2);
        update_allowed      := (a_sqlmode <> sqlm_ansi);
        reuse_allowed       := (a_sqlmode in [ sqlm_internal, sqlm_oracle]);
        with_allowed        := ((a_sqlmode = sqlm_internal) OR
              g01glob.db_is_for_sapr3);
        order_by_count      := 0;
        fetch_only_count    := 0;
        optimize_count      := 0;
        update_count        := 0;
        reuse_count         := 0;
        with_count          := 0;
        curr_n              := put_node;
        continue_parse      := true;
        WHILE ((a_returncode = 0) AND
              (sc_symb <> s_eof) AND
              (continue_parse = true)) DO
            BEGIN
            a01_get_keyword (acv, key_index, key_reserved);
            CASE key_index OF
                cak_i_for: (* FOR ... *)
                    BEGIN
                    scvh := a_scv;
                    a01_next_symbol (acv);
                    a01_get_keyword (acv, subkey_index, key_reserved);
                    CASE subkey_index OF
                        cak_i_fetch: (* FOR FETCH ONLY *)
                            BEGIN
                            IF  (fetch_only_allowed AND
                                (fetch_only_count < 1))
                            THEN
                                BEGIN
                                a01_next_symbol (acv);
                                IF  a01mandatory_keyword (acv, cak_i_only)
                                THEN
                                    BEGIN
                                    fetch_only_count := fetch_only_count + 1;
                                    IF  (a_sqlmode = sqlm_db2)
                                    THEN
                                        update_allowed := false;
                                    (*ENDIF*) 
                                    a01_call_put (acv, a63, cak_x_for_fetch_only, last_n);
                                    a_ap_tree^[ last_n ].n_sa_level := a_ap_tree^[ put_node ].n_sa_level;
                                    a_ap_tree^[ put_node ].n_sa_level := last_n;
                                    curr_n := last_n;
                                    END
                                ELSE
                                    BEGIN
                                    continue_parse := false;
                                    a07_kw_put_error (acv, e_wanted_keyword, a_scv.sc_sypos, cak_i_only);
                                    END;
                                (*ENDIF*) 
                                END
                            ELSE
                                BEGIN
                                continue_parse := false;
                                a07_kw_put_error (acv, e_invalid_keyword, a_scv.sc_sypos, cak_i_fetch);
                                END
                            (*ENDIF*) 
                            END;
                        cak_i_update: (* FOR UPDATE [OF [...]] *)
                            BEGIN
                            IF  (update_allowed AND
                                (update_count < 2))
                            THEN
                                BEGIN
                                update_count := update_count + 1;
                                IF  (a_sqlmode = sqlm_db2)
                                THEN
                                    BEGIN
                                    order_by_allowed := false;
                                    fetch_only_allowed := false;
                                    END;
                                (*ENDIF*) 
                                a_scv := scvh;
                                bool_temp := true;
                                temp_n := curr_n;
                                ak60aupdate_of (acv, temp_n, may_for_update, bool_temp);
                                IF  (update_count > 1)
                                THEN
                                    a_ap_tree^[ curr_n ].n_sa_level := 0
                                ELSE
                                    curr_n := temp_n;
                                (*ENDIF*) 
                                END
                            ELSE
                                BEGIN
                                continue_parse := false;
                                a07_kw_put_error (acv, e_invalid_keyword, a_scv.sc_sypos, cak_i_update);
                                END;
                            (*ENDIF*) 
                            END;
                        cak_i_reuse: (* FOR REUSE *)
                            BEGIN
                            IF  (reuse_allowed AND
                                (reuse_count < 2))
                            THEN
                                BEGIN
                                reuse_count := reuse_count + 1;
                                IF  reuse_count = 1
                                THEN
                                    BEGIN
                                    a01_call_put (acv, a63, cak_x_for_reuse,
                                          a_ap_tree^[ curr_n ].n_sa_level);
                                    curr_n := a_ap_tree^[ curr_n ].n_sa_level;
                                    a01_next_symbol (acv);
                                    CASE a_precomp_info_byte OF
                                        csp1_p_mass_select_found :
                                            a_precomp_info_byte := csp1_p_reuse_mass_select_found;
                                        csp1_p_select_for_update_found :
                                            a_precomp_info_byte := csp1_p_reuse_update_sel_found;
                                        csp1_p_mselect_found :
                                            a_precomp_info_byte := csp1_p_reuse_mselect_found;
                                        csp1_p_for_upd_mselect_found :
                                            a_precomp_info_byte := csp1_p_reuse_upd_mselect_found;
                                        OTHERWISE
                                            BEGIN
                                            END;
                                        END;
                                    (*ENDCASE*) 
                                    END
                                ELSE
                                    a01_next_symbol (acv);
                                (*ENDIF*) 
                                END;
                            (*ENDIF*) 
                            END;
                        OTHERWISE
                            BEGIN
                            continue_parse := false;
                            a07_error (acv, e_missing_keyword, put_node, put_node);
                            END
                        END;
                    (*ENDCASE*) 
                    END;
                cak_i_limit :
                    IF  a_ap_tree^[a_ap_tree^[0].n_lo_level].n_proc = a16
                    THEN
                        a07_error (acv, e_in_view_not_allowed,
                              put_node, put_node)
                    ELSE
                        IF  (a_limit_allowed AND NOT a_rowno_found)
                        THEN
                            BEGIN
                            a01_call_put (acv, a60, cak_x_limit, a_limit_node);
                            a01_next_symbol (acv);
                            a_limit_found := true;
                            IF  sc_symb in [ s_parameter_name, s_unsigned_integer ]
                            THEN
                                BEGIN
                                IF  sc_symb = s_parameter_name
                                THEN
                                    IF  (a_ex_kind <> only_parsing) AND
                                        (* PTS 1111575 E.Z. *)
                                        (a_ex_kind <> only_syntax)  AND
                                        (NOT a_intern_explain)
                                    THEN
                                        a07_error (acv, e_parameter_not_allowed,
                                              put_node, put_node)
                                    ELSE
                                        a02_aparameter_name (acv,
                                              a_ap_tree^[ a_limit_node ].n_lo_level, temp_n)
                                    (*ENDIF*) 
                                ELSE
                                    a03_avalue_spec (acv, NOT c_null_allowed,
                                          NOT c_stamp_allowed, NOT c_default_allowed,
                                          NOT c_sysuser_allowed,
                                          a_ap_tree^[ a_limit_node ].n_lo_level, temp_n);
                                (*ENDIF*) 
                                IF  sc_symb in [ s_parameter_name, s_unsigned_integer ]
                                THEN
                                    a03_avalue_spec (acv, NOT c_null_allowed,
                                          NOT c_stamp_allowed, NOT c_default_allowed,
                                          NOT c_sysuser_allowed,
                                          a_ap_tree^[ temp_n ].n_sa_level, temp_n);
                                (*ENDIF*) 
                                END
                            ELSE
                                a07_error (acv, e_invalid_unsign_integer, put_node, put_node)
                            (*ENDIF*) 
                            END
                        ELSE
                            a07_error (acv, e_invalid_keyword, put_node, put_node);
                        (*ENDIF*) 
                    (*ENDIF*) 
                cak_i_order: (* ORDER BY [..] *)
                    BEGIN
                    IF  (order_by_allowed AND
                        (order_by_count < 1))
                    THEN
                        BEGIN
                        a01_call_put (acv, a63, cak_x_order,
                              a_ap_tree^[ curr_n ].n_sa_level);
                        curr_n := a_ap_tree^[ curr_n ].n_sa_level;
                        a01_next_symbol (acv);
                        IF  a01mandatory_keyword (acv, cak_i_by)
                        THEN
                            BEGIN
                            order_by_count := order_by_count + 1;
                            IF  (a_sqlmode = sqlm_db2)
                            THEN
                                update_allowed := false;
                            (*ENDIF*) 
                            acv.a_allow_functions := tf_unknown;
                            ak60asort_spec (acv, a_ap_tree^[ curr_n ].n_lo_level, last_n);
                            WHILE ((sc_symb = s_comma) AND (a_returncode = 0)) DO
                                BEGIN
                                a01_next_symbol (acv);
                                ak60asort_spec (acv, a_ap_tree^[ last_n ].n_sa_level, last_n);
                                END;
                            (*ENDWHILE*) 
                            IF  a_allow_functions = tf_func
                            THEN
                                a_ap_tree^[ curr_n ].n_symb := s_count
                            ELSE
                                IF  a_allow_functions = tf_func_arith
                                THEN
                                    a_ap_tree^[ curr_n ].n_symb := s_sum;
                                (*ENDIF*) 
                            (*ENDIF*) 
                            END
                        ELSE
                            BEGIN
                            continue_parse := false;
                            a07_kw_put_error (acv, e_wanted_keyword, a_scv.sc_sypos, cak_i_by);
                            END;
                        (*ENDIF*) 
                        END
                    ELSE
                        BEGIN
                        continue_parse := false;
                        a07_kw_put_error (acv, e_invalid_keyword, a_scv.sc_sypos, cak_i_order);
                        END;
                    (*ENDIF*) 
                    END;
                cak_i_optimize: (* OPTIMIZE FOR <n> ROW[S] *)
                    BEGIN
                    IF  (optimize_allowed AND
                        (optimize_count < 1))
                    THEN
                        BEGIN
                        a01_next_symbol (acv);
                        IF  a01mandatory_keyword (acv, cak_i_for)
                        THEN
                            BEGIN
                            IF  sc_symb = s_unsigned_integer
                            THEN
                                BEGIN
                                a01_next_symbol (acv);
                                IF  ((a01_eqkey (a01kw[ cak_i_row], a_sqlmode,
                                    a_cmd_part^.sp1p_buf, a_scv)) OR
                                    (a01_eqkey (a01kw[ cak_i_rows], a_sqlmode,
                                    a_cmd_part^.sp1p_buf, a_scv)))
                                THEN
                                    BEGIN
                                    a01_next_symbol (acv);
                                    optimize_count := optimize_count + 1;
                                    END
                                ELSE
                                    BEGIN
                                    continue_parse := false;
                                    a07_error (acv, e_missing_keyword, put_node, put_node);
                                    END;
                                (*ENDIF*) 
                                END
                            ELSE
                                BEGIN
                                continue_parse := false;
                                a07_error (acv, e_missing_keyword, put_node, put_node);
                                END;
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        END
                    ELSE
                        BEGIN
                        continue_parse := false;
                        a07_kw_put_error (acv, e_invalid_keyword, a_scv.sc_sypos, cak_i_optimize);
                        END;
                    (*ENDIF*) 
                    END;
                cak_i_with: (* WITH [LOCK|ISOLATIONLEVEL] *)
                    BEGIN
                    IF  (with_allowed AND
                        (with_count < 1))
                    THEN
                        BEGIN
                        with_count := with_count + 1;
                        ak60await_option (acv, a_ap_tree^[ curr_n ].n_sa_level);
                        IF  a_ap_tree^[ curr_n ].n_sa_level <> 0
                        THEN
                            curr_n := a_ap_tree^[ curr_n ].n_sa_level;
                        (*ENDIF*) 
                        END
                    ELSE
                        BEGIN
                        continue_parse := false;
                        a07_kw_put_error (acv, e_invalid_keyword, a_scv.sc_sypos, cak_i_with);
                        END;
                    (*ENDIF*) 
                    END;
                OTHERWISE
                    BEGIN
                    continue_parse := false;
                    a07_error (acv, e_invalid_keyword, put_node, put_node);
                    END;
                END;
            (*ENDCASE*) 
            END;
        (*ENDWHILE*) 
        END;
    (*ENDIF*) 
(*ENDWITH*) 
put_node := curr_n;
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60intern_fromsel (VAR acv : tak_all_command_glob;
            VAR curr_n      : tsp00_Int2;
            VAR syntax_help : ak60syntax_helptype;
            for_union       : boolean);
 
VAR
      m_symbol       : tak_sc_symbol;
      fs_curr_n1     : tsp00_Int2;
      fs_curr_n2     : tsp00_Int2;
      info_node      : tsp00_Int2;
      predicate_node : tsp00_Int2;
      m_symb         : tak_sc_symbol;
 
BEGIN
WITH acv, a_scv DO
    BEGIN
    fs_curr_n1 := curr_n;
    WHILE (fs_curr_n1 > 0)
          AND
          ((a_ap_tree^[fs_curr_n1].n_proc <> a63) OR
          ( a_ap_tree^[fs_curr_n1].n_subproc <> cak_x_mass_select)) DO
        fs_curr_n1 := a_ap_tree^[fs_curr_n1].n_lo_level;
    (*ENDWHILE*) 
    IF  fs_curr_n1 > 0
    THEN
        WITH a_ap_tree^[fs_curr_n1] DO
            BEGIN
            n_proc := a63query_spec;
            n_subproc := cak_is_undefined;
            END;
        (*ENDWITH*) 
    (*ENDIF*) 
    IF  syntax_help.sh_is_query_spec
    THEN
        a01info_call_put (acv, a63query_spec, cak_is_undefined, fs_curr_n1, info_node)
    ELSE
        a01_call_put(acv, a63, cak_x_mass_select, fs_curr_n1);
    (*ENDIF*) 
    a01_call_put (acv, a60, cak_x_select_list,
          a_ap_tree^[fs_curr_n1].n_lo_level);
    fs_curr_n2 := a_ap_tree^[fs_curr_n1].n_lo_level;
    a01info_call_put (acv, a60, cak_x_select_column,
          a_ap_tree^[fs_curr_n2].n_lo_level, info_node);
    fs_curr_n2 := a_ap_tree^[fs_curr_n2].n_lo_level;
    m_symbol := sc_symb;
    sc_symb := s_asterisk;
    a01_put_node (acv, a_ap_tree^[ fs_curr_n2 ].n_lo_level);
    sc_symb := m_symbol;
    fs_curr_n2 := a_ap_tree^[fs_curr_n1].n_lo_level;
    a01_call_put (acv, a63, cak_x_from_part, a_ap_tree^[ fs_curr_n2 ].n_sa_level);
    fs_curr_n2 := a_ap_tree^[ fs_curr_n2 ].n_sa_level;
    predicate_node := fs_curr_n2;
    a01_call_put (acv, a66, cak_x_select_in_from_part, a_ap_tree^[ fs_curr_n2 ].n_lo_level);
    fs_curr_n2 := a_ap_tree^[fs_curr_n2].n_lo_level;
    a01_call_put (acv, a92fromsel, fs_curr_n2, info_node);
&   ifdef TRACE
    t01int4 (ak_syn, 'a_select_nod', a_select_node);
    t01int4 (ak_syn, 'fs_curr_n2  ', fs_curr_n2);
    t01int4 (ak_syn, 'fs_curr_n1  ', fs_curr_n1);
    t01int4 (ak_syn, 'n_sa_level  ', a_ap_tree^[fs_curr_n1].n_sa_level);
    t01int4 (ak_syn, 'Klammern    ', a_leftpar_cnt - a_rightpar_cnt);
&   endif
    IF  (a_returncode = 0)
    THEN
        IF  for_union
        THEN
            BEGIN
            a_select_node := fs_curr_n1;
            ak60put_new_sub_select_node (a_ap_tree^, a_select_node, info_node, 1);
            a_ap_tree^[ info_node ].n_pos := fs_curr_n2;
            a01_call_put(acv, a63, cak_x_start_union, a_ap_tree^[fs_curr_n2].n_lo_level);
            a_ap_tree^[a_ap_tree^[fs_curr_n2].n_lo_level].n_lo_level := curr_n;
            curr_n := fs_curr_n1;
            a_select_node := 0;
            END
        ELSE
            BEGIN
            ak60put_new_sub_select_node (a_ap_tree^, a_select_node, info_node,
                  a_leftpar_cnt - a_rightpar_cnt + 1);
            a_ap_tree^[ info_node ].n_pos := fs_curr_n2;
            a_ap_tree^[fs_curr_n2].n_lo_level := curr_n;
            curr_n := fs_curr_n1;
            IF  (a_returncode = 0)
            THEN
                BEGIN
                a01info_call_put (acv, a63, cak_x_search_condition,
                      a_ap_tree^[predicate_node].n_sa_level, info_node);
                predicate_node := a_ap_tree^[ predicate_node ].n_sa_level;
                m_symb := sc_symb;
                a01_call_put(acv, a64, cak_x_predicate, a_ap_tree^[ predicate_node ].n_lo_level );
                predicate_node := a_ap_tree^[ predicate_node ].n_lo_level;
                a_ap_tree^[ predicate_node ].n_symb := s_less_or_eq;
                sc_symb := s_rowno;
                a01_put_node (acv, a_ap_tree^[ predicate_node ].n_lo_level);
                predicate_node := a_ap_tree^[ predicate_node ].n_lo_level;
                a_ap_tree^[ predicate_node ].n_sa_level := a_ap_tree^[a_limit_node].n_lo_level;
                a_limit_node := 0;
                sc_symb := m_symb
                END
            (*ENDIF*) 
            END
        (*ENDIF*) 
    (*ENDIF*) 
    END
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60get_sel_info (VAR acv : tak_all_command_glob;
            put_node       : tsp00_Int2;
            VAR indkey     : integer;
            VAR all_or_not : ak60all_or_not);
 
BEGIN
WITH acv DO
    BEGIN
    indkey := 0;
    all_or_not := is_unknown;
    IF  a_ap_tree^[put_node].n_proc = a63
    THEN
        CASE a_ap_tree^[put_node].n_subproc OF
            cak_x_union, cak_x_union_all :
                indkey := cak_i_union;
            cak_x_except, cak_x_except_all :
                indkey := cak_i_except;
            cak_x_intersect, cak_x_intersect_all :
                indkey := cak_i_intersect;
            OTHERWISE
            END;
        (*ENDCASE*) 
    (*ENDIF*) 
    CASE a_ap_tree^[put_node].n_subproc OF
        cak_x_union, cak_x_except, cak_x_intersect :
            all_or_not := is_distinct;
        cak_x_union_all, cak_x_except_all, cak_x_intersect_all :
            all_or_not := is_all;
        OTHERWISE
        END;
    (*ENDCASE*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60intersect_select (
            VAR acv         : tak_all_command_glob;
            VAR put_node    : tsp00_Int2;
            VAR syntax_help : ak60syntax_helptype;
            last_node       : tsp00_Int2); (* PTS 1138343 D.T. *)
 
VAR
      m_limit_allowed: boolean;
      curr_n         : tsp00_Int2;
      m_leftpar_cnt  : tsp00_Int2;
      m_rightpar_cnt : tsp00_Int2;
      m_select_n     : tsp00_Int2;
      indkey         : integer;
      full_indkey    : integer;
      all_or_not     : ak60all_or_not;
      full_all_or_not: ak60all_or_not;
      intern_fromsel : boolean;
 
BEGIN
WITH acv, a_scv DO
    BEGIN
    m_select_n := a_select_node;
    m_limit_allowed := a_limit_allowed;
&   ifdef trace
    t01int4 (ak_syn, 'intersect st', put_node);
    t01aptree (ak_syn, a_ap_tree^, a_scv_index, a_first_hint_node);
&   endif
    ak60one_select (acv, put_node, syntax_help, last_node);
    a_limit_allowed := false;
    IF  (sc_symb <> s_eof)      AND
        (a_returncode = 0)
    THEN
        BEGIN
        ak60get_sel_info (acv, put_node, full_indkey, full_all_or_not);
        intern_fromsel := false;
        IF  a01_eqkey(a01kw[ cak_i_intersect], a_sqlmode,
            a_cmd_part^.sp1p_buf, a_scv) AND
            ((a_sqlmode = sqlm_internal) OR
            ( a_sqlmode = sqlm_ansi))
        THEN (* *** the priority of intersect is in sql_db higher     *)
            (*     than union or except                          *** *)
            BEGIN
            curr_n := put_node;
            REPEAT
                a01_next_symbol(acv);
                IF  a01_eqkey(a01kw[ cak_i_all], a_sqlmode,
                    a_cmd_part^.sp1p_buf, a_scv)
                THEN
                    BEGIN
                    all_or_not := is_all;
                    IF  (full_indkey = 0)
                    THEN
                        BEGIN
                        full_indkey := cak_i_intersect;
                        full_all_or_not := is_all
                        END
                    ELSE
                        IF  NOT ((full_indkey = cak_i_intersect) OR (full_all_or_not = is_all))
                        THEN
                            BEGIN
                            intern_fromsel := true;
                            IF  full_indkey <> cak_i_intersect
                            THEN
                                full_indkey := cak_i_list;
                            (*ENDIF*) 
                            IF  full_all_or_not <> is_all
                            THEN
                                full_all_or_not := is_mixture;
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                    (*ENDIF*) 
                    a01_next_symbol(acv);
                    a01_call_put(acv, a63, cak_x_intersect_all, put_node);
                    END
                ELSE
                    BEGIN
                    all_or_not := is_distinct;
                    IF  (full_indkey = 0)
                    THEN
                        BEGIN
                        full_indkey := cak_i_intersect;
                        full_all_or_not := is_distinct
                        END
                    ELSE
                        IF  NOT ((full_indkey = cak_i_intersect) OR (full_all_or_not = is_distinct))
                        THEN
                            BEGIN
                            intern_fromsel := true;
                            IF  full_indkey <> cak_i_intersect
                            THEN
                                full_indkey := cak_i_list;
                            (*ENDIF*) 
                            IF  full_all_or_not <> is_distinct
                            THEN
                                full_all_or_not := is_mixture;
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                    (*ENDIF*) 
                    a01_call_put(acv, a63, cak_x_intersect, put_node);
                    END;
                (*ENDIF*) 
                IF  intern_fromsel
                THEN
                    BEGIN
                    ak60intern_fromsel (acv, curr_n, syntax_help, c_for_union);
                    full_indkey := cak_i_intersect;
                    full_all_or_not := all_or_not;
                    END;
                (*ENDIF*) 
                a_ap_tree^[ put_node ].n_lo_level := curr_n;
                curr_n := put_node;
                IF  a_rowno_found
                THEN
                    a07_error (acv, e_rowno_not_allowed, put_node,
                          put_node)
                ELSE
                    BEGIN
                    m_leftpar_cnt  := a_leftpar_cnt;
                    m_rightpar_cnt := a_rightpar_cnt;
                    a_leftpar_cnt  := 0;
                    a_rightpar_cnt := 0;
                    a_select_node := 0;
                    ak60one_select (acv,
                          a_ap_tree^[ curr_n ].n_sa_level,
                          syntax_help, cak_is_undefined);
                    a_leftpar_cnt  := m_leftpar_cnt  + a_leftpar_cnt;
                    a_rightpar_cnt := m_rightpar_cnt + a_rightpar_cnt;
&                   ifdef trace
                    t01int4 (ak_syn, 'intersect mi', put_node);
                    t01aptree (ak_syn, a_ap_tree^, a_scv_index, a_first_hint_node);
&                   endif
                    ak60get_sel_info (acv, a_ap_tree^[ curr_n ].n_sa_level, indkey, all_or_not);
                    IF  (indkey <> 0) AND
                        NOT ((full_indkey = indkey) OR (full_all_or_not = all_or_not))
                    THEN
                        BEGIN
                        ak60intern_fromsel (acv, a_ap_tree^[ curr_n ].n_sa_level, syntax_help, c_for_union);
                        full_indkey := indkey;
                        full_all_or_not := all_or_not;
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                curr_n := put_node;
            UNTIL
                ((a_returncode <> 0 ) OR
                (NOT a01_eqkey(a01kw[ cak_i_intersect], a_sqlmode,
                a_cmd_part^.sp1p_buf, a_scv)));
            (*ENDREPEAT*) 
            a_select_node := m_select_n;
            END
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    a_limit_allowed := m_limit_allowed;
&   ifdef trace
    t01int4 (ak_syn, 'intersect en', put_node);
    t01aptree (ak_syn, a_ap_tree^, a_scv_index, a_first_hint_node);
&   endif
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60union_select (
            VAR acv         : tak_all_command_glob;
            VAR put_node    : tsp00_Int2;
            outer_level     : boolean;
            VAR syntax_help : ak60syntax_helptype;
            last_node       : tsp00_Int2);  (* PTS 1138343 D.T. *)
 
VAR
      curr_n         : tsp00_Int2;
      cv_i_except    : tsp00_Int2;
      indkey         : integer;
      full_indkey    : integer;
      res_kw         : boolean;
      limit_allowed  : boolean;
      intern_fromsel : boolean;
      full_all_or_not: ak60all_or_not;
      all_or_not     : ak60all_or_not;
      m_select_n     : tsp00_Int2;
      m_leftpar_cnt  : tsp00_Int2;
      m_rightpar_cnt : tsp00_Int2;
 
BEGIN
WITH acv, a_scv DO
    BEGIN
    m_select_n := a_select_node;
    IF  outer_level
    THEN
        BEGIN
        syntax_help.sh_subcount := a_next_upos;
        IF  (a_next_upos DIV cak_maxsubcnt_per_level) >= (MAX_INT2_SP00 DIV cak_maxsubcnt_per_level)
        THEN
            a07_error (acv, e_too_many_subqueries, put_node, put_node)
        ELSE
            a_next_upos := ((a_next_upos DIV cak_maxsubcnt_per_level) + 1) * cak_maxsubcnt_per_level + 2;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    ak60intersect_select (acv, put_node, syntax_help, last_node);
    IF  (sc_symb <> s_eof)      AND
        (a_returncode = 0)
    THEN
        BEGIN
        ak60get_sel_info (acv, put_node, full_indkey, full_all_or_not);
        intern_fromsel := false;
        IF  a_sqlmode = sqlm_oracle
        THEN
            cv_i_except := cak_i_minus
        ELSE
            cv_i_except := cak_i_except;
        (*ENDIF*) 
        a01_get_keyword (acv, indkey, res_kw);
        IF  (indkey = cak_i_union) OR
            (indkey = cv_i_except) OR
            ((indkey = cak_i_intersect) AND (a_sqlmode = sqlm_oracle))
        THEN
            BEGIN
&           ifdef trace
            t01int4 (ak_syn, 'union st    ', put_node);
            t01aptree (ak_syn, a_ap_tree^, a_scv_index, a_first_hint_node);
&           endif
            curr_n    := put_node;
            limit_allowed   := a_limit_allowed;
            a_limit_allowed := false;
            REPEAT
                a01_next_symbol(acv);
                IF  a01_eqkey(a01kw[ cak_i_all], a_sqlmode,
                    a_cmd_part^.sp1p_buf, a_scv)
                THEN
                    BEGIN
                    all_or_not := is_all;
                    IF  (full_indkey = 0)
                    THEN
                        BEGIN
                        full_indkey := indkey;
                        full_all_or_not := is_all
                        END
                    ELSE
                        IF  NOT ((full_indkey = indkey) OR (full_all_or_not = is_all))
                        THEN
                            BEGIN
                            intern_fromsel := true;
                            IF  full_indkey <> indkey
                            THEN
                                full_indkey := cak_i_list;
                            (*ENDIF*) 
                            IF  full_all_or_not <> is_all
                            THEN
                                full_all_or_not := is_mixture;
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                    (*ENDIF*) 
                    a01_next_symbol(acv);
                    IF  indkey = cak_i_union
                    THEN
                        a01_call_put(acv, a63, cak_x_union_all,
                              put_node)
                    ELSE
                        IF  a_sqlmode = sqlm_oracle
                        THEN
                            a07_error (acv, e_missing_keyword, put_node,
                                  put_node)
                        ELSE
                            a01_call_put(acv, a63, cak_x_except_all,
                                  put_node);
                        (*ENDIF*) 
                    (*ENDIF*) 
                    END
                ELSE
                    BEGIN
                    all_or_not := is_distinct;
                    IF  (full_indkey = 0)
                    THEN
                        BEGIN
                        full_indkey := indkey;
                        full_all_or_not := is_distinct
                        END
                    ELSE
                        IF  NOT ((full_indkey = indkey) OR (full_all_or_not = is_distinct))
                        THEN
                            BEGIN
                            intern_fromsel := true;
                            IF  full_indkey <> indkey
                            THEN
                                full_indkey := cak_i_list;
                            (*ENDIF*) 
                            IF  full_all_or_not <> is_distinct
                            THEN
                                full_all_or_not := is_mixture;
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                    (*ENDIF*) 
                    IF  indkey = cak_i_union
                    THEN
                        a01_call_put(acv, a63, cak_x_union,
                              put_node)
                    ELSE
                        IF  indkey = cv_i_except
                        THEN
                            a01_call_put(acv, a63, cak_x_except,
                                  put_node)
                        ELSE
                            a01_call_put(acv, a63, cak_x_intersect,
                                  put_node);
                        (*ENDIF*) 
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                IF  intern_fromsel
                THEN
                    BEGIN
                    ak60intern_fromsel (acv, curr_n, syntax_help, c_for_union);
                    full_indkey := indkey;
                    full_all_or_not := all_or_not;
                    END;
                (*ENDIF*) 
                a_ap_tree^[ put_node ].n_lo_level := curr_n;
                curr_n := put_node;
                m_leftpar_cnt  := a_leftpar_cnt;
                m_rightpar_cnt := a_rightpar_cnt;
                a_leftpar_cnt  := 0;
                a_rightpar_cnt := 0;
                a_select_node := 0;
                IF  a_rowno_found
                THEN
                    a07_error (acv, e_rowno_not_allowed, put_node,
                          put_node)
                ELSE
                    ak60intersect_select (acv,
                          a_ap_tree^[ curr_n ].n_sa_level, syntax_help, cak_is_undefined);
                (*ENDIF*) 
                a_leftpar_cnt  := m_leftpar_cnt  + a_leftpar_cnt;
                a_rightpar_cnt := m_rightpar_cnt + a_rightpar_cnt;
&               ifdef trace
                t01int4 (ak_syn, 'union middle', put_node);
                t01aptree (ak_syn, a_ap_tree^, a_scv_index, a_first_hint_node);
&               endif
                ak60get_sel_info (acv, a_ap_tree^[ curr_n ].n_sa_level, indkey, all_or_not);
                IF  (indkey <> 0) AND
                    NOT ((full_indkey = indkey) OR (full_all_or_not = all_or_not))
                THEN
                    BEGIN
                    ak60intern_fromsel (acv, a_ap_tree^[ curr_n ].n_sa_level, syntax_help, c_for_union);
                    full_indkey := indkey;
                    full_all_or_not := all_or_not;
                    END;
                (*ENDIF*) 
                curr_n := put_node;
                a01_get_keyword (acv, indkey, res_kw);
            UNTIL
                ( (a_returncode <> 0 ) OR
                NOT ((indkey = cak_i_union) OR
                ( indkey = cv_i_except) OR
                ( (indkey = cak_i_intersect) AND (a_sqlmode = sqlm_oracle))));
            (*ENDREPEAT*) 
            a_select_node   := m_select_n;
            a_limit_allowed := limit_allowed;
&           ifdef trace
            t01int4 (ak_syn, 'union end   ', put_node);
            t01aptree (ak_syn, a_ap_tree^, a_scv_index, a_first_hint_node);
&           endif
            END
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  a_returncode = 0
    THEN
        IF  outer_level
        THEN
            BEGIN
            IF  (a_ap_tree^[ put_node ].n_proc = a63) AND
                (a_ap_tree^[ put_node ].n_subproc >= cak_x_union) AND
                (a_ap_tree^[ put_node ].n_subproc <= cak_x_intersect_all)
            THEN
                BEGIN
                a01_call_put(acv, a63, cak_x_start_union, curr_n);
                a_ap_tree^[ curr_n ].n_lo_level := put_node;
                put_node                       := curr_n;
                IF  a_precomp_info_byte = csp1_p_mselect_found
                THEN
                    a_precomp_info_byte := csp1_p_mass_select_found;
                (*ENDIF*) 
                END;
            (* subquery-Level *)
            (*ENDIF*) 
            a_ap_tree^[ put_node ].n_length := syntax_help.sh_subcount;
            IF  (syntax_help.sh_subcount > 0) AND
                (syntax_help.sh_subcount MOD cak_maxsubcnt_per_level = 0)
            THEN
                a07_error (acv, e_too_many_subqueries, put_node, put_node)
            ELSE
                a_next_upos := syntax_help.sh_subcount + 1
            (*ENDIF*) 
            END
        (*ENDIF*) 
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60whole_select (
            VAR acv         : tak_all_command_glob;
            VAR put_node    : tsp00_Int2;
            VAR syntax_help : ak60syntax_helptype);
 
VAR
      recursive   : boolean;
      last_node   : tsp00_Int2;
      curr_n      : tsp00_Int2;
      curr1_n     : tsp00_Int2;
      result_n    : tsp00_Int2;
 
BEGIN
WITH acv, a_scv DO
    BEGIN
    IF  a_precomp_info_byte = csp1_p_none
    THEN
        (* because of (M)DECLARE *)
        IF  a_cmd_segment_header.sp1c_mass_cmd
        THEN
            a_precomp_info_byte := csp1_p_mselect_found
        ELSE
            a_precomp_info_byte := csp1_p_mass_select_found;
        (*ENDIF*) 
    (*ENDIF*) 
    a_rowno_allowed   := true;
    a_rowno_found     := false;
    a_limit_allowed   := true;
    a_limit_found     := false;
    curr_n            := 0;
    IF  a01_eqkey (a01kw[ cak_i_with], a_sqlmode,
        a_cmd_part^.sp1p_buf, a_scv)
    THEN
        BEGIN
        recursive := true;
        a01_next_symbol (acv);
        IF  a01mandatory_keyword (acv, cak_i_recursive)
        THEN
            BEGIN
            a_limit_allowed := false;
            a01_call_put(acv, a63, cak_x_recursive_select, curr_n);
            put_node := curr_n;
            a02_aresulttablename (acv, result_n, curr_n);
            a01_force_symbol (acv, s_leftpar, put_node, put_node);
            IF  (a_returncode = 0)
            THEN
                BEGIN
                curr_n := put_node;
                a01_call_put(acv, a63, cak_x_new_columnname_list,
                      a_ap_tree^[ curr_n ].n_lo_level);
                curr_n := a_ap_tree^[ curr_n ].n_lo_level;
                a02_l_acolumn_list (acv, a_ap_tree^[ curr_n ].
                      n_lo_level, last_node);
                a01_force_symbol (acv, s_rightpar, put_node, put_node);
                END;
            (*ENDIF*) 
            IF  (a_returncode = 0)
            THEN
                BEGIN
                IF  a01mandatory_keyword (acv, cak_i_as)
                THEN
                    BEGIN
                    IF  a_precomp_info_byte = csp1_p_mselect_found
                    THEN
                        a_precomp_info_byte := csp1_p_mass_select_found;
                    (*ENDIF*) 
                    syntax_help.sh_for_update_allowed := false;
                    a01_force_symbol (acv, s_leftpar, put_node, put_node);
                    IF  (a_returncode = 0)
                    THEN
                        ak60union_select (acv, a_ap_tree^[ curr_n ].n_sa_level,
                              c_outer_level, syntax_help, cak_is_undefined);
                    (*ENDIF*) 
                    a01_force_symbol (acv, s_rightpar, put_node, put_node);
                    IF  (a_returncode = 0)
                    THEN
                        BEGIN
                        curr_n := a_ap_tree^[ curr_n ].n_sa_level;
                        last_node := curr_n;
                        IF  ((a_ap_tree^[ last_node ].n_proc <> a63) OR
                            ( a_ap_tree^[ last_node ].n_subproc <> cak_x_start_union))
                        THEN
                            a07_kw_put_error (acv, e_wanted_keyword,
                                  a_scv.sc_sypos, cak_i_union)
                        ELSE
                            BEGIN
                            last_node := a_ap_tree^[ last_node ].n_lo_level;
                            IF  (a_ap_tree^ [ last_node ].n_subproc <> cak_x_union_all) OR
                                (a_ap_tree^[ a_ap_tree^ [ last_node ].n_lo_level ].n_proc <> a63) OR
                                (a_ap_tree^[ a_ap_tree^ [ last_node ].n_lo_level ].n_subproc
                                <> cak_x_mass_select)
                            THEN
                                a07_b_put_error (acv, e_not_implemented,
                                      a_ap_tree^ [ last_node ].n_pos)
                            ELSE
                                BEGIN
                                a_limit_allowed := true;
                                last_node := curr_n;
                                WHILE ((a_ap_tree^[ last_node ].n_proc <> a63)              OR
                                      ( a_ap_tree^[ last_node ].n_subproc <> cak_x_mass_select)) DO
                                    last_node := a_ap_tree^[ last_node ].n_lo_level;
                                (*ENDWHILE*) 
                                curr1_n := a_ap_tree^[ last_node ].n_lo_level;
                                IF  ((a_ap_tree^[ curr1_n ].n_proc = a63) AND
                                    ( a_ap_tree^[ curr1_n ].n_subproc = cak_x_distinct))
                                THEN
                                    last_node := curr1_n;
                                (*ENDIF*) 
                                a_ap_tree^[ result_n ].n_sa_level := a_ap_tree^[ last_node ].n_lo_level;
                                a_ap_tree^[ last_node ].n_lo_level := result_n;
                                ak60one_select (acv, a_ap_tree^[ curr_n ].n_sa_level,
                                      syntax_help, cak_is_undefined);
                                curr_n := a_ap_tree^[ curr_n ].n_sa_level;
                                END
                            (*ENDIF*) 
                            END
                        (*ENDIF*) 
                        END
                    (*ENDIF*) 
                    END
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        recursive := false;
        ak60union_select (acv, put_node, c_outer_level, syntax_help, cak_is_undefined);
        curr_n := put_node;
        IF  (a_returncode = 0)
        THEN
            IF  (a_ap_tree^[ put_node ].n_proc = a63) AND
                (a_ap_tree^[ put_node ].n_subproc = cak_x_start_union)
            THEN
                syntax_help.sh_for_update_allowed := false;
            (*ENDIF*) 
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  (a_returncode = 0)
    THEN
        BEGIN
        last_node := curr_n;
        REPEAT
            last_node := acv.a_ap_tree^[ last_node ].n_lo_level
        UNTIL
            (((acv.a_ap_tree^[ last_node ].n_proc = a60) AND
            (  acv.a_ap_tree^[ last_node ].n_subproc  = cak_x_select_list))
            OR (acv.a_ap_tree^[ last_node ].n_proc = no_proc))
            (* resulttablename *);
        (*ENDREPEAT*) 
        WHILE acv.a_ap_tree^[ last_node ].n_sa_level > 0 DO
            last_node := acv.a_ap_tree^[ last_node ].n_sa_level;
        (*ENDWHILE*) 
        IF  (sc_symb <> s_eof)                           AND
            (* no select INTO *)
            (a_precomp_info_byte <> csp1_p_mass_command) AND
            (a_precomp_info_byte <> csp1_p_none)
        THEN
            ak60arest_select_expression (acv, last_node,
                  syntax_help.sh_for_update_allowed);
        (*ENDIF*) 
        IF  (a_returncode = 0) AND
            (a_limit_node <> 0)
        THEN
            a_ap_tree^[ last_node ].n_sa_level := a_limit_node;
        (*ENDIF*) 
        END
    (*ENDIF*) 
    END
(*ENDWITH*) 
END;
 
(* PTS 1138343 D.T. *)
(*------------------------------*) 
 
PROCEDURE
      a60build_special_fromselect(
            VAR acv         : tak_all_command_glob;
            VAR syntax_help : ak60syntax_helptype;
            curr_n          : tsp00_Int2);
 
VAR
      put_n          : tsp00_Int2;
      inf_n          : tsp00_Int2;
      a92_n          : tsp00_Int2;
      a63_n          : tsp00_Int2;
      org_n          : tsp00_Int2;
      sav_n          : tsp00_Int2;
      sav_symb       : tak_sc_symbol;
      sav_node       : tak_ap_node;
      cnt_tabs       : integer;
      sav_built      : boolean;
      inc_pars       : boolean;
      add_fromselnode: boolean;
 
BEGIN
WITH acv, a_scv DO
    BEGIN
    add_fromselnode := false;
    IF  ( a_ap_tree^[ curr_n ].n_proc = a66 ) AND
        ((a_ap_tree^[ curr_n ].n_subproc = cak_x_table_spec) OR
        (a_ap_tree^[ curr_n ].n_subproc = cak_x_select_in_from_part))
    THEN
        BEGIN
        inf_n := a_ap_tree^[ curr_n ].n_lo_level;
        IF  (a_ap_tree^[ inf_n ].n_proc = a66 ) AND
            (a_ap_tree^[ inf_n ].n_subproc = cak_x_table_spec)
        THEN
            BEGIN
            add_fromselnode := false;
            IF  NOT (qcn_ContainsSJFromSelect in
                a_ap_tree^[ a_select_node ].n_querycheck)
            THEN
                BEGIN
                a_ap_tree^[ a_select_node ].n_querycheck :=
                      a_ap_tree^[ a_select_node ].n_querycheck + [ qcn_ContainsSJFromSelect ];
                inf_n := a_ap_tree^[ inf_n ].n_lo_level;
                a_ap_tree^[ a_select_node ].n_refback
                      := a_ap_tree^[ inf_n ].n_pos;
                END
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            add_fromselnode := true;
            IF  NOT (qcn_ContainsSJFromSelect in
                a_ap_tree^[ a_select_node ].n_querycheck)
            THEN
                BEGIN
                a_ap_tree^[ a_select_node ].n_querycheck :=
                      a_ap_tree^[ a_select_node ].n_querycheck + [ qcn_ContainsSJFromSelect ];
                a_ap_tree^[ a_select_node ].n_refback
                      := a_ap_tree^[ curr_n ].n_pos;
                END
            (*ENDIF*) 
            END
        (*ENDIF*) 
        END
    ELSE
        BEGIN
        a07_error (acv, e_internal_error, curr_n, curr_n)
        END;
    (*ENDIF*) 
    sav_node := a_ap_tree^[ curr_n ];
    sav_symb := sc_symb;
    sav_n    := curr_n;
    org_n    := curr_n;
    inc_pars := add_fromselnode;
    a_from_select := true;
    a_fromsel_n   := succ (a_fromsel_n);
    a01info_call_put (acv, a63query_spec, cak_is_undefined, put_n, inf_n);
    a_ap_tree^[ put_n ].n_length := syntax_help.sh_subcount;
    a_ap_tree^[ put_n ].n_querycheck :=
          a_ap_tree^[ put_n ].n_querycheck + [ qcn_SpecialJoinFromSelect ];
    a_ap_tree^[ put_n ].n_pos      := a_ap_tree^[ sav_n ].n_pos;
    a_ap_tree^[ put_n ].n_length   := a_ap_tree^[ sav_n ].n_length;
    IF  add_fromselnode
    THEN
        BEGIN
        a_ap_tree^[ put_n ].n_lo_level := curr_n;
        a_ap_tree^[ sav_n ].n_subproc  := cak_x_select_in_from_part;
        a_ap_tree^[ sav_n ].n_pos      := a_fromsel_n;
        a_ap_tree^[ sav_n ].n_lo_level := put_n;
        curr_n := put_n;
        a01_call_put (acv, a60, cak_x_select_list,
              a_ap_tree^[ curr_n ].n_lo_level);
        curr_n  := a_ap_tree^[ curr_n ].n_lo_level;
        sav_n   := curr_n;
        a01info_call_put (acv, a60, cak_x_select_column,
              a_ap_tree^[ curr_n ].n_lo_level, inf_n);
        curr_n  := a_ap_tree^[ curr_n ].n_lo_level;
        sav_symb:= sc_symb;
        sc_symb := s_asterisk;
        a01_put_node (acv, a_ap_tree^[ curr_n ].n_lo_level);
        sc_symb := sav_symb;
        curr_n  := sav_n;
        a01_call_put (acv, a63, cak_x_from_part, a_ap_tree^[ curr_n ].n_sa_level);
        curr_n  := a_ap_tree^[ curr_n ].n_sa_level;
        a63_n := curr_n;
        a01_put_node (acv, put_n);
        a_ap_tree^[ put_n ] := sav_node;
        a_ap_tree^[ curr_n ].n_lo_level := put_n;
        curr_n := put_n;
        END
    ELSE
        BEGIN
        curr_n  := org_n;
        sav_n   := a_ap_tree^[ curr_n ].n_lo_level;
        a_ap_tree^[ curr_n ].n_lo_level := put_n;
        curr_n := put_n;
        a01_call_put (acv, a60, cak_x_select_list,
              a_ap_tree^[ curr_n ].n_lo_level);
        curr_n := a_ap_tree^[ curr_n ].n_lo_level;
        a01_call_put (acv, a63, cak_x_from_part, a_ap_tree^[ curr_n ].n_sa_level);
        org_n := a_ap_tree^[ curr_n ].n_sa_level;
        a63_n := org_n;
        a_ap_tree^[ org_n ].n_lo_level := sav_n;
        a_ap_tree^[ put_n ].n_pos      := a_ap_tree^[ sav_n ].n_pos;
        a_ap_tree^[ put_n ].n_length   := a_ap_tree^[ sav_n ].n_length;
        sav_n   := a_ap_tree^[ org_n ].n_lo_level;
        a01info_call_put (acv, a60, cak_x_select_column,
              a_ap_tree^[ curr_n ].n_lo_level, inf_n);
        curr_n  := a_ap_tree^[ curr_n ].n_lo_level;
        sav_symb:= sc_symb;
        sc_symb := s_asterisk;
        a01_put_node (acv, a_ap_tree^[ curr_n ].n_lo_level);
        sc_symb := sav_symb;
        curr_n := sav_n;
        END;
    (*ENDIF*) 
    ak60atable_lspec_list (acv, syntax_help,
          a_ap_tree^[ curr_n ].n_sa_level, curr_n, a63_n,
          cnt_tabs, true);
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60one_select (
            VAR acv         : tak_all_command_glob;
            VAR put_node    : tsp00_Int2;
            VAR syntax_help : ak60syntax_helptype;
            last_node       : tsp00_Int2); (* PTS 1138343 D.T. *)
 
VAR
      res_node       : tsp00_Int2;
      curr_n         : tsp00_Int2;
      info_n         : tsp00_Int2;
      aux_n          : tsp00_Int2; (* PTS 1138343 D.T. *)
      sc_pos         : tsp00_Int2; (* PTS 1138343 D.T. *)
      cnt_tabs       : integer;    (* PTS 1138343 D.T. *)
      m_rowno_allowed: boolean;
      _erg           : boolean;
 
BEGIN
WITH acv, a_scv DO
    BEGIN
    IF  sc_symb = s_leftpar
    THEN
        BEGIN
        a01_next_symbol(acv);
        ak60union_select (acv, put_node,
              NOT c_outer_level, syntax_help, last_node);
        (* ******* *)
        IF  NOT syntax_help.sh_is_fromsel (* PTS 1138343 D.T. *)
        THEN
            BEGIN
            a01_force_symbol (acv, s_rightpar,
                  put_node, put_node);
            END
        ELSE
            BEGIN
            IF  a_scv.sc_symb = s_rightpar (* PTS 1138343 D.T. *)
            THEN
                a01_next_symbol (acv)
            ELSE
                BEGIN
                a60build_special_fromselect(acv, syntax_help, last_node);
                a01_force_symbol (acv, s_rightpar,
                      put_node, put_node);
                END
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        (* ******* *)
        END
    ELSE
        BEGIN
        a_scv.sc_states := a_scv.sc_states + [ scs_hint_allowed ];
        sc_pos := sc_sypos;
        IF  NOT syntax_help.sh_is_fromsel (* PTS 1138343 D.T. *)
        THEN
            _erg := a01mandatory_keyword (acv, cak_i_select)
        ELSE
            BEGIN
            IF  a01_eqkey (a01kw[cak_i_select], acv.a_sqlmode,
                acv.a_cmd_part^.sp1p_buf, acv.a_scv)
            THEN
                BEGIN
                _erg := true;
                a01_next_symbol (acv);
                END
            ELSE
                BEGIN
                _erg := false;
                last_node := put_node;
                ak60atable_spec(acv, syntax_help, put_node, last_node, aux_n, cnt_tabs);
                END
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  _erg
        THEN
            BEGIN
            IF  syntax_help.sh_is_query_spec
            THEN
                BEGIN
                a01info_call_put (acv, a63query_spec,
                      cak_is_undefined, put_node, info_n);
                IF  a_returncode = 0
                THEN
                    BEGIN
                    a_ap_tree^[ put_node ].n_pos := sc_pos;
                    a_ap_tree^[ put_node ].n_length := syntax_help.sh_subcount
                    END;
                (*ENDIF*) 
                END
            ELSE
                (* info node will be set by calling routine *)
                BEGIN
                a01_call_put(acv, a63, cak_x_mass_select, put_node);
                IF  a_returncode = 0
                THEN
                    a_ap_tree^[ put_node ].n_pos := sc_pos;
                (*ENDIF*) 
                syntax_help.sh_is_query_spec := true
                END;
            (*ENDIF*) 
            (* PTS 1001097 E.Z. *)
            curr_n         := put_node;
            IF  a_select_node = 0
            THEN
                a_select_node := put_node;
            (*ENDIF*) 
            m_rowno_allowed := a_rowno_allowed;
            IF  a_scv.sc_symb = s_hint
            THEN
                a80_ahint_statement(acv, cak_x_select_hint, put_node);
            (*ENDIF*) 
            a_scv.sc_states := a_scv.sc_states - [ scs_hint_allowed ];
            IF  ((a01_eqkey (a01kw[ cak_i_distinct], a_sqlmode,
                a_cmd_part^.sp1p_buf, a_scv))
                OR
                ((a01_eqkey (a01kw[ cak_i_unique], a_sqlmode,
                a_cmd_part^.sp1p_buf, a_scv)) AND
                (a_sqlmode = sqlm_oracle)))
            THEN
                BEGIN
                a01_call_put (acv, a63, cak_x_distinct,
                      a_ap_tree^[ put_node ].n_lo_level);
                curr_n := a_ap_tree^[ put_node ].n_lo_level;
                a01_next_symbol (acv);
                a_may_be_direct_sel := false;
                syntax_help.sh_for_update_allowed := false;
                IF  a_precomp_info_byte = csp1_p_mass_command
                THEN (* for MINSERT..SELECT *)
                    a_precomp_info_byte := csp1_p_none;
                (*ENDIF*) 
                END
            ELSE
                BEGIN
                IF  a01_eqkey (a01kw[ cak_i_all], a_sqlmode,
                    a_cmd_part^.sp1p_buf, a_scv)
                THEN
                    a01_next_symbol (acv);
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            a_allow_functions := tf_unknown;
            IF  a_returncode = 0
            THEN
                IF  a01_eqkey (a01kw[ cak_i_top], a_sqlmode,
                    a_cmd_part^.sp1p_buf, a_scv)
                THEN
                    IF  a_ap_tree^[a_ap_tree^[0].n_lo_level].n_proc = a16
                    THEN
                        a07_error (acv, e_in_view_not_allowed,
                              put_node, put_node)
                    ELSE
                        IF  a_limit_allowed
                        THEN
                            BEGIN
                            a01_call_put (acv, a60, cak_x_limit, a_limit_node);
                            a01_next_symbol (acv);
                            a_limit_found := true;
                            IF  sc_symb in [ s_parameter_name, s_unsigned_integer ]
                            THEN
                                a03_avalue_spec (acv, NOT c_null_allowed,
                                      NOT c_stamp_allowed, NOT c_default_allowed,
                                      NOT c_sysuser_allowed,
                                      a_ap_tree^[ a_limit_node ].n_lo_level, info_n);
                            (*ENDIF*) 
                            IF  a01_eqkey (a01kw[ cak_i_percent], a_sqlmode,
                                a_cmd_part^.sp1p_buf, a_scv)
                            THEN
                                BEGIN
                                a_ap_tree^[a_limit_node].n_subproc := cak_x_top_percent;
                                a01_next_symbol (acv);
                                IF  a01_eqkey (a01kw[ cak_i_with], a_sqlmode,
                                    a_cmd_part^.sp1p_buf, a_scv)
                                THEN
                                    (* then BUILD resultset is needed !! *)
                                    a07_error (acv, e_not_implemented, put_node, put_node);
                                (*ENDIF*) 
                                END
                            (*ENDIF*) 
                            END
                        ELSE
                            a07_error (acv, e_invalid_keyword,
                                  put_node, put_node);
                        (*ENDIF*) 
                    (*ENDIF*) 
                (*ENDIF*) 
            (*ENDIF*) 
            IF  a_returncode = 0
            THEN
                BEGIN
                ak60select_list (acv, syntax_help.sh_stamp_allowed,
                      a_ap_tree^[ curr_n ].n_lo_level, curr_n);
                IF  ((a_allow_functions <> tf_unknown) OR
                    a_rowno_found)
                THEN
                    a_may_be_direct_sel := false;
                (*ENDIF*) 
                IF  a01_eqkey (a01kw[ cak_i_into], a_sqlmode,
                    a_cmd_part^.sp1p_buf, a_scv)
                    AND
                    ((syntax_help.sh_into_allowed = ak60is_allowed) OR
                    ( syntax_help.sh_into_allowed = ak60is_needed))
                    AND
                    ((a_precomp_info_byte = csp1_p_mass_select_found)
                    OR ((a_precomp_info_byte = csp1_p_mselect_found) AND
                    (a_ex_kind in [only_syntax, only_parsing]) AND
                    (* PTS 1118879 *)
                    (a_sqlmode in [sqlm_oracle, sqlm_internal])))
                THEN
                    BEGIN
                    IF  (a_return_segm^.sp1r_function_code <>
                        csp1_explain_fc)
                    THEN
                        IF  a_precomp_info_byte = csp1_p_mselect_found
                        THEN
                            BEGIN
                            a_may_be_direct_sel := false;
                            a_return_segm^.sp1r_function_code :=
                                  csp1_mselect_into_fc
                            END
                        ELSE
                            a_return_segm^.sp1r_function_code :=
                                  csp1_select_into_fc;
                        (*ENDIF*) 
                    (*ENDIF*) 
                    a_precomp_info_byte := csp1_p_none;
                    syntax_help.sh_into_allowed := ak60was_found;
                    (* PTS 1002008 E.Z. + h.b. PTS 1002073 *)
                    (* Torsten Pfeiffer will das auch in 7.2 haben *)
                    a_rowno_allowed   := true;
                    ak60aselect_single_spec (acv, syntax_help,
                          a_ap_tree^[ curr_n ].n_sa_level, curr_n); (* PTS 1138343 D.T. *)
                    (* because of subqueries *)
                    IF  a_return_segm^.sp1r_function_code =
                        csp1_mselect_into_fc
                    THEN
                        a_precomp_info_byte := csp1_p_mass_command
                    ELSE
                        a_precomp_info_byte := csp1_p_none;
                    (*ENDIF*) 
                    END
                ELSE
                    IF  syntax_help.sh_into_allowed = ak60is_needed
                    THEN
                        a07_error (acv, e_missing_keyword, put_node, put_node)
                    ELSE
                        BEGIN (* not called by alter table *)
                        a_may_be_direct_sel := false;
                        a_rowno_allowed     := m_rowno_allowed;
                        ak60atable_expression (acv, syntax_help,
                              a_ap_tree^[ curr_n ].n_sa_level,
                              curr_n,
                              syntax_help.sh_for_update_allowed); (* PTS 1138343 D.T. *)
                        END
                    (*ENDIF*) 
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60aselect_single_spec (
            VAR acv       : tak_all_command_glob;
            VAR syntax_help : ak60syntax_helptype; (* PTS 1138343 D.T. *)
            VAR put_node  : tsp00_Int2;
            VAR last_node : tsp00_Int2);
 
VAR
      update_allowed : boolean;
      cnt_tabs       : integer;
      m_index        : integer;
      m_count_variab : integer;
      curr_n         : tsp00_Int2;
      last_n         : tsp00_Int2;
      m_curr_n       : tsp00_Int2;
      hallow         : tak_function;
      scvh           : tak_scanner_glob;
 
BEGIN
WITH acv, a_scv DO
    IF  a_returncode = 0
    THEN
        BEGIN
        a01_next_symbol (acv);
        a01_call_put (acv, a60, cak_x_single_select, curr_n);
        put_node          := curr_n;
        hallow            := a_allow_functions;
        a_allow_functions := tf_no_func;
        a02_l_aparameter_list (acv, a_ap_tree^[ curr_n ].n_lo_level,
              last_n);
        IF  NOT a01_eqkey (a01kw[ cak_i_from], a_sqlmode,
            a_cmd_part^.sp1p_buf, a_scv)
        THEN
            a07_error (acv, e_missing_keyword, put_node, last_node)
        ELSE
            BEGIN
            IF  a_may_be_direct_sel
            THEN
                BEGIN
                m_index        := a_scv_index;
                scvh           := a_scv;
                m_curr_n       := curr_n;
                m_count_variab := a_count_variab;
                a01_next_symbol (acv);
                a01_call_put (acv, a66, cak_x_table_spec,
                      a_ap_tree^[ curr_n ].n_sa_level);
                curr_n := a_ap_tree^[ curr_n ].n_sa_level;
                last_node := curr_n;
                a02_atablename (acv, a_ap_tree^[curr_n].n_lo_level,
                      last_n);
                IF  a01_eqkey (a01kw[ cak_i_where], a_sqlmode,
                    a_cmd_part^.sp1p_buf, a_scv)
                THEN
                    BEGIN
                    a55_aselectinto_key_spec_list (acv,
                          a_ap_tree^[ curr_n ].n_sa_level, last_node);
                    IF  ((sc_symb <> s_eof) AND (a_returncode = 0))
                    THEN
                        BEGIN
                        ak60await_option (acv,
                              a_ap_tree^[ last_node ].n_sa_level);
                        IF  a_returncode = 0
                        THEN
                            last_node :=
                                  a_ap_tree^[ last_node ].n_sa_level
                        (*ENDIF*) 
                        END
                    (*ENDIF*) 
                    END
                ELSE
                    a07_error (acv, e_missing_keyword,
                          last_node, last_node);
                (*ENDIF*) 
                a01_is_end_symbol (acv);
                IF  a_returncode = 0
                THEN
                    WITH a_ap_tree^ [ a_ap_tree^[ 0 ].n_lo_level ] DO
                        BEGIN
                        n_proc := a62;
                        n_subproc  := cak_x_select_direct
                        END
                    (*ENDWITH*) 
                ELSE
                    BEGIN
                    a_may_be_direct_sel := false;
                    a_scv               := scvh;
                    a_scv_index         := m_index;
                    a_count_variab      := m_count_variab;
                    curr_n              := m_curr_n;
                    a_returncode         := 0;
                    a_errorpos   := 0;
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            IF  NOT a_may_be_direct_sel
            THEN
                BEGIN
                a01_next_symbol (acv);
                a01_call_put (acv, a63, cak_x_from_part,
                      a_ap_tree^[ curr_n ].n_sa_level);
                curr_n := a_ap_tree^[ curr_n ].n_sa_level;
                ak60atable_lspec_list (acv, syntax_help,
                      a_ap_tree^[ curr_n ].n_lo_level, last_n, last_n,
                      cnt_tabs, false); (* PTS 1138343 D.T. *)
                update_allowed := true;
                ak60atab_expr (acv, curr_n, last_node,
                      hallow, update_allowed,
                      c_is_single_select, (cnt_tabs > 1));
                IF  ((sc_symb <> s_eof) AND
                    (a_sqlmode = sqlm_oracle) AND
                    (a_returncode = 0))
                THEN
                    IF  a01_eqkey (a01kw[ cak_i_for], a_sqlmode,
                        a_cmd_part^.sp1p_buf, a_scv)
                    THEN
                        BEGIN
                        update_allowed := true;
                        ak60aupdate_of (acv, curr_n,
                              c_may_for_update, update_allowed);
                        END;
                    (*ENDIF*) 
                (*ENDIF*) 
                IF  (sc_symb <> s_eof) AND
                    (a_returncode = 0)
                THEN
                    BEGIN
                    ak60await_option (acv,
                          a_ap_tree^[ curr_n ].n_sa_level);
                    IF  a_returncode = 0
                    THEN
                        last_node := a_ap_tree^[ curr_n ].n_sa_level
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                a01_is_end_symbol (acv)
                END
            (*ENDIF*) 
            END
        (*ENDIF*) 
        END
    (*ENDIF*) 
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60asort_spec (
            VAR acv       : tak_all_command_glob;
            VAR put_node  : tsp00_Int2;
            VAR last_node : tsp00_Int2);
 
VAR
      curr_n              : tsp00_Int2;
      oneval_subq_allowed : boolean;
 
BEGIN
WITH acv, a_scv DO
    IF  a_returncode = 0
    THEN
        BEGIN
        a01_call_put (acv, a63, cak_x_sort_spec, put_node);
        curr_n := put_node;
        last_node := put_node;
        (* PTS 1116169 E.Z. *)
        oneval_subq_allowed := a_oneval_subq_allowed;
        a_oneval_subq_allowed := false;
        IF  (a_sqlmode = sqlm_internal) OR (a_sqlmode = sqlm_oracle)
        THEN
            a63_avalue_expression (acv,
                  a_ap_tree^[ curr_n ].n_lo_level, curr_n)
        ELSE
            IF  sc_symb = s_unsigned_integer
            THEN
                BEGIN
                a01_put_node (acv, a_ap_tree^[ curr_n ].n_lo_level);
                curr_n := a_ap_tree^[ curr_n ].n_lo_level;
                a01_next_symbol (acv);
                END
            ELSE
                a02_acolumnspec (acv, NOT c_table_required,
                      a_ap_tree^[ curr_n ].n_lo_level, curr_n);
            (*ENDIF*) 
        (*ENDIF*) 
        a_oneval_subq_allowed := oneval_subq_allowed;
        IF  (sc_symb <> s_comma) AND
            (a_returncode = 0)
        THEN
            IF  a01_eqkey (a01kw[ cak_i_asc], a_sqlmode,
                a_cmd_part^.sp1p_buf, a_scv)
            THEN
                BEGIN
                sc_symb := s_asc;
                a01_put_node (acv, a_ap_tree^[ curr_n ].n_sa_level);
                curr_n := a_ap_tree^[ curr_n ].n_sa_level;
                a01_next_symbol (acv);
                END
            ELSE
                IF  a01_eqkey (a01kw[ cak_i_desc], a_sqlmode,
                    a_cmd_part^.sp1p_buf, a_scv)
                THEN
                    BEGIN
                    sc_symb := s_desc;
                    a01_put_node (acv, a_ap_tree^[ curr_n ].n_sa_level);
                    curr_n := a_ap_tree^[ curr_n ].n_sa_level;
                    a01_next_symbol (acv);
                    END;
                (*ENDIF*) 
            (*ENDIF*) 
        (*ENDIF*) 
        END
    (*ENDIF*) 
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60atab_expr (
            VAR acv            : tak_all_command_glob;
            VAR curr_n         : tsp00_Int2;
            VAR last_node      : tsp00_Int2;
            hallow             : tak_function;
            VAR may_for_update : boolean;
            s_single_select    : boolean;
            is_join            : boolean);
 
VAR
      h_cpt    : tak_cmd_part_type;
      last_n   : tsp00_Int2;
      old_n    : tsp00_Int2;
      from_n   : tsp00_Int2;
      where_n  : tsp00_Int2;
      group_n  : tsp00_Int2;
      having_n : tsp00_Int2;
      cond_n   : tsp00_Int2;
      info_n   : tsp00_Int2;
      havingscv: tak_scanner_glob;
 
BEGIN
WITH acv, a_scv DO
    BEGIN
    from_n := curr_n;
    IF  a01_eqkey (a01kw[ cak_i_where], a_sqlmode,
        a_cmd_part^.sp1p_buf, a_scv)
    THEN
        BEGIN
        h_cpt := a_cpart_type;
        a_cpart_type := cpt_in_where_clause;
        (* PTS 1115725 E.Z. *)
        IF  h_cpt = cpt_in_having_clause
        THEN
            a_allow_functions := tf_unknown;
        (*ENDIF*) 
        a01info_call_put (acv, a63, cak_x_search_condition,
              cond_n, info_n);
        a_ap_tree^[ curr_n ].n_sa_level := cond_n;
        curr_n  := cond_n;
        where_n := curr_n;
        a01_next_symbol (acv);
        a63_asearch_condition (acv,
              a_ap_tree^[ curr_n ].n_lo_level, last_n);
        IF  info_n > 0
        THEN
            IF  g01unicode
            THEN
                a_ap_tree^[info_n].n_length := sc_lastpos -
                      a_ap_tree^[info_n].n_pos + 2
            ELSE
                a_ap_tree^[info_n].n_length := sc_lastpos -
                      a_ap_tree^[info_n].n_pos + 1;
            (*ENDIF*) 
        (*ENDIF*) 
        a_cpart_type := h_cpt;
        END
    ELSE
        where_n := 0;
    (*ENDIF*) 
    IF  ((a01_eqkey (a01kw[ cak_i_group], a_sqlmode,
        a_cmd_part^.sp1p_buf, a_scv))
        AND
        ((NOT s_single_select)    OR
        (a_sqlmode = sqlm_internal) OR
        (a_sqlmode = sqlm_ansi)   OR
        (a_sqlmode = sqlm_oracle)))
    THEN
        BEGIN
        ak60agroup_by (acv, curr_n, may_for_update);
        group_n := curr_n
        END
    ELSE
        group_n := 0;
    (*ENDIF*) 
    a_allow_functions := hallow;
    old_n := curr_n;
    havingscv := a_scv;
    IF  ((a01_eqkey (a01kw[ cak_i_having], a_sqlmode,
        a_cmd_part^.sp1p_buf, a_scv))
        AND
        ((NOT s_single_select)    OR
        (a_sqlmode = sqlm_internal) OR
        (a_sqlmode = sqlm_ansi)   OR
        (a_sqlmode = sqlm_oracle)))
    THEN
        BEGIN
        IF  a_precomp_info_byte = csp1_p_mselect_found
        THEN
            a_precomp_info_byte := csp1_p_mass_select_found;
        (*ENDIF*) 
        h_cpt := a_cpart_type;
        a_cpart_type := cpt_in_having_clause;
        a_allow_functions := tf_unknown;
        a01_next_symbol (acv);
        a01_call_put (acv, a63, cak_x_having,
              a_ap_tree^[ curr_n ].n_sa_level);
        curr_n := a_ap_tree^[ curr_n ].n_sa_level;
        having_n := curr_n;
        a_rowno_allowed := false;
        a63_asearch_condition (acv,
              a_ap_tree^[ curr_n ].n_lo_level, last_n);
        IF  ((a_allow_functions = tf_func) OR
            ( a_allow_functions = tf_func_arith))
        THEN
            a_ap_tree^[ curr_n ].n_symb := s_count;
        (*ENDIF*) 
        a_cpart_type := h_cpt;
        END
    ELSE
        having_n := 0;
    (*ENDIF*) 
    IF  (a01_eqkey (a01kw[ cak_i_group], a_sqlmode,
        a_cmd_part^.sp1p_buf, a_scv)
        AND (group_n = 0)
        AND ((a_sqlmode = sqlm_internal) OR (a_sqlmode = sqlm_oracle)))
    THEN
        BEGIN
        ak60agroup_by (acv, curr_n, may_for_update);
        group_n := curr_n;
        (* having-clause <-> group by-clause *)
        a_ap_tree^[ curr_n ].n_sa_level :=
              a_ap_tree^[ old_n ].n_sa_level;
        a_ap_tree^[ old_n ].n_sa_level := curr_n;
        curr_n := a_ap_tree^[ curr_n ].n_sa_level;
        a_ap_tree^[ curr_n ].n_sa_level := 0;
        END;
&   ifdef TRACE
    (*ENDIF*) 
    t01int4 (ak_syn, 'where_n     ', where_n);
    t01int4 (ak_syn, 'group_n     ', group_n);
    t01int4 (ak_syn, 'having_n    ', having_n);
    t01int4 (ak_syn, 'sel_n       ', last_node);
&   endif
    IF  ((group_n = 0) AND
        ( having_n > 0))
    THEN
        IF  NOT (hallow in [ tf_func, tf_func_arith ])
        THEN
            IF  a_ap_tree^[ having_n ].n_symb = s_count
                (* set-function in having *)
            THEN
                BEGIN
                a_scv := havingscv;
                a07_error (acv, e_invalid_keyword,
                      last_node, last_node);
                END;
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    IF  is_join
    THEN
        ak60move_join_node (acv, last_node, from_n, where_n);
    (*ENDIF*) 
    last_node := curr_n;
    END
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60atable_expression (
            VAR acv                    : tak_all_command_glob;
            VAR syntax_help            : ak60syntax_helptype; (* PTS 1138343 D.T. *)
            VAR put_node               : tsp00_Int2;
            VAR sel_list_and_last_node : tsp00_Int2;
            VAR may_for_update         : boolean);
 
VAR
      having_f : boolean;
      curr_n   : tsp00_Int2;
      last_n   : tsp00_Int2;
      less_pos : tsp00_Int2;
      cnt_tabs : integer;
      hallow   : tak_function;
 
BEGIN
WITH acv, a_scv DO
    IF  a_returncode = 0
    THEN
        IF  a01mandatory_keyword (acv, cak_i_from)
        THEN
            BEGIN
            last_n            := 0;
            hallow            := a_allow_functions;
            IF  a_sqlmode = sqlm_ansi
            THEN
                a_allow_functions := tf_unknown
            ELSE
                a_allow_functions := tf_no_func;
            (*ENDIF*) 
            having_f := false;
            IF  sc_symb = s_less
            THEN
                BEGIN
                a01_call_put (acv, a66, cak_x_given_sequence, curr_n);
                put_node := curr_n;
                less_pos := sc_sypos;
                a01_next_symbol (acv);
                a01_call_put (acv, a63, cak_x_from_part, curr_n);
                a_ap_tree^[ put_node ].n_sa_level := curr_n;
                ak60atable_lspec_list (acv, syntax_help,
                      a_ap_tree^[ curr_n ].n_lo_level, last_n, last_n,
                      cnt_tabs, false); (* PTS 1138343 D.T. *)
                IF  sc_symb = s_greater
                THEN
                    a01_next_symbol (acv)
                ELSE
                    BEGIN
                    sc_sypos := less_pos;
                    a07_error (acv, e_invalid_keyword, put_node,
                          sel_list_and_last_node)
                    END
                (*ENDIF*) 
                END
            ELSE
                BEGIN
                a01_call_put (acv, a63, cak_x_from_part, curr_n);
                put_node := curr_n;
                ak60atable_lspec_list (acv, syntax_help,
                      a_ap_tree^[ curr_n ].n_lo_level, last_n, last_n,
                      cnt_tabs, false); (* PTS 1138343 D.T. *)
                END;
            (*ENDIF*) 
            IF  cnt_tabs > 1
            THEN
                may_for_update := false;
            (*ENDIF*) 
            ak60atab_expr (acv, curr_n, sel_list_and_last_node,
                  hallow, may_for_update,
                  NOT c_is_single_select, (cnt_tabs > 1));
            END
        (*ENDIF*) 
    (*ENDIF*) 
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60atable_lspec_list (
            VAR acv       : tak_all_command_glob;
            VAR syntax_help : ak60syntax_helptype; (* PTS 1138343 D.T. *)
            VAR put_node  : tsp00_Int2;
            VAR last_node : tsp00_Int2;
            a63_node      : tsp00_Int2;
            VAR cnt_tabs  : integer;
            _continue     : boolean); (* PTS 1138343 D.T. *)
 
VAR
      aux_node           : tsp00_Int2;
      outer_type         : tsp00_Int2;
      in_tablist         : boolean;
      on_clause_expected : boolean;
      odbc_partype       : tak_odbc_partype;
      odbc_functype      : tak_odbc_functiontype;
 
BEGIN
outer_type   := 0;       (* to silence var-not-init warning *)
cnt_tabs := 0;
on_clause_expected := false;
WITH acv, a_scv DO
    IF  a_returncode = 0
    THEN
        BEGIN
&       ifdef TRACE
        t01int4 (ak_syn, 'put_node  01', put_node);
        t01int4 (ak_syn, 'last_node 01', last_node);
&       endif
        IF  (a_comp_type = at_odbc)
        THEN
            BEGIN
            odbc_partype := no_odbc;
            odbc_functype := odbc_nothing;
            a01_is_odbc_syntax (acv, odbc_partype, odbc_functype);
            IF  (odbc_partype <> no_odbc) AND (odbc_functype = odbc_oj)
            THEN
                a01_next_symbol (acv);
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        aux_node := cak_is_undefined;
        IF  NOT _continue (* PTS 1138343 D.T. *)
        THEN
            ak60atable_spec (acv, syntax_help,
                  put_node, last_node, aux_node, cnt_tabs); (* PTS 1138343 D.T. *)
        (*ENDIF*) 
        in_tablist := (sc_symb = s_comma);
        IF  (sc_symb = s_identifier)
        THEN
            (* check for CROSS | INNER | (LEFT|RIGHT|FULL) [OUTER] JOIN *)
            ak60check_join_syntax(acv, outer_type, in_tablist, on_clause_expected);
        (*ENDIF*) 
        WHILE (a_returncode = 0) AND in_tablist DO
            BEGIN
            a01_next_symbol (acv);
&           ifdef TRACE
            t01int4 (ak_syn, '************', put_node);
            t01int4 (ak_syn, 'put_node  02', put_node);
            t01int4 (ak_syn, 'last_node 02', last_node);
&           endif
            ak60atable_spec (acv, syntax_help,
                  a_ap_tree^[ last_node ].n_sa_level, last_node,
                  aux_node, cnt_tabs); (* PTS 1138343 D.T. *)
&           ifdef TRACE
            t01int4 (ak_syn, '************', put_node);
            t01int4 (ak_syn, 'put_node  03', put_node);
            t01int4 (ak_syn, 'last_node 03', last_node);
&           endif
            IF  on_clause_expected
            THEN
                BEGIN
                (* check for ON ...*)
                IF  _continue (* PTS 1138343 D.T. *)
                THEN
                    last_node := a63_node;
                (*ENDIF*) 
                ak60on_clause (acv, a_ap_tree^[ last_node ].n_sa_level,
                      last_node, aux_node, outer_type, cnt_tabs);
                END;
&           ifdef TRACE
            (*ENDIF*) 
            t01int4 (ak_syn, '************', put_node);
            t01int4 (ak_syn, 'last_node 04', last_node);
            t01int4 (ak_syn, ' aux_node 04', aux_node);
&           endif
            in_tablist := (sc_symb = s_comma);
            on_clause_expected := false; (* PTS 1119500 *)
            IF  (sc_symb = s_identifier)
            THEN
                (* check for CROSS | INNER | (LEFT|RIGHT|FULL) [OUTER] JOIN *)
                ak60check_join_syntax(acv, outer_type, in_tablist, on_clause_expected);
            (*ENDIF*) 
            END;
        (*ENDWHILE*) 
        IF  (a_comp_type = at_odbc) AND (odbc_partype <> no_odbc)
        THEN
            BEGIN
            IF  a01_odbc_end_ok (acv, odbc_partype)
            THEN
                a01_next_symbol (acv)
            ELSE
                a07_error (acv, e_missing_keyword,
                      put_node, last_node)
            (*ENDIF*) 
            END
        (*ENDIF*) 
        END;
    (*ENDIF*) 
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
FUNCTION
      ak60is_join_syntax (
            VAR acv         : tak_all_command_glob) : boolean;
 
VAR
      scvh         : tak_scanner_glob;
      is_join_syn  : boolean;
 
BEGIN
WITH acv DO
    BEGIN
    is_join_syn := false;
    scvh        := a_scv;
    IF  a01_eqkey (a01kw [cak_i_inner], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv) OR
        a01_eqkey (a01kw [cak_i_cross], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv)
    THEN
        a01_next_symbol (acv)
    ELSE
        IF  a01_eqkey (a01kw [cak_i_left], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv) OR
            a01_eqkey (a01kw [cak_i_right], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv) OR
            a01_eqkey (a01kw [cak_i_full], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv)
        THEN
            BEGIN
            a01_next_symbol (acv);
            IF  a01_eqkey (a01kw [cak_i_outer], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv)
            THEN
                a01_next_symbol (acv);
            (*ENDIF*) 
            END;
        (*ENDIF*) 
    (*ENDIF*) 
    IF  a01_eqkey (a01kw [cak_i_join], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv)
    THEN
        is_join_syn := true;
    (*ENDIF*) 
    a_scv := scvh;
    ak60is_join_syntax := is_join_syn;
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60check_join_syntax (
            VAR acv         : tak_all_command_glob;
            VAR outer_type  : tsp00_Int2;
            VAR is_join_syn : boolean;
            VAR with_on     : boolean);
 
VAR
      scvh            : tak_scanner_glob;
 
BEGIN
WITH acv DO
    BEGIN
    is_join_syn := true;
    with_on     := true;
    scvh        := a_scv;
    outer_type  := cak_is_undefined;
    IF  a01_eqkey (a01kw [cak_i_inner], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv)
    THEN
        BEGIN
        a01_next_symbol (acv);
        END
    ELSE
        IF  a01_eqkey (a01kw [cak_i_left], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv) OR
            a01_eqkey (a01kw [cak_i_right], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv) OR
            a01_eqkey (a01kw [cak_i_full], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv)
        THEN
            BEGIN
            IF  a01_eqkey (a01kw [cak_i_left], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv)
            THEN
                outer_type := cak_x_left_outer_join;
            (*ENDIF*) 
            IF  a01_eqkey (a01kw [cak_i_right], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv)
            THEN
                outer_type := cak_x_right_outer_join;
            (*ENDIF*) 
            IF  a01_eqkey (a01kw [cak_i_full], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv)
            THEN
                outer_type := cak_x_full_outer_join;
            (*ENDIF*) 
            a01_next_symbol (acv);
            IF  a01_eqkey (a01kw [cak_i_outer], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv)
            THEN
                a01_next_symbol (acv);
            (*ENDIF*) 
            END
        ELSE
            IF  a01_eqkey (a01kw [cak_i_cross], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv)
            THEN
                BEGIN
                with_on := false;
                a01_next_symbol (acv);
                END;
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    IF  NOT a01_eqkey (a01kw [cak_i_join], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv)
    THEN
        BEGIN
        a_scv       := scvh;
        is_join_syn := false;
        END;
&   ifdef trace
    (*ENDIF*) 
    t01int4 (ak_syn, 'outer type  ', outer_type);
&   endif
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60on_clause (
            VAR acv         : tak_all_command_glob;
            VAR put_node    : tsp00_Int2;
            VAR last_node   : tsp00_Int2;
            VAR last_n      : tsp00_Int2;
            outer_type      : tsp00_Int2;
            acttab          : tsp00_Int2);
 
VAR
      h_cpt             : tak_cmd_part_type;
      last_table_n      : tsp00_Int2;
      info_n            : tsp00_Int2;
 
BEGIN
WITH acv DO
    BEGIN
    info_n       := 0;
    last_table_n := last_n;
    IF  (a_scv.sc_symb = s_identifier) AND
        a01_eqkey (a01kw [cak_i_on], a_sqlmode, a_cmd_part^.sp1p_buf, a_scv)
    THEN
        BEGIN
        a01_next_symbol (acv);
        h_cpt := a_cpart_type;
        a_cpart_type := cpt_in_where_clause;
        a01info_call_put (acv, a63, cak_x_search_condition, put_node, info_n);
        last_node := put_node;
        a63_asearch_condition (acv, a_ap_tree^[ put_node ].n_lo_level, last_n);
        IF  info_n > 0
        THEN
            IF  g01unicode
            THEN
                a_ap_tree^[info_n].n_length := a_scv.sc_lastpos -
                      a_ap_tree^[info_n].n_pos + 2
            ELSE
                a_ap_tree^[info_n].n_length := a_scv.sc_lastpos -
                      a_ap_tree^[info_n].n_pos + 1;
            (*ENDIF*) 
        (*ENDIF*) 
        a_cpart_type := h_cpt;
&       ifdef trace
        t01aptree (ak_syn, a_ap_tree^, a_scv_index, a_first_hint_node);
        t01int4 (ak_syn, 'last_n bcto ', last_n);
&       endif
        IF  (a_returncode = 0) AND
            (outer_type <> cak_is_undefined)
        THEN
            ak60change_to_outer (acv,
                  a_ap_tree^[ put_node ].n_lo_level,
                  outer_type, acttab, last_table_n);
        (*ENDIF*) 
        END
    ELSE
        a07_kw_put_error (acv, e_wanted_keyword, acv.a_scv.sc_sypos, cak_i_on);
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60atable_spec (
            VAR acv         : tak_all_command_glob;
            VAR syntax_help : ak60syntax_helptype; (* PTS 1138343 D.T. *)
            VAR put_node    : tsp00_Int2;
            VAR last_node   : tsp00_Int2;
            VAR last_n      : tsp00_Int2;
            VAR cnt_tabs    : integer);
 
VAR
      indkey               : integer;
      pos                  : integer;
      curr_n               : tsp00_Int2;
      new_n                : tsp00_Int2;
      help_n               : tsp00_Int2; (* PTS 1138343 D.T. *)
      lo_n                 : tsp00_Int2; (* PTS 1138343 D.T. *)
      sa_n                 : tsp00_Int2; (* PTS 1138343 D.T. *)
      i_n                  : tsp00_Int2; (* PTS 1138343 D.T. *)
      as_found             : boolean;
      res_kw               : boolean;
      old_a_from_select    : boolean; (* PTS 1138343 D.T. *)
 
BEGIN
indkey := cak_i_no_keyword;
WITH acv, a_scv DO
    IF  a_returncode = 0
    THEN
        BEGIN
        IF  (sc_symb = s_leftpar) AND
            (a_sqlmode in [ sqlm_internal, sqlm_oracle ])
        THEN
            BEGIN
            a_leftpar_cnt := succ (a_leftpar_cnt);
            a01_next_symbol (acv);
            a01_get_keyword (acv, indkey, res_kw);
            a01_call_put (acv, a66, cak_x_select_in_from_part, curr_n);
            old_a_from_select := a_from_select; (* PTS 1138343 D.T. *)
            a_from_select := true;
            a_fromsel_n   := succ (a_fromsel_n);
            (* *** ID for fromselect *** *)
            a_ap_tree^[ curr_n ].n_pos := a_fromsel_n;
            IF  NOT (qcn_ContainsSJFromSelect in a_ap_tree^[ a_select_node ].n_querycheck)
                (* PTS 1138343 D.T. *)
            THEN
                BEGIN
                a01_call_put (acv, a92fromsel, curr_n, new_n);
                ak60put_new_sub_select_node (a_ap_tree^, a_select_node,
                      new_n, a_leftpar_cnt - a_rightpar_cnt);
                END
            ELSE
                BEGIN
                new_n := cak_is_undefined;
                END;
            (*ENDIF*) 
            IF  ( new_n>0 ) (* PTS 1138343 D.T. *)
            THEN
                a_ap_tree^[ new_n ].n_pos := curr_n;
            (*ENDIF*) 
            put_node  := curr_n;
            last_node := curr_n;
            a60_aquery_spec (acv, NOT c_stamp_allowed, true,
                  a_ap_tree^[ curr_n ].n_lo_level, last_n, curr_n, false);
            (* PTS 1138343 D.T. *)
            help_n := a_ap_tree^[ curr_n ].n_lo_level;
            IF  ((a_ap_tree^[ help_n ].n_proc = a66) AND
                (a_ap_tree^[ help_n ].n_subproc = cak_x_table_spec))
            THEN
                BEGIN
                (* remove previously added node              *)
                (* this node may got children meanwhile !    *)
                (* maybe we could change order to avoid that *)
                a_from_select := old_a_from_select;
                a_fromsel_n   := pred (a_fromsel_n);
                IF  ((a_ap_tree^[ help_n ].n_proc = a66) AND
                    (a_ap_tree^[ help_n ].n_subproc = cak_x_table_spec))
                THEN
                    BEGIN
                    a_ap_tree^[ curr_n ] := a_ap_tree^[ help_n ];
                    a_ap_tree^[ curr_n ].n_subproc := cak_x_table_spec;
                    a_ap_tree^[ curr_n ].n_length   := 0;
                    a_ap_tree^[ help_n ].n_proc     := no_proc;
                    a_ap_tree^[ help_n ].n_subproc  := 0;
                    a_ap_tree^[ help_n ].n_pos      := 0;
                    a_ap_tree^[ help_n ].n_length   := 0;
                    a_ap_tree^[ help_n ].n_lo_level := 0;
                    END;
                (*ENDIF*) 
                IF  ( new_n>0 ) (* PTS 1138343 D.T. *)
                THEN
                    BEGIN
                    help_n := a_ap_tree^[ new_n ].n_refback;
                    sa_n   := a_ap_tree^[ new_n ].n_sa_level;
                    lo_n   := a_ap_tree^[ new_n ].n_lo_level;
                    IF  ( a_ap_tree^[help_n].n_sa_level = new_n )
                    THEN
                        IF  ( lo_n > 0 )
                        THEN
                            a_ap_tree^[help_n].n_sa_level := lo_n
                        ELSE
                            BEGIN
                            a_ap_tree^[help_n].n_sa_level := sa_n;
                            IF  ( sa_n>0 )
                            THEN
                                a_ap_tree^[sa_n].n_refback := help_n;
                            (*ENDIF*) 
                            END
                        (*ENDIF*) 
                    ELSE
                        BEGIN
                        IF  ( lo_n > 0 )
                        THEN
                            a_ap_tree^[help_n].n_lo_level := lo_n
                        ELSE
                            BEGIN
                            a_ap_tree^[help_n].n_lo_level := sa_n;
                            IF  ( sa_n>0 )
                            THEN
                                a_ap_tree^[sa_n].n_refback := help_n;
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    IF  ( lo_n > 0 )
                    THEN
                        BEGIN
                        a_ap_tree^[lo_n].n_refback := help_n;
                        IF  ( sa_n > 0 )
                        THEN
                            BEGIN
                            i_n := lo_n;
                            WHILE a_ap_tree^[i_n].n_sa_level > 0 DO
                                BEGIN
                                i_n := a_ap_tree^[i_n].n_sa_level;
                                END;
                            (*ENDWHILE*) 
                            a_ap_tree^[i_n].n_sa_level := sa_n;
                            a_ap_tree^[sa_n].n_refback := i_n;
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    a_ap_tree^[ new_n ].n_proc    := no_proc;
                    a_ap_tree^[ new_n ].n_subproc := 0;
                    a_ap_tree^[ new_n ].n_pos     := 0;
                    a_ap_tree^[ new_n ].n_length  := 0;
                    a_ap_tree^[ new_n ].n_sa_level:= 0;
                    a_ap_tree^[ new_n ].n_lo_level:= 0;
                    a_ap_tree^[ new_n ].n_refback := -1;
                    END;
                (*ENDIF*) 
                END
            ELSE
                BEGIN
                last_n := a_ap_tree^[ put_node ].n_lo_level;
                (* PTS 1114017 E.Z. *)
                (* subqueries of first union_part are below new_node *)
                (* they have to be at the a631, -2-node.n_sa_level   *)
                IF  ( new_n>0 ) (* PTS 1138343 D.T. *)
                THEN
                    BEGIN
                    pos := a_ap_tree^[ put_node ].n_lo_level;
                    IF  (a_ap_tree^[ new_n ].n_lo_level > 0) AND
                        (a_ap_tree^[ pos ].n_proc = a63)   AND
                        (a_ap_tree^[ pos ].n_subproc = cak_x_start_union)
                    THEN
                        BEGIN
                        REPEAT
                            pos := a_ap_tree^[ pos ].n_lo_level
                        UNTIL
                            (a_ap_tree^[ pos ].n_proc = a63query_spec) AND
                            (a_ap_tree^[ pos ].n_subproc = cak_is_undefined);
                        (*ENDREPEAT*) 
                        a_ap_tree^[ pos ].n_sa_level := a_ap_tree^[ new_n ].n_lo_level;
                        a_ap_tree^[ new_n ].n_lo_level := 0
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            IF  a_scv.sc_symb = s_rightpar (* PTS 1138343 D.T. *)
            THEN
                BEGIN
                a_rightpar_cnt := succ (a_rightpar_cnt);
                a01_next_symbol (acv)
                END
            ELSE
                BEGIN
                a60build_special_fromselect(acv, syntax_help, curr_n);
                a01_force_symbol (acv, s_rightpar,
                      put_node, put_node);
                a_rightpar_cnt := succ (a_rightpar_cnt);
                END
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            a01_call_put (acv, a66, cak_x_table_spec, curr_n);
            put_node  := curr_n;
            last_node := curr_n;
            a02_atablename  (acv,
                  a_ap_tree^[ curr_n ].n_lo_level, last_n);
            curr_n := last_node;
            END;
        (*ENDIF*) 
        IF  (sc_symb  = s_identifier) AND
            (a_returncode = 0)
        THEN
            BEGIN
            (* PTS 1122678 E.Z. *)
            as_found := false;
            a01_get_keyword (acv, indkey, res_kw);
            IF  indkey = cak_i_as
            THEN
                BEGIN
                as_found := true;
                a01_next_symbol (acv);
                a01_get_keyword (acv, indkey, res_kw);
                END;
            (*ENDIF*) 
            IF  (sc_symb  = s_identifier)
                AND
                (NOT res_kw OR
                (
                (* for Oracle-systemviews with INTERNAL, although INTERNAL is no keyword *)
                (a_initial_segment_header.sp1c_producer in
                [sp1pr_internal_cmd, sp1pr_installation]) AND
                a01_eqkey (a01kw[ cak_i_internal ], sqlm_internal,
                a_cmd_part^.sp1p_buf, a_scv) AND
                (acv.a_sqlmode = sqlm_oracle)
                )
                )
                AND
                ((a_sqlmode <> sqlm_db2) OR (indkey = cak_i_no_keyword))
            THEN
                BEGIN
                IF  NOT ak60is_join_syntax (acv)
                THEN
                    BEGIN
                    a02_put_identifier (acv,
                          a_ap_tree^[ last_n ].n_sa_level, last_n);
                    as_found := false
                    END
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            IF  as_found
            THEN
                a07_error (acv, e_missing_identifier,
                      put_node, last_node);
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        cnt_tabs := succ(cnt_tabs);
        END;
    (*ENDIF*) 
(*ENDWITH*) 
END; { ak60atable_spec }
 
(*------------------------------*) 
 
PROCEDURE
      ak60change_to_outer (
            VAR acv    : tak_all_command_glob;
            curr_node  : tsp00_Int2;
            outer_type : tsp00_Int2;
            acttab     : tsp00_Int2;
            last_tab_n : tsp00_Int2);
 
VAR
      l_result : tsp00_LcompResult;
 
BEGIN
WITH acv, a_scv DO
    BEGIN
&   ifdef TRACE
    t01int4 (ak_syn, 'outer type  ', outer_type);
    t01int4 (ak_syn, 'curr_node   ', curr_node);
    t01int4 (ak_syn, 'last_tab_n  ', last_tab_n);
&   endif
    IF  (a_ap_tree^[ curr_node ].n_lo_level <> 0)
    THEN
        ak60change_to_outer (acv,
              a_ap_tree^[ curr_node ].n_lo_level,
              outer_type, acttab, last_tab_n);
    (*ENDIF*) 
    IF  (a_ap_tree^[ curr_node ].n_sa_level <> 0)
    THEN
        ak60change_to_outer (acv,
              a_ap_tree^[ curr_node ].n_sa_level,
              outer_type, acttab, last_tab_n);
    (*ENDIF*) 
    IF  (a_ap_tree^[ curr_node ].n_proc = a64) AND
        ((a_ap_tree^[ curr_node ].n_subproc in [cak_x_predicate, cak_x_in_pred,
        cak_x_between_pred, cak_x_like_pred] ) OR
        (a_ap_tree^[ curr_node ].n_subproc = cak_x_left_outer_join)  OR
        (a_ap_tree^[ curr_node ].n_subproc = cak_x_right_outer_join))
    THEN
        BEGIN
&       ifdef TRACE
        t01int4 (ak_syn, 'curr_node   ', curr_node);
        t01int4 (ak_syn, 'last_tab_n  ', last_tab_n);
&       endif
        a_outer_join := true;
        WITH a_ap_tree^[ a_ap_tree^[ curr_node ].n_lo_level ] DO
            s30cmp (a_cmd_part^.sp1p_buf, a_ap_tree^[ last_tab_n ].n_pos,
                  a_ap_tree^[ last_tab_n ].n_length, a_cmd_part^.sp1p_buf,
                  n_pos, n_length, l_result);
        (*ENDWITH*) 
&       ifdef TRACE
        t01moveobj (ak_syn, a_cmd_part^.sp1p_buf,
              a_ap_tree^[ last_tab_n ].n_pos,
              a_ap_tree^[ last_tab_n ].n_pos +
              a_ap_tree^[ last_tab_n ].n_length - 1);
        WITH a_ap_tree^[ a_ap_tree^[ curr_node ].n_lo_level ] DO
            t01moveobj (ak_syn, a_cmd_part^.sp1p_buf, n_pos, n_pos + n_length - 1);
        (*ENDWITH*) 
        CASE l_result OF
            l_equal :
                t01int4 (ak_syn, 'left = right', 1);
            l_less :
                t01int4 (ak_syn, 'left < right', 1);
            l_greater :
                t01int4 (ak_syn, 'left > right', 1);
            l_undef :
                t01int4 (ak_syn, 'undefined   ', 1);
            END;
        (*ENDCASE*) 
        { CASE }
&       endif
        WITH a_ap_tree^[ curr_node ] DO
            BEGIN
            (* mark acttab and outer type in syntax node see ak65predicate *)
            n_length := acttab;
            n_pos    := outer_type;
            CASE outer_type OF
                cak_x_left_outer_join:
                    BEGIN
                    IF  l_result = l_equal
                    THEN
                        ak60_put_outer (n_subproc, cak_x_left_outer_join)
                    ELSE
                        ak60_put_outer (n_subproc, cak_x_right_outer_join);
                    (*ENDIF*) 
                    END;
                cak_x_right_outer_join:
                    BEGIN
                    IF  l_result = l_equal
                    THEN
                        ak60_put_outer (n_subproc, cak_x_right_outer_join)
                    ELSE
                        ak60_put_outer (n_subproc, cak_x_left_outer_join);
                    (*ENDIF*) 
                    END;
                cak_x_full_outer_join:
                    ak60_put_outer (n_subproc, cak_x_full_outer_join);
                END;
            (*ENDCASE*) 
            END;
        (*ENDWITH*) 
        END;
    (*ENDIF*) 
    END
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60_put_outer (
            VAR subproc : tsp00_Int2;
            outer_type : tsp00_Int2);
 
BEGIN
CASE outer_type OF
    cak_x_left_outer_join:
        BEGIN
        IF  subproc = cak_x_right_outer_join
        THEN
            subproc := cak_x_full_outer_join
        ELSE
            subproc := outer_type;
        (*ENDIF*) 
        END;
    cak_x_right_outer_join:
        BEGIN
        IF  subproc = cak_x_left_outer_join
        THEN
            subproc := cak_x_full_outer_join
        ELSE
            subproc := outer_type;
        (*ENDIF*) 
        END;
    OTHERWISE:
        subproc := outer_type;
    END;
(*ENDCASE*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60move_join_node (
            VAR acv      : tak_all_command_glob;
            select_node  : tsp00_Int2;
            from_node    : tsp00_Int2;
            where_node   : tsp00_Int2);
 
VAR
      curr_n    : tsp00_Int2;
      _join_root : tsp00_Int2;
      _join_n    : tsp00_Int2;
 
BEGIN
WITH acv, a_scv DO
    BEGIN
&   ifdef TRACE
    t01int4 (ak_syn, 'before mv oj', 1);
    t01int4 (ak_syn, 'a_select_n  ', select_node);
    t01int4 (ak_syn, 'from_n      ', from_node);
    t01int4 (ak_syn, 'where_n     ', where_node);
    t01aptree (ak_syn, a_ap_tree^, a_scv_index, a_first_hint_node);
&   endif
    (* start at from node and search outer join part *)
    curr_n := a_ap_tree^[ from_node ].n_lo_level;
    WHILE ( curr_n <> 0)  DO
        BEGIN
        _join_n     := 0;
        _join_root  := curr_n;
        WHILE NOT ((a_ap_tree^[ curr_n ].n_proc = a63) AND
              (a_ap_tree^[ curr_n ].n_subproc = cak_x_search_condition))
              AND (a_ap_tree^[ curr_n ].n_sa_level <> 0)  DO
            BEGIN
            _join_root := curr_n;
            curr_n  := a_ap_tree^[ curr_n ].n_sa_level;
            END;
        (*ENDWHILE*) 
        IF  (a_ap_tree^[ curr_n ].n_proc = a63) AND
            (a_ap_tree^[ curr_n ].n_subproc = cak_x_search_condition)
        THEN
            _join_n := curr_n;
        (*ENDIF*) 
        curr_n := a_ap_tree^[ curr_n ].n_sa_level;
&       ifdef TRACE
        t01int4 (ak_syn, '_join_root  ', _join_root);
        t01int4 (ak_syn, '_join_n     ', _join_n);
        t01int4 (ak_syn, 'curr_n      ', curr_n);
&       endif
        IF  _join_n <> 0
        THEN
            BEGIN
            a_ap_tree^[ _join_root ].n_sa_level := a_ap_tree^[ _join_n ].n_sa_level;
            IF  where_node <> 0
            THEN
                BEGIN
                a_ap_tree^[ a_ap_tree^[ _join_n ].n_lo_level ].n_sa_level :=
                      a_ap_tree^[ where_node ].n_lo_level;
                a_ap_tree^[ where_node ].n_lo_level := _join_n;
                WITH a_ap_tree^[ _join_n ] DO
                    BEGIN
                    n_proc     := a64;
                    n_subproc  := cak_x_and_operator;
                    n_special  := [ ];
                    n_symb     := s_and;
                    n_length   := 0;
                    n_datatype := dunknown;
                    n_sa_level := 0;
                    END;
                (*ENDWITH*) 
                END
            ELSE
                BEGIN
                a_ap_tree^[ _join_n ].n_sa_level :=
                      a_ap_tree^[ from_node ].n_sa_level;
                a_ap_tree^[ from_node ].n_sa_level := _join_n;
                where_node := _join_n;
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDWHILE*) 
&   ifdef TRACE
    t01int4 (ak_syn, 'a_select_n  ', select_node);
    t01int4 (ak_syn, 'from_n      ', from_node);
    t01int4 (ak_syn, 'where_n     ', where_node);
    t01aptree (ak_syn, a_ap_tree^, a_scv_index, a_first_hint_node);
    t01int4 (ak_syn, 'after mv oj ', 1);
&   endif
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60put_new_sub_select_node (
            VAR a_ap_tree : tak_ap_max_tree;
            sel_n    : tsp00_Int2;
            new_node : tsp00_Int2;
            level_no : tsp00_Int2);
 
VAR
      curr_sel_n : tsp00_Int2;
      curr_level : tsp00_Int2;
 
BEGIN
&IFDEF TRACE
t01int4 (ak_sem, 'sel_n       ', sel_n);
t01int4 (ak_sem, 'new_node    ', new_node);
t01int4 (ak_sem, 'level_no    ', level_no);
curr_level := 0;
&ENDIF
(* PTS 1122056 E.Z. *)
IF  sel_n > 0
THEN
    IF  NOT (qcn_ContainsSJFromSelect in a_ap_tree[ sel_n ].n_querycheck) (* PTS 1138343 D.T. *)
    THEN
        BEGIN
        IF  (level_no > 0)
        THEN
            BEGIN
            WHILE (a_ap_tree [ sel_n ].n_sa_level > 0) DO
                sel_n := a_ap_tree [ sel_n ].n_sa_level;
            (*ENDWHILE*) 
&           IFDEF TRACE
            t01int4 (ak_sem, 'sel_n      0', sel_n);
&           ENDIF
            IF  (level_no = 1)
            THEN
                BEGIN
                a_ap_tree [ sel_n    ].n_sa_level := new_node;
                a_ap_tree [ new_node ].n_refback  := sel_n (* PTS 1138343 D.T. *)
                END
            ELSE
                BEGIN
                curr_sel_n := sel_n;
                curr_level := 2;
                WHILE curr_level < level_no DO
                    BEGIN
                    WHILE (curr_level < level_no)                   AND
                          (a_ap_tree [ curr_sel_n ].n_lo_level > 0) AND
                          (a_ap_tree [ curr_sel_n ].n_sa_level = 0) DO
                        BEGIN
                        curr_sel_n := a_ap_tree [ curr_sel_n ].n_lo_level;
                        curr_level := succ (curr_level);
                        END;
                    (*ENDWHILE*) 
&                   IFDEF TRACE
                    t01int4 (ak_sem, 'sel_n      1', curr_sel_n);
                    t01int4 (ak_sem, 'new_node   1', new_node);
                    t01int4 (ak_sem, 'level_no   1', level_no);
                    t01int4 (ak_sem, 'curr_level 1', curr_level);
&                   ENDIF
                    WHILE (a_ap_tree [ curr_sel_n ].n_sa_level > 0) DO
                        curr_sel_n := a_ap_tree [ curr_sel_n ].n_sa_level;
                    (*ENDWHILE*) 
&                   IFDEF TRACE
                    t01int4 (ak_sem, 'sel_n      1', curr_sel_n);
                    t01int4 (ak_sem, 'new_node   1', new_node);
                    t01int4 (ak_sem, 'level_no   1', level_no);
                    t01int4 (ak_sem, 'curr_level 1', curr_level);
&                   ENDIF
                    END;
                (*ENDWHILE*) 
                IF  (curr_level = level_no)
                THEN
                    BEGIN
                    IF  (a_ap_tree [ curr_sel_n ].n_lo_level <= 0)
                    THEN
                        BEGIN
                        a_ap_tree [ curr_sel_n ].n_lo_level := new_node;
                        a_ap_tree [ new_node   ].n_refback  := curr_sel_n; (* PTS 1138343 D.T. *)
                        END
                    ELSE
                        BEGIN
                        curr_sel_n := a_ap_tree [ curr_sel_n ].n_lo_level;
                        WHILE (a_ap_tree [ curr_sel_n ].n_sa_level > 0) DO
                            curr_sel_n := a_ap_tree [ curr_sel_n ].n_sa_level;
                        (*ENDWHILE*) 
                        a_ap_tree [ curr_sel_n ].n_sa_level := new_node;
                        a_ap_tree [ new_node   ].n_refback  := curr_sel_n (* PTS 1138343 D.T. *)
                        END;
                    (*ENDIF*) 
                    END
                (*ENDIF*) 
                END;
            (*ENDIF*) 
&           IFDEF TRACE
            t01int4 (ak_sem, 'sel_n       ', sel_n);
            t01int4 (ak_sem, 'new_node    ', new_node);
            t01int4 (ak_sem, 'level_no    ', level_no);
            t01int4 (ak_sem, 'curr_level  ', curr_level);
&           ENDIF
            END
        ELSE
            BEGIN
            WHILE (a_ap_tree [ sel_n ].n_sa_level > 0) DO
                sel_n := a_ap_tree [ sel_n ].n_sa_level;
            (*ENDWHILE*) 
            a_ap_tree [ sel_n    ].n_sa_level := new_node;
            a_ap_tree [ new_node ].n_refback  := sel_n; (* PTS 1138343 D.T. *)
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60select_column (
            VAR acv       : tak_all_command_glob;
            stamp_allowed : boolean;
            VAR put_node  : tsp00_Int2;
            VAR last_node : tsp00_Int2);
 
VAR
      as_found        : boolean;
      index           : integer;
      curr_n          : tsp00_Int2;
      old_curr_n      : tsp00_Int2;
      ref_n           : tsp00_Int2;
      info_node       : tsp00_Int2;
      last_pos        : integer;
      scvh            : tak_scanner_glob;
      scvh1           : tak_scanner_glob;
      res_kw          : boolean;
      refname_allowed : boolean;
 
BEGIN
WITH acv, a_scv DO
    IF  a_returncode = 0
    THEN
        BEGIN
        refname_allowed := true;
        a01info_call_put (acv, a60, cak_x_select_column,
              curr_n, info_node);
        put_node  := curr_n;
        last_node := curr_n;
        IF  (sc_symb               = s_point) AND
            (acv.a_qualified_jv_upd <> no_jv_upd)
        THEN
            BEGIN
            a01_put_node (acv, a_ap_tree^[ curr_n ].n_lo_level);
            a01_next_symbol (acv);
            last_pos := sc_lastpos; (* PTS 1113725, T.A. *)
            END
        ELSE
            IF  sc_symb = s_asterisk
            THEN
                BEGIN
                a01_put_node (acv, a_ap_tree^[ curr_n ].n_lo_level);
                a01_next_symbol (acv);
                last_pos := sc_lastpos; (* PTS 1113725, T.A. *)
                END
            ELSE
                BEGIN
                old_curr_n := curr_n;
                IF  sc_symb <> s_identifier
                THEN
                    a63_avalue_expression (acv,
                          a_ap_tree^[ curr_n ].n_lo_level, curr_n)
                ELSE
                    BEGIN
                    scvh      := a_scv;
                    a01_next_symbol (acv);
                    IF  sc_symb = s_point
                    THEN
                        BEGIN
                        a01_next_symbol (acv);
                        IF  ((sc_symb <> s_identifier) AND
                            (a_sqlmode = sqlm_ansi))
                        THEN
                            a07_error (acv, e_missing_identifier,
                                  put_node, last_node);
                        (*ENDIF*) 
                        IF  sc_symb = s_asterisk
                        THEN
                            BEGIN
                            refname_allowed := false;
                            scvh1   := a_scv;
                            a_scv   := scvh;
                            sc_symb := s_tablename;
                            a01_put_node (acv, a_ap_tree^[ curr_n ].n_lo_level);
                            curr_n := a_ap_tree^[ curr_n ].n_lo_level;
                            a_scv  := scvh1;
                            a01_put_node (acv, a_ap_tree^[ curr_n ].n_sa_level);
                            a01_next_symbol (acv)
                            END
                        ELSE
                            BEGIN
                            a01_next_symbol (acv);
                            IF  sc_symb = s_point
                            THEN
                                BEGIN
                                a01_next_symbol (acv);
                                IF  sc_symb = s_asterisk
                                THEN
                                    BEGIN
                                    refname_allowed := false;
                                    a_scv := scvh;
                                    a02_atablename (acv, a_ap_tree^[ curr_n ].
                                          n_lo_level, curr_n);
                                    a01_next_symbol (acv);
                                    a01_put_node (acv, a_ap_tree^[ curr_n ].n_sa_level);
                                    a01_next_symbol (acv)
                                    END
                                ELSE
                                    BEGIN
                                    a_scv := scvh;
                                    a63_avalue_expression (acv,
                                          a_ap_tree^[ curr_n ].n_lo_level, curr_n)
                                    END
                                (*ENDIF*) 
                                END
                            ELSE
                                BEGIN
                                a_scv := scvh;
                                a63_avalue_expression (acv,
                                      a_ap_tree^[ curr_n ].n_lo_level, curr_n)
                                END
                            (*ENDIF*) 
                            END
                        (*ENDIF*) 
                        END
                    ELSE
                        BEGIN
                        a_scv          := scvh;
                        a_special_expr := false;
                        IF  sc_symb = s_identifier
                        THEN
                            IF  (stamp_allowed AND
                                (a_sqlmode = sqlm_internal) AND
                                (a01_eqkey (a01kw[ cak_i_stamp], a_sqlmode,
                                a_cmd_part^.sp1p_buf,
                                a_scv)))
                            THEN
                                BEGIN
                                sc_symb := s_stamp;
                                a01_put_node (acv,
                                      a_ap_tree^[ curr_n ].n_lo_level);
                                a01_next_symbol (acv);
                                curr_n := a_ap_tree^[ curr_n ].n_lo_level
                                END
                            ELSE
                                IF  (stamp_allowed AND
                                    (a_sqlmode = sqlm_internal) AND
                                    (a01_eqkey (a01kw[ cak_i_default], a_sqlmode,
                                    a_cmd_part^.sp1p_buf,
                                    a_scv)))
                                THEN
                                    BEGIN
                                    sc_symb := s_default;
                                    a01_put_node (acv,
                                          a_ap_tree^[ curr_n ].n_lo_level);
                                    a01_next_symbol (acv);
                                    curr_n := a_ap_tree^[ curr_n ].n_lo_level
                                    END
                                ELSE
                                    IF  ((a_sqlmode <> sqlm_internal) AND
                                        ( a_sqlmode <> sqlm_oracle) AND
                                        (* in both sqlmodes it is in a63_avalue_expr *)
                                        (a01_eqkey (a01kw[ cak_i_null], a_sqlmode,
                                        a_cmd_part^.sp1p_buf,
                                        a_scv)))
                                    THEN
                                        BEGIN
                                        sc_symb := s_null;
                                        a01_put_node (acv,
                                              a_ap_tree^[ curr_n ].n_lo_level);
                                        a01_next_symbol (acv);
                                        curr_n := a_ap_tree^[ curr_n ].
                                              n_lo_level
                                        END
                                    ELSE
                                        a63_avalue_expression (acv,
                                              a_ap_tree^[ curr_n ].n_lo_level, curr_n)
                                    (*ENDIF*) 
                                (*ENDIF*) 
                            (*ENDIF*) 
                        ELSE
                            a63_avalue_expression (acv,
                                  a_ap_tree^[ curr_n ].n_lo_level, curr_n)
                        (*ENDIF*) 
                        END
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                last_pos := sc_lastpos; (* PTS 1113725, T.A. *)
                IF  (refname_allowed AND (a_returncode = 0) AND
                    (a_sqlmode <> sqlm_db2))
                THEN
                    IF  sc_symb = s_identifier
                    THEN
                        BEGIN
                        as_found := false;
                        IF  ((a_sqlmode in [sqlm_ansi, sqlm_internal,
                            sqlm_oracle]) AND
                            (a01_eqkey (a01kw[ cak_i_as], a_sqlmode,
                            a_cmd_part^.sp1p_buf, a_scv)))
                        THEN
                            BEGIN
                            as_found := true;
                            a01_next_symbol (acv);
                            IF  sc_symb <> s_identifier
                            THEN
                                a07_error (acv, e_missing_identifier,
                                      put_node, last_node)
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        IF  a_returncode = 0
                        THEN
                            BEGIN
                            a01_get_keyword (acv, index, res_kw);
                            IF  ((index <> cak_i_into) AND
                                (index <> cak_i_from))
                                OR as_found
                            THEN
                                IF  res_kw
                                THEN
                                    a07_error (acv, e_reserved_identifier,
                                          put_node, last_node)
                                ELSE
                                    BEGIN
                                    sc_symb := s_reference_name;
                                    a01_put_node (acv, ref_n);
                                    a_ap_tree^[ ref_n ].n_sa_level :=
                                          a_ap_tree^[ old_curr_n ].n_lo_level;
                                    a_ap_tree^[ old_curr_n ].n_lo_level := ref_n;
                                    a01_next_symbol (acv);
                                    END
                                (*ENDIF*) 
                            (*ENDIF*) 
                            END
                        (*ENDIF*) 
                        END
                    (*ENDIF*) 
                (*ENDIF*) 
                END;
            (*ENDIF*) 
        (*ENDIF*) 
        IF  info_node > 0
        THEN
            IF  g01unicode
            THEN
                a_ap_tree^[info_node].n_length := last_pos - (* PTS 1113725, T.A. *)
                      a_ap_tree^[info_node].n_pos + 2
            ELSE
                a_ap_tree^[info_node].n_length := last_pos - (* PTS 1113725, T.A. *)
                      a_ap_tree^[info_node].n_pos + 1
            (*ENDIF*) 
        (*ENDIF*) 
        END
    (*ENDIF*) 
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60_declare (
            VAR acv        : tak_all_command_glob;
            VAR put_node   : tsp00_Int2;
            VAR result_n   : tsp00_Int2;
            VAR hold_found : boolean);
 
VAR
      _index          : integer;
      _res_kw         : boolean;
 
BEGIN
a01_next_symbol (acv);
IF  acv.a_scv.sc_double_quote = 0
THEN
    a01_get_keyword (acv, _index, _res_kw)
ELSE
    _res_kw := a01_eqkey (a01kw[ cak_i_show], acv.a_sqlmode,
          acv.a_cmd_part^.sp1p_buf, acv.a_scv);
(*ENDIF*) 
IF  _res_kw
THEN
    a07_error (acv, e_reserved_identifier, put_node, put_node)
ELSE
    BEGIN
    IF  acv.a_scv.sc_symb = s_parameter_name
    THEN
        IF  NOT (acv.a_ex_kind in [only_syntax, only_parsing])
        THEN
            a07_error (acv, e_parameter_not_allowed, put_node, put_node)
        ELSE
            a02_aparameter_name (acv, result_n, result_n)
        (*ENDIF*) 
    ELSE
        a02_aresulttablename (acv, result_n, result_n);
    (*ENDIF*) 
    IF  a01mandatory_keyword (acv, cak_i_cursor)
    THEN
        BEGIN
        hold_found := false;
        IF  ((a01_eqkey(a01kw[ cak_i_with], acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv)) AND
            (acv.a_sqlmode = sqlm_db2))
        THEN
            BEGIN
            a01_next_symbol(acv);
            IF  a01mandatory_keyword (acv, cak_i_hold)
            THEN
                hold_found := true;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  NOT a01mandatory_keyword (acv, cak_i_for)
        THEN
            put_node := 0
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a60_adeclare (
            VAR acv      : tak_all_command_glob;
            VAR put_node : tsp00_Int2);
 
VAR
      _curr_n         : tsp00_Int2;
      _last_n         : tsp00_Int2;
      _result_n       : tsp00_Int2;
      _hold_found     : boolean;
      _syntax_help    : ak60syntax_helptype;
 
BEGIN
acv.a_leftpar_cnt  := 0;
acv.a_rightpar_cnt := 0;
acv.a_allow_functions := tf_unknown;
ak60_declare(acv, put_node, _result_n, _hold_found);
IF  acv.a_returncode = 0
THEN
    BEGIN
    IF  a01_eqkey (a01kw[cak_i_call], acv.a_sqlmode,
        acv.a_cmd_part^.sp1p_buf, acv.a_scv)
    THEN (* PTS 1114109, T.A. *)
        a201call_proc (acv, no_odbc, _result_n, put_node)
    ELSE
        BEGIN
        IF  acv.a_return_segm^.sp1r_function_code = csp1_nil_fc
        THEN
            BEGIN
            acv.a_return_segm^.sp1r_function_code := csp1_select_fc;
            IF  acv.a_cmd_segment_header.sp1c_mass_cmd
            THEN
                BEGIN
                acv.a_precomp_info_byte := csp1_p_mselect_found;
                acv.a_return_segm^.sp1r_function_code :=
                      acv.a_return_segm^.sp1r_function_code + csp1_masscmd_fc_offset;
                END
            ELSE
                acv.a_precomp_info_byte := csp1_p_mass_select_found;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        _syntax_help.sh_into_allowed   := ak60is_not_allowed;
        _syntax_help.sh_for_update_allowed := true;
        _syntax_help.sh_stamp_allowed      := false;
        _syntax_help.sh_is_query_spec      := false;
        _syntax_help.sh_is_fromsel         := false; (* PTS 1138343 D.T. *)
        (* PTS 1116169 E.Z. *)
        acv.a_oneval_subq_allowed := true;
        ak60whole_select (acv, put_node, _syntax_help);
        (* PTS 1116169 E.Z. *)
        acv.a_oneval_subq_allowed := false;
        IF  acv.a_returncode = 0
        THEN
            BEGIN
            (* press the result_node into the correct place *)
            _last_n := 0;
            _last_n := acv.a_ap_tree^[ _last_n ].n_lo_level;
            IF  (acv.a_ap_tree^[ _last_n ].n_proc = a63) AND
                (acv.a_ap_tree^[ _last_n ].n_subproc = cak_x_recursive_select)
            THEN
                BEGIN
                _last_n := acv.a_ap_tree^[ _last_n ].n_lo_level; (*collist*)
                _last_n := acv.a_ap_tree^[ _last_n ].n_sa_level; (*'union'start*)
                _last_n := acv.a_ap_tree^[ _last_n ].n_sa_level; (*last select*)
                IF  (acv.a_ap_tree^[ _last_n ].n_proc = a63query_spec) AND
                    (acv.a_ap_tree^[ _last_n ].n_subproc = cak_is_undefined)
                THEN
                    BEGIN
                    acv.a_ap_tree^[ _last_n ].n_proc := a63;
                    acv.a_ap_tree^[ _last_n ].n_subproc := cak_x_mass_select;
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            WHILE ((acv.a_ap_tree^[ _last_n ].n_proc <> a63)              OR
                  ( acv.a_ap_tree^[ _last_n ].n_subproc <> cak_x_mass_select)) AND
                  (acv.a_ap_tree^[ _last_n ].n_proc <> a63query_spec)              DO
                _last_n := acv.a_ap_tree^[ _last_n ].n_lo_level;
            (*ENDWHILE*) 
            IF  acv.a_ap_tree^[ _last_n ].n_proc = a63query_spec
                (* implicit intern_fromselect-inclusion checks sh_is_query_spec ... *)
            THEN
                acv.a_ap_tree^[ _last_n ].n_proc := a63;
            (*ENDIF*) 
            acv.a_ap_tree^[ _last_n ].n_subproc := cak_x_decl_cursor;
            _curr_n := acv.a_ap_tree^[ _last_n ].n_lo_level;
            IF  ((acv.a_ap_tree^[ _curr_n ].n_proc = a63) AND
                ( acv.a_ap_tree^[ _curr_n ].n_subproc = cak_x_distinct))
            THEN
                _last_n := _curr_n;
            (*ENDIF*) 
            acv.a_ap_tree^[ _result_n ].n_sa_level := acv.a_ap_tree^[ _last_n ].n_lo_level;
            acv.a_ap_tree^[ _last_n   ].n_lo_level := _result_n;
            _last_n := _result_n;
            WHILE acv.a_ap_tree^[ _last_n ].n_sa_level > 0 DO
                _last_n := acv.a_ap_tree^[ _last_n ].n_sa_level;
            (*ENDWHILE*) 
            IF  NOT _hold_found
            THEN
                a01_call_put (acv, a63, cak_x_res_delete,
                      acv.a_ap_tree^[ _last_n ].n_sa_level)
            ELSE
                a01_call_put (acv, a63, cak_x_res_no_delete,
                      acv.a_ap_tree^[ _last_n ].n_sa_level);
            (*ENDIF*) 
            a01_is_end_symbol(acv);
            END
        (*ENDIF*) 
        END
    (*ENDIF*) 
    END
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a60_aexplain_statement (
            VAR acv      : tak_all_command_glob;
            VAR put_node : tsp00_Int2);
 
VAR
      _aux_scv        : tak_scanner_glob;
      _syntax_help    : ak60syntax_helptype;
      _index          : tsp00_Int4;
      _dummy_n        : tsp00_Int2;
      _dummy          : boolean;
      _res_kw         : boolean;
 
BEGIN
acv.a_return_segm^.sp1r_function_code := csp1_explain_fc;
_aux_scv := acv.a_scv;
a01_next_symbol (acv);
a01_call_put (acv, a43, cak_x_explain, put_node);
IF  a01_eqkey (a01kw[cak_i_join], acv.a_sqlmode,
    acv.a_cmd_part^.sp1p_buf, acv.a_scv)
THEN
    acv.a_ap_tree^[put_node].n_length := cak_i_join
ELSE
    IF  a01_eqkey (a01kw[cak_i_sequence], acv.a_sqlmode,
        acv.a_cmd_part^.sp1p_buf, acv.a_scv)
    THEN
        acv.a_ap_tree^[put_node].n_length := cak_i_sequence
    ELSE
        IF  a01_eqkey(a01kw[ cak_i_view], acv.a_sqlmode,
            acv.a_cmd_part^.sp1p_buf, acv.a_scv)
        THEN
            BEGIN
            END
        ELSE
            BEGIN
            acv.a_ap_tree^[put_node].n_length := cak_i_no_keyword;
            acv.a_scv := _aux_scv
            END;
        (*ENDIF*) 
    (*ENDIF*) 
(*ENDIF*) 
IF  acv.a_returncode = 0
THEN
    BEGIN
    _aux_scv := acv.a_scv;
    a41show_result_name (acv, acv.a_ap_tree^[ put_node ].n_sa_level);
    IF  acv.a_returncode <> 0
    THEN
        BEGIN
        acv.a_returncode := 0;
        acv.a_errorpos   := 0;
        acv.a_scv := _aux_scv;
        a01_next_symbol (acv);
        END
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  ((acv.a_sqlmode <> sqlm_internal) AND
    (acv.a_sqlmode <> sqlm_oracle)  AND
    NOT ((acv.a_sqlmode = sqlm_db2)
    AND acv.a_cmd_segment_header.sp1c_prepare))  AND
    (acv.a_intern_select_cnt = acv.a_max_intern_select)
THEN
    _syntax_help.sh_into_allowed   := ak60is_needed
ELSE
    _syntax_help.sh_into_allowed   := ak60is_allowed;
(*ENDIF*) 
_syntax_help.sh_for_update_allowed := true;
_syntax_help.sh_stamp_allowed      := false;
_syntax_help.sh_is_query_spec      := false;
_syntax_help.sh_is_fromsel         := false; (* PTS 1138343 D.T. *)
acv.a_leftpar_cnt  := 0;
acv.a_rightpar_cnt := 0;
(* PTS 1116169 E.Z. *)
acv.a_oneval_subq_allowed := true;
a01_get_keyword (acv, _index, _res_kw);
IF  _index = cak_i_declare
THEN
    ak60_declare(acv, put_node, _dummy_n, _dummy);
(*ENDIF*) 
;
ak60whole_select (acv, acv.a_ap_tree^[ put_node ].n_lo_level, _syntax_help);
(* PTS 1116169 E.Z. *)
acv.a_oneval_subq_allowed := false;
a01_is_end_symbol(acv);
END;
 
(*------------------------------*) 
 
PROCEDURE
      a60_aquery_spec (
            VAR acv       : tak_all_command_glob;
            stamp_allowed : boolean;
            from_select   : boolean; (* PTS 1138343 D.T. *)
            VAR put_node  : tsp00_Int2;
            VAR last_node : tsp00_Int2;
            last_n        : tsp00_Int2;   (* PTS 1138343 D.T. *)
            fromselnode_built : boolean); (* PTS 1138343 D.T. *)
 
VAR
      syntax_help    : ak60syntax_helptype;
 
BEGIN
syntax_help.sh_into_allowed       := ak60is_not_allowed;
syntax_help.sh_for_update_allowed := false;
syntax_help.sh_stamp_allowed      := stamp_allowed;
syntax_help.sh_is_query_spec      := true;
syntax_help.sh_is_fromsel         := from_select; (* PTS 1138343 D.T. *)
ak60union_select (acv, put_node, c_outer_level, syntax_help, last_n); (* PTS 1138343 D.T. *)
last_node := put_node;
END;
 
(*------------------------------*) 
 
PROCEDURE
      a60_aselect_statement (
            VAR acv      : tak_all_command_glob;
            VAR put_node : tsp00_Int2);
 
VAR
      syntax_help    : ak60syntax_helptype;
 
BEGIN
IF  ((acv.a_sqlmode <> sqlm_internal) AND
    (acv.a_sqlmode <> sqlm_oracle)  AND
    NOT ((acv.a_sqlmode = sqlm_db2)
    AND acv.a_cmd_segment_header.sp1c_prepare))  AND
    (acv.a_intern_select_cnt = acv.a_max_intern_select)
THEN
    syntax_help.sh_into_allowed   := ak60is_needed
ELSE
    syntax_help.sh_into_allowed   := ak60is_allowed;
(*ENDIF*) 
syntax_help.sh_for_update_allowed := true;
syntax_help.sh_stamp_allowed      := false;
syntax_help.sh_is_query_spec      := false;
syntax_help.sh_is_fromsel         := false; (* PTS 1138343 D.T. *)
acv.a_leftpar_cnt  := 0;
acv.a_rightpar_cnt := 0;
(* 1122398 E.Z. *)
(* upd joinview-function_code should survive *)
IF  acv.a_return_segm^.sp1r_function_code = csp1_nil_fc
THEN
    BEGIN
    acv.a_return_segm^.sp1r_function_code := csp1_select_fc;
    IF  acv.a_cmd_segment_header.sp1c_mass_cmd
    THEN
        acv.a_return_segm^.sp1r_function_code :=
              acv.a_return_segm^.sp1r_function_code + csp1_masscmd_fc_offset;
    (*ENDIF*) 
    END;
(* PTS 1116169 E.Z. *)
(*ENDIF*) 
acv.a_oneval_subq_allowed := true;
ak60whole_select (acv, put_node, syntax_help);
(* PTS 1116169 E.Z. *)
acv.a_oneval_subq_allowed := false;
a01_is_end_symbol(acv);
END;
 
(*------------------------------*) 
 
PROCEDURE
      a60_asub_query (
            VAR acv         : tak_all_command_glob;
            VAR put_node    : tsp00_Int2;
            list_cnt        : integer;
            one_valsubquery : boolean);
 
VAR
      m_limit_allowed         : boolean;
      m_limit_found           : boolean;
      m_limit_node            : tsp00_Int2;
      m_rowno_allowed         : boolean;
      m_rowno_found           : boolean;
      m_allow_functions       : tak_function;
      mcommand                : tak_commandkind;
      new_node                : tsp00_Int2;
      sub_of_new_node         : tsp00_Int2;
      pos                     : integer;
      syntax_help             : ak60syntax_helptype;
 
BEGIN
WITH acv, a_scv DO
    BEGIN
    IF  a_returncode = 0
    THEN
        IF  (a_is_ddl <> no_ddl)               AND
            (a_is_ddl <> ddl_create_view)      AND
            (a_is_ddl <> ddl_create_as_select) AND
            (a_is_ddl <> ddl_create_procedure) AND (* PTS 1107161 *)
            (a_is_ddl <> ddl_create_trigger  ) AND
            (a_is_ddl <> ddl_create_dbfunc   )
        THEN
            a07_error (acv, e_subquery_not_allowed,
                  put_node, put_node)
        ELSE
            IF  sc_symb <> s_leftpar
            THEN
                a07_error (acv, e_missing_keyword, put_node, put_node);
            (* check, if there is enough stack for another *)
            (* call which may call a60_asub_query again... *)
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    IF  g01userstackoverflow
    THEN
        (* stack usage too high to call kb layer *)
        a07_error (acv, e_program_stack_overflow, put_node, put_node);
    (*ENDIF*) 
    IF  a_returncode = 0
    THEN
        BEGIN
        a_leftpar_cnt := succ (a_leftpar_cnt);
        pos            := sc_sypos;
        (* subquery in update/delete or so *)
        IF  a_next_upos = 0
        THEN
            a_next_upos := cak_maxsubcnt_per_level+2;
        (*ENDIF*) 
        mcommand       := a_command_kind;
        a_command_kind := subquery_command;
        IF  NOT (qcn_ContainsSJFromSelect in a_ap_tree^[ a_select_node ].n_querycheck)
        THEN
            BEGIN
            IF  one_valsubquery
            THEN
                a01_call_put (acv, a63, cak_x_one_val_subquery, new_node)
            ELSE
                a01_call_put (acv, a63, cak_x_subquery, new_node);
            (*ENDIF*) 
            IF  a_returncode = 0
            THEN
                IF  a_cpart_type = cpt_in_where_clause
                THEN
                    a_ap_tree^[ new_node ].n_symb := s_where
                ELSE
                    IF  a_cpart_type = cpt_in_having_clause
                    THEN
                        a_ap_tree^[ new_node ].n_symb := s_having
                              (* PTS 1123051 E.Z. *)
                    ELSE
                        IF  a_cpart_type = cpt_in_select_list
                        THEN
                            a_ap_tree^[ new_node ].n_symb := s_select;
&                       ifdef TRACE
                        (*ENDIF*) 
                    (*ENDIF*) 
                (*ENDIF*) 
            (*ENDIF*) 
            t01int4 (ak_sem, 'a_cpart_type', ord(a_cpart_type));
            t01int4 (ak_sem, 'new_node    ', new_node);
            t01int4 (ak_sem, 'n_symb      ',
                  ord(a_ap_tree^[ new_node ].n_symb));
&           endif
            ak60put_new_sub_select_node (a_ap_tree^, a_select_node, new_node,
                  a_leftpar_cnt - a_rightpar_cnt);
            END
        ELSE
            BEGIN
            new_node := cak_is_undefined;
            END;
        (*ENDIF*) 
        a01_next_symbol (acv);
        m_rowno_allowed := a_rowno_allowed;
        m_rowno_found   := a_rowno_found;
        a_rowno_allowed := true;
        a_rowno_found   := false;
        m_limit_allowed := a_limit_allowed;
        a_limit_allowed := true;
        m_limit_found   := a_limit_found;
        a_limit_found   := false;
        m_limit_node    := a_limit_node;
        a_limit_node    := 0;
        (* PTS 1103081 E.Z. *)
        m_allow_functions := a_allow_functions;
        syntax_help.sh_into_allowed   := ak60is_not_allowed;
        syntax_help.sh_for_update_allowed := false;
        syntax_help.sh_stamp_allowed      := false;
        syntax_help.sh_is_query_spec      := true;
        syntax_help.sh_is_fromsel         := false; (* PTS 1138343 D.T. *)
        ak60union_select (acv, put_node, c_outer_level, syntax_help, cak_is_undefined);
        IF  a_returncode = 0
        THEN
            a01_force_symbol (acv, s_rightpar, put_node, put_node);
&       ifdef trace
        (*ENDIF*) 
        t01aptree (ak_syn, a_ap_tree^, a_scv_index, a_first_hint_node);
        t01int4 (ak_syn, 'after union ', put_node);
&       endif
        IF  a_returncode = 0
        THEN
            BEGIN
            IF  a_limit_found
            THEN
                BEGIN
&               ifdef trace
                t01int4 (ak_syn, 'limit found1', put_node);
                t01aptree (ak_syn, a_ap_tree^, a_scv_index, a_first_hint_node);
&               endif
                sub_of_new_node := a_ap_tree^[new_node].n_lo_level;
                a_ap_tree^[new_node].n_lo_level := 0;
                ak60intern_fromsel (acv, put_node, syntax_help, NOT c_for_union);
                IF  (a_returncode = 0) AND
                    (a_ap_tree^[new_node].n_lo_level > 0)
                THEN
                    a_ap_tree^[a_ap_tree^[new_node].n_lo_level].n_lo_level := sub_of_new_node;
&               ifdef trace
                (*ENDIF*) 
                t01int4 (ak_syn, 'limit found2', put_node);
                t01aptree (ak_syn, a_ap_tree^, a_scv_index, a_first_hint_node);
&               endif
                END;
            (*ENDIF*) 
            a_rightpar_cnt := succ (a_rightpar_cnt);
            IF  ( new_node>0 ) (* PTS 1138343 D.T. *)
            THEN
                BEGIN
                WITH a_ap_tree^[ new_node ] DO
                    n_pos := put_node;
                (*ENDWITH*) 
                IF  ni_info_node in a_ap_tree^[put_node].n_special
                THEN
                    BEGIN
                    a_ap_tree^[put_node+1].n_pos    := pos;
                    a_ap_tree^[put_node+1].n_length := sc_lastpos - pos + 1
                    END;
                (* subqueries of first union_part are below new_node *)
                (* they have to be at the a631, -2-node.n_sa_level   *)
                (*ENDIF*) 
                IF  (a_ap_tree^[ new_node ].n_lo_level > 0) AND
                    (a_ap_tree^[ put_node ].n_proc = a63)   AND
                    (a_ap_tree^[ put_node ].n_subproc = cak_x_start_union)
                THEN
                    BEGIN
                    pos := put_node;
                    REPEAT
                        pos := a_ap_tree^[ pos ].n_lo_level
                    UNTIL
                        (a_ap_tree^[ pos ].n_proc = a63query_spec) AND
                        (a_ap_tree^[ pos ].n_subproc = cak_is_undefined);
                    (*ENDREPEAT*) 
                    a_ap_tree^[ pos ].n_sa_level := a_ap_tree^[ new_node ].n_lo_level;
                    a_ap_tree^[ new_node ].n_lo_level := 0
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            a_rowno_allowed := m_rowno_allowed;
            a_rowno_found   := m_rowno_found;
            a_limit_allowed := m_limit_allowed;
            a_limit_found   := m_limit_found;
            a_limit_node    := m_limit_node;
            (* PTS 1103081 E.Z. *)
            a_allow_functions := m_allow_functions;
            ak60put_order_nodes (acv, put_node, list_cnt, one_valsubquery);
            a_command_kind := mcommand;
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60put_order_nodes (
            VAR acv         : tak_all_command_glob;
            start_n         : tsp00_Int2;
            list_cnt        : integer;
            one_valsubquery : boolean);
 
VAR
      insert_order_by : boolean;
      sel_n           : tsp00_Int2;
      scvh            : tak_scanner_glob;
      order_cnt       : integer;
 
BEGIN
WITH acv, a_scv DO
    BEGIN
    insert_order_by := NOT one_valsubquery;
    sel_n     := start_n;
    WHILE (a_ap_tree^[ sel_n ].n_lo_level <> 0) AND
          (NOT ((a_ap_tree^[ sel_n ].n_proc = a60) AND
          (a_ap_tree^[ sel_n ].n_subproc = cak_x_select_list))) DO
        sel_n := a_ap_tree^[ sel_n ].n_lo_level;
    (*ENDWHILE*) 
    WHILE (a_ap_tree^[ sel_n ].n_sa_level <> 0) AND
          (a_ap_tree^[ sel_n ].n_proc <> a92fromsel) DO
        BEGIN
        sel_n := a_ap_tree^[ sel_n ].n_sa_level;
        IF  (a_ap_tree^[ sel_n ].n_proc = a63)                  AND
            ((a_ap_tree^[ sel_n ].n_subproc = cak_x_group_by) OR
            (a_ap_tree^[ sel_n ].n_subproc = cak_x_having))
        THEN
            insert_order_by := true;
        (*ENDIF*) 
        END;
    (*ENDWHILE*) 
    IF  insert_order_by
    THEN
        BEGIN
        (* Let's create a fake order-by clause with *)
        (* all columns from 1 upto 'list_cnt'.      *)
        a01_call_put (acv, a63, cak_x_order,
              a_ap_tree^[ sel_n ].n_sa_level);
        sel_n := a_ap_tree^[ sel_n ].n_sa_level;
        a01_call_put (acv, a63, cak_x_sort_spec,
              a_ap_tree^[ sel_n ].n_lo_level);
        sel_n       := a_ap_tree^[ sel_n ].n_lo_level;
        scvh        := a_scv;
        sc_symb     := s_equal;
        sc_sypos    := 1;
        sc_sylength := 0;
        a01_put_node (acv, a_ap_tree^[ sel_n ].n_lo_level);
        (* DT QueryRewrite *)
        a_ap_tree^[a_ap_tree^[ sel_n ].n_lo_level].n_querycheck :=
              a_ap_tree^[a_ap_tree^[ sel_n ].n_lo_level].n_querycheck + [qcn_FixedPos];
        (* *)
        FOR order_cnt := 2 TO list_cnt DO
            BEGIN
            a01_call_put (acv, a63, cak_x_sort_spec,
                  a_ap_tree^[ sel_n ].n_sa_level);
            sel_n       := a_ap_tree^[ sel_n ].n_sa_level;
            sc_symb     := s_equal;
            sc_sypos    := order_cnt;
            sc_sylength := 0;
            a01_put_node (acv, a_ap_tree^[ sel_n ].n_lo_level);
            (* DT QueryRewrite *)
            a_ap_tree^[a_ap_tree^[ sel_n ].n_lo_level].n_querycheck :=
                  a_ap_tree^[a_ap_tree^[ sel_n ].n_lo_level].n_querycheck + [qcn_FixedPos];
            (* *)
            END;
        (*ENDFOR*) 
        a_scv          := scvh;
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60aupdate_of (
            VAR acv            : tak_all_command_glob;
            VAR curr_n         : tsp00_Int2;
            may_for_update     : boolean;
            VAR update_allowed : boolean);
 
VAR
      scvh   : tak_scanner_glob;
      last_n : tsp00_Int2;
 
BEGIN
WITH acv, a_scv DO
    BEGIN
    scvh := a_scv;
    a01_next_symbol (acv);
    IF  a01_eqkey (a01kw[ cak_i_update], a_sqlmode,
        a_cmd_part^.sp1p_buf, a_scv)
    THEN
        IF  ((a_allow_functions in [ tf_func, tf_func_arith ])
            OR NOT may_for_update)
        THEN
            a07_error (acv, e_update_not_allowed,
                  curr_n, curr_n)
        ELSE
            BEGIN
            CASE a_precomp_info_byte OF
                csp1_p_mass_select_found :
                    a_precomp_info_byte := csp1_p_select_for_update_found;
                csp1_p_mselect_found :
                    a_precomp_info_byte := csp1_p_for_upd_mselect_found;
                csp1_p_reuse_mass_select_found :
                    a_precomp_info_byte := csp1_p_reuse_update_sel_found;
                csp1_p_reuse_mselect_found :
                    a_precomp_info_byte := csp1_p_reuse_upd_mselect_found;
                OTHERWISE
                    BEGIN
                    END
                END;
            (*ENDCASE*) 
            a01_call_put (acv, a63, cak_x_for_update,
                  a_ap_tree^[ curr_n ].n_sa_level);
            curr_n := a_ap_tree^[ curr_n ].n_sa_level;
            a01_next_symbol (acv);
            IF  a01_eqkey (a01kw[ cak_i_of], a_sqlmode,
                a_cmd_part^.sp1p_buf, a_scv)
            THEN
                BEGIN
                a01_next_symbol (acv);
                IF  (a_comp_type = at_odbc) OR (a_comp_type = at_jdbc)
                THEN
                    BEGIN
                    (* columnlist behind 'of' is optional in odbc *)
                    IF  NOT(a01_eqkey (a01kw[ cak_i_with], a_sqlmode,
                        a_cmd_part^.sp1p_buf, a_scv)) AND
                        NOT(a01_eqkey (a01kw[ cak_i_nowait], a_sqlmode,
                        a_cmd_part^.sp1p_buf, a_scv)) AND
                        NOT(a01_eqkey (a01kw[ cak_i_for], a_sqlmode,
                        a_cmd_part^.sp1p_buf, a_scv)) AND
                        NOT(a01_eqkey (a01kw[ cak_i_order], a_sqlmode,
                        a_cmd_part^.sp1p_buf, a_scv)) AND
                        NOT(a01_eqkey (a01kw[ cak_i_optimize], a_sqlmode,
                        a_cmd_part^.sp1p_buf, a_scv)) AND
                        (sc_symb <> s_eof)
                    THEN
                        a02_ls_acolumnspec_list (acv,
                              NOT c_table_required,
                              a_ap_tree^[ curr_n ].n_lo_level, last_n);
                    (*ENDIF*) 
                    END
                ELSE
                    a02_l_acolumn_list (acv, a_ap_tree^[ curr_n ].
                          n_lo_level, last_n);
                (*ENDIF*) 
                END
            ELSE
                IF  (a_sqlmode = sqlm_db2)
                    (* PTS 1116704 E.Z. *)
                THEN
                    a07_error (acv, e_wanted_keyword,
                          curr_n, curr_n);
                (* PTS 1119023 E.Z. *)
                (*ENDIF*) 
            (*ENDIF*) 
            IF  a_sqlmode <> sqlm_ansi
            THEN
                BEGIN
                a01_call_put (acv, a60, cak_x_lock_exclusive,
                      a_ap_tree^[ curr_n ].n_sa_level);
                curr_n := a_ap_tree^[ curr_n ].n_sa_level;
                IF  ((a01_eqkey (a01kw[ cak_i_nowait], a_sqlmode,
                    a_cmd_part^.sp1p_buf, a_scv))
                    AND
                    ((a_sqlmode = sqlm_oracle) OR (a_sqlmode = sqlm_internal)))
                THEN
                    BEGIN
                    a01_call_put (acv, a60, cak_x_lock_nowait,
                          a_ap_tree^[ curr_n ].n_lo_level);
                    a01_next_symbol (acv);
                    END;
                (*ENDIF*) 
                update_allowed := false;
                END
            (*ENDIF*) 
            END
        (*ENDIF*) 
    ELSE
        a_scv := scvh
    (*ENDIF*) 
    END
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60await_option (
            VAR acv             : tak_all_command_glob;
            VAR put_node        : tsp00_Int2);
 
VAR
      iso_n       : tsp00_Int2;
      uint_n      : tsp00_Int2;
      nowait_n    : tsp00_Int2;
      lmode_n     : tsp00_Int2;
      scvh        : tak_scanner_glob;
 
BEGIN (* PTS 1108174 *)
(* **************************************************************** *)
(* This procedure builds syntax nodes for lock option               *)
(* handled by a660_lock                                             *)
(*                                                                  *)
(* Command syntax:                                                  *)
(*                                                                  *)
(*    ... with lock [(nowait|ignore)]                               *)
(*                  [optimistic|exclusive]                          *)
(*                  [isolation level <uint>] ...                    *)
(*                                                                  *)
(* generated Syntax nodes:                                          *)
(*                                                                  *)
(*       11------12------10------ 9------                           *)
(*         | a51|__|Symb|__| a60|__| a60|                           *)
(*         | 234|  |uns_|  |   7|  |   4|                           *)
(*         ------  ------  ------  ------                           *)
(*                                                                  *)
(*       => with lock (nowait) optimistic isolation level 2         *)
(*                                                                  *)
(* or                                                               *)
(*       11------12------ 9------                                   *)
(*         | a51|__|Symb|__| a60|                                   *)
(*         | 234|  |uns_|  |   4|                                   *)
(*         ------  ------  ------                                   *)
(*                                                                  *)
(*       => with lock (nowait) isolation level 2                    *)
(*          Attention!!! only one!!! a60 node                       *)
(*                                                                  *)
(* or                                                               *)
(*                                                                  *)
(*       10------ 9------                                           *)
(*         | a60|__| a60|                                           *)
(*         |   6|  |   8|                                           *)
(*         ------  ------                                           *)
(*                                                                  *)
(*       => with lock (ignore)                                      *)
(*                                                                  *)
(* because of the contrarily sequence fo command syntax and         *)
(* nodes the procedure seems to be a bit confusing                  *)
(*                                                                  *)
(* **************************************************************** *)
WITH acv, a_scv DO
    IF  ((a01_eqkey (a01kw[ cak_i_with], a_sqlmode,
        a_cmd_part^.sp1p_buf, a_scv) ) AND
        (a_returncode = 0))
    THEN
        BEGIN
        scvh     := a_scv;
        iso_n    := 0;
        uint_n   := 0;
        nowait_n := 0;
        lmode_n  := 0;
        a01_next_symbol (acv);
        IF  ((a01_eqkey (a01kw[ cak_i_lock], a_sqlmode,
            a_cmd_part^.sp1p_buf, a_scv)) AND
            ((a_sqlmode = sqlm_internal) OR
            g01glob.db_is_for_sapr3))
        THEN
            BEGIN
            a01_next_symbol (acv);
            IF  sc_symb = s_leftpar
            THEN
                BEGIN
                a01_next_symbol (acv);
                IF  a01_eqkey (a01kw [ cak_i_nowait], a_sqlmode,
                    a_cmd_part^.sp1p_buf, a_scv)
                THEN
                    BEGIN
                    a01_call_put (acv, a60, cak_x_lock_nowait, nowait_n);
                    a01_next_symbol (acv);
                    a01_force_symbol (acv, s_rightpar,
                          nowait_n, nowait_n);
                    END
                ELSE
                    BEGIN
                    IF  a01_eqkey (a01kw [ cak_i_ignore], a_sqlmode,
                        a_cmd_part^.sp1p_buf, a_scv)
                    THEN
                        BEGIN
                        a01_call_put (acv, a60, cak_x_lock_ignore, nowait_n);
                        a01_next_symbol (acv);
                        a01_force_symbol (acv, s_rightpar,
                              nowait_n, nowait_n);
                        END
                    ELSE
                        a07_error (acv, e_wanted_keyword,
                              nowait_n, nowait_n);
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            IF  (a_returncode = 0)
            THEN
                BEGIN
                IF  a01_eqkey (a01kw [ cak_i_exclusive], a_sqlmode,
                    a_cmd_part^.sp1p_buf, a_scv)
                THEN
                    BEGIN
                    a01_call_put (acv, a60, cak_x_lock_exclusive, lmode_n);
                    a01_next_symbol (acv);
                    END
                ELSE
                    IF  a01_eqkey (a01kw [ cak_i_optimistic], a_sqlmode,
                        a_cmd_part^.sp1p_buf, a_scv)
                    THEN
                        BEGIN
                        a01_call_put (acv, a60, cak_x_lock_optimistic, lmode_n);
                        a01_next_symbol (acv);
                        END;
                    (*ENDIF*) 
                (*ENDIF*) 
                IF  lmode_n > 0
                THEN
                    a_ap_tree^[ lmode_n ].n_lo_level := nowait_n;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            IF  ((a_returncode = 0) AND
                (a01_eqkey (a01kw [ cak_i_isolation], a_sqlmode,
                a_cmd_part^.sp1p_buf, a_scv)))
            THEN
                BEGIN
                a01_next_symbol (acv);
                IF  a01mandatory_keyword (acv, cak_i_level)
                THEN
                    BEGIN
                    a01_call_put (acv, a51, cak_i_isolation, put_node);
                    a03_aunsigned_integer (acv,
                          a_ap_tree^[ put_node ].n_lo_level, uint_n);
                    IF  (a_returncode = 0)
                    THEN
                        IF  (lmode_n > 0)
                        THEN
                            a_ap_tree^[ uint_n ].n_lo_level := lmode_n
                        ELSE
                            a_ap_tree^[ uint_n ].n_lo_level := nowait_n;
                        (*ENDIF*) 
                    (*ENDIF*) 
                    END
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            IF  put_node = 0
            THEN
                BEGIN
                IF  lmode_n > 0
                THEN
                    put_node := lmode_n
                ELSE
                    BEGIN
                    a01_call_put (acv, a60, cak_x_lock_share, put_node);
                    a_ap_tree^[ put_node ].n_lo_level := nowait_n;
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END
        ELSE
            a_scv := scvh
        (*ENDIF*) 
        END
    (*ENDIF*) 
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a60_change_results (
            VAR acv         : tak_all_command_glob;
            VAR data        : tsp00_MoveObj;
            VAR change_rec  : tak_changerecord;
            startpos       : integer;
            curr_resreclen : integer);
 
CONST
      maxonebytelen   =   255;
      uni_max_collen  = 16000 (* 2*cak_maxdeffieldlength *);
 
VAR
      e             : tgg00_BasisError;
      overfl        : boolean;
      error         : tsp8_uni_error;
      i             : integer;
      index         : integer;
      is_all        : boolean;
      uni_fill_c2   : tsp00_C2;
      length        : tsp00_Int4;
      curr_startpos : tsp00_Int4;
      curr_ch_len   : tsp00_Int4;
      uni_startpos  : tsp00_Int4;
      uni_outlen    : tsp00_Int4;
      err_char_no   : tsp00_Int4;
      dest_pos      : tsp00_Int4;
      dest_len      : tsp00_Int4;
      h_buf         : PACKED ARRAY [1..uni_max_collen] OF char;
      uni_buf       : PACKED ARRAY [1..uni_max_collen] OF char;
      date_e        : tsp6_date_error;
      ret           : tsp00_NumError;
 
BEGIN
&IFDEF TRACE
t01int4 (ak_sem, 'cr_colcount ', change_rec.cr_colcount);
&ENDIF
WITH acv, change_rec DO
    BEGIN
    IF  a_out_packet^.sp1_header.sp1h_mess_code = csp_unicode
    THEN
        uni_fill_c2 := csp_unicode_blank
    ELSE
        IF  a_out_packet^.sp1_header.sp1h_mess_code = csp_unicode_swap
        THEN
            uni_fill_c2 := '\20\00'
        ELSE
            uni_fill_c2 := '  ';
        (*ENDIF*) 
    (*ENDIF*) 
    a_long_desc_pos := 0;
    i := 1;
    WHILE i <= cr_colcount DO
        BEGIN
        WITH cr_columns[ i ] DO
            IF  (ch_startpos <= curr_resreclen) OR
                (ch_to_warn2 in ch_type)
            THEN
                BEGIN
&               IFDEF TRACE
                t01int4 (ak_sem, 'ch_startpos ', ch_startpos);
                t01int4 (ak_sem, '   startpos ',    startpos);
                t01int4 (ak_sem, 'ch_length   ', ord(ch_length));
                IF  ch_date in ch_type
                THEN
                    t01name (ak_sem, 'change date       ');
                (*ENDIF*) 
                IF  ch_time_or_timestamp in ch_type
                THEN
                    t01name (ak_sem, 'change time(stamp)');
                (*ENDIF*) 
                IF  ch_to_multibyte_set in ch_type
                THEN
                    t01name (ak_sem, 'change to swap uni');
                (*ENDIF*) 
                IF  ch_to_ascii in ch_type
                THEN
                    t01name (ak_sem, 'change to ascii   ');
                (*ENDIF*) 
                IF  ch_to_longsupport in ch_type
                THEN
                    t01name (ak_sem, 'ch_to_longsupport ');
                (*ENDIF*) 
                IF  ch_to_warn2 in ch_type
                THEN
                    t01name (ak_sem, 'change to warn2   ');
                (*ENDIF*) 
                IF  ch_number_change_in_next_entry in ch_type
                THEN
                    BEGIN
                    t01name (ak_sem, 'ch_number         ');
                    IF  nch_nativeint8 in cr_columns[ i+1 ].ch_number_type
                    THEN
                        t01name (ak_sem, 'ch_nativeint8     ');
                    (*ENDIF*) 
                    IF  nch_div_by_count in cr_columns[ i+1 ].ch_number_type
                    THEN
                        t01name (ak_sem, 'ch_div_by_count   ');
                    (*ENDIF*) 
                    END;
&               ENDIF
                (*ENDIF*) 
                e := e_ok;
                (* in the case of ch_to_multibyte            *)
                (* ch_startpos is 1 byte behind defined byte *)
                (* otherwise one cannot distinct between     *)
                (* first portion of long (>255) unicodes     *)
                (* and two following each other              *)
                IF  (ch_to_multibyte_set in ch_type) AND
                    NOT (ch_to_longsupport in ch_type)
                THEN
                    BEGIN
                    curr_startpos := pred(ch_startpos + startpos);
                    curr_ch_len   := succ(ord(ch_length))
                    END
                ELSE
                    BEGIN
                    curr_startpos := ch_startpos + startpos;
                    curr_ch_len   := ord (ch_length)
                    END;
                (*ENDIF*) 
                IF  (ch_to_longsupport in ch_type)
                THEN
                    BEGIN
                    IF  a_long_desc_pos = 0
                    THEN
                        a_long_desc_pos := i;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                IF  a_dt_format <> dtf_normal
                THEN
                    IF  ch_date in ch_type
                    THEN
                        g03dchange_format_date (data, data,
                              curr_startpos, curr_startpos,
                              a_dt_format, e)
                    ELSE
                        IF  ch_time_or_timestamp in ch_type
                        THEN
                            IF  (curr_ch_len <= succ(mxsp_exttime))
                                OR
                                ((curr_ch_len <= succ(2*mxsp_exttime)) AND
                                (ch_to_multibyte_set in ch_type))
                            THEN
                                BEGIN
                                g03tchange_format_time (data, data,
                                      curr_startpos, curr_startpos,
                                      a_dt_format, e);
                                IF  e = e_time_value_too_long
                                THEN
                                    WITH a_transinf.tri_trans DO
                                        BEGIN
                                        e := e_ok;
                                        trWarning_gg00 := trWarning_gg00 +
                                              [ warn0_exist,
                                              warn11_time_value_too_long ]
                                        END
                                    (*ENDWITH*) 
                                (*ENDIF*) 
                                END
                            ELSE
                                IF  a_dt_format = dtf_oracle_date
                                THEN
                                    BEGIN
                                    dest_pos := curr_startpos+1;
                                    dest_len := curr_startpos+curr_ch_len-1;
                                    (* PTS 1002080 E.Z. *)
                                    s78d2c_to_char (g03dictionary.dict [
                                          a_nls_params.dl_language_no ],
                                          @data[ curr_startpos ],
                                          @a_nls_params.date_format,
                                          a_nls_params.df_length,
                                          startpos+curr_resreclen, @data,
                                          dest_pos, dest_len, date_e);
&                                   ifdef trace
                                    t01int4 (ak_sem, 'date_err    ',
                                          ord (date_e));
&                                   endif
                                    IF  date_e <> sp6de_ok
                                    THEN
                                        e := g03date_error_to_b_err (date_e);
                                    (*ENDIF*) 
                                    IF  dest_pos <= dest_len
                                    THEN (* Fill it up with blanks. *)
                                        SAPDB_PascalFill ('VAK60 ',   1,    
                                              startpos+curr_resreclen, @data, dest_pos,
                                              dest_len-dest_pos+1, ' ',
                                              a_returncode);
                                    (*ENDIF*) 
                                    END
                                ELSE
                                    g03tschange_format_timestamp (data, data,
                                          curr_startpos, curr_startpos,
                                          a_dt_format, a_ak_language, e);
                                (*ENDIF*) 
                            (*ENDIF*) 
                        (*ENDIF*) 
                    (*ENDIF*) 
                (*ENDIF*) 
                IF  e <> e_ok
                THEN
                    BEGIN
&                   IFDEF TRACE
                    t01int4 (ak_sem, 'e           ', e);
&                   ENDIF
                    a07_b_put_error (acv, e, 1);
                    END;
                (*ENDIF*) 
                IF  (ch_to_multibyte_set in ch_type)
                    AND
                    NOT (ch_to_longsupport in ch_type)
                THEN
                    BEGIN
                    (* ch_startpos is 1 byte behind defined byte *)
                    (* otherwise one cannot distinct between     *)
                    (* first portion of long (>255) unicodes     *)
                    (* and two following each other              *)
                    length       := pred(curr_ch_len);
                    uni_startpos := succ(curr_startpos);
                    is_all       := false;
                    WHILE ((ord(cr_columns[i].ch_length) = maxonebytelen) AND
                          NOT is_all) DO
                        IF  i < cr_colcount
                        THEN
                            IF  ((cr_columns[i].ch_startpos +
                                ord(cr_columns[i].ch_length) =
                                cr_columns[ i+1 ].ch_startpos) AND
                                (ch_to_multibyte_set in cr_columns[ i+1 ].ch_type))
                            THEN
                                BEGIN
                                i := succ(i);
                                length := length + ord(cr_columns[ i ].ch_length);
                                END
                            ELSE
                                is_all := true
                            (*ENDIF*) 
                        ELSE
                            is_all := true;
                        (*ENDIF*) 
                    (*ENDWHILE*) 
                    uni_outlen := length;
                    curr_ch_len := length;
&                   ifdef TRACE
                    t01int4 (ak_sem, 'ch_length   ', length);
                    t01moveobj (unicode, data, uni_startpos,
                          uni_startpos + length - 1);
&                   endif
                    IF  data[ curr_startpos ] <> csp_undef_byte
                    THEN
                        BEGIN
                        IF  data[ curr_startpos ] = csp_unicode_def_byte
                        THEN
                            BEGIN
                            IF  (a_out_packet^.sp1_header.sp1h_mess_swap <> sw_normal) AND
                                (a_out_packet^.sp1_header.sp1h_mess_code <> csp_unicode)
                            THEN
                                BEGIN
                                s80uni_trans (@data[ uni_startpos ], length, csp_unicode,
                                      @data[ uni_startpos ], uni_outlen,
                                      csp_unicode_swap,
                                      [ ], error, err_char_no);
                                IF  error <> uni_ok
                                THEN
                                    a07_hex_uni_error (acv, error, 1, NOT c_trans_to_uni,
                                          @data [ uni_startpos + err_char_no - 1],
                                          c_unicode_wid)
                                (*ENDIF*) 
                                END;
                            (*ENDIF*) 
                            END
                        ELSE
                            (* PTS 1121482 E.Z. *)
                            IF  (a_out_packet^.sp1_header.sp1h_mess_code in
                                [csp_unicode_swap, csp_unicode])
                                AND
                                NOT acv.a_ascii_in_and_output (* new feature *)
                            THEN
                                BEGIN
                                length := s30lnr_defbyte (@data,
                                      data[ curr_startpos ], uni_startpos, length);
                                (* change dcha, ddate, dtime,  *)
                                (* dtimestamp to unicode.            *)
                                (* Since either src or dest have to  *)
                                (* be unicode we must call it twice. *)
                                s80uni_trans (@data[ uni_startpos ], length, csp_ascii,
                                      @uni_buf, uni_outlen, csp_unicode,
                                      [ ], error, err_char_no);
                                IF  error = uni_ok
                                THEN
                                    s80uni_trans (@uni_buf, uni_outlen, csp_unicode,
                                          @h_buf, uni_outlen,
                                          a_out_packet^.sp1_header.sp1h_mess_code,
                                          [ ], error, err_char_no);
                                (*ENDIF*) 
                                IF  error <> uni_ok
                                THEN
                                    a07_hex_uni_error (acv, error, 1, c_trans_to_uni,
                                          @data [ uni_startpos + err_char_no - 1], 1)
                                ELSE
                                    BEGIN
                                    SAPDB_PascalMove ('VAK60 ',   2,    
                                          sizeof (h_buf),
                                          uni_startpos+curr_ch_len-1,
                                          @h_buf, 1, @data, uni_startpos,
                                          uni_outlen,
                                          a_returncode);
                                    IF  curr_ch_len > uni_outlen
                                    THEN
                                        SAPDB_PascalUnicodeFill ('VAK60 ',   3,    
                                              uni_startpos+curr_ch_len-1,
                                              @data, uni_startpos+uni_outlen,
                                              curr_ch_len - uni_outlen,
                                              uni_fill_c2,
                                              a_returncode);
                                    (*ENDIF*) 
                                    END;
                                (*ENDIF*) 
                                (* PTS 1121482 E.Z. *)
                                data[ curr_startpos ] := csp_unicode_def_byte;
                                END
                            ELSE
                                BEGIN
                                length := length DIV 2;
                                SAPDB_PascalOverlappingMove ('VAK60 ',   4,    
                                      curr_startpos + length, curr_startpos + 2*length,
                                      @data, curr_startpos,
                                      @data, curr_startpos + length,
                                      length+1, a_returncode);
                                END;
                            (*ENDIF*) 
                        (*ENDIF*) 
                        END
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                IF  ((ch_to_warn2 in ch_type) AND
                    (data[ curr_startpos ] = csp_undef_byte))
                THEN
                    WITH a_transinf.tri_trans DO
                        trWarning_gg00 := trWarning_gg00 +
                              [ warn0_exist, warn2_null_in_builtin_func ]
                    (*ENDWITH*) 
                ELSE
                    IF  ch_number_change_in_next_entry in ch_type
                    THEN
                        BEGIN
                        IF  nch_div_by_count in cr_columns[ i + 1 ].ch_number_type
                        THEN
                            IF  ( data[ curr_startpos ] <> csp_undef_byte ) AND
                                ( data[ curr_startpos ] <> csp_oflw_byte )
                            THEN
                                s51div (data, curr_startpos+1, NUMBER_MXGG04-1,
                                      data, curr_startpos+NUMBER_MXGG04+1, mxsp_resnum-1,
                                      data, curr_startpos+1,
                                      csp_fixed, csp_float_frac, index, ret);
                            (*ENDIF*) 
                        (*ENDIF*) 
                        i := succ(i);
                        END
                    (*ENDIF*) 
                (*ENDIF*) 
                END;
            (*ENDIF*) 
        (*ENDWITH*) 
        i := succ(i)
        END
    (*ENDWHILE*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a60_get_longinfobuffer (
            VAR acv   : tak_all_command_glob;
            VAR sparr : tak_syspointerarr;
            col_cnt   : integer;
            resultno  : tsp00_Int4);
 
VAR
      e          : tgg00_BasisError;
      ke         : tgg00_SysInfoKey;
 
BEGIN
WITH sparr, ke DO
    BEGIN
    ke        := a01sysnullkey;
    stempid   := resultno;
    sentrytyp := cak_eshortinfo;
    IF  pinfop = NIL
    THEN
        BEGIN
        a10_nil_get_sysinfo (acv, ke, d_fix, sizeof(tak_shortinforecord) -
              sizeof (tak_paraminfoarr) +
              col_cnt*sizeof(tsp1_param_info), pinfop, e);
        (* PTS 1105338 E.Z. *)
        IF  e <> e_ok
        THEN
            a07_b_put_error (acv, e, 1)
        ELSE
            BEGIN
            pinfop^.sshortinfo.sicount := 0;
            pinfop^.sshortinfo.sisl    := col_cnt;
            END
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  acv.a_returncode = 0
    THEN
        BEGIN
        sentrytyp := cak_ecolnames;
        a10_nil_get_sysinfo (acv, ke, d_fix, sizeof (tak_columnnamesrecord),
              pcolnamep, e);
        IF  e <> e_ok
        THEN
            a07_b_put_error (acv, e, 1)
        ELSE
            BEGIN
            pcolnamep^.scolnames.cncount  := 0;
            pcolnamep^.scolnames.cnreclen := cak_sysbufferoffset +
                  sizeof (pcolnamep^.scolnames.cnbit64fill) +
                  sizeof (pcolnamep^.scolnames.cnfullen) +
                  sizeof (pcolnamep^.scolnames.cncount);
            pcolnamep^.scolnames.cnfullen := pcolnamep^.scolnames.cnreclen;
            pcolnamep^.scolnames.cnnext   := NIL;
            pcolnamep^.scolnames.cnlast   := pcolnamep
            END
        (*ENDIF*) 
        END
    (*ENDIF*) 
    END
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a60_columnnames_return (
            VAR acv   : tak_all_command_glob;
            pcolnamep : tak_sysbufferaddress);
 
VAR
      exit_loop : boolean;
      offset    : integer;
      move_len  : integer;
      traversed : tsp00_Int4;
      p         : tak_sysbufferaddress;
 
BEGIN
&IFDEF TRACE
t01int4 (ak_sem, 'cnfullen    ', pcolnamep^.scolnames.cnfullen);
&ENDIF
p         := pcolnamep;
offset    := sizeof (pcolnamep^.scolnames.cnfullen) +
      sizeof (pcolnamep^.scolnames.cncount);
traversed := 0;
exit_loop := false;
WHILE NOT exit_loop DO
    BEGIN
    traversed := traversed + cgg_rec_key_offset +
          p^.b_kl + sizeof (p^.scolnames.cnbit64fill) + offset;
    move_len := p^.b_sl - cgg_rec_key_offset - p^.b_kl -
          sizeof (p^.scolnames.cnbit64fill) - offset;
&   IFDEF TRACE
    t01buf (ak_sem, p^.scolnames.cnbuf, offset + 1, offset + move_len);
&   ENDIF
    a06retpart_move (acv, @p^.scolnames.cnbuf[offset+1], move_len);
    offset    := 0;
    traversed := traversed + move_len;
&   IFDEF TRACE
    t01int4 (ak_sem, 'traversed   ', traversed);
&   ENDIF
    IF  traversed < pcolnamep^.scolnames.cnfullen
    THEN
        p := p^.scolnames.cnnext
    ELSE
        exit_loop := true;
    (*ENDIF*) 
    END;
(*ENDWHILE*) 
a06finish_curr_retpart (acv, sp1pk_columnnames,
      pcolnamep^.scolnames.cncount);
END;
 
(*------------------------------*) 
 
PROCEDURE
      a60_p_info_output (
            VAR acv   : tak_all_command_glob;
            VAR sparr : tak_syspointerarr);
 
BEGIN
WITH acv, sparr DO
    BEGIN
    IF  a_returncode = 0
    THEN
        BEGIN
        (* PTS 1115263 E.Z. *)
        IF  (a_ex_kind <> only_parsing)                            OR
            (a_precomp_info_byte = csp1_p_mass_select_found)       OR
            (a_precomp_info_byte = csp1_p_reuse_mass_select_found) OR
            (a_precomp_info_byte = csp1_p_select_for_update_found) OR
            (a_precomp_info_byte = csp1_p_reuse_update_sel_found)  OR
            (a_precomp_info_byte = csp1_p_mselect_found)           OR
            (a_precomp_info_byte = csp1_p_reuse_mselect_found)     OR
            (a_precomp_info_byte = csp1_p_for_upd_mselect_found)   OR
            (a_precomp_info_byte = csp1_p_reuse_upd_mselect_found)
            OR
            (
            (
            (acv.a_comp_type = at_xci)
            OR (acv.a_comp_type = at_odbc)
            )                          AND
            (a_ex_kind = only_parsing) AND
            (a_return_segm^.sp1r_function_code = csp1_select_into_fc)
            )
        THEN
            a60_columnnames_return (acv, sparr.pcolnamep);
        (*ENDIF*) 
        IF  a_ex_kind <> only_parsing
        THEN
            BEGIN
            (* otherwise it's done in a54_select_last_part *)
            (*==== return shortfield info's ======*)
            a06retpart_move (acv, @pinfop^.sshortinfo.siinfo,
                  pinfop^.sshortinfo.sicount * sizeof(tsp1_param_info));
            a06finish_curr_retpart (acv, sp1pk_shortinfo,
                  pinfop^.sshortinfo.sicount);
            END
        (*ENDIF*) 
        END
    (*ENDIF*) 
    END
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a60_put_result (
            VAR acv    : tak_all_command_glob;
            VAR mblock : tgg00_MessBlock;
            spos       : integer);
 
VAR
      movelen : tsp00_Int4;
 
BEGIN
IF  acv.a_returncode = 0
THEN
    WITH acv, mblock, mb_data^ DO
        BEGIN
        movelen := mb_data_len  - spos;
        a06retpart_move (acv, @mbp_buf[spos + 1], movelen)
        END
    (*ENDWITH*) 
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak60select_list (
            VAR acv       : tak_all_command_glob;
            stamp_allowed : boolean;
            VAR put_node  : tsp00_Int2;
            VAR last_node : tsp00_Int2);
 
VAR
      s_rowno_found     : boolean;
      curr_n            : tsp00_Int2;
      m_allow_functions : tak_function;
      s_allow_functions : tak_function;
      h_cpt             : tak_cmd_part_type;
 
BEGIN
WITH acv, a_scv DO
    IF  a_returncode = 0
    THEN
        BEGIN
        a01_call_put (acv, a60, cak_x_select_list, curr_n);
        a_in_select_list := true;
        put_node := curr_n;
        last_node := curr_n;
        m_allow_functions := a_allow_functions;
        a_rowno_found := false;
        h_cpt := a_cpart_type;
        (* PTS 1123051 E.Z. *)
        a_cpart_type := cpt_in_select_list;
        ak60select_column (acv, stamp_allowed,
              a_ap_tree^[ curr_n ].n_lo_level, curr_n);
        s_allow_functions := a_allow_functions;
        s_rowno_found     := a_rowno_found;
        WHILE ((sc_symb = s_comma) AND (a_returncode = 0)) DO
            BEGIN
            a01_next_symbol (acv);
            a_allow_functions := m_allow_functions;
            a_rowno_found     := false;
            ak60select_column (acv, stamp_allowed,
                  a_ap_tree^[ curr_n ].n_sa_level, curr_n);
            IF  ord(a_allow_functions) > ord(s_allow_functions)
            THEN
                s_allow_functions := a_allow_functions;
            (*ENDIF*) 
            s_rowno_found := s_rowno_found OR a_rowno_found;
            END;
        (*ENDWHILE*) 
        a_cpart_type := h_cpt;
        a_rowno_found := s_rowno_found;
        a_allow_functions := s_allow_functions;
        IF  a_allow_functions = tf_func
        THEN
            a_ap_tree^[ put_node ].n_symb := s_count
        ELSE
            IF  a_allow_functions = tf_func_arith
            THEN
                a_ap_tree^[ put_node ].n_symb := s_sum;
            (*ENDIF*) 
        (*ENDIF*) 
        a_in_select_list := false;
        END
    (*ENDIF*) 
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a60rescount (
            VAR acv  : tak_all_command_glob;
            rescount : tsp00_Int4);
 
VAR
      old_rescount_part : tsp1_part_ptr;
      res               : tsp00_NumError;
      help_num          : tsp00_Number;
 
BEGIN
WITH acv DO
    BEGIN
    CASE rescount OF
        -1 :
            a_resultnum := csp_rescnt_unknown;
        0 :
            a_resultnum := g01glob.rescnt_0;
        1 :
            a_resultnum := g01glob.rescnt_1;
        OTHERWISE
            BEGIN
            a_resultnum [1] := csp_defined_byte;
            s41p4int (a_resultnum, 2, rescount, res);
            END;
        END;
    (*ENDCASE*) 
    a92find_return_part (acv, sp1pk_resultcount, old_rescount_part);
    IF  old_rescount_part <> NIL
    THEN
        SAPDB_PascalMove ('VAK60 ',   5,    
              sizeof (a_resultnum), old_rescount_part^.sp1p_buf_len,
              @a_resultnum, 1, @old_rescount_part^.sp1p_buf, 1,
              sizeof (a_resultnum), a_returncode)
    ELSE
        BEGIN
        a06retpart_move (acv, @a_resultnum, sizeof (a_resultnum));
        a06finish_curr_retpart (acv, sp1pk_resultcount, 1)
        END
    (*ENDIF*) 
    END
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a60resnum (
            VAR acv     : tak_all_command_glob;
            VAR moveobj : tsp00_MoveObj;
            startpos    : integer);
 
VAR
      old_rescount_part : tsp1_part_ptr;
      help_num          : tsp00_Number;
 
BEGIN
WITH acv DO
    BEGIN
    SAPDB_PascalMove ('VAK60 ',   6,    
          sizeof (moveobj), sizeof (a_resultnum),
          @moveobj, startpos, @a_resultnum, 1, sizeof (a_resultnum),
          a_returncode);
    a92find_return_part (acv, sp1pk_resultcount, old_rescount_part);
    IF  old_rescount_part <> NIL
    THEN
        SAPDB_PascalMove ('VAK60 ',   7,    
              sizeof (a_resultnum), old_rescount_part^.sp1p_buf_len,
              @a_resultnum, 1, @old_rescount_part^.sp1p_buf, 1,
              sizeof (a_resultnum), a_returncode)
    ELSE
        BEGIN
        a06retpart_move (acv, @a_resultnum, sizeof (a_resultnum));
        a06finish_curr_retpart (acv, sp1pk_resultcount, 1)
        END
    (*ENDIF*) 
    END
(*ENDWITH*) 
END;
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
.PA 
