.nf
 
 .nf

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

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

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

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

 
.fo
*****************************************************
Copyright (c) 2000-2005 SAP AG
SAP Database Technology
 
Release :      Date : 2000-11-23
*****************************************************
modname : VAK25
changed : 2000-11-23
module  : AK_Link
 
Author  : ThomasA
Created : 1987-09-22
*****************************************************
 
Purpose :
 
Define  :
 
        PROCEDURE
              a25get_linkname (
                    VAR acv        : tak_all_command_glob;
                    linkbuf        : tak_sysbufferaddress;
                    index          : integer;
                    VAR link_name  : tsp00_KnlIdentifier);
 
        FUNCTION
              a25is_link_index (
                    VAR acv   : tak_all_command_glob;
                    col_count : integer;
                    index_id  : integer) : boolean;
 
        PROCEDURE
              a25link_semantic (
                    VAR acv    : tak_all_command_glob;
                    start_node : integer);
 
        PROCEDURE
              a25linkload_info (VAR acv : tak_all_command_glob);
 
        FUNCTION
              a25lnk_pending (VAR acv : tak_all_command_glob) : boolean;
 
        PROCEDURE
              a25check_fk_priv (
                    VAR acv     : tak_all_command_glob;
                    pk_rec      : tak_sysbufferaddress;
                    VAR priv    : tak_privilege;
                    VAR grantee : tgg00_Surrogate);
 
        PROCEDURE
              a25drop_link (
                    VAR acv         : tak_all_command_glob;
                    VAR a25v        : tak_a25_glob;
                    tabno           : integer;
                    VAR viewscanpar : tak_save_viewscan_par);
 
        PROCEDURE
              a25FindForeignKeyInfo (
                    VAR acv             : tak_all_command_glob;
                    VAR PrimaryKeyBuf   : tak_sysbufferaddress;
                    PrimaryKeyIndex     : integer;
                    VAR ForeignKeyBuf   : tak_sysbufferaddress;
                    VAR ForeignKeyIndex : integer);
 
        PROCEDURE
              a25foreign_key_spec (
                    VAR acv    : tak_all_command_glob;
                    fk_node    : integer);
 
        PROCEDURE
              a25pending_link (
                    VAR acv    : tak_all_command_glob;
                    VAR tablen : tsp00_KnlIdentifier);
 
        PROCEDURE
              a25drop_foreign_link (
                    VAR acv      : tak_all_command_glob;
                    VAR sysk     : tgg00_SysInfoKey;
                    VAR linkname : tsp00_KnlIdentifier);
 
.CM *-END-* define --------------------------------------
***********************************************************
 
Use     :
 
        FROM
              AK_VIEW_SCAN : VAK27;
 
        PROCEDURE
              a27init_viewscanpar (
                    VAR acv         : tak_all_command_glob;
                    VAR viewscanpar : tak_save_viewscan_par;
                    v_type          : tak_viewscantype);
&       ifdef TRACE
 
      ------------------------------ 
 
        FROM
              Test_Procedures : vta01;
 
        PROCEDURE
              t01bool (
                    debug    : tgg00_Debug;
                    nam      : tsp00_Sname;
                    curr_bool: boolean);
 
        PROCEDURE
              t01lidentifier (
                    layer      : tgg00_Debug;
                    identifier : tsp00_KnlIdentifier);
 
        PROCEDURE
              t01int4 (
                    layer : tgg00_Debug;
                    nam : tsp00_Sname;
                    int : tsp00_Int4);
 
        PROCEDURE
              t01name (
                    layer : tgg00_Debug;
                    nam : tsp00_Name);
 
        PROCEDURE
              t01buf  (
                    layer    : tgg00_Debug;
                    VAR buf  : tak_systembuffer;
                    startpos : integer;
                    endpos   : integer);
 
        PROCEDURE
              t01surrogate (
                    layer     : tgg00_Debug;
                    nam       : tsp00_Sname;
                    VAR tabid : tgg00_Surrogate);
&       endif
 
      ------------------------------ 
 
        FROM
              Scanner : VAK01;
 
        VAR
              a01char_size        : integer;
              a01kw               : tak_keywordtab;
              a01defaultkey       : tgg00_SysInfoKey;
              a01_il_b_identifier : tsp00_KnlIdentifier;
 
        PROCEDURE
              a01_next_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;
 
      ------------------------------ 
 
        FROM
              AK_semantic_scanner_tools : VAK05;
 
        PROCEDURE
              a05_identifier_get (
                    VAR acv     : tak_all_command_glob;
                    tree_index  : integer;
                    obj_len     : integer;
                    VAR moveobj : tsp00_KnlIdentifier);
 
      ------------------------------ 
 
        FROM
              AK_universal_semantic_tools : VAK06;
 
        PROCEDURE
              a06_get_priv  (
                    VAR acv     : tak_all_command_glob;
                    VAR brec    : tak_sysbufferaddress;
                    VAR priv    : tak_privilege);
 
        PROCEDURE
              a06put_errtext (
                    VAR acv       : tak_all_command_glob;
                    b_err_in      : tgg00_BasisError;
                    err_type      : tgg04_ErrorText;
                    errtext_len   : integer;
                    VAR errtext   : tsp00_C256;
                    VAR b_err_out : tgg00_BasisError);
 
        PROCEDURE
              a06lsend_mess_buf (
                    VAR acv         : tak_all_command_glob;
                    VAR mbuf        : tgg00_MessBlock;
                    call_from_rsend : boolean;
                    VAR b_err       : tgg00_BasisError);
 
        PROCEDURE
              a06_systable_get (
                    VAR acv      : tak_all_command_glob;
                    dstate       : tak_directory_state;
                    VAR tableid  : tgg00_Surrogate;
                    VAR base_ptr : tak_sysbufferaddress;
                    get_all      : boolean;
                    VAR ok       : boolean);
 
        PROCEDURE
              a06determine_username (
                    VAR acv       : tak_all_command_glob;
                    VAR userid    : tgg00_Surrogate;
                    VAR user_name : tsp00_KnlIdentifier);
 
        PROCEDURE
              a06extcolno (
                    VAR baserec     : tak_baserecord;
                    extcolno        : integer;
                    VAR colinfo_ptr : tak00_colinfo_ptr);
 
        PROCEDURE
              a06inc_linkage (VAR linkage : tsp00_C2);
 
        PROCEDURE
              a06rsend_mess_buf (
                    VAR acv    : tak_all_command_glob;
                    VAR mbuf   : tgg00_MessBlock;
                    result_req : boolean;
                    VAR e      : tgg00_BasisError);
 
        PROCEDURE
              a06a_mblock_init (
                    VAR acv         : tak_all_command_glob;
                    mtype           : tgg00_MessType;
                    m2type          : tgg00_MessType2;
                    VAR tree        : tgg00_FileId);
&       IFDEF TRACE
 
        PROCEDURE
              a06td_priv (
                    p        : tak_privilege;
                    id       : tsp00_C18;
                    unpacked : boolean);
&       ENDIF
 
      ------------------------------ 
 
        FROM
              AK_Identifier_Handling : VAK061;
 
        FUNCTION
              a061exist_columnname (
                    VAR base_rec    : tak_baserecord;
                    VAR column      : tsp00_KnlIdentifier;
                    VAR colinfo_ptr : tak00_colinfo_ptr) : boolean;
 
        FUNCTION
              a061identifier_len (VAR id : tsp00_KnlIdentifier) : integer;
&       ifdef trace
 
        PROCEDURE
              a061td_colinfo (
                    VAR colinfo : tak00_columninfo;
                    index : integer);
&       endif
 
        PROCEDURE
              a061get_colname (VAR col_info : tak00_columninfo;
                    VAR colname  : tsp00_KnlIdentifier);
 
      ------------------------------ 
 
        FROM
              AK_error_handling : VAK07;
 
        PROCEDURE
              a07ak_system_error (
                    VAR acv  : tak_all_command_glob;
                    modul_no : integer;
                    id       : integer);
 
        PROCEDURE
              a07_b_put_error (
                    VAR acv : tak_all_command_glob;
                    b_err : tgg00_BasisError;
                    err_code : tsp00_Int4);
 
        PROCEDURE
              a07_kw_put_error (
                    VAR acv  : tak_all_command_glob;
                    b_err    : tgg00_BasisError;
                    err_code : tsp00_Int4;
                    kw       : integer);
 
        PROCEDURE
              a07_nb_put_error (
                    VAR acv  : tak_all_command_glob;
                    b_err    : tgg00_BasisError;
                    err_code : tsp00_Int4;
                    VAR n    : tsp00_KnlIdentifier);
 
      ------------------------------ 
 
        FROM
              AK_error_handling : VAK071;
 
        FUNCTION
              a071_return_code (
                    b_err   : tgg00_BasisError;
                    sqlmode : tsp00_SqlMode) : tsp00_Int2;
 
      ------------------------------ 
 
        FROM
              Systeminfo_cache : VAK10;
 
        PROCEDURE
              a10_copy_catalog_rec (
                    VAR acv         : tak_all_command_glob;
                    VAR old_key     : tgg00_SysInfoKey;
                    del_old_rec     : boolean;
                    VAR new_key     : tgg00_SysInfoKey;
                    new_segment_id  : tsp00_C2;
                    add_new_rec     : boolean;
                    VAR b_err       : tgg00_BasisError);
 
        PROCEDURE
              a10_fix_len_get_sysinfo (
                    VAR acv      : tak_all_command_glob;
                    VAR syskey   : tgg00_SysInfoKey;
                    dstate       : tak_directory_state;
                    required_len : integer;
                    plus         : integer;
                    VAR syspoint : tak_sysbufferaddress;
                    VAR b_err    : tgg00_BasisError);
 
        PROCEDURE
              a10get_sysinfo (
                    VAR acv    : tak_all_command_glob;
                    VAR syskey : tgg00_SysInfoKey;
                    dstate     : tak_directory_state;
                    VAR syspoint : tak_sysbufferaddress;
                    VAR b_err    : tgg00_BasisError);
 
        PROCEDURE
              a10_lock_sysinfo (
                    VAR acv    : tak_all_command_glob;
                    VAR syskey : tgg00_SysInfoKey;
                    lockm      : tgg00_LockReqMode);
 
        PROCEDURE
              a10_add_repl_sysinfo (
                    VAR acv      : tak_all_command_glob;
                    VAR syspoint : tak_sysbufferaddress;
                    add_sysinfo  : boolean;
                    VAR b_err    : tgg00_BasisError);
 
        PROCEDURE
              a10repl_sysinfo (
                    VAR acv      : tak_all_command_glob;
                    VAR syspoint : tak_sysbufferaddress;
                    VAR b_err    : tgg00_BasisError);
 
        PROCEDURE
              a10del_sysinfo (
                    VAR acv      : tak_all_command_glob;
                    VAR syskey   : tgg00_SysInfoKey;
                    VAR b_err    : tgg00_BasisError);
 
        PROCEDURE
              a10_version (
                    VAR acv         : tak_all_command_glob;
                    VAR base_rec    : tak_baserecord;
                    m_type          : tgg00_MessType;
                    view_scan       : boolean);
 
        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);
 
        PROCEDURE
              a10_rel_sysinfo (
                    VAR acv    : tak_all_command_glob;
                    VAR syskey : tgg00_SysInfoKey);
 
        PROCEDURE
              a10_cache_delete  (
                    VAR acv     : tak_all_command_glob;
                    is_rollback : boolean);
 
      ------------------------------ 
 
        FROM
              SQLManager : VAK101;
 
        PROCEDURE
              a101_SetTempFileLevel(
                    VAR acv        : tak_all_command_glob;
                    VAR tempFileId : tgg00_FileId;
                    level          : tsp00_Int2(*ptocConst*));
 
        PROCEDURE
              a101_SetTempFileIndex(
                    VAR acv        : tak_all_command_glob;
                    VAR tempFileId : tgg00_FileId;
                    sublevel       : tsp00_Int4(*ptocConst*));
 
        PROCEDURE
              a101_CreateGroupedTempFile(
                    VAR trans      : tgg00_TransContext;
                    VAR tempFileId : tgg00_FileId;
                    tempFileType   : tgg00_TfnTemp);
 
        PROCEDURE
              a101_DestroyGroupedTempFile(
                    VAR trans      : tgg00_TransContext;
                    VAR tempFileId : tgg00_FileId);
 
        PROCEDURE
              a101_GetTempFileInstance(
                    VAR trans      : tgg00_TransContext;
                    VAR tempFileId : tgg00_FileId);
 
        PROCEDURE
              a101_AddGroupedTempFile(
                    VAR trans      : tgg00_TransContext;
                    VAR tempFileId : tgg00_FileId;
                    VAR instanceId : tgg00_Surrogate);
 
        PROCEDURE
              a101_RemoveGroupedTempFile(
                    VAR trans      : tgg00_TransContext;
                    VAR tempFileId : tgg00_FileId);
 
      ------------------------------ 
 
        FROM
              AK_Table : VAK11;
 
        PROCEDURE
              a11put_date_time (
                    VAR date : tsp00_Int4;
                    VAR time : tsp00_Int4);
 
        PROCEDURE
              a11get_check_table (
                    VAR acv          : tak_all_command_glob;
                    new_table        : boolean;
                    basetable        : boolean;
                    unload_allowed   : boolean;
                    required_priv    : tak00_PrivilegeSet;
                    any_priv         : boolean;
                    all_base_rec     : boolean;
                    d_state          : tak_directory_state;
                    VAR act_tree_ind : tsp00_Int4;
                    VAR authid       : tsp00_KnlIdentifier;
                    VAR tablen       : tsp00_KnlIdentifier;
                    VAR d_sparr      : tak_syspointerarr);
 
      ------------------------------ 
 
        FROM
              AK_Data_Type_Options : VAK14;
 
        FUNCTION
              a14LengthOfDefaultValue (
                    VAR DefaultRec : tak_defaultrecord) : integer; (* PTS 1108428 *)
 
      ------------------------------ 
 
        FROM
              AK_save_scheme : VAK15;
 
        PROCEDURE
              a15restore_catalog (
                    VAR acv         : tak_all_command_glob;
                    VAR treeid      : tgg00_FileId;
                    VAR viewscanpar : tak_save_viewscan_par);
 
        PROCEDURE
              a15catalog_save (
                    VAR acv         : tak_all_command_glob;
                    VAR viewscanpar : tak_save_viewscan_par);
 
      ------------------------------ 
 
        FROM
              AK_Index : VAK24;
 
        PROCEDURE
              a24init_index_scan (
                    VAR acv            : tak_all_command_glob;
                    VAR tabid          : tgg00_Surrogate;
                    VAR index_scan_rec : tak_index_scan_record);
 
        PROCEDURE
              a24finish_index_scan (
                    VAR acv            : tak_all_command_glob;
                    VAR index_scan_rec : tak_index_scan_record);
 
        FUNCTION
              a24next_named_index (
                    VAR acv            : tak_all_command_glob;
                    VAR index_scan_rec : tak_index_scan_record) : boolean;
 
      ------------------------------ 
 
        FROM
              AK_Comment : VAK26;
 
        PROCEDURE
              a26drop_comment (
                    VAR acv      : tak_all_command_glob;
                    comment_type : tak_comment_type;
                    VAR id1      : tgg00_Surrogate;
                    VAR id2      : tgg00_Surrogate;
                    colno        : integer);
 
      ------------------------------ 
 
        FROM
              AK_distributor : VAK35;
 
        PROCEDURE
              a35_asql_statement (VAR acv : tak_all_command_glob);
 
      ------------------------------ 
 
        FROM
              AK_data_dictionary : VAK38;
 
        PROCEDURE
              a38fk_drop (
                    VAR acv       : tak_all_command_glob;
                    VAR username  : tsp00_KnlIdentifier;
                    VAR tablename : tsp00_KnlIdentifier;
                    VAR linkname  : tsp00_KnlIdentifier);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_1 : VBD01;
 
        VAR
              b01niltree_id : tgg00_FileId;
 
        PROCEDURE
              b01empty_file (
                    VAR t       : tgg00_TransContext;
                    VAR current : tgg00_FileId);
 
        PROCEDURE
              b01filestate (
                    VAR t       : tgg00_TransContext;
                    VAR file_id : tgg00_FileId);
 
      ------------------------------ 
 
        FROM
              filesysteminterface_2 : VBD07;
 
        PROCEDURE
              b07cdel_record (
                    VAR t       : tgg00_TransContext;
                    VAR file_id : tgg00_FileId;
                    VAR rk      : tgg00_Lkey);
 
        PROCEDURE
              b07cadd_record (
                    VAR t    : tgg00_TransContext;
                    VAR curr : tgg00_FileId;
                    VAR b    : tgg00_Rec);
 
        PROCEDURE
              b07cnext_record (
                    VAR t            : tgg00_TransContext;
                    VAR curr         : tgg00_FileId;
                    VAR rk           : tgg00_Lkey;
                    VAR set_result   : tgg00_BdSetResultRecord;
                    VAR tree_pos     : tgg00_FilePos;
                    VAR b            : tsp00_Buf);
 
      ------------------------------ 
 
        FROM
              FileDir_Wrapper :vbd998;
 
        PROCEDURE
              bd998NewTempFileNo (
                    VAR file_no : tgg00_Surrogate);
 
      ------------------------------ 
 
        FROM
              Configuration_Parameter : VGG01;
 
        VAR
              g01unicode       : boolean;
 
      ------------------------------ 
 
        FROM
              Select_Help_Procedures : VGG04;
 
        PROCEDURE
              g04build_temp_tree_id (
                    VAR curr : tgg00_FileId;
                    VAR t : tgg00_TransContext);
 
        PROCEDURE
              g04index_tree_build (
                    VAR file_id    : tgg00_FileId;
                    VAR index_tree : tgg00_FileId;
                    index_no       : tsp00_Int2);
 
      ------------------------------ 
 
        FROM
              Kernel_move_and_fill : VGG101;
 
        PROCEDURE
              SAPDB_PascalForcedFill (
                    size        : tsp00_Int4;
                    m           : tsp00_MoveObjPtr;
                    pos         : tsp00_Int4;
                    len         : tsp00_Int4;
                    fillchar    : char);
 
        PROCEDURE
              SAPDB_PascalForcedMove (
                    source_upb  : tsp00_Int4;
                    destin_upb  : tsp00_Int4;
                    source      : tsp00_MoveObjPtr;
                    source_pos  : tsp00_Int4;
                    destin      : tsp00_MoveObjPtr;
                    destin_pos  : tsp00_Int4;
                    length      : tsp00_Int4);
 
        PROCEDURE
              SAPDB_PascalForcedUnicodeFill (
                    obj_upb     : tsp00_Int4;
                    obj         : tsp00_MoveObjPtr;
                    obj_pos     : tsp00_Int4;
                    length      : tsp00_Int4;
                    fillchar    : tsp00_C2 );
 
        PROCEDURE
              SAPDB_PascalMove (
                    mod_id      : tsp00_C6;
                    mod_num     : tsp00_Int4;
                    source_upb  : tsp00_Int4;
                    dest_upb    : tsp00_Int4;
                    source      : tsp00_MoveObjPtr;
                    src_pos     : tsp00_Int4;
                    destin      : tsp00_MoveObjPtr;
                    dest_pos    : tsp00_Int4;
                    length      : tsp00_Int4;
                    VAR e       : tgg00_BasisError);
 
      ------------------------------ 
 
        FROM
              RTE-Extension-30 : VSP30;
 
        PROCEDURE
              s30cmp (
                    VAR buf1     : tsp00_Key;
                    fieldpos1    : tsp00_Int4;
                    fieldlength1 : tsp00_Int4;
                    VAR buf2     : tsp00_Key;
                    fieldpos2    : tsp00_Int4;
                    fieldlength2 : tsp00_Int4;
                    VAR l_result : tsp00_LcompResult);
 
        PROCEDURE
              s30cmp1 (
                    VAR buf1     : tsp00_Buf;
                    fieldpos1    : tsp00_Int4;
                    fieldlength1 : tsp00_Int4;
                    VAR buf2     : tsp00_KnlIdentifier;
                    fieldpos2    : tsp00_Int4;
                    fieldlength2 : tsp00_Int4;
                    VAR l_result : tsp00_LcompResult);
 
        FUNCTION
              s30lnr_defbyte (str : tsp00_MoveObjPtr   (*ptocSynonym const void**);
                    defbyte   : char;
                    start_pos : tsp00_Int4;
                    length    : tsp00_Int4) : tsp00_Int4;
 
      ------------------------------ 
 
        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);
 
.CM *-END-* use -----------------------------------------
.sp;.cp 3
Synonym :
 
        PROCEDURE
              a27init_viewscanpar;
 
              tak_viewscan_par tak_save_viewscan_par
 
        PROCEDURE
              a05_identifier_get;
 
              tsp00_MoveObj tsp00_KnlIdentifier
 
        PROCEDURE
              b07cnext_record;
 
              tsp00_MoveObj tsp00_Buf
 
        PROCEDURE
              t01buf;
 
              tsp00_Buf tak_systembuffer
 
        PROCEDURE
              s30cmp;
 
              tsp00_MoveObj tsp00_Key
              tsp00_MoveObj tsp00_Key
 
        PROCEDURE
              s30cmp1;
 
              tsp00_MoveObj tsp00_Buf
              tsp00_MoveObj tsp00_KnlIdentifier
 
.CM *-END-* synonym -------------------------------------
***********************************************************
 
Specification:
 
PROCEDURE  A25_CALL_SEMANTIC
 
The procedure takes care of the implementation of the commands
Create and Drop Link, i.e. the necessary integrity
checks are performed and the corresponding
catalog information is built or deleted.
 
.CM *-END-* specification -------------------------------
***********************************************************
 
Description:
.sp;.nf
PROCEDURE  A25LINK_SEMANTIC (VAR acv : all_command_glob);
.sp;.fo
The procedure is called in the course of a Create or Drop Link command in order
to perform the necessary sysinfo modifications.
.br
When the procedure is called, the syntax tree of the corresponding command has
already been built.
.br
First of all, the cache is deleted in order to ensure that all sysinfo records
that are read in the course of processing are implicitly share-locked. The
catalog record of type tbaserecord of the primary table is loaded into the
cache by a11get_check_table and the table is share-locked. In case of a
create Link command, the same procedure is performed with the secondary table.
Depending on the command (Create or Drop), a branch is then made to
a25_create_link or a25_drop_link, where the command is further processed.
.br
If errors have occurred in the course of processing, sysinfo modifications that
have already been made are cancelled again (a06_partial_rollback).
.sp 2;.nf
PROCEDURE  A25_CREATE_LINK (VAR acv : all_command_glob;
            VAR a25v : a25_glob);
.sp;.fo
The procedure checks the legality of the link defined by the user and creates
the catalog information required for producing the link.
.br
First of all, it is checked whether the specified link violates the already
existing link structure (==> a25_structure_check). If this is not the case, the
sysinfo records required for producing the link are built in the cache. Each
table that is the primary table of at least one link has a catalog record
type tlinkrecord in which all links in which the table is the primary table are
recorded (max. 16). The key of this sysinfo record has the slinkage = 1.
.br
Each table that is the secondary table of at least one link has catalog
information of type tlinkrecord in which all links in which the table is the
secondary table are recorded (max.16). The key of this sysinfo record has the
slinkage = 2.
These records must be either created or extended. By means of
a10fix_get_sysinfo, first of all, the tlinkrecord of the primary table is
allocated in the cache. If the record has not existed up to now, it is
initialized as tlinkrecord. By means of a25_unique_link, it is then checked
whether the specified link name is unique and whether the number of links in
which the table is the primary table is less than 16. The secondary-table name
is entered in the tlinkrecord by means of a25_init_link_record.
.br
The tlinkrecord for the secondary table is allocated in the cache and
initialized in the same manner (without uniqueness check). Then, each specified
column is determined by a25_get_check_column_type, compatibility with the
corresponding key column of the primary table is checked, and the tlinkrecords
are filled with the corresponding information. By means of verify_link, the
legality of the link is then checked, i.e. it is checked whether each foreign
key of the secondary table exists as a key of the primary table.
.br
If no errors have occurred, the two tlinkrecords are inserted into system file
1.
.br
If a link has been defined with ON DELETE SET DEFAULT, a catalog record
type tlinkdefrecord in which the default foreign key is stored is created and
is inserted into the system file.
.br
After the link catalog records have been built, it must now also be ensured that
the tbaserecords of the base tables are adjusted and that the new link
definition is made known to all dependent views. The primary-table flag is
written to the tbaserecord of the primary table. The tbaserecords of the
secondary table are released in the cache in order to provide sufficient cache
for a25_replace_base_records. In this procedure, the version number of the
table is increased, the tbaserecords are written back and an internal Save
Schema of the primary table is performed. Then, the tbaserecords of the
secondary table are loaded into the cache (since they may have been displaced
by a25_version_save_scheme) and a25_version_save_scheme is called for the
secondary table, as a result of which the version number for it, too, is
increased and all dependent views are saved by an internal Save Schema. The
definitions of all dependent views of the primary and secondary tables are then
stored in the temporary file vsc_filename. By means of the procedure
a25_restore_scheme, the catalog information of all views dependent on the
primary and secondary tables is re-built. This is necessary in order to update
the version numbers in the views and in order to re-determine the correct
execution sequence in Join Views for Update.
.sp 4;.nf
PROCEDURE  A25_UNIQUE_LINK (VAR acv : all_command_glob;
            VAR a25v     : a25_glob;
            VAR linkaddr : tsysbufferaddress);
.sp;.fo
The procedure checks whether there is still space for a link definition on the
tlinkrecord allocated in the cache starting at address linkaddr, and whether
the name a2linkname is unique on the tlinkrecord. If this is not the case, a
corresponding error message is created.
.sp 4;.nf
PROCEDURE  A25_SEARCH_LINK (VAR acv : all_command_glob;
            VAR link_name : name;
            VAR linkbuf   : tsysbufferaddress;
            VAR index     : integer);
.sp;.fo
On the tlinkrecord allocated starting at address linkbuf, the procedure
searches for the definition of the link with link name link_name. If the link
is found, the array index of the description is returned in index; otherwise,
index = 0.
.sp 4;.nf
PROCEDURE  A25_VERIFY_LINK (VAR acv : all_command_glob;
            VAR a25v : a25_glob;
            outpos   : integer);
.sp;.fo
The procedure checks whether the data stored in the secondary table are in
compliance with the link, i.e. it is checked whether each foreign key of the
secondary table occurs as a key of the primary table.
.br
For this purpose, first of all, a Select Distinct <Foreign Keys> From secondary
table command is sent to KB. When the procedure is called, the corresponding
message buffer has already been built except for the strategy. The missing
strategy is created by a25_build_strategy. The result obtained is a temporary
result table with all foreign keys of the secondary table (acv_into_file of the
acv).
.br
For each row of this result table, it is now checked whether the respective
foreign key contains a null column or whether it is the default foreign key. In
these cases, the key need not be searched for in the primary table. Otherwise,
a key of the primary table is formed from the foreign key and the associated
record is selected by a Get Direct command to KB. If the record that is
searched for does not exist, the link condition is violated and a corresponding
error message is returned.
.sp 4;.nf
PROCEDURE  A25_BUILD_STRATEGY (VAR acv : all_command_glob;
            VAR a25v : a25_glob;
            outpos   : integer);
.sp;.fo
A strategy description for the execution of the Select Distinct command from
a25_verify_link is stored in the message buffer. The strategy is purely
sequential and the result is built in the acv_into_file.
.sp 4;.nf
PROCEDURE  A25_GET_CHECK_COLUMN_TYPE (VAR acv : all_command_glob;
            VAR a25v        : a25_glob;
            col_count       : integer;
            VAR outpos      : integer);
.sp;.fo
The procedure determines the next foreign-key column from the SQL packet,
checks compatibility with the corresponding key column of the primary table,
ensures the description of the columns in the tlinkrecords of the primary and
secondary tables and builds the output description of the column for the Select
command in a25_verify_link in the message buffer.
.br
The column name is determined from the SQL packet with the aid of the syntax
tree and it is checked whether the column exists in the secondary table. The
data type and the length of the column must agree with data type and length of
the corresponding key column of the primary table. If the link has been defined
with ON DELETE SET NULL, the foreign-key column must not be a NOT NULL column
and must not be a key column. If the link has been defined with ON DELETE SET
DEFAULT, the foreign-key column must have a default definition.
.br
The stack entry of the corresponding key column is entered in the tlinkrecord
of the primary table.
.sp 4;.nf
PROCEDURE  A25_GET_DEFAULT_VALUE (VAR acv : all_command_glob;
            VAR a25v     : a25_glob;
            VAR col_info : tcolumninfo;
            last         : boolean);
.sp;.fo
The procedure serves to construct the default foreign keys.
The part of the default
foreign key already built at the time the procedure is called (in a2default) is
extended by the default value of the column col_info. If the column is not the
last one of the foreign key, it is filled up to the definition length of the
column with the Def-Byte. Default functions (DATE, TIME, USER, USERGROUP,
STAMP) are illegal.
.sp 4;.nf
PROCEDURE  A25_INIT_LINK_RECORD (VAR acv : all_command_glob;
            VAR a25v       : a25_glob;
            VAR linkptr    : tsysbufferaddress;
            table_no       : integer);
.sp;.fo
The tlinkrecord allocated in the cache starting at address linkptr is extended
by a link description. On entry into the procedure, it is ensured that there is
still space for the link description. The new link description becomes the last
one in the tlinkrecord. The link description is initialized with the values
from a25v, with the table name being identified by the parameter table_no.
.sp 4;.nf
PROCEDURE  A25DROP_LINK (VAR acv : all_command_glob;
            VAR a25v        : a25_glob;
            tabno           : integer;
            VAR viewscanpar : save_viewscan_par);
.sp;.fo
The procedure is called in the course of a drop table command if the table to
be deleted is the primary and/or secondary table of links. The procedure then
ensures that all links in which the table is the primary (tabno = 1) or
secondary table (tabno = 2) are deleted.
.br
The necessary sysinfo modifications are performed by DROP_LINK.
.sp 4;.nf
PROCEDURE  A25_DROP_LINK (VAR acv : all_command_glob;
            VAR a25v      : a25_glob);
.sp 4;.fo
The procedure deletes from the catalog record the link specified by the
user. The necessary sysinfo modifications are performed by DROP_LINK.
.sp 4;.nf
PROCEDURE  DROP_LINK (VAR acv    : all_command_glob;
            VAR a25v        : a25_glob;
            drop_one_link   : boolean;
            tabno           : integer;
            VAR viewscanpar : save_viewscan_par);
.sp;.fo
The procedure deletes one (drop_one_link = TRUE) or all (drop_one_link = FALSE)
link definition(s) in which the table specified by tabno is the primary (tabno
= 1) or secondary (tabno = 2) table. It is recorded in viewscanpar whether this
is the first call of the procedure (vsc_first_save = TRUE) and/or last call of
the procedure (vsc_last_save = TRUE). This is necessary, because an implicit
Save Schema of the relevant tables is performed in which all view definitions
are saved to a temporary file. When the procedure is first called, this file
must first of all be created, whereas, after the last call, the Into file,
which is used for internal Save Schema, must be emptied again.
.br
Implementation is basically by means of a Repeat loop that is run through twice
in the case of a drop link command and otherwise linkcount times. On each run
through the loop, the relevant tlinkrecord is first of all re-allocated in the
cache. This is necessary, because the tlinkrecord may have been displaced by an
internal Save Schema in the procedure del_link_in_record. The two cases
of deleting a link definition and of deleting all link definitions are now
considered separately:
.br
i)@@Deletion of precisely one link definition
.in +4
In the first run through the loop, the link description to be deleted is first
of all determined (a25_search_link). By means of a25_del_link_in_record,
the link that has been found is deleted in the tlinkrecord of the corresponding
secondary table and all views dependent on the secondary table are saved into
the save_schema_file.
.br
In the second run through the loop, the link description is removed from the
tlinkrecord of the primary table (a25_link_del_from_linkrec). The Repeat loop
then terminates.
.br
The version number of the primary table is then increased by
a25_version_save_scheme. For this purpose, the tbaserecords of the primary
table must first of all be re-allocated in
the cache, since they may have already
been displaced. The views dependent on the primary table are likewise saved to
the save_schema_file. By means of a25_restore_scheme, the catalog information of
all views dependent on the primary and secondary tables is then re-built.
.in -4
ii)@Deletion of all link definitions (Drop Table)
.in +4
a25_del_link_in_record is called for each link definition that does not
describe a self-referencing link, as a result of which the link definition is
deleted from the tlinkrecord of the corresponding table and all dependent view
definitions of this table are saved in the save_schema_file. Before the
procedure is called, it is checked whether this is the last call in the course
of the command in order then, if necessary, to delete the acv_into_file
(vsc_last_save = TRUE). The Repeat loop then terminates and all catalog
information of the views that have been saved is re-built (a25_restore_scheme).
The tbaserecords of the table to be deleted are then re-allocated in the cache,
since they may have been displaced and are still required in the further course
of the drop table command.
.in -4;.sp 4;.nf
PROCEDURE  A25_RESTORE_SCHEME (VAR acv : all_command_glob;
            VAR viewscanpar : save_viewscan_par);
.sp;.fo
The catalog information of the view definitions that have been saved in the
save_catalog_file is re-built by a15restore_catalog if this is the last
a25_restore_scheme call in the course of the command (vsc_save_last = TRUE). If
the a_returncode before or after a15restore_catalog is <> 0, the save_catalog_file
is deleted and the Into file is emptied.
.sp 4;.nf
PROCEDURE  A25RENAME_TAB_IN_LINK (VAR acv : all_command_glob;
            VAR a25v       : a25_glob;
            VAR oldtabname : name);
.sp;.fo
The procedure is called in the course of a Rename Table command if the renamed
table is the primary and/or secondary table of links. The table name in the
tlinkrecords of the corresponding link tables must be appropriately updated.
The system key of the relevant tlinkrecord of the renamed base table is
transferred to a2syskey(1).
If the slinkage of the key = 1, the links in which
the renamed table is the primary table are handled; otherwise, the links in
which the table is the secondary table are processed. One of the following
actions is performed for each description of a link on the current tlinkrecord:
.br;.hi +4
i)@@The description contains the old table name of the renamed table (self-
referencing link):
.hi -4;.in +4
The table name in the current tlinkrecord of the table is updated.
.in -4;
.br;.hi +4
ii)@The description contains a non-self-referencing link, i.e. the table name T
differs from the name of the renamed table.
.hi -4;.in +4
In the tlinkrecord of T, the old name of the renamed table is replaced by the
new name by a25_del_link_in_record and the version of T is increased. In
addition, all views dependent on T are saved in the save_schema_file.
.in -4
If the current tlinkrecord contains self-referencing links, the tlinkrecord is
written to the system file. All views that are saved are re-built by
a25_restore_scheme.
.sp 4;.nf
PROCEDURE  A25_DEL_LINK_IN_RECORD (VAR acv : all_command_glob;
            VAR linkname   : name;
            VAR authid     : user_id;
            VAR tablen     : name;
            VAR linkauth   : user_id;
            VAR linktabl   : name;
            linkseqno      : integer;
            drop_link      : boolean;
            VAR viewscanpar: save_viewscan_par);
.sp;.fo
A search is made for the link with name linkname on the tlinkrecord with slinkage
= linkseqno of the table authid.tablen. If the procedure has been called as the
result of a Drop Link command, the link definition that is found is deleted
from the tlinkrecord (a25_link_del_from_linkrec).
.br
If the procedure has been called as the result of a Rename Table command, the
new table name is allocated to the table name in the link definition and the
tlinkrecord is written back. In both cases, the version number of authid.tablen
is increased and all view definitions dependent on authid.tablen are saved
(a25_version_save_scheme);
.sp 4;.nf
PROCEDURE  A25_REPL_LINK_INF_IN_BASEREC (VAR acv : all_command_glob;
            VAR p_arr   : tsyspointerarr;
            VAR linkbuf : tsysbufferaddress;
            index       : integer);
.sp;.fo
The procedure is called if a link definition has been deleted. In the
tbaserecords of the foreign-key table, it is necessary in the relevant column
definitions to remove the link flag unless the column is still the foreign-key
column of other link definitions. If, after deletion of the link, the table is
no longer a foreign-key table, i.e. if there is no longer a link in which the
table is the secondary table, the foreign-key table flag is_secondary_table is
also removed from the first tbaserecord.
.sp 4;.nf
PROCEDURE  A25_LINK_DEL_FROM_LINKREC (VAR acv : all_command_glob;
            VAR linkbuf : tsysbufferaddress;
            VAR index   : integer;
            VAR locset  : locnoset;
            VAR p_arr   : tsyspointerarr);
.sp;.fo
The link definition described in linkdef(index) of the tlinkrecord allocated
starting at address linkbuf is removed. If, as a result, the tlinkrecord is
empty, it is deleted from the system file. If a default foreign key was
allocated to the link, the corresponding catalog record is deleted.
.sp 4;.nf
PROCEDURE  A25_eval_link_pos_info (VAR acv : all_command_glob;
            VAR linkbuf : tsysbufferaddress);
.sp;.fo
On insertion into a foreign-key table, all foreign-key values of all links in
which the table is the foreign-key table are written by KB to a temporary file.
Although a foreign-key column may occur in more than one link, it is stored
only once by KB. It must, therefore, be possible to determine the column of a
link from a row of the temporary file in order to be able to build the key of
the primary table. For this reason, the procedure computes for each column the
position at which the corresponding value is found in a row of the temporary
file. The computed value is stored in
lrecpos in the tlinkrecord.
.sp 4;.nf;.cp 8
PROCEDURE  A25_CASCADE_DEPENDENCY (VAR acv : all_command_glob;
            from_authid    : user_id;
            from_tablen    : name;
            from_table_loc : location;
            VAR to_authid  : user_id;
            VAR to_tablen  : name;
            VAR cycle_par  : cycle_parameter);
.sp;.fo
In order to understand the procedure, the following definitions are necessary:
.br
10. A table T1 is called CASCADE-dependent on a table T if there exists a
sequence of links L(1),L(2),...,L(n) where n>=1, with the result that
.in +4
.sp
.of 3
a. T1 is the secondary table of L(1) and
.sp
.of 3
b. T is the primary table of L(n) and
.sp
.of 3
c. all links specify CASCADE und
.sp
.of 3
d. for i=1,...,n-1 and n>1 the primary table of L(i) is identical with the
secondary table of L(i+1).
.sp
.of 3
Graphic illustration in an example where n=3:
.sp;.nf
       L(1)           L(2)           L(3)
T1 <---------- T2 <---------- T3 <---------- T
      CASCADE        CASCADE        CASCADE
.fo;.in -4
.sp
12. A reference cycle is a sequence of links L(1),L(2),...,L(n) where n>1, with
the result that
.in +4
.sp
.of 3
a. for i=1,...,n-1 the primary table of L(i) is identical with the secondary
table of L(i+1) and
.sp
.of 3
b. the primary table of L(n) is identical with the secondary table of L(1).
.in -4
.sp
.of 4
13. A reference cycle in which all links specify CASCADE is not allowed.
.br;.in +4
A reference cycle in which one link does not specify CASCADE and in which all
other links specify CASCADE is not allowed.
.in -4
.sp
The procedure is able to recognize CASCADE dependencies and illegal reference
cycles, i.e. it checks
.br
i)@@is there a link sequence L(1)..L(N) where
.in +4;.nf
                    L(1)            L(N)
to_authid.to_tablen <-- T1 .. TN-1 <-- from_authid.from_tablen
.sp;.fo
with the result that T1 is CASCADE-dependent on from_authid.from_tablen. The
link L1 must be equal to the transferred linkrule (crule_ind) and must be not
equal to SET NULL and not equal to SET DEFAULT. If this is not the case, there
is a corresponding error message. (see A25_CHECK_RULE_11).
.in -4
ii)@is there a link sequence L(1)..L(N) where
.br;.in +4;.nf
                    L(1)            L(N)
to_authid.to_tablen <-- T1 .. TN-1 <-- from_authid.from_tablen
.br;.fo
with it being allowable for one of the links L(1)..L(N) to be not equal to
Cascade if the link to be created between from_authid.from_tablen and
to_authid.to_tablen specifies Cascade. If there is such a sequence, there is a
corresponding error message. (illegal reference cycle).
.in -4
.br
The recognition of illegal reference cycles is basically the recognition of
CASCADE dependencies, with the difference that a link that does not specify
Cascade may occur in the link sequence. Whether the procedure has been called
for the cycle test is specified by the parameter ccycletest (TRUE).
.sp 4;.nf
PROCEDURE  A25_CHECK_RULE_11 (VAR acv : all_command_glob;
            authid           : user_id;
            tablen           : name;
            table_loc        : location;
            VAR prim_authid  : user_id;
            VAR prim_tablen  : name;
            VAR prim_loc     : location;
            init_link_rule   : integer;
            VAR cycle_par    : cycle_parameter);
.sp;.fo
In order to understand the procedure, the following definitions are necessary:
.sp
11. Let L1 and L2 be two different links with the same secondary table S. Let
the primary table of L1 be called T1 and that of L2 T2. If T1 is equal to T2,
or if there is a table T, with the result that T1 and T2 are CASCADE-dependent
on T, then L1 and L2 must either both specify CASCADE or both specify RESTRICT.
.sp
The procedure now checks whether this condition is violated by the new link
definition. For this purpose, it is first of all determined by means of
a25_rule_11_tab_check whether the condition is violated if authid.tablen
assumes the role of S. If this is not the case, each secondary table of links
in which authid.tablen is the primary table assumes the role of S. This is done
by recursive calling of a25_check_rule_11.
.br
Graphic illustration :
.sp;.nf
                   casc         casc
        T4 <--- T1 <--- sec_tab <--- prim_tab
                      )
                T2 <--+
.sp;
1st call       : a25_check_rule_11 (sec_tab, prim_tab)
                 check whether the rule is violated if
                 sec_tab assumes the role of S.
2nd call       : a25_check_rule_11 (T1, prim_tab)
                 Check whether the rule is violated if
                 T1 assumes the role of S.
3rd call       : a25_check_rule_11 (T4, prim_tab)
                 Check whether the rule is violated if
                 T1 assumes the role of S.
4th call       : a25_check_rule_11 (T2, prim_tab)
                 Check whether the rule is violated if
                 T2 assumes the role of S.
.sp 4;.nf
PROCEDURE  A25_STRUCTURE_CHECK (VAR acv : all_command_glob;
            VAR prim_auth   : user_id;
            VAR prim_tablen : name;
            VAR prim_loc    : location;
            linkrule        : integer;
            VAR sec_auth    : user_id;
            VAR sec_tablen  : name;
            VAR sec_loc     : location);
.sp;.fo
The procedure checks whether the definition of a link between
prim_auth.prim_tablen and sec_auth.sec_tabl is compatible with the already
existing link structure.
.br
First of all, it is checked by a25_cascade_dependency whether an illegal
reference cycle would result from the new link definition. If this is not the
case, a25_check_rule_11 checks rule 11 of the link description from the manual
(see a25_check_rule_11).
.sp 4;.nf
PROCEDURE  A25_RULE_11_TAB_CHECK (VAR acv : all_command_glob;
            curr_authid         : user_id;
            curr_tablen         : name;
            curr_loc            : location;
            VAR destauthid      : user_id;
            VAR desttablen      : name;
            VAR cycle_par       : cycle_parameter);
.sp;.fo
The procedure checks rule 11 (see a25_check_rule_11), assuming that the table
destauthid.desttablen represents table S in the rule. Let T be the table
destauthid.desttablen and let L1 be the link to be created. It is now checked
whether a link L2 exists, with the result that
.br;
.hi +4
i)@@The link condition of L1 is not equal to that of L2 or L1 or L2 specifies
SET NULL or SET DEFAULT.
.hi -4;.nf;.sp
        L1            L2
ii) S <---- T and S <---- T
 
    or
 
        L1      casc         casc
    S <---- T  <----- ..... <---- X and
 
        L2      casc         casc
    S <---- T1 <----- ..... <---- X
.fo;.sp
When the procedure is called, it is therefore first of all checked whether
there is a link L from S <-- T that violates the condition
(a25_cascade_dependency). If this is not the case, it is checked for each
primary table Ti of a Cascade link in which T is the foreign-key table whether
Ti is playing the role of X. This is done by recursive calling of
a25_rule_11_tab_check with curr_authid.curr_tablen = Ti.
.sp 4;.nf
PROCEDURE  A25_REPLACE_BASE_RECORDS (VAR acv : all_command_glob;
            VAR p_arr       : tsyspointerarr;
            VAR locset      : locnoset;
            VAR viewscanpar : save_viewscan_par);
.sp;.fo
The file version of the table specified by p_arr is increased, is entered in
the tbaserecords allocated in the cache and the latter are inserted into the
system file.
.br
The definitions of all views dependent on the table are saved to the temporary
save_catalog_file by a15catalog_save.
.CM *-END-* description ---------------------------------
***********************************************************
.CM -lll-
Code    :
 
 
CONST
      c_primary_table    = 1;
      c_secondary_table  = 2;
      c_drop_one_link    = true;
      c_call_from_rsend  = true (* a06lsend_mess_buf *);
      c_get_all          = true;
      c_scan_views       = true;
      c_is_rollback      = true;
 
TYPE
 
      cycle_parameter = RECORD
            clinkbuf       : tak_sysbufferaddress;
            clinkkey       : tgg00_SysInfoKey;
            crule_ind      : integer;
            ccycletest     : boolean;
            cnot_cascade   : boolean;
            cself_ref      : boolean;
      END;
 
 
      tak25_get_col_info = RECORD
            gci_prim_key    : boolean;
            gci_mult_index  : boolean;
            gci_is_pk_key   : boolean;
            gci_is_unique   : boolean;
            gci_fk_is_key   : boolean;
            gci_col_count   : integer;
            gci_first_colno : integer;
            gci_outpos      : integer;
            gci_fk_colindex : integer;
            gci_pk_colindex : integer;
            gci_p_priv      : tak_privilege;
      END;
 
 
 
(*------------------------------*) 
 
PROCEDURE
      ak25check_unique_pk (
            VAR acv   : tak_all_command_glob;
            base_ptr  : tak_sysbufferaddress);
 
VAR
      b_err      : tgg00_BasisError;
      i          : integer;
      link_index : integer;
      link_count : integer;
      unique_cnt : integer;
      linkbuf    : tak_sysbufferaddress;
      sysk       : tgg00_SysInfoKey;
 
BEGIN
i              := 1;
link_index     := 1;
unique_cnt     := 0;
link_count     := cak_is_undefined;
sysk           := base_ptr^.syskey;
sysk.sentrytyp := cak_eprimarykey;
REPEAT
    a10get_sysinfo (acv, sysk, d_release, linkbuf, b_err);
    IF  b_err = e_ok
    THEN
        WITH linkbuf^.slink DO
            BEGIN
            IF  link_count = cak_is_undefined
            THEN
                link_count := linkcount;
            (*ENDIF*) 
            FOR i := 1 TO linkbuf^.b_sl DIV sizeof (linkdef[1]) DO
                WITH linkdef[ i ] DO
                    IF  ord (lindexid[ 1 ]) > 0
                    THEN
                        unique_cnt := unique_cnt + 1;
                    (*ENDIF*) 
                (*ENDWITH*) 
            (*ENDFOR*) 
            link_index := link_index + cak_maxlinkdef;
            a06inc_linkage (sysk.slinkage)
            END;
        (*ENDWITH*) 
    (*ENDIF*) 
    IF  b_err <> e_ok
    THEN
        a07_b_put_error (acv, b_err, 1)
    (*ENDIF*) 
UNTIL
    (link_index > link_count) OR
    (unique_cnt > 0)          OR
    (acv.a_returncode <> 0);
(*ENDREPEAT*) 
IF  unique_cnt = 0
THEN
    WITH base_ptr^.sbase DO
        blinkexist := blinkexist - [ unique_pk_table ]
    (*ENDWITH*) 
(*ENDIF*) 
END;
 
(* PTS 1104808, T.A. 04.01.2000 *)
(*------------------------------*) 
 
PROCEDURE
      a25FindForeignKeyInfo (
            VAR acv             : tak_all_command_glob;
            VAR PrimaryKeyBuf   : tak_sysbufferaddress;
            PrimaryKeyIndex     : integer;
            VAR ForeignKeyBuf   : tak_sysbufferaddress;
            VAR ForeignKeyIndex : integer);
 
VAR
      e               : tgg00_BasisError;
      sysk            : tgg00_SysInfoKey;
      linkCnt         : integer;
      PrimaryKeyTabid : tgg00_Surrogate;
      LinkName        : tsp00_KnlIdentifier;
 
BEGIN
ForeignKeyBuf   := NIL;
ForeignKeyIndex := 0;
PrimaryKeyTabid := PrimaryKeyBuf^.syskey.stableid;
a25get_linkname (acv, PrimaryKeyBuf, PrimaryKeyIndex, LinkName);
sysk            := a01defaultkey;
sysk.stableid   := PrimaryKeyBuf^.slink.linkdef[PrimaryKeyIndex].ltableid;
sysk.sentrytyp  := cak_eforeignkey;
a10get_sysinfo (acv, sysk, d_release, ForeignKeyBuf, e);
IF  e = e_ok
THEN
    BEGIN
    linkCnt         := ForeignKeyBuf^.slink.linkcount;
    ForeignKeyIndex := 1;
    ak25search_link (acv, LinkName, PrimaryKeyTabid,
          linkCnt, ForeignKeyBuf, ForeignKeyIndex);
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a25get_linkname (
            VAR acv        : tak_all_command_glob;
            linkbuf        : tak_sysbufferaddress;
            index          : integer;
            VAR link_name  : tsp00_KnlIdentifier);
 
VAR
      b_err     : tgg00_BasisError;
      offset    : integer;
      rest_len  : integer;
      len       : integer;
      lname_pos : integer;
      sysk      : tgg00_SysInfoKey;
 
BEGIN
WITH linkbuf^.slink.linkdef[index] DO
    BEGIN
    SAPDB_PascalForcedMove (sizeof (linkn_prefix), sizeof (link_name), @linkn_prefix, 1,
          @link_name, 1, sizeof (linkn_prefix));
    lname_pos := sizeof (linkn_prefix) + 1;
    rest_len  := lsuffixlen;
    IF  rest_len > 0
    THEN
        BEGIN
        IF  lcolcount = 1
        THEN
            offset := 1
        ELSE
            offset := 0;
        (*ENDIF*) 
        len := sizeof (lstack) - (lcolcount + offset) * sizeof (lstack[1]);
        IF  len > rest_len
        THEN
            len := rest_len;
        (*ENDIF*) 
        SAPDB_PascalMove ('VAK25 ',   1,    
              sizeof (lstack), sizeof (link_name),
              @lstack, (lcolcount + offset) * sizeof (lstack[1]) + 1,
              @link_name, lname_pos, len, acv.a_returncode);
        lname_pos := lname_pos + len;
        rest_len  := rest_len - len
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
IF  rest_len > 0
THEN
    BEGIN
    sysk             := linkbuf^.syskey;
    sysk.slinkage[1] := chr(index);
    a10get_sysinfo (acv, sysk, d_release, linkbuf, b_err);
    IF  b_err <> e_ok
    THEN
        a07_b_put_error (acv, b_err, 1)
    ELSE
        BEGIN
        offset := cgg_rec_key_offset + linkbuf^.syskey.skeylen +
              sizeof (linkbuf^.slink.lsegmentid);
        SAPDB_PascalMove ('VAK25 ',   2,    
              sizeof (linkbuf^.slink), sizeof (link_name),
              @linkbuf^.slink, offset + 1,
              @link_name, lname_pos, linkbuf^.b_sl - offset,
              acv.a_returncode);
        lname_pos := lname_pos + linkbuf^.b_sl - offset
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
SAPDB_PascalMove ('VAK25 ',   3,    
      sizeof (a01_il_b_identifier), sizeof (link_name),
      @a01_il_b_identifier, 1, @link_name, lname_pos,
      sizeof (link_name) - lname_pos + 1,
      acv.a_returncode)
END;
 
(*------------------------------*) 
 
FUNCTION
      a25is_link_index (
            VAR acv   : tak_all_command_glob;
            col_count : integer;
            index_id  : integer) : boolean;
 
VAR
      b_err      : tgg00_BasisError;
      i          : integer;
      link_index : integer;
      link_count : integer;
      linkbuf    : tak_sysbufferaddress;
      sysk       : tgg00_SysInfoKey;
 
BEGIN
WITH acv DO
    BEGIN
&   ifdef trace
    t01int4 (ak_sem, 'col_count   ', col_count);
    t01int4 (ak_sem, 'index_id    ', index_id);
&   endif
    i              := 1;
    link_index     := 1;
    link_count     := cak_is_undefined;
    sysk           := a_p_arr1.pbasep^.syskey;
    sysk.sentrytyp := cak_eprimarykey;
    REPEAT
        a10get_sysinfo (acv, sysk, d_release, linkbuf, b_err);
        IF  b_err = e_ok
        THEN
            WITH linkbuf^.slink DO
                BEGIN
                IF  link_count = cak_is_undefined
                THEN
                    link_count := linkcount;
                (*ENDIF*) 
                i := 1;
                WHILE i <= linkbuf^.b_sl DIV sizeof (linkdef[1]) DO
                    WITH linkdef[ i ] DO
                        IF  (ord (lindexid[ 1 ]) = index_id) AND
                            (lcolcount = col_count)
                        THEN
                            BEGIN
                            i          := csp_maxint2;
                            link_index := csp_maxint2 - cak_maxlinkdef;
                            END
                        ELSE
                            i := i + 1;
                        (*ENDIF*) 
                    (*ENDWITH*) 
                (*ENDWHILE*) 
                link_index := link_index + cak_maxlinkdef;
                a06inc_linkage (sysk.slinkage)
                END;
            (*ENDWITH*) 
        (*ENDIF*) 
        IF  b_err <> e_ok
        THEN
            a07_b_put_error (acv, b_err, 1)
        (*ENDIF*) 
    UNTIL
        (link_index > link_count) OR (a_returncode <> 0);
    (*ENDREPEAT*) 
    a25is_link_index := link_index = csp_maxint2
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a25link_semantic (
            VAR acv    : tak_all_command_glob;
            start_node : integer);
 
VAR
      i               : integer;
      init_start_node : integer;
      tab_count       : integer;
      sec_tab_ti      : integer;
      error_pos       : integer;
      req_priv        : tak00_PrivilegeSet;
      p_arr           : tak_syspointerarr;
      a25v            : tak_a25_glob;
 
BEGIN
WITH acv, a25v DO
    BEGIN
    a2base_p[2]      := NIL;
    a2create_tab     := start_node > 1;
    init_start_node  := start_node;
    IF  a2create_tab
    THEN
        BEGIN
        start_node := a_ap_tree^[ start_node ].n_sa_level;
&       ifdef  TRACE
        t01int4(ak_sem, 'new startnod', start_node);
&       endif
        END;
    (*ENDIF*) 
    WITH a_ap_tree^[ start_node ] DO
        BEGIN
        IF  n_subproc = cak_x_create_link
        THEN
            BEGIN
            tab_count := 2;
            CASE n_length OF
                cak_i_cascade :
                    a2delact := cak_x_cascade;
                cak_i_null    :
                    a2delact := cak_x_set_null;
                cak_i_default :
                    a2delact := cak_x_set_default;
                cak_i_restrict :
                    a2delact := cak_x_restrict;
                END;
            (*ENDCASE*) 
            END
        ELSE
            tab_count := 1;
        (*ENDIF*) 
        a2ti := n_sa_level
        END;
    (*ENDWITH*) 
    a2linkname := a01_il_b_identifier;
    error_pos  := 1;
    WITH a_ap_tree^[ a2ti ] DO
        BEGIN
        IF  (n_symb = s_identifier) AND
            (a_init_ddl <> ddl_save_restore_cmd)
        THEN
            BEGIN
            error_pos := n_pos;
            a05_identifier_get (acv, a2ti,
                  sizeof(a2linkname), a2linkname)
            END;
        (*ENDIF*) 
        sec_tab_ti := n_lo_level;
        a2ti       := n_sa_level;
        END;
    (*ENDWITH*) 
    IF  a2create_tab
    THEN
        WITH a_p_arr1.pbasep^.sbase DO
            BEGIN
            a06determine_username (acv, bauthid, a2authname[ c_secondary_table ]);
            a2tablen [ c_secondary_table ] := btablen^;
            a2base_p [ c_secondary_table ] := a_p_arr1.pbasep
            END
        (*ENDWITH*) 
    ELSE
        a10_cache_delete (acv, NOT c_is_rollback);
    (*ENDIF*) 
    FOR i := c_primary_table TO tab_count DO
        IF  a_returncode = 0
        THEN
            BEGIN
            IF  NOT((i = c_secondary_table) AND a2create_tab)
            THEN
                BEGIN
                IF  i = c_secondary_table
                THEN
                    BEGIN
                    a2ti     := sec_tab_ti;
                    req_priv := [r_alter]
                    END
                ELSE
                    req_priv := [r_link];
                (*ENDIF*) 
                a11get_check_table (acv,
                      false, true, true, req_priv, false,
                      true, d_fix, a2ti, a2authname[ i ],
                      a2tablen[ i ], p_arr);
                a2base_p[i] := p_arr.pbasep
                END;
            (*ENDIF*) 
            IF  (a_ap_tree^[ start_node ].n_subproc = cak_x_drop_foreign_key)
                AND
                (a_returncode = 0)
            THEN
                ak25find_primary_table (acv, a25v, error_pos);
            (*ENDIF*) 
            IF  a_returncode = 0
            THEN
                WITH a2base_p[ i ]^.sbase, a2syskey[ i ] DO
                    BEGIN
                    a2syskey[ i ] := a01defaultkey;
                    stableid := btreeid.fileTabId_gg00;
                    a10_lock_sysinfo (acv,
                          a2syskey[ i ], lckTabShare_egg00);
                    a2ti := a_ap_tree^[ a2ti ].n_lo_level;
                    IF  i = 1
                    THEN
                        BEGIN
                        a2refcol_ti := a2ti;
                        sentrytyp   := cak_eprimarykey
                        END
                    ELSE
                        sentrytyp := cak_eforeignkey;
                    (*ENDIF*) 
                    END;
                (*ENDWITH*) 
            (*ENDIF*) 
            END;
        (*ENDIF*) 
    (*ENDFOR*) 
    IF  a2create_tab
    THEN
        a2ti := sec_tab_ti;
&   ifdef trace
    (*ENDIF*) 
    t01int4 (ak_sem, 'a2ti        ', a2ti);
    t01int4 (ak_sem, 'a2refcol_ti ', a2refcol_ti);
&   endif
    IF  a_returncode = 0
    THEN
        IF  a_ap_tree^[ start_node ].n_subproc = cak_x_create_link
        THEN
            ak25create_link (acv, a25v, error_pos)
        ELSE
            ak25link_drop (acv, a25v)
        (*ENDIF*) 
    ELSE
        IF  (a_returncode =
            a071_return_code (e_unknown_tablename, a_sqlmode))   AND
            (a2authname [ c_primary_table ] = a_curr_user_name) AND
            (a_sqlmode = sqlm_ansi)                           AND
            a2create_tab
        THEN
            ak25store_pending_link (acv, a25v, init_start_node);
        (*ENDIF*) 
    (*ENDIF*) 
    IF  a_returncode <> 0
    THEN
        a_part_rollback := true;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a25linkload_info (VAR acv : tak_all_command_glob);
 
VAR
      ok       : boolean;
      indexid  : char;
      b_err    : tgg00_BasisError;
      fk_buf   : tak_sysbufferaddress;
      lp_buf   : tak_sysbufferaddress;
      ic2      : tsp00_IntMapC2;
      i        : integer;
      j        : integer;
      pos      : integer;
      link_cnt : integer;
      curr_cnt : integer;
      extno    : integer;
      pCol     : tak00_colinfo_ptr;
      instanceId : tgg00_Surrogate;
      fk_key   : tgg00_SysInfoKey;
      lp_key   : tgg00_SysInfoKey;
 
BEGIN
WITH acv DO
    BEGIN
    fk_key           := a_p_arr1.pbasep^.syskey;
    fk_key.sentrytyp := cak_eforeignkey;
    REPEAT
        a10get_sysinfo (acv, fk_key, d_fix, fk_buf, b_err);
        IF  b_err = e_ok
        THEN
            BEGIN
            IF  fk_key.slinkage = cak_init_linkage
            THEN
                link_cnt := fk_buf^.slink.linkcount;
            (*ENDIF*) 
            curr_cnt         :=
                  fk_buf^.b_sl DIV sizeof (fk_buf^.slink.linkdef[1]);
            lp_key           := fk_key;
            lp_key.sentrytyp := cak_elinkparsinfo;
            a10_nil_get_sysinfo (acv, lp_key, d_fix,
                  cak_sysbufferoffset + 4 + curr_cnt * mxak_linkparsinfo,
                  lp_buf, b_err)
            END;
        (*ENDIF*) 
        IF  b_err = e_ok
        THEN
            BEGIN
            lp_buf^.slinkparsinfo.lpcount := fk_buf^.slink.linkcount;
            i := 1;
            WHILE (i <= curr_cnt) AND (a_returncode = 0) DO
                BEGIN
                a06_systable_get (acv, d_release,
                      fk_buf^.slink.linkdef[ i ].ltableid,
                      a_p_arr2.pbasep, NOT c_get_all, ok);
                IF  NOT ok
                THEN
                    a07ak_system_error (acv, 25, 1)
                ELSE
                    WITH fk_buf^.slink.linkdef[ i ],
                         lp_buf^.slinkparsinfo.lpinfo[ i ] DO
                        BEGIN
                        lpcolcount    := lcolcount;
                        lpstack       := lstack;
                        lp_one_to_one := false;
                        indexid       := lindexid[1];
                        j   := 1;
                        pos := 1;
                        WHILE j <= lcolcount DO
                            BEGIN
                            extno := lprimcolseq[j];
&                           ifdef trace
                            t01int4 (ak_sem, 'extno       ', extno);
&                           endif
                            a06extcolno (a_p_arr2.pbasep^.sbase, extno, pCol);
                            lpstack[j].ecol_pos := pCol^.cinoutlen;
                            CASE lstack[ j ].etype OF
                                st_fixkey :
                                    IF  lstack[j].epos = pos
                                    THEN
                                        pos := pos + lstack[j].elen_var
                                    ELSE
                                        j := lcolcount;
                                    (*ENDIF*) 
                                st_varkey :
                                    IF  pos = lstack[ j ].epos
                                    THEN
                                        lp_one_to_one := true;
                                    (*ENDIF*) 
                                OTHERWISE
                                    BEGIN
                                    lp_one_to_one := false;
                                    j := lcolcount
                                    END;
                                END;
                            (*ENDCASE*) 
                            j := j + 1
                            END;
                        (*ENDWHILE*) 
                        IF  NOT lp_one_to_one
                        THEN
                            IF  a_p_arr1.pbasep^.sbase.bindexexist
                            THEN
                                ak25columns_indexed (acv,
                                      a_p_arr1.pbasep^.sbase,
                                      fk_buf, true,
                                      false, lp_one_to_one);
                            (* PTS 2100 *)
                            (*ENDIF*) 
                        (*ENDIF*) 
                        lindexid[1] := indexid;
                        IF  NOT lp_one_to_one
                        THEN
                            BEGIN
                            ic2.mapC2_sp00 := fk_buf^.syskey.slinkage;
                            g04build_temp_tree_id (lpauxfile,
                                  a_transinf.tri_trans);
                            lpauxfile.fileTfnTemp_gg00 := ttfnLink_egg00;
                            a101_SetTempFileLevel (acv, lpauxfile,
                                  ic2.mapInt_sp00);
                            a101_SetTempFileIndex (acv, lpauxfile, i);
                            lpauxfile.fileHandling_gg00   := lpauxfile.fileHandling_gg00 -
                                  [ hsNoLog_egg00 ];
                            bd998NewTempFileNo (instanceId);
                            (* file must be entered into temp-mapper *)
                            a101_AddGroupedTempFile (
                                  acv.a_transinf.tri_trans,
                                  lpauxfile,
                                  instanceId);
                            (* mark new_treeid as fileid of an instantiated temp file *)
                            (* (as opposed to a logical temp file id)              *)
                            lpauxfile.fileTabId_gg00     := instanceId;
                            a06a_mblock_init (acv,
                                  m_create_table, mm_nil, lpauxfile);
                            a06lsend_mess_buf (acv,
                                  a_mblock, c_call_from_rsend, b_err);
                            IF  b_err <> e_ok
                            THEN
                                BEGIN
                                a101_RemoveGroupedTempFile (
                                      acv.a_transinf.tri_trans,
                                      lpauxfile);
                                a07_b_put_error (acv,
                                      a_transinf.tri_trans.trError_gg00, 1);
                                END
                            ELSE
                                BEGIN
                                lpauxfile := a_mblock.mb_qual^.mtree;
                                lpauxfile.fileHandling_gg00 :=
                                      lpauxfile.fileHandling_gg00 +
                                      [ hsNoLog_egg00 ]
                                END;
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        lptreeid   := a_p_arr2.pbasep^.sbase.btreeid;
                        IF  ord (lindexid[1]) > 0
                        THEN
                            BEGIN
                            g04index_tree_build (
                                  a_p_arr2.pbasep^.sbase.btreeid,
                                  lptreeid,
                                  ord (lindexid[1]));
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDWITH*) 
                (*ENDIF*) 
                i := i + 1
                END;
            (*ENDWHILE*) 
            IF  a_returncode = 0
            THEN
                BEGIN
                a_fk_check_cnt := a_fk_check_cnt + 1;
                a10_add_repl_sysinfo (acv, lp_buf, true, b_err)
                END;
            (*ENDIF*) 
            a10_rel_sysinfo (acv, lp_key);
            a10_rel_sysinfo (acv, fk_key);
            END;
        (*ENDIF*) 
        IF  b_err <> e_ok
        THEN
            a07_b_put_error (acv, b_err, 1)
        ELSE
            BEGIN
            a06inc_linkage (fk_key.slinkage);
            link_cnt := link_cnt - curr_cnt
            END;
        (*ENDIF*) 
    UNTIL
        (link_cnt <= 0) OR (a_returncode <> 0);
    (*ENDREPEAT*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
FUNCTION
      a25lnk_pending (VAR acv : tak_all_command_glob) : boolean;
 
CONST
      err_msg = ' LINK PENDING TO                        ';
 
VAR
      b_err_out  : tgg00_BasisError;
      tree       : tgg00_FileId;
      move_len   : integer;
      set_result : tgg00_BdSetResultRecord;
      tree_pos   : tgg00_FilePos;
      err        : tgg04_Err;
      key        : tgg00_Lkey;
      s40        : tsp00_C40;
 
BEGIN
WITH acv DO
    BEGIN
    a25lnk_pending := false;
    g04build_temp_tree_id (tree, a_transinf.tri_trans);
    tree.fileTfnTemp_gg00  := ttfnPendingLink_egg00;
    tree.fileHandling_gg00 := tree.fileHandling_gg00 - [ hsNoLog_egg00 ];
    a101_GetTempFileInstance (acv.a_transinf.tri_trans, tree);
    b01filestate (a_transinf.tri_trans, tree);
    IF  a_transinf.tri_trans.trError_gg00 = e_ok
    THEN
        BEGIN
        WITH set_result DO
            BEGIN
            bd_key_check_len:= 0;
            bd_max_rec_cnt  := 1;
            bd_max_fill_len := sizeof (a_mblock.mb_data^.mbp_4kbuf);
            bd_next         := true;
            END;
        (*ENDWITH*) 
        key.len := 0;
        tree_pos.tpsPno_gg00 := NIL_PAGE_NO_GG00;
        b07cnext_record (a_transinf.tri_trans, tree,
              key, set_result, tree_pos, a_mblock.mb_data^.mbp_4kbuf);
        IF  a_transinf.tri_trans.trError_gg00 = e_key_not_found
        THEN
            BEGIN
            a25lnk_pending := true;
            s40 := err_msg;
            SAPDB_PascalForcedFill (mxsp_c256, @err.errt, 1, mxsp_c256, bsp_c1);
            SAPDB_PascalForcedMove (mxsp_c40, mxsp_c256, @s40, 1, @err.errt, 1, mxsp_c40);
            move_len       := sizeof (err.errt) - 18 + 1;
            IF  move_len > sizeof (tsp00_KnlIdentifier)
            THEN
                move_len := sizeof (tsp00_KnlIdentifier);
            (*ENDIF*) 
            SAPDB_PascalForcedMove (a_mblock.mb_data_size, sizeof(err.errt),
                  @a_mblock.mb_data^.mbp_4kbuf, cgg_rec_key_offset + 1,
                  @err.errt, 18, move_len);
            a06put_errtext (acv, e_work_rolled_back, errtext_char,
                  mxsp_c40, err.errt, b_err_out)
            END
        ELSE
            IF  a_transinf.tri_trans.trError_gg00 <> e_no_next_record
            THEN
                a07_b_put_error (acv,
                      a_transinf.tri_trans.trError_gg00, 1);
            (*ENDIF*) 
        (*ENDIF*) 
        a101_DestroyGroupedTempFile (a_transinf.tri_trans, tree)
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a25pending_link (
            VAR acv    : tak_all_command_glob;
            VAR tablen : tsp00_KnlIdentifier);
 
VAR
      init_sqlm  : tsp00_SqlMode;
      b_err      : tgg00_BasisError;
      res        : tsp00_LcompResult;
      set_result : tgg00_BdSetResultRecord;
      tree_pos   : tgg00_FilePos;
      tree       : tgg00_FileId;
      key        : tgg00_Lkey;
 
BEGIN
WITH acv DO
    BEGIN
    g04build_temp_tree_id (tree, a_transinf.tri_trans);
    tree.fileTfnTemp_gg00 := ttfnPendingLink_egg00;
    a101_GetTempFileInstance (acv.a_transinf.tri_trans, tree);
    WITH set_result DO
        BEGIN
        bd_key_check_len:= 0;
        bd_max_rec_cnt  := 1;
        bd_max_fill_len := sizeof (a_mblock.mb_data^.mbp_4kbuf);
        bd_next         := true
        END;
    (*ENDWITH*) 
    SAPDB_PascalForcedMove (sizeof(tablen), sizeof(key.k),
          @tablen, 1, @key.k, 1, sizeof(tablen));
    key.len := sizeof (tablen);
    REPEAT
        tree_pos.tpsPno_gg00 := NIL_PAGE_NO_GG00;
        b07cnext_record (a_transinf.tri_trans, tree,
              key, set_result, tree_pos, a_mblock.mb_data^.mbp_4kbuf);
        b_err := a_transinf.tri_trans.trError_gg00;
        IF  (b_err = e_ok) OR (b_err = e_key_not_found)
        THEN
            BEGIN
            b_err   := e_ok;
            key.len := a_mblock.mb_data^.mbp_keylen;
            SAPDB_PascalMove ('VAK25 ',   4,    
                  a_mblock.mb_data_size, sizeof(key.k),
                  @a_mblock.mb_data^.mbp_4kbuf, cgg_rec_key_offset + 1,
                  @key.k, 1, key.len, b_err);
            s30cmp1 (a_mblock.mb_data^.mbp_4kbuf,
                  cgg_rec_key_offset + 1, sizeof(tablen),
                  tablen, 1, sizeof(tablen), res);
            IF  (res = l_equal) AND (b_err = e_ok)
            THEN
                BEGIN
                b07cdel_record (a_transinf.tri_trans, tree, key);
                b_err := a_transinf.tri_trans.trError_gg00;
                IF  b_err = e_ok
                THEN
                    BEGIN
                    a_cmd_part^.sp1p_buf_len := a_mblock.mb_data^.mbp_reclen -
                          cgg_rec_key_offset-sizeof (tsp00_KnlIdentifier)-1;
                    SAPDB_PascalMove ('VAK25 ',   5,    
                          a_mblock.mb_data_size,
                          a_cmd_part^.sp1p_buf_size,
                          @a_mblock.mb_data^.mbp_4kbuf,
                          cgg_rec_key_offset +
                          sizeof (tsp00_KnlIdentifier) + 1 + 1,
                          @a_cmd_part^.sp1p_buf, 1,
                          a_cmd_part^.sp1p_buf_len, b_err);
                    init_sqlm  := a_sqlmode;
                    a_sqlmode  := sqlm_internal;
                    a_init_ddl := ddl_save_restore_cmd;
                    IF  b_err = e_ok
                    THEN
                        a35_asql_statement (acv);
                    (*ENDIF*) 
                    a_init_ddl := ddl_create_table;
                    a_sqlmode  := init_sqlm
                    END;
                (*ENDIF*) 
                END
            ELSE
                b_err := e_no_next_record;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
    UNTIL
        (b_err <> e_ok) OR (a_returncode <> 0);
    (*ENDREPEAT*) 
    IF  b_err <> e_no_next_record
    THEN
        a07_b_put_error (acv, b_err, 1)
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25find_primary_table (
            VAR acv   : tak_all_command_glob;
            VAR a25v  : tak_a25_glob;
            error_pos : integer);
 
VAR
      ok       : boolean;
      b_err    : tgg00_BasisError;
      link_cnt : integer;
      index    : integer;
      tabid    : tgg00_Surrogate;
      sysk     : tgg00_SysInfoKey;
 
BEGIN
WITH acv, a25v DO
    BEGIN
    tabid              := cgg_zero_id;
    sysk               := a2base_p[ 1 ]^.syskey;
    sysk.sentrytyp     := cak_eforeignkey;
    a10get_sysinfo (acv, sysk, d_fix, a_ptr1, b_err);
    IF  b_err = e_ok
    THEN
        BEGIN
        a2base_p[ 2 ] := a2base_p[ 1 ];
        link_cnt      := a_ptr1^.slink.linkcount;
        index         := 1;
        ak25search_link (acv, a2linkname, tabid, link_cnt,
              a_ptr1, index);
        IF  index <> 0
        THEN
            WITH a_ptr1^.slink,
                 linkdef[ (index-1) MOD cak_maxlinkdef+1 ] DO
                BEGIN
                a06_systable_get (acv, d_fix, ltableid,
                      a2base_p[ 1 ], c_get_all, ok);
                IF  ok
                THEN
                    BEGIN
                    a2tablen[ 1 ] := a2base_p[ 1 ]^.sbase.btablen^;
                    a06determine_username (acv,
                          a2base_p[ 1 ]^.sbase.bauthid,
                          a2authname[ 1 ]);
                    index := index + 1;
                    ak25search_link (acv, a2linkname,
                          a_ptr1^.syskey.stableid, link_cnt,
                          a_ptr1, index);
                    IF  index <> 0
                    THEN
                        b_err := e_missing_privilege
                    (*ENDIF*) 
                    END
                ELSE
                    a07ak_system_error (acv, 25, 2)
                (*ENDIF*) 
                END
            (*ENDWITH*) 
        ELSE
            b_err := e_unknown_linkname
        (*ENDIF*) 
        END
    ELSE
        IF  b_err = e_sysinfo_not_found
        THEN
            b_err := e_unknown_linkname;
        (*ENDIF*) 
    (*ENDIF*) 
    IF  b_err <> e_ok
    THEN
        a07_b_put_error (acv, b_err, error_pos);
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25create_link (
            VAR acv   : tak_all_command_glob;
            VAR a25v  : tak_a25_glob;
            error_pos : integer);
 
VAR
      dummy            : boolean;
      new_prim         : boolean;
      new_sec          : boolean;
      ok               : boolean;
      name_spec        : boolean;
      b_err            : tgg00_BasisError;
      pos              : integer;
      len              : integer;
      i, j, k          : integer;
      maxIdentifierLen : integer; (* PTS 1112229 *)
      linkbuf          : tak_sysbufferaddress;
      get_col_info     : tak25_get_col_info;
      linkkey          : tgg00_SysInfoKey;
      viewscanpar      : tak_save_viewscan_par;
      stop             : boolean;
 
BEGIN
WITH acv, a25v DO
    BEGIN
    a27init_viewscanpar (acv, viewscanpar, v_intern_save_scheme);
    ak25structure_check(acv,a2syskey[ 1 ].stableid,
          a2delact, a2syskey[ 2 ].stableid);
    ak25alloc_linkrecord (acv, a25v, c_primary_table, a2primlink, new_prim);
&   ifdef TRACE
    t01bool(ak_sem, 'new primlink', new_prim);
&   endif
    IF  a_returncode = 0
    THEN
        BEGIN
        name_spec := a2linkname <> a01_il_b_identifier;
        i         := sizeof (a2linkname);
        maxIdentifierLen := sizeof (a2linkname) DIV 2 * a01char_size; (* PTS 1112229 *)
        IF  NOT name_spec
        THEN
            BEGIN
            a2linkname       := a2base_p[c_primary_table]^.sbase.btablen^;
            i                := a061identifier_len (a2linkname);
            IF  i < maxIdentifierLen
            THEN
                BEGIN
                IF  g01unicode
                THEN
                    BEGIN
                    i := succ(i);
                    a2linkname[ i ] := csp_unicode_mark
                    END;
                (*ENDIF*) 
                i := succ(i);
                a2linkname[ i ] := '_';
                SAPDB_PascalMove ('VAK25 ',   6,    
                      sizeof(a2base_p[ 2 ]^.sbase.btablen^),
                      sizeof(a2linkname),
                      @a2base_p[ 2 ]^.sbase.btablen^, 1,
                      @a2linkname, i + 1, maxIdentifierLen - i,
                      a_returncode);
                i := a061identifier_len (a2linkname);
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        ak25alloc_linkrecord (acv, a25v, 2, a2seclink, new_sec);
&       ifdef TRACE
        t01bool(ak_sem, 'new seclink ', new_sec);
&       endif
        j := 0;
        REPEAT
            ak25add_linkname (acv, a2linkname, b_err);
            IF  b_err <> e_ok
            THEN
                BEGIN
                j   := succ(j);
                IF  j < 10
                THEN
                    len := 0
                ELSE
                    len := 1;
                (*ENDIF*) 
                IF  g01unicode
                THEN
                    pos := i + 2 * (1 + len)
                ELSE
                    pos := i + 1 + len;
                (*ENDIF*) 
                IF  pos > maxIdentifierLen (* PTS 1112229 *)
                THEN
                    pos := maxIdentifierLen;
                (*ENDIF*) 
                k := j;
                REPEAT
                    IF  k >= 0
                    THEN
                        BEGIN
                        a2linkname [ pos ] :=
                              chr (k MOD 10 + ord ('0'));
                        k   := k DIV 10;
                        IF  g01unicode
                        THEN
                            BEGIN
                            pos := pred(pos);
                            a2linkname[ pos ] := csp_unicode_mark
                            END;
                        (*ENDIF*) 
                        pos := pred(pos)
                        END;
                    (*ENDIF*) 
                UNTIL
                    k <= 0;
                (*ENDREPEAT*) 
                END;
            (*ENDIF*) 
        UNTIL
            (b_err = e_ok) OR name_spec OR (j > 99);
        (*ENDREPEAT*) 
        IF  b_err = e_duplicate_key
        THEN
            a07_b_put_error (acv, e_duplicate_name, error_pos);
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    ak25init_link_record (acv, a25v, a2primlink, c_secondary_table);
    ak25init_link_record (acv, a25v, a2seclink, c_primary_table);
    IF  a_returncode = 0
    THEN
        BEGIN
        a06a_mblock_init (acv,
              m_column_statistic, mm_nil,
              a2base_p[c_secondary_table]^.sbase.btreeid);
        a_mblock.mb_qual^.mcol_pos := 1;
        a2default.len                := 0;
        WITH get_col_info DO
            BEGIN
            gci_prim_key := a2refcol_ti = 0;
            WITH a2base_p[ c_primary_table ]^.sbase DO
                BEGIN
                a2keycount    := bkeycolcount;
                a2key_col_ptr := bcolumn[bfirstcolind];
&               ifdef trace
                a061td_colinfo (a2key_col_ptr^, bfirstcolind)
&                     endif
                END;
            (*ENDWITH*) 
            IF  NOT gci_prim_key
            THEN
                BEGIN
                i          := a2refcol_ti;
                a2keycount := 0;
                REPEAT
                    a2keycount := a2keycount + 1;
                    i := a_ap_tree^[ i ].n_sa_level;
                UNTIL
                    i = 0
                (*ENDREPEAT*) 
                END;
            (*ENDIF*) 
            gci_mult_index  := true;
            gci_is_pk_key   := (a2keycount =
                  a2base_p[ c_primary_table ]^.sbase.bkeycolcount);
            gci_fk_is_key   := true;
            gci_col_count   := 0;
            gci_first_colno := 0;
            gci_outpos      := 1;
            gci_fk_colindex := a2ti;
            gci_pk_colindex := a2refcol_ti;
            a06_get_priv  (acv, a2base_p[ c_primary_table ], gci_p_priv);
            IF  a2keycount > MAX_COL_SEQUENCE_GG00
            THEN
                a07_b_put_error (acv, e_too_many_columns,
                      a_ap_tree^[ gci_fk_colindex ].n_pos)
            ELSE
                REPEAT
                    ak25get_check_column_type (acv, a25v, get_col_info);
                UNTIL
                    (gci_fk_colindex = 0) OR (a_returncode <> 0);
                (*ENDREPEAT*) 
            (*ENDIF*) 
            END;
        (*ENDWITH*) 
        END;
    (*ENDIF*) 
    IF  a_returncode = 0
    THEN
        IF  get_col_info.gci_col_count <> a2keycount
        THEN
            a07_b_put_error (acv, e_too_few_columns, 1)
        ELSE
            IF  get_col_info.gci_fk_is_key AND
                (a2base_p[ c_primary_table ]^.syskey.stableid =
                a2base_p[ c_secondary_table ]^.syskey.stableid)
            THEN (* foreign key references itself, not allowed *)
                a07_b_put_error (acv, e_link_rule_not_allowed, 1)
            ELSE
                BEGIN
&               ifdef trace
                t01int4 (ak_sem, 'is_prim_key ',
                      ord (get_col_info.gci_is_pk_key));
&               endif
                a2resfile := a2base_p[ c_primary_table ]^.sbase.btreeid;
                IF  NOT get_col_info.gci_is_pk_key
                THEN
                    BEGIN
                    IF  (a2base_p[ c_primary_table ]^.syskey.stableid =
                        a2base_p[ c_secondary_table ]^.syskey.stableid)
                        AND
                        (a2delact = cak_x_cascade)
                    THEN
                        a07_b_put_error (acv, e_link_rule_not_allowed, 1)
                    ELSE
                        BEGIN
                        WITH a2base_p[ c_primary_table ]^.sbase DO
                            blinkexist := blinkexist + [ unique_pk_table ];
                        (*ENDWITH*) 
                        WITH get_col_info DO
                            BEGIN
                            ak25columns_indexed (acv,
                                  a2base_p  [ c_primary_table ]^.sbase,
                                  a2primlink,
                                  a2base_p[ c_primary_table ]^.sbase.bindexexist,
                                  false, get_col_info.gci_is_unique)
                            END;
                        (*ENDWITH*) 
                        IF  NOT get_col_info.gci_is_unique
                        THEN
                            a07_b_put_error (acv, e_column_not_indexed, 1)
                        ELSE
                            WITH a2seclink^.slink,
                                 linkdef[ (linkcount-1) MOD
                                 cak_maxlinkdef+1 ] DO
                                BEGIN
                                lindexid := a2primlink^.slink.linkdef[
                                      (a2primlink^.slink.linkcount - 1)
                                      MOD cak_maxlinkdef + 1 ].lindexid;
                                g04index_tree_build (
                                      a2base_p[ c_primary_table ]^.sbase.btreeid,
                                      a2resfile,
                                      ord (lindexid[1]));
                                END;
                            (*ENDWITH*) 
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                IF  a2delact = cak_x_set_default
                THEN
                    BEGIN
                    (* h.b. 01.11.1994  Fehler bei DEFAULT = '   ' !!! *)
                    stop := false;
                    IF  a2fillchar [1] = csp_unicode_def_byte
                    THEN
                        a2default.len := 1 + s30lnr_defbyte (@a2default.k,
                              csp_unicode_def_byte, 2, a2default.len - 1)
                    ELSE
                        WHILE (a2default.len > 1) AND NOT stop DO
                            IF  (a2default.k [a2default.len] = a2fillchar [1])
                            THEN
                                a2default.len := a2default.len - 1
                            ELSE
                                stop := true;
                            (*ENDIF*) 
                        (*ENDWHILE*) 
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    IF  a_returncode = 0
    THEN
        ak25columns_indexed (acv,
              a2base_p[ c_secondary_table ]^.sbase,
              a2seclink, get_col_info.gci_mult_index, true, dummy);
    (*ENDIF*) 
    ak25verify_link (acv, a25v);
    IF  a_returncode = 0
    THEN
        BEGIN
        a10_add_repl_sysinfo (acv, a2primlink, new_prim, b_err);
        a10_rel_sysinfo (acv, a2primlink^.syskey);
        IF  b_err = e_ok
        THEN
            ak25eval_link_pos_info (acv, a2seclink, new_sec, b_err);
        (*ENDIF*) 
        IF  (b_err = e_ok) AND (a2default.len > 0)
        THEN
            BEGIN
            linkkey:= a2base_p[ c_secondary_table ]^.syskey;
            linkkey.sentrytyp   := cak_elinkdef;
            linkkey.sidentifier := a2linkname;
            linkkey.skeylen :=
                  mxak_standard_sysk + sizeof (linkkey.sidentifier);
            len                := sizeof (tak_link_def_record);
            a10_nil_get_sysinfo (acv, linkkey, d_release, len, linkbuf, b_err);
            IF  b_err = e_ok
            THEN
                BEGIN
                WITH linkbuf^, slinkdefault DO
                    BEGIN
                    ldefault_len := a2default.len;
                    ldefault_key := a2default.k;
                    sfiller      := 0;
                    len          := sizeof (slinkdefault) -
                          sizeof (ldefault_key) + ldefault_len;
                    b_sl         := len
                    END;
                (*ENDWITH*) 
                a10_add_repl_sysinfo(acv,
                      linkbuf, true, b_err);
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  b_err <> e_ok
        THEN
            a07_b_put_error (acv, b_err, 1);
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  a_returncode = 0
    THEN
        BEGIN
        WITH a2base_p[ c_primary_table ]^.sbase DO
            blinkexist := blinkexist + [ is_primary_table ];
        (*ENDWITH*) 
        a10_rel_sysinfo (acv, a2base_p[c_secondary_table]^.syskey);
        IF  a2create_tab
        THEN
            BEGIN
            (* create link in the course of a create table *)
            (* statement, increase file version number of  *)
            (* referenced table                            *)
            a10_version (acv, a2base_p[ c_primary_table ]^.sbase,
                  m_succ_file_version, c_scan_views);
            a10_add_repl_sysinfo (acv,
                  a2base_p[ c_primary_table ], false, b_err);
            IF  b_err <> e_ok
            THEN
                a07_b_put_error (acv, b_err, 1)
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            (* save all views depending on the referenced table *)
            (* to be able to recreate them together with the    *)
            (* views of the referencing table                   *)
            (* this must be done, because the views may change  *)
            (* their privileges                                 *)
            viewscanpar.vsc_first_save  := true;
            viewscanpar.vsc_last_save   := a2create_tab;
            ak25version_save_scheme (acv,
                  a2base_p[ c_primary_table ], true, viewscanpar);
            END;
        (*ENDIF*) 
        WITH a2syskey[ c_secondary_table ] DO
            a06_systable_get (acv, d_fix, stableid,
                  a2base_p[ c_secondary_table ], c_get_all, ok);
        (*ENDWITH*) 
        IF  ok
        THEN
            BEGIN
            WITH a2base_p[ c_secondary_table ]^.sbase DO
                blinkexist := blinkexist + [ is_secondary_table ];
            (*ENDWITH*) 
            IF  a2create_tab
            THEN
                BEGIN
                a10_add_repl_sysinfo (acv,
                      a2base_p[ c_secondary_table ], false, b_err);
                IF  b_err <> e_ok
                THEN
                    a07_b_put_error (acv, b_err, 1)
                (*ENDIF*) 
                END
            ELSE
                BEGIN
                (* save all views of the referencing table and    *)
                (* recreate them and all views of then referenced *)
                (* table by ak25restore_scheme                    *)
                viewscanpar.vsc_first_save := false;
                viewscanpar.vsc_last_save  := true;
                ak25version_save_scheme (acv, a2base_p[ c_secondary_table ],
                      NOT a2create_tab, viewscanpar);
                ak25restore_scheme (acv, viewscanpar)
                END;
            (*ENDIF*) 
            END
        ELSE
            a07ak_system_error (acv, 25, 3);
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25search_link (
            VAR acv       : tak_all_command_glob;
            VAR link_name : tsp00_KnlIdentifier;
            VAR tabid     : tgg00_Surrogate;
            linkcnt       : integer;
            VAR linkbuf   : tak_sysbufferaddress;
            VAR index     : integer);
 
VAR
      found         : boolean;
      b_err         : tgg00_BasisError;
      first_index   : integer;
      curr_linkname : tsp00_KnlIdentifier;
      syskey        : tgg00_SysInfoKey;
 
BEGIN
&ifdef trace
t01surrogate (ak_sem, 'tabid       ', tabid);
t01int4      (ak_sem, 'linkcnt     ', linkcnt);
t01int4      (ak_sem, 'index       ', index);
&endif
found       := false;
first_index := cak_is_undefined;
WHILE (index <= linkcnt) AND NOT (found)
      AND (acv.a_returncode = 0) DO
    WITH acv, linkbuf^.slink DO
        BEGIN
        a25get_linkname (acv, linkbuf,
              (index-1) MOD cak_maxlinkdef+1, curr_linkname);
        IF  curr_linkname = link_name
        THEN
            IF  tabid = cgg_zero_id
            THEN
                IF  a_ap_tree^[ a_ap_tree^[ 0 ].n_lo_level ].n_subproc =
                    cak_x_drop_link
                THEN
                    IF  first_index = cak_is_undefined
                    THEN
                        first_index := index
                    ELSE
                        a07_b_put_error (acv, e_duplicate_name, 1)
                    (*ENDIF*) 
                ELSE
                    found := true
                (*ENDIF*) 
            ELSE
                IF  linkdef[ (index-1) MOD
                    cak_maxlinkdef+1 ].ltableid = tabid
                THEN
                    found := true;
                (*ENDIF*) 
            (*ENDIF*) 
        (*ENDIF*) 
        IF  NOT found
        THEN
            BEGIN
            IF  (index MOD cak_maxlinkdef = 0) AND (index < linkcnt)
            THEN
                BEGIN
                syskey := linkbuf^.syskey;
                a10_rel_sysinfo (acv, syskey);
                a06inc_linkage (syskey.slinkage);
                a10get_sysinfo (acv,
                      syskey, d_fix, linkbuf, b_err);
                IF  b_err <> e_ok
                THEN
                    a07_b_put_error (acv, b_err, 1);
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            index := succ(index);
            END;
        (*ENDIF*) 
        END;
    (*ENDWITH*) 
(*ENDWHILE*) 
IF  first_index <> cak_is_undefined
THEN
    index := first_index
ELSE
    IF  NOT (found)
    THEN
        index := 0;
&   ifdef trace
    (*ENDIF*) 
(*ENDIF*) 
t01int4 (ak_sem, 'index=      ', index);
&endif
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25store_pending_link (
            VAR acv    : tak_all_command_glob;
            VAR a25v   : tak_a25_glob;
            start_node : integer);
 
CONST
      c_cmd = 'ALTER TABLE "  FOREIGN KEY L1 ';
 
VAR
      pos        : integer;
      i          : integer;
      curr       : integer;
      err_char_no: tsp00_Int4;
      uni_err    : tsp8_uni_error;
      tree       : tgg00_FileId;
      c30        : tsp00_C30;
 
BEGIN
WITH acv, a25v DO
    BEGIN
&   ifdef trace
    t01int4 (ak_sem, 'start_node  ', start_node);
    t01int4 (ak_sem, 'start_pos   ', a_ap_tree^[ start_node ].n_pos);
    t01int4 (ak_sem, 'end_pos     ',
          a_ap_tree^[ start_node ].n_length);
&   endif
    a_returncode := 0;
    a_errorpos   := 0;
    a_link_pending                 := true;
    g04build_temp_tree_id (tree, a_transinf.tri_trans);
    tree.fileTfnTemp_gg00 := ttfnPendingLink_egg00;
    b01filestate (a_transinf.tri_trans, tree);
    IF  a_transinf.tri_trans.trError_gg00 = e_file_not_found
    THEN
        a101_CreateGroupedTempFile (a_transinf.tri_trans, tree,
              ttfnPendingLink_egg00);
    (*ENDIF*) 
    IF  a_transinf.tri_trans.trError_gg00 = e_ok
    THEN
        BEGIN
        (* construct <alter table statement> to be executed *)
        (* when unknown Table is created                    *)
        SAPDB_PascalMove ('VAK25 ',   7,    
              sizeof(a2tablen[ 1 ]), a_mblock.mb_data_size,
              @a2tablen[1], 1, @a_mblock.mb_data^.mbp_rec,
              cgg_rec_key_offset + 1, sizeof(a2tablen[ 1 ]), a_returncode);
        pos := cgg_rec_key_offset + sizeof (a2tablen[1]) + 2;
        IF  g01unicode
        THEN
            BEGIN
            i := 2 * 13;
            s80uni_trans (@c_cmd, 13, csp_ascii,
                  @a_mblock.mb_data^.mbp_buf[ pos ], i,
                  csp_unicode, [ ], uni_err, err_char_no);
            pos := pos + i;
            END
        ELSE
            BEGIN
            c30 := c_cmd;
            SAPDB_PascalMove ('VAK25 ',   8,    
                  mxsp_c30, a_mblock.mb_data_size, @c30, 1,
                  @a_mblock.mb_data^.mbp_rec, pos, 13, a_returncode);
            pos := pos + 13;
            END;
        (*ENDIF*) 
        SAPDB_PascalMove ('VAK25 ',   9,    
              sizeof(a_p_arr1.pbasep^.sbase.btablen^),
              a_mblock.mb_data_size,
              @a_p_arr1.pbasep^.sbase.btablen^, 1,
              @a_mblock.mb_data^.mbp_rec, pos,
              sizeof(a_p_arr1.pbasep^.sbase.btablen^), a_returncode);
        pos := pos + sizeof(a_p_arr1.pbasep^.sbase.btablen^);
        IF  g01unicode
        THEN
            BEGIN
            a_mblock.mb_data^.mbp_buf[pos  ] := csp_unicode_mark;
            a_mblock.mb_data^.mbp_buf[pos+1] := '"';
            a_mblock.mb_data^.mbp_buf[pos+2] := csp_unicode_mark;
            a_mblock.mb_data^.mbp_buf[pos+3] := csp_ascii_blank;
            pos := pos + 4;
            END
        ELSE
            BEGIN
            a_mblock.mb_data^.mbp_buf[pos  ] := '"';
            a_mblock.mb_data^.mbp_buf[pos+1] := ' ';
            pos := pos + 2;
            END;
        (*ENDIF*) 
        IF  g01unicode
        THEN
            BEGIN
            i := 2 * 15;
            c30 := c_cmd;
            s80uni_trans (@c30[16], 15, csp_ascii,
                  @a_mblock.mb_data^.mbp_buf[ pos ], i,
                  csp_unicode, [ ], uni_err, err_char_no);
            pos := pos + i;
            END
        ELSE
            BEGIN
            c30 := c_cmd;
            SAPDB_PascalMove ('VAK25 ',  10,    
                  mxsp_c30, a_mblock.mb_data_size, @c30, 16,
                  @a_mblock.mb_data^.mbp_rec, pos, 15, a_returncode);
            pos := pos + 15;
            END;
        (*ENDIF*) 
        WITH a_ap_tree^[ start_node ] DO
            BEGIN
            a_scv.sc_newpos := n_pos;
            a01_next_symbol (acv);
            IF  a01_eqkey (a01kw[ cak_i_references ], a_sqlmode,
                a_cmd_part^.sp1p_buf, a_scv)
            THEN
                BEGIN (* <col name> <datatype> REFERENCES .. *)
                a_mblock.mb_data^.mbp_buf[pos  ] := '(';
                a_mblock.mb_data^.mbp_buf[pos+1] := '"';
                pos  := pos + 2;
                curr := start_node;
                (* find syntax tree entry describing the column *)
                FOR i := 1 TO 2 DO
                    curr := a_ap_tree^[ curr ].n_sa_level;
                (*ENDFOR*) 
                curr := a_ap_tree^[ curr ].n_lo_level;
&               ifdef trace
                t01int4 (ak_sem, 'curr        ', curr);
&               endif
                SAPDB_PascalMove ('VAK25 ',  11,    
                      a_cmd_part^.sp1p_buf_size, a_mblock.mb_data_size,
                      @a_cmd_part^.sp1p_buf, a_ap_tree^[ curr ].n_pos,
                      @a_mblock.mb_data^.mbp_rec, pos,
                      a_ap_tree^[ curr ].n_length,
                      a_transinf.tri_trans.trError_gg00);
                pos := pos + a_ap_tree^[curr ].n_length;
                a_mblock.mb_data^.mbp_buf[pos  ] := '"';
                a_mblock.mb_data^.mbp_buf[pos+1] := ')';
                a_mblock.mb_data^.mbp_buf[pos+1] := ' ';
                pos  := pos + 3
                END;
            (*ENDIF*) 
            SAPDB_PascalMove ('VAK25 ',  12,    
                  a_cmd_part^.sp1p_buf_size, a_mblock.mb_data_size,
                  @a_cmd_part^.sp1p_buf, n_pos,
                  @a_mblock.mb_data^.mbp_rec, pos, n_length - n_pos,
                  a_transinf.tri_trans.trError_gg00);
            WITH a_mblock.mb_data^ DO
                BEGIN
                mbp_keylen := sizeof (a2tablen[1])+1;
                mbp_reclen := pos + n_length - n_pos - 1;
                mbp_varcol_offset := mbp_reclen - cgg_rec_key_offset - mbp_keylen;
                mbp_varcol_cnt    := 0;
                END;
            (*ENDWITH*) 
            END;
        (*ENDWITH*) 
        i := 1;
        IF  a_transinf.tri_trans.trError_gg00 = e_ok
        THEN
            REPEAT
                a_mblock.mb_data^.mbp_buf[ cgg_rec_key_offset +
                      sizeof (a2tablen[1]) + 1 ] := chr(i);
                b07cadd_record (a_transinf.tri_trans,
                      tree, a_mblock.mb_data^.mbp_rec);
                i := i + 1;
            UNTIL
                (a_transinf.tri_trans.trError_gg00 <> e_duplicate_key) OR
                (i > 255);
            (*ENDREPEAT*) 
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  a_transinf.tri_trans.trError_gg00 <> e_ok
    THEN
        a07_b_put_error (acv, a_transinf.tri_trans.trError_gg00, 1)
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25verify_link (
            VAR acv  : tak_all_command_glob;
            VAR a25v : tak_a25_glob);
 
VAR
      set_result   : tgg00_BdSetResultRecord;
      search_key   : boolean;
      send_messbuf : boolean;
      last_rec_buf : boolean;
      b_err        : tgg00_BasisError;
      res          : tsp00_LcompResult;
      curr_keylen  : tsp_int_map_c2;
      tree_id_len  : integer;
      rec_pos      : integer;
      rec_len      : integer;
      i            : integer;
      tree_pos     : tgg00_FilePos;
      res_tree     : tgg00_FileId;
      treeid       : tgg00_FileId;
      curr_key     : tgg00_Lkey;
      zerokey      : tgg00_Lkey;
      b            : tsp00_Buf;
 
BEGIN
WITH acv, a25v DO
    BEGIN
    IF  (a_returncode = 0) AND NOT (a2create_tab)
    THEN
        BEGIN
        b01empty_file (a_transinf.tri_trans, a_into_tree);
        b_err := a_transinf.tri_trans.trError_gg00;
        IF  b_err = e_ok
        THEN
            BEGIN
            treeid               := acv.a_into_tree;
            treeid.fileRoot_gg00 := NIL_PAGE_NO_GG00;
            SAPDB_PascalMove ('VAK25 ',  13,    
                  sizeof (treeid), a_mblock.mb_data_size,
                  @treeid, 1, @a_mblock.mb_data^.mbp_4kbuf, 1,
                  sizeof (treeid), a_returncode);
            tree_id_len := sizeof (treeid);
            WITH a_mblock, mb_qual^ DO
                BEGIN
                mstrat_pos := mcol_pos + mcol_cnt;
                mstrat_cnt := 1;
                WITH mb_st^ [mstrat_pos] DO
                    BEGIN
                    etype       := st_strat;
                    eop         := op_none;
                    epos        := 1;
                    elen_var    := tree_id_len;
                    ecol_tab[1] := chr(0);
                    ecol_tab[2] := chr(0)
                    END;
                (*ENDWITH*) 
                mfirst_free := mstrat_pos + 1;
                END;
            (*ENDWITH*) 
            a_mblock.mb_data_len                      := tree_id_len;
            a_mblock.mb_qual^.mtree.fileRoot_gg00     := NIL_PAGE_NO_GG00;
            a_mblock.mb_qual^.mtree.fileHandling_gg00 := [ hsWithoutLock_egg00 ];
            a06rsend_mess_buf (acv, a_mblock, cak_return_req, b_err)
            END;
        (*ENDIF*) 
        IF  b_err = e_ok
        THEN
            res_tree := a_into_tree;
        (*ENDIF*) 
        IF  b_err <> e_ok
        THEN
            a07_b_put_error (acv, b_err, 1)
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  (a_returncode = 0) AND NOT(a2create_tab)
    THEN
        BEGIN
        b01filestate (a_transinf.tri_trans, a2resfile);
        IF  a_transinf.tri_trans.trError_gg00 <> e_ok
        THEN
            a07_b_put_error (acv, a_transinf.tri_trans.trError_gg00, 1)
        ELSE
            BEGIN
            curr_key.len := 0;
            a06a_mblock_init (acv, m_get, mm_test, a2resfile);
            a_mblock.mb_qual^.mtree.fileHandling_gg00 := [ hsWithoutLock_egg00 ];
            a_mblock.mb_struct := mbs_buf;
            WITH set_result DO
                BEGIN
                bd_key_check_len:= 0;
                bd_max_rec_cnt  := csp_maxint2;
                bd_max_fill_len := sizeof (b);
                bd_next         := false;
                END;
            (*ENDWITH*) 
            rec_pos         := 1;
            rec_len         := 0;
            zerokey.len     := 0;
            tree_pos.tpsPno_gg00  := NIL_PAGE_NO_GG00;
            last_rec_buf    := false;
            REPEAT
                b_err := e_ok;
                IF  rec_pos >= rec_len
                THEN
                    BEGIN
                    rec_pos := 0;
                    IF  last_rec_buf
                    THEN
                        b_err := e_no_next_record
                    ELSE
                        BEGIN
                        b07cnext_record (a_transinf.tri_trans, a_into_tree,
                              zerokey, set_result, tree_pos, b);
                        b_err := a_transinf.tri_trans.trError_gg00
                        END;
                    (*ENDIF*) 
                    IF  (b_err = e_ok) OR (b_err = e_key_not_found) OR
                        (b_err = e_buffer_limit)
                    THEN
                        BEGIN
                        IF  b_err <> e_buffer_limit
                        THEN
                            last_rec_buf := true;
                        (*ENDIF*) 
                        rec_len := set_result.bd_fill_len;
                        b_err   := e_ok
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                search_key   := false;
                send_messbuf := false;
                IF  b_err = e_ok
                THEN
                    BEGIN
                    curr_keylen.map_c2[ 1 ] := b[ rec_pos + 3 ];
                    curr_keylen.map_c2[ 2 ] := b[ rec_pos + 4 ];
                    curr_key.len := curr_keylen.map_int;
                    SAPDB_PascalMove ('VAK25 ',  14,    
                          sizeof(b), sizeof(curr_key.k) + 2,
                          @b, cgg_rec_key_offset + rec_pos + 1,
                          @curr_key.k, 1, curr_key.len, b_err);
                    rec_pos := rec_pos + curr_key.len + cgg_rec_key_offset;
                    search_key := true;
                    (*======================================*)
                    (* If one columnvalue of sec_table is   *)
                    (* NULL no check in prim_table          *)
                    (*======================================*)
                    i := 0;
                    WHILE i < a2keycount DO
                        BEGIN
                        i := i + 1;
                        IF  curr_key.k[ a2fieldpos[ i ] ] = csp_undef_byte
                        THEN
                            BEGIN
                            i          := a2keycount;
                            search_key := false;
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDWHILE*) 
                    END;
                (*ENDIF*) 
                IF  search_key
                THEN
                    BEGIN
                    IF  a2delact = cak_x_set_default
                    THEN
                        BEGIN
                        (*======================================*)
                        (* If all selected columns of sec_table *)
                        (* have their default value no check    *)
                        (*======================================*)
                        s30cmp (curr_key.k, 1 , curr_key.len,
                              a2default.k, 1, a2default.len, res);
                        search_key :=  res <> l_equal;
                        END;
                    (*ENDIF*) 
                    IF  search_key
                    THEN
                        BEGIN
                        IF  a_mblock.mb_data_len + 2 + curr_key.len <
                            a_mblock.mb_data_size
                        THEN
                            BEGIN
                            a_mblock.mb_data^.mbp_buf[
                                  a_mblock.mb_data_len+1] :=
                                  chr(curr_key.len DIV 256);
                            a_mblock.mb_data^.mbp_buf[
                                  a_mblock.mb_data_len+2] :=
                                  chr(curr_key.len MOD 256);
                            SAPDB_PascalMove ('VAK25 ',  15,    
                                  sizeof(curr_key.k),
                                  a_mblock.mb_data_size,
                                  @curr_key.k, 1,
                                  @a_mblock.mb_data^.mbp_buf,
                                  a_mblock.mb_data_len + 3,
                                  curr_key.len, b_err);
                            a_mblock.mb_data_len :=
                                  a_mblock.mb_data_len + 2 + curr_key.len
                            END
                        ELSE
                            BEGIN
                            rec_pos := rec_pos -
                                  curr_key.len - cgg_rec_key_offset;
                            send_messbuf := true
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                IF  send_messbuf OR
                    ((rec_pos >= rec_len) AND last_rec_buf)
                THEN
                    BEGIN
                    IF  b_err = e_ok
                    THEN
                        a06rsend_mess_buf (acv, a_mblock,
                              NOT cak_return_req, b_err);
                    (*ENDIF*) 
                    IF  b_err = e_ok
                    THEN
                        BEGIN
                        a06a_mblock_init (acv, m_get, mm_test, a2resfile (* PTS 1115080 *));
                        END;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
            UNTIL
                b_err <> e_ok;
            (*ENDREPEAT*) 
            IF  b_err = e_key_not_found
            THEN
                a07_b_put_error (acv, e_link_rule_violation, 1)
            ELSE
                IF  b_err <> e_no_next_record
                THEN
                    a07_b_put_error (acv, b_err, 1);
                (*ENDIF*) 
            (*ENDIF*) 
            END
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    b01empty_file (a_transinf.tri_trans, a_into_tree);
    IF  a_transinf.tri_trans.trError_gg00 <> e_ok
    THEN
        a07_b_put_error (acv, a_transinf.tri_trans.trError_gg00, 1)
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25columns_indexed (
            VAR acv         : tak_all_command_glob;
            VAR base_rec    : tak_baserecord;
            linkbuf         : tak_sysbufferaddress;
            strat_multindex : boolean;
            modify_messbuf  : boolean;
            VAR is_unique   : boolean);
 
VAR
      found          : boolean;
      j              : integer;
      extno          : integer;
      index_scan_rec : tak_index_scan_record;
 
BEGIN
WITH acv, a_mblock, mb_qual^, index_scan_rec DO
    BEGIN
&   ifdef trace
    t01int4 (ak_sem, 'mult index  ', ord(strat_multindex));
&   endif
    is_unique := false;
    WITH linkbuf^.slink,
         linkdef[ (linkcount - 1) MOD cak_maxlinkdef + 1 ] DO
        IF  ( strat_multindex )
        THEN
            BEGIN
            a24init_index_scan (acv, base_rec.bsurrogate, index_scan_rec);
            found := false;
            REPEAT
                IF  ( a24next_named_index (acv, index_scan_rec))
                THEN
                    WITH isr_buf^.smindex.indexdef[isr_index] DO
                        BEGIN
                        j := 1;
                        IF  ( icount = lcolcount )
                        THEN
                            BEGIN
                            found := true;
                            WHILE j <= icount DO
                                BEGIN
                                IF  linkbuf^.syskey.sentrytyp = cak_eforeignkey
                                THEN
                                    extno := lseccolseq[j]
                                ELSE
                                    extno := lprimcolseq[j];
                                (*ENDIF*) 
&                               ifdef trace
                                t01int4 (ak_sem,
                                      'index colno ', icolseq[ j ]);
                                t01int4 (ak_sem,
                                      'link  colno ', extno);
&                               endif
                                IF  icolseq[ j ] <> extno
                                THEN
                                    BEGIN
                                    found     := false;
                                    j         := icount + 1
                                    END
                                ELSE
                                    j := succ(j);
                                (*ENDIF*) 
                                END;
                            (*ENDWHILE*) 
                            END;
                        (*ENDIF*) 
                        IF  found
                        THEN
                            BEGIN
                            is_unique := iunique;
                            IF  modify_messbuf
                            THEN
                                BEGIN (* PTS 1106145 *)
                                END
                            ELSE
                                lindexid [ 1 ] := chr (indexno)
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        END
                    (*ENDWITH*) 
                ELSE
                    found := true;
                (*ENDIF*) 
            UNTIL
                found OR (a_returncode <> 0);
            (*ENDREPEAT*) 
            a24finish_index_scan (acv, index_scan_rec)
            END;
        (*ENDIF*) 
    (*ENDWITH*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25get_check_column_type (
            VAR acv          : tak_all_command_glob;
            VAR a25v         : tak_a25_glob;
            VAR get_col_info : tak25_get_col_info);
 
VAR
      b_err        : tgg00_BasisError;
      primdatatyp  : tsp00_DataType;
      secdatatyp   : tsp00_DataType;
      ix           : integer;
      err_pos      : integer;
      priminoutlen : integer;
      primdatalen  : integer;
      primfraction : integer;
      secinoutlen  : integer;
      secextcolno  : integer;
      primextcolno : integer;
      secdatalen   : integer;
      secfraction  : integer;
      columnName   : tsp00_KnlIdentifier;
      col_ptr      : tak00_colinfo_ptr;
      key_col_ptr  : tak00_colinfo_ptr;
 
BEGIN
b_err := e_ok;
WITH acv, a25v, get_col_info DO
    BEGIN
    err_pos       := a_ap_tree^[ gci_fk_colindex ].n_pos;
    gci_col_count := gci_col_count + 1;
    gci_is_unique := false;
    col_ptr       := NIL;
    columnName    := a01_il_b_identifier;
    IF  gci_col_count > a2keycount
    THEN
        b_err := e_too_many_columns
    ELSE
        BEGIN
        a05_identifier_get (acv, gci_fk_colindex,
              sizeof(a2columnn), a2columnn);
        columnName := a2columnn;
        IF  a061exist_columnname (a2base_p[ c_secondary_table ]^.sbase,
            a2columnn, col_ptr)
        THEN
            BEGIN
            WITH col_ptr^ DO
                BEGIN
                secdatatyp  := cdatatyp;
                secinoutlen := cinoutlen;
                secdatalen  := cdatalen;
                secfraction := cdatafrac;
                secextcolno := cextcolno;
                ccolpropset := ccolpropset + [ ctlink ];
                IF  NOT (ctmulti in ccolpropset)
                THEN
                    gci_mult_index := false;
                (*ENDIF*) 
                IF  (a2delact = cak_x_set_null)
                    AND
                    (NOT (ctopt in ccolpropset) OR
                    ( ctdefault in ccolpropset))
                THEN
                    IF  ctkey in ccolpropset
                    THEN
                        b_err := e_null_value_illegal
                    ELSE
                        b_err := e_null_not_allowed;
                    (*ENDIF*) 
                (*ENDIF*) 
                IF  a2delact = cak_x_set_default
                THEN
                    IF  NOT (ctdefault in ccolpropset)
                    THEN
                        b_err := e_column_must_have_default
                    ELSE
                        ak25get_default_value (acv, a25v, col_ptr^,
                              gci_col_count = a2keycount)
                    (*ENDIF*) 
                (*ENDIF*) 
                END
            (*ENDWITH*) 
            END
        ELSE
            b_err := e_unknown_columnname;
        (*ENDIF*) 
        IF  NOT gci_prim_key AND (b_err = e_ok)
        THEN
            BEGIN
            a05_identifier_get (acv, gci_pk_colindex,
                  sizeof(a2columnn), a2columnn);
            columnName := a2columnn;
            IF  NOT a061exist_columnname (a2base_p[ c_primary_table ]^.sbase,
                a2columnn, key_col_ptr)
            THEN
                BEGIN
                b_err   := e_unknown_columnname;
                err_pos := a_ap_tree^[ a2refcol_ti ].n_pos
                END
            ELSE
                WITH key_col_ptr^ DO
                    BEGIN
                    IF  (key_col_ptr <> a2key_col_ptr) OR
                        NOT (ctkey in ccolpropset)
                    THEN
                        BEGIN
                        gci_is_pk_key := false;
                        a2key_col_ptr := key_col_ptr
                        END;
                    (*ENDIF*) 
                    IF  gci_col_count = 1
                    THEN
                        gci_first_colno := cextcolno;
                    (*ENDIF*) 
                    IF  ccolstack.ecol_tab[ 1 ] <> chr(0)
                    THEN
                        gci_is_unique :=
                              (ccolstack.eop = op_unique) OR
                              (ccolstack.eop = op_unique_desc)
                    (*ENDIF*) 
                    END;
                (*ENDWITH*) 
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  b_err = e_ok
        THEN
            BEGIN
            a061get_colname (col_ptr^, columnName);
            WITH a2key_col_ptr^ DO
                IF  NOT (r_link in gci_p_priv.priv_all_set) AND
                    NOT (cextcolno in gci_p_priv.priv_ref_set)
                THEN
                    BEGIN
                    b_err := e_missing_privilege;
                    a07_kw_put_error (acv, b_err, 1, cak_i_references)
                    END
                ELSE
                    BEGIN
                    primextcolno := cextcolno;
                    primdatatyp  := cdatatyp;
                    priminoutlen := cinoutlen;
                    primdatalen  := cdatalen;
                    primfraction := cdatafrac;
                    IF  (primdatatyp  <> secdatatyp) OR
                        (primdatalen  <> secdatalen) OR
                        (primfraction <> secfraction)
                    THEN
                        b_err := e_incompatible_datatypes;
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
            (*ENDWITH*) 
            (* PTS 1112200 E.Z. *)
            END;
        (*ENDIF*) 
        IF  b_err = e_ok
        THEN
            BEGIN
            WITH a2primlink^.slink,
                 linkdef[ (linkcount - 1) MOD cak_maxlinkdef + 1 ],
                 a2base_p[ 1 ]^.sbase DO
                BEGIN
                IF  secextcolno <> primextcolno
                THEN
                    gci_fk_is_key := false;
                (*ENDIF*) 
                lcolcount := lcolcount + 1;
                WITH a2key_col_ptr^ DO
                    BEGIN
                    lseccolseq [lcolcount] := secextcolno;
                    lprimcolseq[lcolcount] := primextcolno;
                    lstack  [ lcolcount ]  := ccolstack;
                    IF  cnextind > 0
                    THEN
                        a2key_col_ptr := bcolumn[cnextind]
                    ELSE
                        a2key_col_ptr := NIL;
                    (*ENDIF*) 
                    END;
                (*ENDWITH*) 
                lstack[ lcolcount ].eop_new_rec := true;
                a2fieldpos[ lcolcount ] := gci_outpos;
                gci_outpos := gci_outpos + secinoutlen;
                END;
            (*ENDWITH*) 
            WITH a2seclink^.slink,
                 linkdef[ (linkcount - 1) MOD cak_maxlinkdef + 1 ] DO
                BEGIN
                FOR ix := 1 TO lcolcount DO (* PTS 1123762 *)
                    IF  lseccolseq[ix] = secextcolno
                    THEN
                        b_err := e_duplicate_columnname;
                    (*ENDIF*) 
                (*ENDFOR*) 
                lcolcount := lcolcount + 1;
                lseccolseq[lcolcount]  := secextcolno;
                lprimcolseq[lcolcount] := primextcolno;
                lstack[ lcolcount ]    := col_ptr^.ccolstack;
                lstack[ lcolcount ].eop_new_rec := true;
&               ifdef TRACE
                t01buf (ak_sem, a2seclink^, 1, 1000);
&               endif
                CASE primdatatyp OF
                    dcha, ddate, dtime, dtimestamp :
                        a2fillchar[ 1 ] := csp_ascii_blank;
                    dunicode :
                        a2fillchar[ 1 ] := csp_unicode_def_byte;
                    OTHERWISE
                        a2fillchar[ 1 ] := chr(0);
                    END;
                (*ENDCASE*) 
                IF  gci_col_count = a2keycount
                THEN
                    BEGIN
                    ldatatyp := primdatatyp;
                    IF  (gci_col_count = 1) AND NOT gci_prim_key
                    THEN
                        lstack[ lcolcount+1 ] := key_col_ptr^.ccolstack
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                WITH a_mblock, mb_qual^ DO
                    BEGIN
                    mb_st^ [mcol_pos+mcol_cnt] := lstack[ lcolcount ];
                    mcol_cnt                   := succ (mcol_cnt);
                    END;
                (*ENDWITH*) 
                END;
            (*ENDWITH*) 
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  b_err <> e_ok
    THEN
        IF  columnName <> a01_il_b_identifier
        THEN
            a07_nb_put_error (acv, b_err, err_pos, columnName)
        ELSE
            a07_b_put_error (acv, b_err, err_pos)
        (*ENDIF*) 
    ELSE
        BEGIN
        gci_fk_colindex := a_ap_tree^[ gci_fk_colindex ].n_sa_level;
        IF  NOT gci_prim_key
        THEN
            gci_pk_colindex :=
                  a_ap_tree^[ gci_pk_colindex ].n_sa_level
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25get_default_value (
            VAR acv      : tak_all_command_glob;
            VAR a25v     : tak_a25_glob;
            VAR col_info : tak00_columninfo;
            last         : boolean);
 
VAR
      b_err      : tgg00_BasisError;
      defaultlen : integer;
      defbuf     : tak_sysbufferaddress;
      defkey     : tgg00_SysInfoKey;
 
BEGIN
WITH acv, a25v DO
    IF  a_returncode = 0
    THEN
        BEGIN
        defkey.stableid      := a2syskey[ c_secondary_table ].stableid;
        defkey.sentrytyp     := cak_edefault;
        defkey.slinkage[1]   := chr (col_info.cextcolno DIV 256);
        defkey.slinkage[2]   := chr (col_info.cextcolno MOD 256);
        defkey.skeylen       := mxak_standard_sysk;
        a10get_sysinfo (acv, defkey, d_release, defbuf, b_err);
        IF  b_err = e_ok
        THEN
            WITH defbuf^.sdefault DO
                BEGIN
                IF  dfdefault_function = 0
                THEN
                    BEGIN
                    defaultlen := a14LengthOfDefaultValue (defbuf^.sdefault);
                    SAPDB_PascalMove ('VAK25 ',  16,    
                          sizeof(dfvalues), sizeof(a2default.k),
                          @dfvalues, 2,
                          @a2default.k, a2default.len + 1, defaultlen,
                          a_returncode);
                    IF  NOT last
                    THEN
                        BEGIN
                        IF  g01unicode AND
                            (a2default.k[ a2default.len + 1 ] =
                            csp_unicode_def_byte)
                        THEN
                            SAPDB_PascalForcedUnicodeFill (PERM_KEY_MXSP00, @a2default.k,
                                  a2default.len + defaultlen + 1,
                                  col_info.cinoutlen - defaultlen,
                                  csp_unicode_blank)
                        ELSE
                            SAPDB_PascalForcedFill (PERM_KEY_MXSP00, @a2default.k,
                                  a2default.len + defaultlen + 1,
                                  col_info.cinoutlen - defaultlen,
                                  a2default.k[ a2default.len + 1 ]);
                        (*ENDIF*) 
                        (* PTS 1112200 E.Z. *)
                        a2default.len := a2default.len + col_info.cinoutlen;
                        END
                    ELSE
                        a2default.len := a2default.len + defaultlen;
                    (*ENDIF*) 
                    END
                ELSE
                    IF  (dfdefault_function = cak_x_false)
                        OR (dfdefault_function = cak_x_true)
                    THEN
                        BEGIN
                        defaultlen := 2;
                        a2default.k[a2default.len+1] := csp_defined_byte;
                        a2default.k[a2default.len+2] :=
                              chr (dfdefault_function = cak_x_true);
                        a2default.len := a2default.len + 2
                        END
                    ELSE
                        a07_b_put_error (acv,
                              e_default_not_allowed, 1)
                    (*ENDIF*) 
                (*ENDIF*) 
                END
            (*ENDWITH*) 
        ELSE
            a07_b_put_error (acv, b_err, 1);
        (*ENDIF*) 
        END;
    (*ENDIF*) 
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25init_link_record (
            VAR acv        : tak_all_command_glob;
            VAR a25v       : tak_a25_glob;
            VAR linkptr    : tak_sysbufferaddress;
            table_no       : integer);
 
VAR
      b_err      : tgg00_BasisError;
      ti         : integer;
      col_cnt    : integer;
      name_pos   : integer;
      rest_len   : integer;
      move_len   : integer;
      offset     : integer;
      suffix_len : integer;
      suffix_p   : tak_sysbufferaddress;
      sysk       : tgg00_SysInfoKey;
 
BEGIN
IF  acv.a_returncode = 0
THEN
    WITH a25v, linkptr^, slink DO
        BEGIN
        col_cnt := 0;
        ti      := a2ti;
        REPEAT
            ti      := acv.a_ap_tree^[ti].n_sa_level;
            col_cnt := col_cnt + 1;
        UNTIL
            ti = 0;
        (*ENDREPEAT*) 
        b_sl      := b_sl + sizeof (linkdef[1]);
        WITH linkdef[ (linkcount-1) MOD cak_maxlinkdef +1 ] DO
            BEGIN
            suffix_len := a061identifier_len (a2linkname) -
                  sizeof (linkn_prefix);
&           ifdef trace
            t01int4 (ak_sem, 'col_cnt     ', col_cnt);
            t01int4 (ak_sem, 'suffix_len  ', suffix_len);
&           endif
            IF  col_cnt = 1
            THEN
                col_cnt := 2;
            (*ENDIF*) 
            SAPDB_PascalForcedMove (sizeof (a2linkname), sizeof (linkn_prefix),
                  @a2linkname, 1, @linkn_prefix, 1,
                  sizeof (linkn_prefix));
            name_pos := sizeof (linkn_prefix) + 1;
            IF  suffix_len < 0
            THEN
                lsuffixlen := 0
            ELSE
                lsuffixlen := suffix_len;
            (*ENDIF*) 
            rest_len := lsuffixlen;
            IF  rest_len > 0
            THEN
                BEGIN
                move_len := sizeof (lstack) -
                      col_cnt * sizeof (lstack[1]);
                IF  move_len > 0
                THEN
                    BEGIN
                    IF  move_len > rest_len
                    THEN
                        move_len := rest_len;
                    (*ENDIF*) 
                    SAPDB_PascalMove ('VAK25 ',  17,    
                          sizeof (a2linkname), sizeof (lstack),
                          @a2linkname, name_pos,
                          @lstack, col_cnt * sizeof (lstack[1]) + 1,
                          move_len, acv.a_returncode);
                    name_pos := name_pos + move_len;
                    rest_len := rest_len - move_len
                    END
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            IF  rest_len > 0
            THEN
                BEGIN
                sysk             := linkptr^.syskey;
                sysk.slinkage[1] := chr((linkcount-1) MOD cak_maxlinkdef +1);
                offset           := cgg_rec_key_offset + sysk.skeylen +
                      sizeof (lsegmentid);
                a10_nil_get_sysinfo (acv, sysk, d_release,
                      offset + rest_len, suffix_p, b_err);
                IF  b_err = e_ok
                THEN
                    BEGIN
                    SAPDB_PascalForcedMove (sizeof (a2linkname),
                          offset + rest_len,
                          @a2linkname, name_pos,
                          @suffix_p^.slink, offset + 1,
                          rest_len);
                    a10_add_repl_sysinfo (acv, suffix_p, true, b_err)
                    END;
                (*ENDIF*) 
                IF  b_err <> e_ok
                THEN
                    a07_b_put_error (acv, b_err, 1)
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            ltableid       := a2syskey[ table_no ].stableid;
            a11put_date_time (ldatecre, ltimecre);
            laction        := a2delact;
            lcolcount      := 0;
            lcomment       := false;
            lfiller2       := 0;
            lindexid [ 1 ] := chr (0)
            END;
        (*ENDWITH*) 
        END;
    (*ENDWITH*) 
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a25check_fk_priv (
            VAR acv     : tak_all_command_glob;
            pk_rec      : tak_sysbufferaddress;
            VAR priv    : tak_privilege;
            VAR grantee : tgg00_Surrogate);
 
VAR
      ok          : boolean;
      drop_fk     : boolean;
      b_err       : tgg00_BasisError;
      ix          : integer;
      pk_index    : integer;
      pk_count    : integer;
      fk_index    : integer;
      link_count  : integer;
      pk_buf      : tak_sysbufferaddress;
      fk_buf      : tak_sysbufferaddress;
      fk_base     : ^tak_baserecord;
      pk_first_buf: tak_sysbufferaddress;
      dummy_owner : tsp00_KnlIdentifier;
      fk_ptr      : tak_sysbufferaddress;
      link_name   : tsp00_KnlIdentifier;
      pk_key      : tgg00_SysInfoKey;
      fk_key      : tgg00_SysInfoKey;
      viewscanpar : tak_save_viewscan_par;
 
BEGIN
WITH acv DO
    BEGIN
&   IFDEF TRACE
    a06td_priv (priv, 'priv              ', true);
&   ENDIF
    a27init_viewscanpar (acv, viewscanpar, v_intern_save_scheme);
    viewscanpar.vsc_first_save := true;
    pk_key           := pk_rec^.syskey;
    pk_key.sentrytyp := cak_eprimarykey;
    link_count       := cak_is_undefined;
    pk_index         := 0;
    pk_count         := 0;
    pk_first_buf     := NIL;
    REPEAT
        pk_index := pk_index + 1;
        pk_count := pk_count + 1;
        a10get_sysinfo (acv, pk_key, d_fix, pk_buf, b_err);
        IF  b_err = e_ok
        THEN
            WITH pk_buf^.slink, linkdef[pk_index] DO
                BEGIN
                a25get_linkname (acv, pk_buf, pk_index,
                      link_name);
&               ifdef trace
                t01int4 (ak_sem, 'pk_index    ', pk_index);
                t01lidentifier (ak_sem, link_name);
&               endif
                IF  link_count = cak_is_undefined
                THEN
                    BEGIN
                    pk_first_buf := pk_buf;
                    link_count   := linkcount
                    END;
                (*ENDIF*) 
                drop_fk := false;
                a06_systable_get (acv, d_fix,
                      ltableid, fk_ptr, NOT c_get_all, ok);
                IF  NOT ok
                THEN
                    a07ak_system_error (acv, 25, 4)
                ELSE
                    BEGIN
                    fk_base := @fk_ptr^.sbase;
                    IF  fk_base^.bauthid = grantee
                    THEN (* check privilege *)
                        BEGIN
                        fk_key           := fk_ptr^.syskey;
                        fk_key.sentrytyp := cak_eforeignkey;
                        a10get_sysinfo (acv, fk_key,
                              d_release, fk_buf, b_err);
                        fk_index := 1;
                        IF  b_err = e_ok
                        THEN
                            ak25search_link (acv, link_name,
                                  pk_buf^.syskey.stableid,
                                  fk_buf^.slink.linkcount,
                                  fk_buf, fk_index)
                        ELSE
                            a07_b_put_error (acv, b_err, 1);
                        (*ENDIF*) 
                        IF  (fk_index <> 0) AND
                            (a_returncode = 0)
                        THEN
                            WITH fk_buf^.slink DO
                                IF  NOT (r_link in priv.priv_all_set)
                                THEN
                                    FOR ix := 1 TO lcolcount DO
                                        BEGIN
&                                       ifdef trace
                                        t01int4 (ak_sem, 'colno       ',
                                              lseccolseq[ix]);
&                                       endif
                                        IF  NOT (
                                            linkdef[fk_index].lseccolseq[ix] in
                                            priv.priv_ref_set)
                                        THEN
                                            drop_fk := true
                                        (*ENDIF*) 
                                        END;
                                    (*ENDFOR*) 
                                (*ENDIF*) 
                            (*ENDWITH*) 
                        (*ENDIF*) 
                        END
                    (*ENDIF*) 
                    END;
                (*ENDIF*) 
                IF  drop_fk
                THEN
                    BEGIN
                    a10_version (acv, fk_base^,
                          m_succ_file_version, c_scan_views);
                    IF  a_returncode = 0
                    THEN
                        ak25del_link_in_record (acv,
                              dummy_owner,
                              link_name, fk_buf^.syskey.stableid,
                              pk_buf^.syskey.stableid,
                              c_secondary_table, false,
                              false, viewscanpar);
                    (*ENDIF*) 
                    IF  a_returncode = 0
                    THEN
                        ak25link_del_from_linkrec (acv, link_count,
                              pk_buf, pk_index, pk_rec);
                    (*ENDIF*) 
                    IF  a_returncode = 0
                    THEN
                        BEGIN
                        a06_systable_get (acv, d_fix,
                              ltableid, fk_ptr, c_get_all, ok);
                        IF  NOT ok
                        THEN
                            a07ak_system_error (acv, 25, 5)
                        ELSE
                            BEGIN
                            a10repl_sysinfo (acv, fk_ptr, b_err);
                            a10_rel_sysinfo (acv,
                                  fk_ptr^.syskey);
                            IF  b_err <> e_ok
                            THEN
                                a07_b_put_error (acv, b_err, 1)
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDIF*) 
                    link_count := link_count - 1;
                    pk_count   := pk_count - 1;
                    pk_index   := pk_index - 1
                    END;
                (*ENDIF*) 
                IF  pk_index = cak_maxlinkdef
                THEN
                    BEGIN
                    pk_index := 0;
                    IF  pk_key.slinkage <> cak_init_linkage
                    THEN
                        a10_rel_sysinfo (acv, pk_key);
                    (*ENDIF*) 
                    a06inc_linkage  (pk_key.slinkage)
                    END;
                (*ENDIF*) 
                END;
            (*ENDWITH*) 
        (*ENDIF*) 
    UNTIL
        (pk_count >= link_count) OR
        (b_err <> e_ok)          OR
        (a_returncode <> 0);
    (*ENDREPEAT*) 
    IF  (a_returncode = 0) AND (pk_first_buf <> NIL)
    THEN
        IF  link_count > 0
        THEN
            IF  pk_first_buf^.slink.linkcount <> link_count
            THEN
                BEGIN
                pk_first_buf^.slink.linkcount := link_count;
                a10repl_sysinfo (acv, pk_first_buf, b_err);
                IF  b_err <> e_ok
                THEN
                    a07_b_put_error (acv, b_err, 1)
                (*ENDIF*) 
                END;
            (*ENDIF*) 
        (*ENDIF*) 
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a25drop_link (
            VAR acv         : tak_all_command_glob;
            VAR a25v        : tak_a25_glob;
            tabno           : integer;
            VAR viewscanpar : tak_save_viewscan_par);
 
BEGIN
ak25drop_link (acv, a25v, NOT(c_drop_one_link), tabno, viewscanpar);
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25link_drop (
            VAR acv       : tak_all_command_glob;
            VAR a25v      : tak_a25_glob);
 
VAR
      viewscanpar : tak_save_viewscan_par;
 
BEGIN
a27init_viewscanpar (acv, viewscanpar, v_intern_save_scheme);
viewscanpar.vsc_first_save  := true;
viewscanpar.vsc_last_save   := false;
viewscanpar.vsc_tree_id     := b01niltree_id;
ak25drop_link (acv, a25v, c_drop_one_link, c_secondary_table, viewscanpar);
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25drop_link (
            VAR acv          : tak_all_command_glob;
            VAR a25v         : tak_a25_glob;
            drop_one_link    : boolean;
            tabno            : integer;
            VAR viewscanpar  : tak_save_viewscan_par);
 
VAR
      ok          : boolean;
      last        : boolean;
      b_err       : tgg00_BasisError;
      index       : integer;
      loop_cnt    : integer;
      link_count  : integer;
      link_name   : tsp00_KnlIdentifier;
      tabid       : tgg00_Surrogate;
      sysk        : tgg00_SysInfoKey;
 
BEGIN
WITH acv, a25v DO
    BEGIN
    sysk       := a2syskey[ c_primary_table ];
    last       := viewscanpar.vsc_last_save;
    index      := 1;
    loop_cnt   := 0;
    link_count := 0;
    IF  drop_one_link AND (a2base_p[ 2 ] <> NIL)
    THEN
        tabid := a2base_p[ 2 ]^.syskey.stableid
    ELSE
        tabid := cgg_zero_id;
    (*ENDIF*) 
    REPEAT
        a10get_sysinfo (acv, sysk, d_fix, a2primlink, b_err);
        IF  b_err = e_ok
        THEN
            IF  (loop_cnt = 1) AND (drop_one_link)
            THEN
                BEGIN
                WITH a2syskey[ c_primary_table ] DO
                    a06_systable_get (acv, d_fix, stableid,
                          a2base_p[ c_primary_table ], c_get_all, ok);
                (*ENDWITH*) 
                ak25link_del_from_linkrec (acv, link_count,
                      a2primlink, (index-1) MOD cak_maxlinkdef + 1,
                      a2base_p[ c_primary_table ]);
                index := link_count + 1;
                END
            ELSE
                BEGIN
                IF  sysk.slinkage = cak_init_linkage
                THEN
                    WITH a2primlink^.slink DO
                        BEGIN
                        IF  link_count = 0
                        THEN
                            link_count:= linkcount;
                        (*ENDIF*) 
                        linkcount := linkcount - 1;
                        IF  drop_one_link
                        THEN
                            BEGIN
                            a10repl_sysinfo (acv, a2primlink,  b_err);
                            IF  b_err <> e_ok
                            THEN
                                a07_b_put_error (acv, b_err, 1);
                            (*ENDIF*) 
                            END;
                        (*ENDIF*) 
                        END;
                    (*ENDWITH*) 
                (*ENDIF*) 
                IF  drop_one_link
                THEN
                    ak25search_link (acv, a2linkname, tabid,
                          link_count, a2primlink, index);
                (*ENDIF*) 
                IF  index <> 0
                THEN
                    BEGIN
                    sysk := a2primlink^.syskey;
                    IF  (viewscanpar.vsc_first_save) AND
                        ((index = 1) OR (drop_one_link))
                    THEN
                        a10_rel_sysinfo (acv, a2base_p[c_primary_table]^.syskey);
                    (*ENDIF*) 
                    WITH a2primlink^.slink,
                         linkdef[ (index-1) MOD cak_maxlinkdef+1 ], sysk DO
                        BEGIN
                        IF  (drop_one_link) OR (ltableid <> stableid)
                        THEN
                            BEGIN
                            IF  NOT(drop_one_link) AND (last)
                            THEN
                                ak25last_check (acv, a2primlink, index,
                                      link_count, sysk, viewscanpar);
                            (*ENDIF*) 
                            a10_rel_sysinfo (acv, a2primlink^.syskey);
                            a25get_linkname (acv, a2primlink,
                                  (index - 1) MOD cak_maxlinkdef + 1,
                                  link_name);
                            ak25del_link_in_record(acv,
                                  a2authname[ c_primary_table ], link_name,
                                  ltableid, stableid, tabno,
                                  drop_one_link, true, viewscanpar);
                            viewscanpar.vsc_first_save := false;
                            IF  NOT (drop_one_link)
                            THEN
                                BEGIN
                                IF  index MOD cak_maxlinkdef = 0
                                THEN
                                    a06inc_linkage (sysk.slinkage);
                                (*ENDIF*) 
                                index := succ(index)
                                END;
                            (*ENDIF*) 
                            END
                        ELSE
                            index := succ(index)
                        (*ENDIF*) 
                        END;
                    (*ENDWITH*) 
                    END
                ELSE
                    b_err := e_sysinfo_not_found;
                (*ENDIF*) 
                END;
            (*ENDIF*) 
        (*ENDIF*) 
        loop_cnt := succ(loop_cnt);
    UNTIL
        (index > link_count) OR
        (b_err <> e_ok) OR
        (a_returncode <> 0);
    (*ENDREPEAT*) 
    IF  b_err <> e_ok
    THEN
        IF  b_err = e_sysinfo_not_found
        THEN
            a07_b_put_error (acv, e_unknown_linkname, 1)
        ELSE
            a07_b_put_error (acv, b_err, 1)
        (*ENDIF*) 
    ELSE
        BEGIN
        IF  drop_one_link
        THEN
            BEGIN
            viewscanpar.vsc_last_save   := true;
            ak25version_save_scheme (acv,
                  a2base_p[ c_primary_table ], true, viewscanpar)
            END;
        (*ENDIF*) 
        IF  viewscanpar.vsc_tree_id.fileRoot_gg00 <> NIL_PAGE_NO_GG00
        THEN
            ak25restore_scheme (acv, viewscanpar);
        (*ENDIF*) 
        IF  NOT(drop_one_link) AND (viewscanpar.vsc_last_save)
        THEN
            WITH a2syskey[ c_primary_table ] DO
                a06_systable_get (acv, d_fix, stableid,
                      a2base_p[ c_primary_table ], c_get_all, ok);
            (*ENDWITH*) 
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25last_check (
            VAR acv         : tak_all_command_glob;
            linkbuf         : tak_sysbufferaddress;
            link_index      : integer;
            link_cnt        : integer;
            VAR sysk        : tgg00_SysInfoKey;
            VAR viewscanpar : tak_save_viewscan_par);
 
VAR
      b_err   : tgg00_BasisError;
      i       : integer;
      buf     : tak_sysbufferaddress;
      linkkey : tgg00_SysInfoKey;
 
BEGIN
WITH acv DO
    IF  a_returncode = 0
    THEN
        BEGIN
        viewscanpar.vsc_last_save := true;
        linkkey := sysk;
        i       := succ(link_index);
        buf     := linkbuf;
        b_err   := e_ok;
        WHILE (i <= link_cnt) AND (a_returncode = 0) AND
              (viewscanpar.vsc_last_save) DO
            BEGIN
            IF  i MOD cak_maxlinkdef = 1
            THEN
                BEGIN
                a06inc_linkage (linkkey.slinkage);
                a10get_sysinfo (acv, linkkey, d_release,
                      buf, b_err);
                END;
            (*ENDIF*) 
            IF  b_err = e_ok
            THEN
                WITH buf^.slink.linkdef[ (i - 1) MOD cak_maxlinkdef + 1 ] DO
                    IF  (ltableid = sysk.stableid)
                    THEN
                        i := i + 1
                    ELSE
                        viewscanpar.vsc_last_save := false
                    (*ENDIF*) 
                (*ENDWITH*) 
            ELSE
                a07_b_put_error (acv, b_err, 1);
            (*ENDIF*) 
            END;
        (*ENDWHILE*) 
        END;
    (*ENDIF*) 
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25restore_scheme (
            VAR acv         : tak_all_command_glob;
            VAR viewscanpar : tak_save_viewscan_par);
 
VAR
      dummy_treeid : tgg00_FileId;
 
BEGIN
WITH acv, viewscanpar DO
    BEGIN
    IF  (viewscanpar.vsc_last_save) AND (a_returncode = 0)
    THEN
        BEGIN
        dummy_treeid   := b01niltree_id; (* purify *)
        a_internal_sql := sql_alter_table;
        a15restore_catalog (acv, dummy_treeid, viewscanpar);
        a_internal_sql := no_internal_sql
        END;
    (*ENDIF*) 
    IF  (a_returncode <> 0)
    THEN
        BEGIN
        b01empty_file   (acv.a_transinf.tri_trans, a_into_tree);
        a101_DestroyGroupedTempFile (acv.a_transinf.tri_trans,
              viewscanpar.vsc_tree_id)
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25comment_update (
            VAR acv       : tak_all_command_glob;
            VAR base_rec  : tak_baserecord;
            new_id        : integer;
            old_id        : integer);
 
VAR
      b_err    : tgg00_BasisError;
      old_key  : tgg00_SysInfoKey;
      new_key  : tgg00_SysInfoKey;
 
BEGIN
old_key            := a01defaultkey;
old_key.stableid   := base_rec.bsurrogate;
old_key.sentrytyp  := cak_ecomment;
old_key.stablen[1] := chr(ord(cm_foreign_key));
old_key.stablen[2] := chr(old_id);
old_key.skeylen    := old_key.skeylen + 2;
new_key            := old_key;
new_key.stablen[2] := chr(new_id);
REPEAT
    a10_copy_catalog_rec (acv, old_key,
          true, new_key, base_rec.bsegmentid,
          true, b_err);
UNTIL
    b_err <> e_ok;
(*ENDREPEAT*) 
IF  b_err <> e_sysinfo_not_found
THEN
    a07_b_put_error (acv, b_err, 1)
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25del_link_in_record (
            VAR acv        : tak_all_command_glob;
            VAR prim_owner : tsp00_KnlIdentifier;
            linkname       : tsp00_KnlIdentifier;
            tableid        : tgg00_Surrogate;
            linktableid    : tgg00_Surrogate;
            linkseqno      : integer;
            priv_check     : boolean;
            new_version_no : boolean;
            VAR viewscanpar: tak_save_viewscan_par);
      (* linkname, tableid and linktableid must not be     *)
      (* VAR parameters because they are part of a catalog *)
      (* record which is allocated with state d_release    *)
 
VAR
      found       : boolean;
      b_err       : tgg00_BasisError;
      index       : integer;
      linkcnt     : integer;
      linkbuf     : tak_sysbufferaddress;
      base_ptr    : tak_sysbufferaddress;
      linkkey     : tgg00_SysInfoKey;
      ownername   : tsp00_KnlIdentifier;
 
BEGIN
WITH acv DO
    BEGIN
&   ifdef trace
    t01name (ak_sem , 'del_link_in_record');
    t01lidentifier (ak_sem , linkname);
&   endif
    a06_systable_get (acv,
          d_fix, tableid, base_ptr, c_get_all, found);
    IF  NOT found
    THEN
        a07ak_system_error (acv, 25, 6)
    ELSE
        BEGIN
        IF  priv_check
        THEN
            IF  (prim_owner <> a_curr_user_name)
                AND
                (base_ptr^.sbase.bauthid <> a_curr_user_id)
            THEN
                a07_kw_put_error (acv, e_missing_privilege, 1,
                      cak_i_userid);
            (*ENDIF*) 
        (*ENDIF*) 
        IF  (linkseqno = c_secondary_table) AND
            (a_returncode = 0)
        THEN
            BEGIN
            a06determine_username (acv,
                  base_ptr^.sbase.bauthid, ownername);
            a38fk_drop (acv, ownername, base_ptr^.sbase.btablen^, linkname)
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  a_returncode = 0
    THEN
        BEGIN
        linkkey := base_ptr^.syskey;
        IF  linkseqno = c_primary_table
        THEN
            linkkey.sentrytyp := cak_eprimarykey
        ELSE
            linkkey.sentrytyp := cak_eforeignkey;
        (*ENDIF*) 
        a10get_sysinfo (acv, linkkey,
              d_release, linkbuf, b_err);
        IF  b_err = e_ok
        THEN
            WITH linkbuf^.slink DO
                BEGIN
                linkcnt   := linkcount;
                linkcount := linkcount - 1;
                IF  linkcnt > cak_maxlinkdef
                THEN
                    a10repl_sysinfo (acv, linkbuf, b_err);
                (*ENDIF*) 
                END;
            (*ENDWITH*) 
        (*ENDIF*) 
        IF  b_err = e_ok
        THEN
            WITH base_ptr^.sbase DO
                BEGIN
                index   := 1;
                ak25search_link (acv, linkname, linktableid, linkcnt,
                      linkbuf, index);
                IF  index > 0
                THEN
                    BEGIN
                    IF  linkseqno = c_secondary_table
                    THEN
                        ak25repl_link_inf_in_baserec (acv, base_ptr,
                              linkcnt, linkbuf, index);
                    (*ENDIF*) 
                    ak25link_del_from_linkrec (acv, linkcnt,
                          linkbuf, (index-1) MOD cak_maxlinkdef + 1,
                          base_ptr);
                    IF  (a_returncode = 0) AND new_version_no
                    THEN
                        ak25version_save_scheme (acv,
                              base_ptr, true, viewscanpar);
                    (*ENDIF*) 
                    END
                ELSE
                    b_err := e_sysinfo_not_found;
                (*ENDIF*) 
                END;
            (*ENDWITH*) 
        (*ENDIF*) 
        IF  b_err <> e_ok
        THEN
            a07_b_put_error (acv, b_err, 1);
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25repl_link_inf_in_baserec (
            VAR acv     : tak_all_command_glob;
            base_ptr    : tak_sysbufferaddress;
            linkcnt     : integer;
            linkbuf     : tak_sysbufferaddress;
            index       : integer);
 
VAR
      b_err         : tgg00_BasisError;
      colno         : integer;
      linkno        : integer;
      buf           : tak_sysbufferaddress;
      sysk          : tgg00_SysInfoKey;
      used_colseq   : tak_columnset;
      drop_colseq   : tak_columnset;
      nolink_colseq : tak_columnset;
 
BEGIN
WITH acv DO
    BEGIN
    used_colseq        := [  ];
    drop_colseq        := [  ];
    linkno             := 1;
    sysk               := linkbuf^.syskey;
    sysk.sentrytyp     := cak_eforeignkey;
    sysk.slinkage      := cak_init_linkage;
    WHILE (linkno <= linkcnt) AND (a_returncode = 0) DO
        BEGIN
        IF  (linkno MOD cak_maxlinkdef) = 1
        THEN
            BEGIN
            a10get_sysinfo (acv, sysk, d_release, buf, b_err);
            a06inc_linkage (sysk.slinkage)
            END;
        (*ENDIF*) 
        IF  b_err = e_ok
        THEN
            BEGIN
            IF  linkno <> index
            THEN
                WITH buf^.slink.linkdef[ (linkno-1) MOD
                     cak_maxlinkdef+1 ] DO
                    FOR colno := 1 TO lcolcount DO
                        used_colseq := used_colseq +
                              [ lseccolseq[ colno ] ];
                    (*ENDFOR*) 
                (*ENDWITH*) 
            (*ENDIF*) 
            linkno := succ(linkno);
            END
        ELSE
            a07_b_put_error (acv, b_err, 1);
        (*ENDIF*) 
        END;
    (*ENDWHILE*) 
    WITH linkbuf^.slink.linkdef[ (index-1) MOD cak_maxlinkdef + 1 ] DO
        FOR colno := 1 TO lcolcount DO
            drop_colseq := drop_colseq +
                  [ lseccolseq[ colno ] ];
        (*ENDFOR*) 
    (*ENDWITH*) 
    nolink_colseq := drop_colseq - used_colseq;
    WITH base_ptr^.sbase DO
        FOR colno := bfirstindex TO blastindex DO
            WITH bcolumn[colno]^ DO
                IF  cextcolno in nolink_colseq
                THEN
                    ccolpropset := ccolpropset - [ ctlink ];
                (*ENDIF*) 
            (*ENDWITH*) 
        (*ENDFOR*) 
    (*ENDWITH*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25link_del_from_linkrec (
            VAR acv     : tak_all_command_glob;
            linkcnt     : integer;
            VAR linkbuf : tak_sysbufferaddress;
            index       : integer;
            base_ptr    : tak_sysbufferaddress);
 
CONST
      c_del_old = true;
      c_add_new = true;
 
VAR
      b_err          : tgg00_BasisError;
      last_linkrec   : tsp00_C2;
      i              : integer;
      offset         : integer;
      indexid        : integer;
      last_linkindex : integer;
      comment_id     : integer;
      lastbuf        : tak_sysbufferaddress;
      sysk           : tgg00_SysInfoKey;
      default_key    : tgg00_SysInfoKey;
      oldk           : tgg00_SysInfoKey;
      newk           : tgg00_SysInfoKey;
 
BEGIN
WITH acv, linkbuf^, slink, base_ptr^.sbase DO
    BEGIN
    IF  (linkdef[ index ].laction = cak_x_set_default) AND
        (syskey.sentrytyp = cak_eforeignkey)
    THEN
        BEGIN
        default_key.stableid  := syskey.stableid;
        default_key.sentrytyp := cak_elinkdef;
        a25get_linkname (acv, linkbuf, index,
              default_key.sidentifier);
        default_key.slinkage  := cak_init_linkage;
        default_key.skeylen   :=
              mxak_standard_sysk + sizeof (default_key.sidentifier);
        a10del_sysinfo (acv, default_key, b_err);
        IF  b_err <> e_ok
        THEN
            a07_b_put_error (acv, b_err, 1);
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  a_returncode = 0
    THEN
        IF  linkdef[ index ].lcomment
        THEN
            BEGIN
            comment_id := (ord (linkbuf^.syskey.slinkage[2]) - 1)*
                  cak_maxlinkdef + index;
            a26drop_comment (acv, cm_foreign_key,
                  bsurrogate, bsurrogate, comment_id)
            END;
        (*ENDIF*) 
    (*ENDIF*) 
    IF  a_returncode = 0
    THEN
        BEGIN
        IF  linkdef[index].lcolcount = 1
        THEN
            offset := 1
        ELSE
            offset := 0;
        (*ENDIF*) 
        IF  linkdef[index].lsuffixlen >
            sizeof (linkdef[index].lstack) -
            (linkdef[index].lcolcount + offset) *
            sizeof (linkdef[index].lstack[1])
        THEN
            BEGIN
            (* linkname suffix is stored in different record *)
            sysk             := linkbuf^.syskey;
            sysk.slinkage[1] := chr(index);
            a10del_sysinfo (acv, sysk, b_err)
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    IF  a_returncode = 0
    THEN
        BEGIN
        IF  linkcnt > 1
        THEN
            BEGIN
            indexid := ord (linkdef[ index ].lindexid[ 1 ]);
            i       := 1;
            last_linkrec := cak_zero_linkage;
            REPEAT
                a06inc_linkage (last_linkrec);
                i := i + cak_maxlinkdef;
            UNTIL
                i > linkcnt;
            (*ENDREPEAT*) 
            last_linkindex := (linkcnt - 1) MOD cak_maxlinkdef + 1;
            sysk           := syskey;
            IF  last_linkrec <> syskey.slinkage
            THEN
                BEGIN
                sysk.slinkage := last_linkrec;
                a10get_sysinfo (acv, sysk, d_fix, lastbuf, b_err);
                IF  b_err <> e_ok
                THEN
                    a07_b_put_error (acv, b_err, 1)
                (*ENDIF*) 
                END
            ELSE
                lastbuf := linkbuf;
            (*ENDIF*) 
            IF  a_returncode = 0
            THEN
                BEGIN
                linkdef[ index ] :=
                      lastbuf^.slink.linkdef[ last_linkindex ];
                IF  linkdef[ index ].lcomment
                THEN
                    ak25comment_update (acv,
                          base_ptr^.sbase,
                          (ord (linkbuf^.syskey.slinkage[2]) - 1) *
                          cak_maxlinkdef + index,
                          (ord (lastbuf^.syskey.slinkage[2]) - 1) *
                          cak_maxlinkdef + last_linkindex);
                (*ENDIF*) 
                IF  linkdef[index].lcolcount = 1
                THEN
                    offset := 1
                ELSE
                    offset := 0;
                (*ENDIF*) 
                IF  linkdef[index].lsuffixlen >
                    sizeof (linkdef[index].lstack) -
                    (linkdef[index].lcolcount + offset) *
                    sizeof (linkdef[index].lstack[1])
                THEN
                    BEGIN
                    oldk             := lastbuf^.syskey;
                    oldk.slinkage[1] := chr(last_linkindex);
                    newk             := linkbuf^.syskey;
                    newk.slinkage[1] := chr(index);
                    a10_copy_catalog_rec (acv, oldk,
                          c_del_old, newk, linkbuf^.slink.lsegmentid,
                          c_add_new, b_err)
                    END;
                (*ENDIF*) 
                IF  linkcnt MOD cak_maxlinkdef = 1
                THEN
                    a10del_sysinfo (acv, sysk, b_err)
                ELSE
                    WITH lastbuf^ DO
                        BEGIN
                        b_sl := b_sl - sizeof (linkdef[1]);
                        a10repl_sysinfo (acv, lastbuf, b_err);
                        a10_rel_sysinfo (acv, lastbuf^.syskey);
                        END;
                    (*ENDWITH*) 
                (*ENDIF*) 
                IF  (b_err = e_ok) AND (lastbuf <> linkbuf)
                THEN
                    BEGIN
                    a10repl_sysinfo (acv, linkbuf, b_err);
                    a10_rel_sysinfo (acv, linkbuf^.syskey);
                    END;
                (*ENDIF*) 
                IF  (syskey.sentrytyp = cak_eprimarykey) AND
                    (indexid <> 0)                       AND
                    (unique_pk_table in blinkexist)
                THEN
                    ak25check_unique_pk (acv, base_ptr);
                (*ENDIF*) 
                IF  (syskey.sentrytyp = cak_eforeignkey)
                    AND (b_err = e_ok)
                THEN
                    ak25eval_link_pos_info (acv, linkbuf, false, b_err);
                (*ENDIF*) 
                END
            (*ENDIF*) 
            END
        ELSE
            BEGIN
            a10del_sysinfo (acv, linkbuf^.syskey, b_err);
            IF  syskey.sentrytyp = cak_eprimarykey
            THEN
                blinkexist := blinkexist -
                      [ is_primary_table, unique_pk_table ]
            ELSE
                blinkexist := blinkexist - [ is_secondary_table ];
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        IF  b_err <> e_ok
        THEN
            a07_b_put_error (acv, b_err, 1);
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25eval_link_pos_info (
            VAR acv     : tak_all_command_glob;
            VAR linkbuf : tak_sysbufferaddress;
            insert_rec  : boolean;
            VAR b_err   : tgg00_BasisError);
 
VAR
      i          : integer;
      j          : integer;
      rec_pos    : integer;
      linkcnt    : integer;
      syskey     : tgg00_SysInfoKey;
      colset     : tak_columnset;
      pos_info   : tak_colinteger;
 
BEGIN
colset               := [  ];
rec_pos              := cgg_rec_key_offset;
syskey               := linkbuf^.syskey;
syskey.sentrytyp     := cak_eforeignkey;
syskey.slinkage      := cak_init_linkage;
i := 0;
REPEAT
    i := succ(i);
    IF  i MOD cak_maxlinkdef = 1
    THEN
        a10get_sysinfo (acv, syskey, d_release, linkbuf, b_err);
    (*ENDIF*) 
    IF  b_err = e_ok
    THEN
        WITH linkbuf^.slink,
             linkdef [ (i-1) MOD cak_maxlinkdef + 1 ] DO
            BEGIN
            IF  syskey.slinkage = cak_init_linkage
            THEN
                linkcnt := linkcount;
            (*ENDIF*) 
            FOR j := 1 TO lcolcount DO
                IF  NOT (lseccolseq[ j ] in colset)
                THEN
                    BEGIN
                    colset       := colset + [ lseccolseq[ j ] ];
                    lrecpos[ j ] := rec_pos + 1;
                    pos_info[lseccolseq[ j ]] := rec_pos + 1;
                    rec_pos := rec_pos +
                          lstack[ j ].elen_var;
                    IF  rec_pos >= MAX_RECLEN_GG00
                    THEN
                        a07_b_put_error (acv,
                              e_too_many_sec_links, 1);
                    (*ENDIF*) 
                    END
                ELSE
                    BEGIN
                    lrecpos [ j ] :=
                          pos_info[ lseccolseq[ j ] ];
                    END;
                (*ENDIF*) 
            (*ENDFOR*) 
            IF  (i MOD cak_maxlinkdef = 0) OR (i = linkcnt)
            THEN
                BEGIN
                a10_rel_sysinfo (acv, syskey);
                a10_add_repl_sysinfo(acv, linkbuf,
                      (i = linkcnt) AND (insert_rec), b_err);
                a06inc_linkage (syskey.slinkage)
                END;
            (*ENDIF*) 
            END;
        (*ENDWITH*) 
    (*ENDIF*) 
UNTIL
    (i = linkcnt) OR (b_err <> e_ok);
(*ENDREPEAT*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25cascade_dependency (
            VAR acv          : tak_all_command_glob;
            VAR from_tableid : tgg00_Surrogate;
            VAR to_tableid   : tgg00_Surrogate;
            VAR cycle_par    : cycle_parameter);
 
VAR
      search     : boolean;
      b_err      : tgg00_BasisError;
      linkage    : tsp00_C2;
      i          : integer;
      lcount     : integer;
 
BEGIN
WITH acv, cycle_par DO
    BEGIN
    lcount  := 0;
    i       := 0;
    linkage := cak_init_linkage;
    REPEAT
        i := i + 1;
        WITH clinkkey DO
            BEGIN
            stableid  := from_tableid;
            sentrytyp := cak_eprimarykey;
            slinkage  := linkage;
            END;
        (*ENDWITH*) 
        a10get_sysinfo (acv, clinkkey, d_release, clinkbuf, b_err);
        IF  b_err = e_ok
        THEN
            WITH clinkbuf^.slink, linkdef[ (i-1) MOD cak_maxlinkdef + 1 ] DO
                BEGIN
                IF  linkage = cak_init_linkage
                THEN
                    lcount := linkcount;
                (*ENDIF*) 
                search     := false;
                IF  laction = cak_x_cascade
                THEN
                    search := true
                ELSE
                    IF  NOT (cnot_cascade)
                    THEN
                        BEGIN
                        search       := true;
                        cnot_cascade := true
                        END;
                    (*ENDIF*) 
                (*ENDIF*) 
                IF  (ltableid = to_tableid)
                THEN
                    BEGIN
                    IF  (NOT(ccycletest) AND
                        ((crule_ind <> laction)
                        OR
                        (crule_ind = cak_x_set_null)
                        OR
                        (crule_ind = cak_x_set_default)))
                    THEN
                        a07_b_put_error (acv, e_link_rule_not_allowed, 1)
                    ELSE
                        IF  (ccycletest AND search)
                        THEN
                            a07_b_put_error (acv,
                                  e_link_cycle_not_allowed, 1)
                        (*ENDIF*) 
                    (*ENDIF*) 
                    END
                ELSE
                    IF  (search) AND
                        (ltableid <> from_tableid)
                    THEN
                        ak25cascade_dependency (acv,
                              ltableid, to_tableid,cycle_par);
                    (*ENDIF*) 
                (*ENDIF*) 
                IF  (i MOD cak_maxlinkdef) = 0
                THEN
                    a06inc_linkage (linkage)
                (*ENDIF*) 
                END
            (*ENDWITH*) 
        ELSE
            IF  b_err <> e_sysinfo_not_found
            THEN
                a07_b_put_error (acv, b_err, 1)
            ELSE
                i := lcount;
            (*ENDIF*) 
        (*ENDIF*) 
    UNTIL
        (i = lcount) OR (a_returncode <> 0);
    (*ENDREPEAT*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25check_rule_11 (
            VAR acv          : tak_all_command_glob;
            VAR tableid      : tgg00_Surrogate;
            VAR prim_tableid : tgg00_Surrogate;
            init_link_rule   : integer;
            VAR cycle_par    : cycle_parameter);
 
VAR
      b_err      : tgg00_BasisError;
      linkage    : tsp00_C2;
      i          : integer;
      lcount     : integer;
 
BEGIN
WITH acv, cycle_par DO
    BEGIN
    cycle_par.crule_ind := init_link_rule;
    ak25rule_11_tab_check (acv, prim_tableid, tableid, cycle_par);
    IF  (a_returncode = 0) AND
        (init_link_rule = cak_x_cascade) AND
        (tableid <> prim_tableid)
    THEN
        BEGIN
        i       := 0;
        linkage := cak_init_linkage;
        REPEAT
            i := i + 1;
            WITH clinkkey DO
                BEGIN
                stableid  := tableid;
                sentrytyp := cak_eprimarykey;
                slinkage  := linkage
                END;
            (*ENDWITH*) 
            a10get_sysinfo (acv, clinkkey, d_release, clinkbuf, b_err);
            IF  b_err = e_ok
            THEN
                WITH clinkbuf^.slink,
                     linkdef[ (i - 1) MOD cak_maxlinkdef + 1 ] DO
                    BEGIN
                    IF  linkage = cak_init_linkage
                    THEN
                        lcount := linkcount;
                    (*ENDIF*) 
                    IF  (ltableid <> tableid)
                    THEN
                        ak25check_rule_11 (acv, ltableid,
                              prim_tableid, laction, cycle_par);
                    (*ENDIF*) 
                    IF  (i MOD cak_maxlinkdef) = 0
                    THEN
                        a06inc_linkage (linkage)
                    (*ENDIF*) 
                    END
                (*ENDWITH*) 
            ELSE
                IF  b_err <> e_sysinfo_not_found
                THEN
                    a07_b_put_error (acv, b_err, 1)
                ELSE
                    lcount := i;
                (*ENDIF*) 
            (*ENDIF*) 
        UNTIL
            (a_returncode <> 0) OR (i = lcount);
        (*ENDREPEAT*) 
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25structure_check (
            VAR acv          : tak_all_command_glob;
            VAR prim_tableid : tgg00_Surrogate;
            linkrule         : integer;
            VAR sec_tableid  : tgg00_Surrogate);
 
VAR
      cycle_par       : cycle_parameter;
 
BEGIN
cycle_par.clinkkey.sentrytyp := cak_eprimarykey;
cycle_par.clinkkey.skeylen   := mxak_standard_sysk;
cycle_par.cself_ref          := prim_tableid = sec_tableid;
IF  NOT cycle_par.cself_ref
THEN
    BEGIN
    cycle_par.crule_ind     := 0;
    cycle_par.cnot_cascade  := (linkrule <> cak_x_cascade);
    cycle_par.ccycletest    := true;
    ak25cascade_dependency (acv, sec_tableid,
          prim_tableid, cycle_par);
    END;
(*ENDIF*) 
cycle_par.cnot_cascade := true;
cycle_par.ccycletest   := false;
IF  acv.a_returncode = 0
THEN
    BEGIN
    ak25check_rule_11 (acv, sec_tableid,
          prim_tableid, linkrule, cycle_par);
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25rule_11_tab_check (
            VAR acv             : tak_all_command_glob;
            VAR curr_tableid    : tgg00_Surrogate;
            VAR dest_tableid    : tgg00_Surrogate;
            VAR cycle_par       : cycle_parameter);
 
VAR
      b_err         : tgg00_BasisError;
      i             : integer;
      lcount        : integer;
      linkage       : tsp00_C2;
 
BEGIN
WITH cycle_par DO
    BEGIN
    lcount := 0;
    ak25cascade_dependency (acv, curr_tableid,
          dest_tableid, cycle_par);
    IF  (acv.a_returncode = 0) AND NOT cself_ref
    THEN
        BEGIN
        linkage := cak_init_linkage;
        i       := 0;
        REPEAT
            i := i + 1;
            WITH clinkkey DO
                BEGIN
                stableid    := curr_tableid;
                sentrytyp   := cak_eforeignkey;
                slinkage    := linkage
                END;
            (*ENDWITH*) 
            a10get_sysinfo (acv, clinkkey, d_release, clinkbuf, b_err);
            IF  b_err = e_ok
            THEN
                WITH clinkbuf^.slink,
                     linkdef[ (i - 1) MOD cak_maxlinkdef + 1 ] DO
                    BEGIN
                    IF  linkage = cak_init_linkage
                    THEN
                        lcount := linkcount;
                    (*ENDIF*) 
                    IF  (laction = cak_x_cascade)
                    THEN
                        IF  (ltableid <> curr_tableid)
                        THEN
                            ak25rule_11_tab_check (acv, ltableid,
                                  dest_tableid, cycle_par);
                        (*ENDIF*) 
                    (*ENDIF*) 
                    IF  (i MOD cak_maxlinkdef) = 0
                    THEN
                        a06inc_linkage (linkage)
                    (*ENDIF*) 
                    END
                (*ENDWITH*) 
            ELSE
                IF  b_err <> e_sysinfo_not_found
                THEN
                    a07_b_put_error (acv, b_err, 1)
                ELSE
                    i := lcount;
                (*ENDIF*) 
            (*ENDIF*) 
        UNTIL
            (i = lcount) OR (acv.a_returncode <> 0);
        (*ENDREPEAT*) 
        END;
    (*ENDIF*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25version_save_scheme (
            VAR acv         : tak_all_command_glob;
            base_ptr        : tak_sysbufferaddress;
            new_fileversion : boolean;
            VAR viewscanpar : tak_save_viewscan_par);
 
VAR
      b_err       : tgg00_BasisError;
      base_rec_no : integer;
      aux_arr     : tak_syspointerarr;
 
BEGIN
WITH acv, viewscanpar DO
    IF  a_returncode = 0
    THEN
        WITH base_ptr^.sbase DO
            BEGIN
            IF  new_fileversion
            THEN
                a10_version (acv, base_ptr^.sbase,
                      m_succ_file_version, NOT c_scan_views);
            (*ENDIF*) 
            vsc_filevers   := btreeid.fileVersion_gg00;
            vsc_base_tabid := btreeid.fileTabId_gg00;
            base_rec_no    := 1;
            a10repl_sysinfo (acv, base_ptr, b_err);
            a10_rel_sysinfo (acv, base_ptr^.syskey);
            IF  b_err <> e_ok
            THEN
                a07_b_put_error (acv, b_err, 1)
            ELSE
                IF  new_fileversion
                THEN
                    BEGIN
                    vsc_save_into := false;
                    IF  vsc_first_save
                    THEN
                        vsc_cmd_cnt := 0;
                    (*ENDIF*) 
                    aux_arr         := a_p_arr1;
                    a_p_arr1.pbasep := base_ptr;
                    a15catalog_save (acv, viewscanpar);
                    a_p_arr1 := aux_arr
                    END;
                (*ENDIF*) 
            (*ENDIF*) 
            END;
        (*ENDWITH*) 
    (*ENDIF*) 
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25alloc_linkrecord (
            VAR acv         : tak_all_command_glob;
            VAR a25v        : tak_a25_glob;
            tabno           : integer;
            VAR buf         : tak_sysbufferaddress;
            VAR new_sysinfo : boolean);
 
VAR
      found        : boolean;
      b_err        : tgg00_BasisError;
      last_linkage : tsp00_C2;
      i            : integer;
      linkcnt      : integer;
      curr_linkcnt : integer;
      linkname     : tsp00_KnlIdentifier;
 
BEGIN
WITH acv, a25v DO
    BEGIN
    found       := false;
    new_sysinfo := false;
    linkcnt     := 0;
    REPEAT
        a10_fix_len_get_sysinfo (acv, a2syskey[ tabno ], d_fix,
              sizeof (tak_linkrecord) - (cak_maxlinkdef - 1) * sizeof(tak_linkdef),
              sizeof (tak_linkdef),
              buf, b_err);
        IF  b_err = e_ok
        THEN
            WITH buf^, slink DO
                BEGIN
                IF  a2syskey[ tabno ].slinkage = cak_init_linkage
                THEN
                    BEGIN (* first link record *)
&                   ifdef TRACE
                    t01int4(ak_sem, 'frst linkcou', linkcount);
&                   endif
                    i := 0;
                    last_linkage := cak_zero_linkage;
                    REPEAT
                        a06inc_linkage (last_linkage);
                        i := i + cak_maxlinkdef;
                    UNTIL
                        i > linkcount;
                    (*ENDREPEAT*) 
                    linkcnt   := linkcount;
                    linkcount := succ(linkcount);
                    END
                ELSE
                    linkcount := linkcnt + 1;
                (*ENDIF*) 
&               ifdef TRACE
                t01int4(ak_sem, 'linkcount   ', linkcount);
&               endif
                IF  tabno = c_secondary_table
                THEN
                    BEGIN
                    IF  a2syskey[ tabno ].slinkage < last_linkage
                    THEN
                        curr_linkcnt := cak_maxlinkdef
                    ELSE
                        curr_linkcnt := (linkcnt-1) MOD cak_maxlinkdef+1;
                    (*ENDIF*) 
&                   ifdef TRACE
                    t01int4(ak_sem, 'curr linkcnt', curr_linkcnt);
&                   endif
                    FOR i := 1 TO curr_linkcnt DO
                        WITH linkdef[ i ] DO
                            BEGIN
                            a25get_linkname (acv, buf, i,
                                  linkname);
                            ak25add_linkname (acv, linkname, b_err)
                            END;
                        (*ENDWITH*) 
                    (*ENDFOR*) 
                    END;
                (*ENDIF*) 
                IF  a2syskey[ tabno ].slinkage < last_linkage
                THEN
                    BEGIN
                    a10_rel_sysinfo (acv, syskey);
                    IF  a2syskey[ tabno ].slinkage = cak_init_linkage
                    THEN
                        BEGIN
                        a10repl_sysinfo (acv, buf, b_err);
                        END;
                    (*ENDIF*) 
                    a06inc_linkage (a2syskey[ tabno ].slinkage)
                    END
                ELSE
                    found := true
                (*ENDIF*) 
                END
            (*ENDWITH*) 
        ELSE
            IF  b_err = e_sysinfo_not_found
            THEN
                WITH buf^, slink DO
                    BEGIN
                    b_err       := e_ok;
                    found       := true;
                    new_sysinfo := true;
                    lsegmentid  := a2base_p[ tabno ]^.sbase.bsegmentid;
                    linkcount   := linkcnt + 1;
                    b_sl        := sizeof(tak_linkrecord) - cak_maxlinkdef * sizeof(tak_linkdef)
                    END;
                (*ENDWITH*) 
            (*ENDIF*) 
        (*ENDIF*) 
        IF  b_err <> e_ok
        THEN
            a07_b_put_error (acv, b_err, 1);
        (*ENDIF*) 
    UNTIL
        (found) OR (a_returncode <> 0);
    (*ENDREPEAT*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25add_linkname (
            VAR acv      : tak_all_command_glob;
            VAR linkname : tsp00_KnlIdentifier;
            VAR b_err    : tgg00_BasisError);
 
VAR
      buf   : tgg00_Rec;
 
BEGIN
IF  acv.a_returncode = 0
THEN
    BEGIN
    buf.recLen_gg00          := cgg_rec_key_offset + sizeof (linkname);
    buf.recKeyLen_gg00       := sizeof (linkname);
    buf.recVarcolOffset_gg00 := 0;
    buf.recVarcolCnt_gg00    := 0;
    SAPDB_PascalForcedMove (sizeof(linkname), sizeof(buf),
          @linkname, 1, @buf, cgg_rec_key_offset + 1,
          sizeof(linkname));
    b07cadd_record (acv.a_transinf.tri_trans, acv.a_into_tree, buf);
    b_err := acv.a_transinf.tri_trans.trError_gg00;
    IF  b_err <> e_ok
    THEN
        IF  b_err <> e_duplicate_key
        THEN
            a07_b_put_error (acv, b_err, 1);
        (*ENDIF*) 
    (*ENDIF*) 
    END;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a25foreign_key_spec (
            VAR acv    : tak_all_command_glob;
            fk_node    : integer);
 
VAR
      ok         : boolean;
      first      : boolean;
      tabid      : tgg00_Surrogate;
 
BEGIN
WITH acv DO
    BEGIN
&   ifdef trace
    t01int4 (ak_sem, 'fk_node     ', fk_node);
&   endif
    WITH a_p_arr1.pbasep^.sbase DO
        tabid := a_p_arr1.pbasep^.syskey.stableid;
    (*ENDWITH*) 
    first := true;
    REPEAT
        IF  a_ap_tree^[ fk_node ].n_symb = s_reference_name
        THEN
            BEGIN
            ok := true;
            IF  NOT first
            THEN
                a06_systable_get (acv, d_fix, tabid,
                      a_p_arr1.pbasep, c_get_all, ok);
            (*ENDIF*) 
            IF  NOT (ok)
            THEN
                a07ak_system_error (acv, 25, 7)
            ELSE
                BEGIN
                first := false;
                a25link_semantic (acv, fk_node);
                IF  a_transinf.tri_trans.trError_gg00 <> e_ok
                THEN
                    a07_b_put_error (acv, a_transinf.tri_trans.trError_gg00, 1)
                (*ENDIF*) 
                END;
            (*ENDIF*) 
            END;
        (*ENDIF*) 
        fk_node := a_ap_tree^[ fk_node ].n_lo_level;
    UNTIL
        (fk_node = 0) OR (a_returncode <> 0);
    (*ENDREPEAT*) 
    END;
(*ENDWITH*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25find_link (
            VAR acv      : tak_all_command_glob;
            VAR syskey   : tgg00_SysInfoKey;
            entrytyp     : tsp00_C2;
            VAR linkname : tsp00_KnlIdentifier;
            VAR sysbufptr: tak_sysbufferaddress;
            VAR linkno   : integer);
 
VAR
      found     : boolean;
      linkCount : integer;
      currName  : tsp00_KnlIdentifier;
 
BEGIN
(* PTS 1118454 M.Ki. *)
(* if linkname is found, return linkrecord via sysbufptr and set linkno *)
(* to correct value; if linkname is not found, sysbufptr will be NIL    *)
syskey.sentrytyp := entrytyp;
syskey.slinkage  := cak_init_linkage;
linkno := 0;
found  := false;
REPEAT
    linkno := succ (linkno);
    IF  linkno MOD cak_maxlinkdef = 1
    THEN
        a10get_sysinfo (acv, syskey, d_release, sysbufptr,
              acv.a_transinf.tri_trans.trError_gg00);
    (*ENDIF*) 
    IF  acv.a_transinf.tri_trans.trError_gg00 = e_ok
    THEN
        BEGIN
        IF  syskey.slinkage = cak_init_linkage
        THEN
            linkCount := sysbufptr^.slink.linkcount;
        (*ENDIF*) 
        a25get_linkname (acv, sysbufptr, (linkno-1) MOD cak_maxlinkdef + 1,
              currName);
        IF  currName = linkname
        THEN
            found := true
        ELSE
            IF  (linkno MOD cak_maxlinkdef = 0) OR (linkno = linkCount)
            THEN
                a06inc_linkage (syskey.slinkage)
            (*ENDIF*) 
        (*ENDIF*) 
        END;
    (*ENDIF*) 
UNTIL
    found                OR
    (linkno = linkCount) OR
    (acv.a_transinf.tri_trans.trError_gg00 <> e_ok);
(*ENDREPEAT*) 
IF  NOT found
THEN
    sysbufptr := NIL;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      a25drop_foreign_link (
            VAR acv      : tak_all_command_glob;
            VAR sysk     : tgg00_SysInfoKey;
            VAR linkname : tsp00_KnlIdentifier);
 
VAR
      linkno    : integer;
      sysbufptr : tak_sysbufferaddress;
      syskey    : tgg00_SysInfoKey;
      a25v      : tak_a25_glob;
 
BEGIN
(* PTS 1118454 M.Ki. *)
(* find link in referencing table and from there the table being referenced *)
(* fill in a25v and drop link                                               *)
syskey := sysk;
ak25find_link (acv, syskey, cak_eforeignkey, linkname, sysbufptr, linkno);
IF  (acv.a_transinf.tri_trans.trError_gg00 = e_ok) AND
    (sysbufptr <> NIL) (* PTS 1126756 M.Ki. *)
THEN
    BEGIN
    a25v.a2linkname                    := linkname;
    a25v.a2syskey[ c_secondary_table ] := syskey;
    a25v.a2base_p[ c_secondary_table ] := acv.a_p_arr1.pbasep;
    a25v.a2seclink                     := NIL;
    a25v.a2create_tab                  := false;
    syskey.stableid := sysbufptr^.slink.linkdef[ (linkno-1) MOD cak_maxlinkdef + 1 ].ltableid;
    ak25find_link (acv, syskey, cak_eprimarykey, linkname, sysbufptr, linkno);
    IF  (acv.a_transinf.tri_trans.trError_gg00 = e_ok) AND (* PTS 1126756 M.Ki. *)
        (sysbufptr <> NIL)
    THEN
        BEGIN
        a25v.a2syskey[ c_primary_table ] := syskey;
        a25v.a2primlink                  := sysbufptr;
        syskey.sentrytyp := cak_etable;
        syskey.slinkage  := cak_init_linkage;
        a10get_sysinfo (acv, syskey, d_fix, sysbufptr,
              acv.a_transinf.tri_trans.trError_gg00);
        IF  acv.a_transinf.tri_trans.trError_gg00 = e_ok
        THEN
            BEGIN
            a25v.a2base_p[ c_primary_table ] := acv.a_p_arr1.pbasep;
            ak25drop_one_link (acv, a25v);
            a10_rel_sysinfo (acv, syskey);
            END;
        (*ENDIF*) 
        END;
    (*ENDIF*) 
    END;
(*ENDIF*) 
IF  (acv.a_transinf.tri_trans.trError_gg00 = e_ok) AND (sysbufptr = NIL)
THEN
    acv.a_transinf.tri_trans.trError_gg00 := e_sysinfo_not_found;
(*ENDIF*) 
END;
 
(*------------------------------*) 
 
PROCEDURE
      ak25drop_one_link (
            VAR acv  : tak_all_command_glob;
            VAR a25v : tak_a25_glob);
 
BEGIN
(* PTS 1118454 M.Ki. *)
a10_lock_sysinfo (acv, a25v.a2syskey[ c_primary_table ], lckTabShare_egg00);
ak25link_drop (acv, a25v);
IF  acv.a_returncode <> 0
THEN
    acv.a_part_rollback := true;
(*ENDIF*) 
END;
 
.CM *-END-* code ----------------------------------------
.SP 2 
***********************************************************
.PA 
