/*!
  -----------------------------------------------------------------------------

  module: vcn84.cpp

  -----------------------------------------------------------------------------

  responsible:  MartinR
  special area: DBMServer
  description:  implementation module for kernel trace area
  copyright:    (c) 2000-2004 SAP AG

  -----------------------------------------------------------------------------


    ========== 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




  -----------------------------------------------------------------------------
*/

/*
  -----------------------------------------------------------------------------
  includes
  -----------------------------------------------------------------------------
*/

#include <stdio.h>
#include <stdlib.h>

#include "hin110.h"

#include "hcn40.h"
#include "hcn51.h"
#include "hcn80.h"
#include "hcn90.h"

#include "hcn84.h"

/*
  -----------------------------------------------------------------------------
  specification private types and macros
  -----------------------------------------------------------------------------
*/
#define TRACE_PROTOPT_TITLE "name,option\n"

#define TRACE_PROTOPT \
  {{"a"  , "Order Interface (AK)"        },  \
   {"b"  , "Record Interface (BD)"       },  \
   {"k"  , "Show Message Block (KB)"     },  \
   {"m"  , "Message Block"               },  \
   {"e"  , "No Entrypos Output"          },  \
   {"s"  , "Strategy"                    },  \
   {"t"  , "Time"                        },  \
   {"x"  , "Switch Output (Slow Kernel)" },  \
   {NULL , NULL                          }}


typedef struct tcn84TraceProtOpt {
    const char * szOption;
    const char * szName;
} tcn84TraceProtOpt;

#define LEVEL_OFF          0
#define LEVEL_DEFAULT      5

#define SYSDD_DESC_VTRACE  "Vtrace"
#define SYSDD_DESC_VCHECK  "Vtrace check"
#define SYSDD_DESC_CHECK   "Check"

#define SQL_SHOW_VTRACE   "select * from sysdd.server_db_state where description='"SYSDD_DESC_VTRACE"' or description='"SYSDD_DESC_VCHECK"' or description='"SYSDD_DESC_CHECK"'"
#define SQLF_DESC         "DESCRIPTION"
#define SQLF_NUM          "NUMERIC_VALUE"
#define SQLF_VAL          "VALUE"

//     Name                   Syntax                        SysDDDesc           SysDDValue          ShortDesc                   LongDesc                                                               nValue     bValue
#define TRACE_PROT_LIST \                                                                                                
    {{"DEFAULT"             , "DEFAULT"                   , SYSDD_DESC_VTRACE , "DEFAULT"         , "Default"                 , "Includes Index, Lock, Long, Pages, Standard, Table"                  , LEVEL_OFF, false}, \
     {"INDEX"               , "INDEX"                     , SYSDD_DESC_VTRACE , "INDEX"           , "Index"                   , "Interfaces according accesses to indexes"                            , LEVEL_OFF, false}, \
     {"LOCK"                , "LOCK"                      , SYSDD_DESC_VTRACE , "LOCK"            , "Lock"                    , "Lock collisions and their elimination"                               , LEVEL_OFF, false}, \
     {"LONG"                , "LONG"                      , SYSDD_DESC_VTRACE , "LONG"            , "Long"                    , "Accesses to LONG columns"                                            , LEVEL_OFF, false}, \
     {"PAGES"               , "PAGES"                     , SYSDD_DESC_VTRACE , "PAGES"           , "Pages"                   , "I/O of pages"                                                        , LEVEL_OFF, false}, \
     {"STANDARD"            , "ORDER STANDARD"            , SYSDD_DESC_VTRACE , "ORDER STNDRD"    , "Standard"                , "Beginning of all parts of the packet interface"                      , LEVEL_OFF, false}, \
     {"TABLE"               , "TABLE"                     , SYSDD_DESC_VTRACE , "TABLE"           , "Table"                   , "Accesses to primary data"                                            , LEVEL_OFF, false}, \
     {"OBJECT"              , "OBJECT"                    , SYSDD_DESC_VTRACE , "OBJECT"          , "Objects"                 , "Accesses to objects (includes add, get, alter, free)"                , LEVEL_OFF, false}, \
     {"OBJECTADD"           , "OBJECT ADD"                , SYSDD_DESC_VTRACE , "OBJECT ADD"      , "Objects add"             , "Accesses to objects"                                                 , LEVEL_OFF, false}, \
     {"OBJECTGET"           , "OBJECT GET"                , SYSDD_DESC_VTRACE , "OBJECT GET"      , "Objects get"             , "Accesses to objects"                                                 , LEVEL_OFF, false}, \
     {"OBJECTALTER"         , "OBJECT ALTER"              , SYSDD_DESC_VTRACE , "OBJECT ALTER"    , "Objects alter"           , "Accesses to objects"                                                 , LEVEL_OFF, false}, \
     {"OBJECTFREE"          , "OBJECT FREEPAGE"           , SYSDD_DESC_VTRACE , "OBJECT FREE"     , "Objects free"            , "Accesses to objects"                                                 , LEVEL_OFF, false}, \
     {"SELECT"              , "SELECT"                    , SYSDD_DESC_VTRACE , "SELECT"          , "Select"                  , "Complete message buffer of SELECT, GET, FETCH, UNION and SELECT ROW" , LEVEL_OFF, false}, \
     {"INSERT"              , "INSERT"                    , SYSDD_DESC_VTRACE , "INSERT"          , "Insert"                  , "Complete message buffer of INSERT"                                   , LEVEL_OFF, false}, \
     {"UPDATE"              , "UPDATE"                    , SYSDD_DESC_VTRACE , "UPDATE"          , "Update"                  , "Complete message buffer of UPDATE"                                   , LEVEL_OFF, false}, \
     {"DELETE"              , "DELETE"                    , SYSDD_DESC_VTRACE , "DELETE"          , "Delete"                  , "Complete message buffer of DELETE"                                   , LEVEL_OFF, false}, \
     {"ORDER"               , "ORDER"                     , SYSDD_DESC_VTRACE , "ORDER"           , "Order"                   , "Complete order packet"                                               , LEVEL_OFF, false}, \
     {"OPTIMIZER"           , "OPTIMIZE"                  , SYSDD_DESC_VTRACE , "OPTIMIZE"        , "Optimize"                , "Optimizer output"                                                    , LEVEL_OFF, false}, \
     {"TIME"                , "TIME"                      , SYSDD_DESC_VTRACE , "TIME"            , "Time"                    , "Elapsed time in kernel underneath of the message buffer"             , LEVEL_OFF, false}, \
     {"CHECK"               , "CHECK"                     , SYSDD_DESC_VCHECK , "on"              , "Check"                   , "Additional checks on correct state of the regions"                   , LEVEL_OFF, false}, \
     {"COMMANDS"            , "ANALYZE"                   , SYSDD_DESC_VTRACE , "AK"              , "Commands"                , "All order packets (including internal packets)"                      , LEVEL_OFF, false}, \
     {"TOPICCONVERTER"      , "TOPIC 'CONVERTER %d'"      , SYSDD_DESC_VTRACE , "CONVERTER"       , "Topic Converter"         , "Topic trace for converter"                                           , LEVEL_OFF, true }, \
     {"TOPICDATA"           , "TOPIC 'DATA %d'"           , SYSDD_DESC_VTRACE , "DATA"            , "Topic Data"              , "Topic trace for data area"                                           , LEVEL_OFF, true }, \
     {"TOPICDATACHAIN"      , "TOPIC 'DATACHAIN %d'"      , SYSDD_DESC_VTRACE , "DATACHAIN"       , "Topic Data"              , "Topic trace for operations on low level data structures"             , LEVEL_OFF, true }, \
     {"TOPICDATAPAM"        , "TOPIC 'DATAPAM %d'"        , SYSDD_DESC_VTRACE , "DATAPAM"         , "Topic Data"              , "Topic trace for page access with the new interface"                  , LEVEL_OFF, true }, \
     {"TOPICDATATREE"       , "TOPIC 'DATATREE %d'"       , SYSDD_DESC_VTRACE , "DATATREE"        , "Topic Data"              , "Topic trace for update statistics on trees"                          , LEVEL_OFF, true }, \
     {"TOPICFRAMECTRL"      , "TOPIC 'FRAMECTRL %d'"      , SYSDD_DESC_VTRACE , "FRAMECTRL"       , "Topic Framecontrol"      , "Topic trace for framecontrol"                                        , LEVEL_OFF, true }, \
     {"TOPICLOG"            , "TOPIC 'LOG %d'"            , SYSDD_DESC_VTRACE , "LOG"             , "Topic Log"               , "Topic trace for log area"                                            , LEVEL_OFF, true }, \
     {"TOPICLOGVOLUME"      , "TOPIC 'LOGVOLUME %d'"      , SYSDD_DESC_VTRACE , "LOGVOLUME"       , "Topic Log"               , "Topic trace for log reading and writing access"                      , LEVEL_OFF, true }, \
     {"TOPICLOGHISTORY"     , "TOPIC 'LOGHISTORY %d'"     , SYSDD_DESC_VTRACE , "LOGHISTORY"      , "Topic Log"               , "Topic trace for consistent view and garbage collector handling"      , LEVEL_OFF, true }, \
     {"TOPICLOGTRANS"       , "TOPIC 'LOGTRANS %d'"       , SYSDD_DESC_VTRACE , "LOGTRANS"        , "Topic Log"               , "Topic trace for restart, savepoint and transactionhandling"          , LEVEL_OFF, true }, \
     {"TOPICLOGACTION"      , "TOPIC 'LOGACTION %d'"      , SYSDD_DESC_VTRACE , "LOGACTION"       , "Topic Log"               , "Topic trace for build, execute, redo and undo actions"               , LEVEL_OFF, true }, \
     {"TOPICIOMAN"          , "TOPIC 'IOMAN %d'"          , SYSDD_DESC_VTRACE , "IOMAN"           , "Topic I/O manager"       , "Topic trace for I/O mamager"                                         , LEVEL_OFF, true }, \
     {"TOPICMEMORY"         , "TOPIC 'MEMORY %d'"         , SYSDD_DESC_VTRACE , "MEMORY"          , "Topic Memory"            , "Topic trace for memory management"                                   , LEVEL_OFF, true }, \
     {"TOPICVOLUME"         , "TOPIC 'VOLUME %d'"         , SYSDD_DESC_VTRACE , "VOLUME"          , "Topic Volume"            , "Topic trace for volume access"                                       , LEVEL_OFF, true }, \
     {"TOPICRUNTIME"        , "TOPIC 'RUNTIME %d'"        , SYSDD_DESC_VTRACE , "RUNTIME"         , "Topic Runtime"           , "Topic trace for runtime environment"                                 , LEVEL_OFF, true }, \
     {"TOPICALLOCATOR"      , "TOPIC 'ALLOCATOR %d'"      , SYSDD_DESC_VTRACE , "ALLOCATOR"       , "Topic Allocator"         , "Topic trace for allocators"                                          , LEVEL_OFF, true }, \
     {"TOPICDATAPAGEPRIM"   , "TOPIC 'DATAPAGEPRIM %d'"   , SYSDD_DESC_VTRACE , "DATAPAGEPRIM"    , "Topic Page"              , "Topic trace for primary data pages"                                  , LEVEL_OFF, true }, \
     {"TOPICDATAPAGEINV"    , "TOPIC 'DATAPAGEINV %d'"    , SYSDD_DESC_VTRACE , "DATAPAGEINV"     , "Topic Page"              , "Topic trace for index data pages"                                    , LEVEL_OFF, true }, \
     {"TOPICDATAPAGELOG"    , "TOPIC 'DATAPAGELOG %d'"    , SYSDD_DESC_VTRACE , "DATAPAGELOG"     , "Topic Page"              , "Topic trace for undo,redo,history data pages"                        , LEVEL_OFF, true }, \
     {"TOPICLOGPAGE"        , "TOPIC 'LOGPAGE %d'"        , SYSDD_DESC_VTRACE , "LOGPAGE"         , "Topic Page"              , "Topic trace for archive log pages"                                   , LEVEL_OFF, true }, \
     {"TOPICCONVERTERPAGE"  , "TOPIC 'CONVERTERPAGE %d'"  , SYSDD_DESC_VTRACE , "CONVERTERPAGE"   , "Topic Page"              , "Topic trace for all data converter pages"                            , LEVEL_OFF, true }, \
     {"TOPICTABLE"          , "TOPIC 'TABLE %d'"          , SYSDD_DESC_VTRACE , "TABLE"           , "Topic Table"             , "Topic trace for the table handling"                                  , LEVEL_OFF, true }, \
     {"TOPICCOMMON"         , "TOPIC 'COMMON %d'"         , SYSDD_DESC_VTRACE , "COMMON"          , "Topic Common"            , "Topic trace for the common kernel"                                   , LEVEL_OFF, true }, \
     {"CHECKCONVERTER"      , "CHECK 'CONVERTER %d'"      , SYSDD_DESC_CHECK  , "CONVERTER"       , "Check Converter"         , "Checks for converter"                                                , LEVEL_OFF, true }, \
     {"CHECKDATA"           , "CHECK 'DATA %d'"           , SYSDD_DESC_CHECK  , "DATA"            , "Check Data"              , "Checks for data area"                                                , LEVEL_OFF, true }, \
     {"CHECKDATACHAIN"      , "CHECK 'DATACHAIN %d'"      , SYSDD_DESC_CHECK  , "DATACHAIN"       , "Check Data"              , "Checks for operations on low level data structures"                  , LEVEL_OFF, true }, \
     {"CHECKDATAPAM"        , "CHECK 'DATAPAM %d'"        , SYSDD_DESC_CHECK  , "DATAPAM"         , "Check Data"              , "Checks for page access with the new interface"                       , LEVEL_OFF, true }, \
     {"CHECKDATATREE"       , "CHECK 'DATATREE %d'"       , SYSDD_DESC_CHECK  , "DATATREE"        , "Check Data"              , "Checks for update statistics on trees"                               , LEVEL_OFF, true }, \
     {"CHECKFRAMECTRL"      , "CHECK 'FRAMECTRL %d'"      , SYSDD_DESC_CHECK  , "FRAMECTRL"       , "Check Framecontrol"      , "Checks for framecontrol"                                             , LEVEL_OFF, true }, \
     {"CHECKLOG"            , "CHECK 'LOG %d'"            , SYSDD_DESC_CHECK  , "LOG"             , "Check Log"               , "Checks for log area"                                                 , LEVEL_OFF, true }, \
     {"CHECKLOGVOLUME"      , "CHECK 'LOGVOLUME %d'"      , SYSDD_DESC_CHECK  , "LOGVOLUME"       , "Check Log"               , "Checks for log reading and writing access"                           , LEVEL_OFF, true }, \
     {"CHECKLOGHISTORY"     , "CHECK 'LOGHISTORY %d'"     , SYSDD_DESC_CHECK  , "LOGHISTORY"      , "Check Log"               , "Checks for consistent view and garbage collector handling"           , LEVEL_OFF, true }, \
     {"CHECKLOGTRANS"       , "CHECK 'LOGTRANS %d'"       , SYSDD_DESC_CHECK  , "LOGTRANS"        , "Check Log"               , "Checks for restart, savepoint and transactionhandling"               , LEVEL_OFF, true }, \
     {"CHECKLOGACTION"      , "CHECK 'LOGACTION %d'"      , SYSDD_DESC_CHECK  , "LOGACTION"       , "Check Log"               , "Checks for build, execute, redo and undo actions"                    , LEVEL_OFF, true }, \
     {"CHECKIOMAN"          , "CHECK 'IOMAN %d'"          , SYSDD_DESC_CHECK  , "IOMAN"           , "Check I/O manager"       , "Checks for I/O mamager"                                              , LEVEL_OFF, true }, \
     {"CHECKMEMORY"         , "CHECK 'MEMORY %d'"         , SYSDD_DESC_CHECK  , "MEMORY"          , "Check Memory"            , "Checks for memory management"                                        , LEVEL_OFF, true }, \
     {"CHECKVOLUME"         , "CHECK 'VOLUME %d'"         , SYSDD_DESC_CHECK  , "VOLUME"          , "Check Volume"            , "Checks for volume access"                                            , LEVEL_OFF, true }, \
     {"CHECKRUNTIME"        , "CHECK 'RUNTIME %d'"        , SYSDD_DESC_CHECK  , "RUNTIME"         , "Check Runtime"           , "Checks for runtime environment"                                      , LEVEL_OFF, true }, \
     {"CHECKALLOCATOR"      , "CHECK 'ALLOCATOR %d'"      , SYSDD_DESC_CHECK  , "ALLOCATOR"       , "Check Allocator"         , "Checks for allocators"                                               , LEVEL_OFF, true }, \
     {"CHECKDATAPAGEPRIM"   , "CHECK 'DATAPAGEPRIM %d'"   , SYSDD_DESC_CHECK  , "DATAPAGEPRIM"    , "Check Page"              , "Checks for primary data pages"                                       , LEVEL_OFF, true }, \
     {"CHECKDATAPAGEINV"    , "CHECK 'DATAPAGEINV %d'"    , SYSDD_DESC_CHECK  , "DATAPAGEINV"     , "Check Page"              , "Checks for index data pages"                                         , LEVEL_OFF, true }, \
     {"CHECKDATAPAGELOG"    , "CHECK 'DATAPAGELOG %d'"    , SYSDD_DESC_CHECK  , "DATAPAGELOG"     , "Check Page"              , "Checks for undo,redo,history data pages"                             , LEVEL_OFF, true }, \
     {"CHECKLOGPAGE"        , "CHECK 'LOGPAGE %d'"        , SYSDD_DESC_CHECK  , "LOGPAGE"         , "Check Page"              , "Checks for archive log pages"                                        , LEVEL_OFF, true }, \
     {"CHECKCONVERTERPAGE"  , "CHECK 'CONVERTERPAGE %d'"  , SYSDD_DESC_CHECK  , "CONVERTERPAGE"   , "Check Page"              , "Checks for all data converter pages"                                 , LEVEL_OFF, true }, \
     {"CHECKTABLE"          , "CHECK 'TABLE %d'"          , SYSDD_DESC_CHECK  , "TABLE"           , "Check Table"             , "Checks for the table handling"                                       , LEVEL_OFF, true }, \
     {"CHECKCOMMON"         , "CHECK 'COMMON %d'"         , SYSDD_DESC_CHECK  , "COMMON"          , "Check Common"            , "Checks for the common kernel"                                        , LEVEL_OFF, true }, \
     {NULL                  , NULL                        , SYSDD_DESC_CHECK  , NULL              , NULL                      , NULL                                                                  , LEVEL_OFF, false}}


typedef struct tcn84TraceProtList {
    const char * szName;
    const char * szSyntax;
    const char * szSysDDDesc;
    const char * szSysDDValue;
    const char * szShortDesc;
    const char * szLongDesc;
    int          nLevel;
    bool         bLevel;
} tcn84TraceProtList;

#define MAX_COMMANDLEN    2048
#define MAX_TOKENLEN       100


#define SQL_DIAGNOSE_VTRACE "DIAGNOSE VTRACE"
#define SQL_ON              "ON"
#define SQL_OFF             "OFF"

#define SQL_DIAGNOSE_VTRACE_CLEAR "DIAGNOSE VTRACE CLEAR"
#define SQL_DIAGNOSE_VTRACE_FLUSH "DIAGNOSE VTRACE FLUSH"

#define COL_NAME_L        15
#define COL_STATE_L        5
#define COL_LEVEL_L        6

#define COL_NAME_T        "Name"
#define COL_STATE_T       "State"
#define COL_LEVEL_T       "Level"
#define COL_DESC_T        "Description"

#define STR_ON            "ON"
#define STR_OFF           "OFF"
#define STR_NOLEVEL       "-"
#define STR_SEPARATOR     ","

#define VTRACE_ALL        "ALL"

#define OPTION_VERBOSE    "verbose"

/*
  -----------------------------------------------------------------------------
  function:     cn84_TraceSwitch
  -----------------------------------------------------------------------------
 */
static tcn00_Error cn84_TraceSwitch
      ( VControlDataT * vcontrol,
        const char    * szTokens,
        char          * replyData,
        int           * replyLen,
        int             replyLenMax,
        bool            bOn);

/*
  -----------------------------------------------------------------------------
  function:     cn84_TraceSwitchAll
  -----------------------------------------------------------------------------
 */
static tcn00_Error cn84_TraceSwitchAll
      ( VControlDataT * vcontrol,
        int             nLevel,
        char          * replyData,
        int           * replyLen,
        int             replyLenMax,
        bool            bOn);

/*
  -----------------------------------------------------------------------------
  specification private functions
  -----------------------------------------------------------------------------
*/

/*
  -----------------------------------------------------------------------------
  function:     cn84TraceShow
  -----------------------------------------------------------------------------
 */
tcn00_Error cn84TraceShow
      ( VControlDataT * vcontrol,
        CommandT      * command,
        char          * replyData,
        int           * replyLen,
        int             replyLenMax)
{
  FUNCTION_DBG_MCN00_1("cn84TraceShow");

  tcn00_Error        nFuncReturn = OK_CN00;
  tcn84TraceProtList oProtList[] = TRACE_PROT_LIST; 
  tsp00_Namec        szTemp;
  tsp00_Namec        szOption;
  bool               bVerbose = false;
  int                nPos        = 0;
  char               szState[20];
  char               szLevel[20];

  if (cn90GetToken(command->args, szOption, 1, szOption.size())) {
    if (strnicmp(szOption, OPTION_VERBOSE, strlen(szOption)) == 0) {
      bVerbose = true;
    } else {
      nFuncReturn = cn90AnswerIError(replyData, replyLen, ERR_PARAM_CN00);
    } // end if
  } // end if 

  if (nFuncReturn == OK_CN00) {
    nFuncReturn = cn84SaveTrace(vcontrol->dbname, replyData, replyLen);
  } // end if

  if (nFuncReturn == OK_CN00) {
    // read config file
    cn51DBMConfigValue::startBuffering(vcontrol->dbname);
    nPos = 0;
    while (oProtList[nPos].szName != NULL) {
      szTemp.rawAssign(oProtList[nPos].szName);
      cn51DBMConfigValue aValue(vcontrol->dbname, szTemp);
      oProtList[nPos].nLevel  = aValue;
      ++nPos;
    } // end while
    cn51DBMConfigValue::endBuffering(vcontrol->dbname);

    // print answer
    char * pCurrent = replyData;

    // print OK an title
    sprintf (pCurrent, "%s%s%-*s%s%-*s%s%-*s%s%s%s", ANSWER_OK_CN00, LINE_SEPSTRING_CN00,
                                                     COL_NAME_L, COL_NAME_T, VALUE_SEPSTRING_CN00,
                                                     COL_STATE_L, COL_STATE_T, VALUE_SEPSTRING_CN00,
                                                     COL_LEVEL_L, COL_LEVEL_T, VALUE_SEPSTRING_CN00,
                                                     COL_DESC_T, LINE_SEPSTRING_CN00);
    pCurrent += strlen(pCurrent);

    // print vtrace settings
    nPos = 0;
    while (oProtList[nPos].szShortDesc != NULL && oProtList[nPos].szLongDesc != NULL) {

      if (oProtList[nPos].nLevel > LEVEL_OFF) {
        SAPDB_strcpy(szState, STR_ON);
      } else {
        SAPDB_strcpy(szState, STR_OFF);
      } // end if
      if (oProtList[nPos].bLevel) {
        sprintf(szLevel, "%d", oProtList[nPos].nLevel);
      } else {
        SAPDB_strcpy(szLevel, STR_NOLEVEL);
      } // end if

      sprintf (pCurrent, "%-*s%s%-*s%s%-*s%s%s%s%s%s", COL_NAME_L,  oProtList[nPos].szName, VALUE_SEPSTRING_CN00,
                                                       COL_STATE_L, szState, VALUE_SEPSTRING_CN00,
                                                       COL_LEVEL_L, szLevel, VALUE_SEPSTRING_CN00,
                                                       oProtList[nPos].szShortDesc, 
                                                       bVerbose ? STR_SEPARATOR : "", 
                                                       bVerbose ? oProtList[nPos].szLongDesc : "", 
                                                       LINE_SEPSTRING_CN00);
      pCurrent += strlen(pCurrent);
      ++nPos;
    } // end while
  } // end if
  
  *replyLen = (int) strlen(replyData);

  return nFuncReturn;
} // end cn84TraceShow

/*
  -----------------------------------------------------------------------------
  function:     cn84TraceOn
  -----------------------------------------------------------------------------
 */
tcn00_Error cn84TraceOn
      ( VControlDataT * vcontrol,
        CommandT      * command,
        char          * replyData,
        int           * replyLen,
        int             replyLenMax)
{
  tcn00_Error        nFuncReturn = OK_CN00;
  tsp00_Namec        szToken;
  int                nLevel;
  
  // check for ALL keyword
  szToken.rawAssign("");
  cn90GetToken(command->args, szToken, 1, szToken.size());
  if (stricmp(szToken, VTRACE_ALL) == 0) {
    nLevel = LEVEL_DEFAULT;
    if (cn90GetToken(command->args, szToken, 2, szToken.size())) {
      if ((strlen(szToken) ==  1 ) &&
          (szToken[0]      >= '1') &&
          (szToken[0]      <= '9')    ) {
        nLevel = atoi(szToken);
      } else {
        nFuncReturn = cn90AnswerIError(replyData, replyLen, ERR_PARAM_CN00);
      } // end if

      if (cn90GetToken(command->args, szToken, 3, szToken.size())) {
        nFuncReturn = cn90AnswerIError(replyData, replyLen, ERR_PARAM_CN00);
      } // end if
    } // end if

    if (nFuncReturn == OK_CN00) {
      nFuncReturn = cn84_TraceSwitchAll( vcontrol,
                                         nLevel,
                                         replyData,
                                         replyLen,
                                         replyLenMax,
                                         true);
    } // end if

  } else {
    nFuncReturn = cn84_TraceSwitch( vcontrol,
                                    command->args,
                                    replyData,
                                    replyLen,
                                    replyLenMax,
                                    true);
  } // end if
  
  return nFuncReturn;
} // end cn84TraceOn

/*
  -----------------------------------------------------------------------------
  function:     cn84TraceOff
  -----------------------------------------------------------------------------
 */
tcn00_Error cn84TraceOff
      ( VControlDataT * vcontrol,
        CommandT      * command,
        char          * replyData,
        int           * replyLen,
        int             replyLenMax)
{
  tcn00_Error        nFuncReturn = OK_CN00;
  tsp00_Namec        szToken;
  
  // check for ALL keyword
  szToken.rawAssign("");
  cn90GetToken(command->args, szToken, 1, szToken.size());
  if (stricmp(szToken, VTRACE_ALL) == 0) {
    if (cn90GetToken(command->args, szToken, 2, szToken.size())) {
      nFuncReturn = cn90AnswerIError(replyData, replyLen, ERR_PARAM_CN00);
    } // end if

    if (nFuncReturn == OK_CN00) {
      nFuncReturn = cn84_TraceSwitchAll( vcontrol,
                                         LEVEL_OFF,
                                         replyData,
                                         replyLen,
                                         replyLenMax,
                                         false);
    } // end if

  } else {
    nFuncReturn = cn84_TraceSwitch( vcontrol,
                                    command->args,
                                    replyData,
                                    replyLen,
                                    replyLenMax,
                                    false);
  } // end if
  
  return nFuncReturn;
} // end cn84TraceOff

/*
  -----------------------------------------------------------------------------
  function:     cn84TraceFlush
  -----------------------------------------------------------------------------
 */
tcn00_Error cn84TraceFlush
      ( VControlDataT * vcontrol,
        CommandT      * command,
        char          * replyData,
        int           * replyLen,
        int             replyLenMax)
{
  return cn80ExecuteSQL (  vcontrol->dbname,
                           SQL_DIAGNOSE_VTRACE_FLUSH,
                           replyData,
                           replyLenMax,
                           *replyLen );
} // end cn84TraceFlush

/*
  -----------------------------------------------------------------------------
  function:     cn84TraceClear
  -----------------------------------------------------------------------------
 */
tcn00_Error cn84TraceClear
      ( VControlDataT * vcontrol,
        CommandT      * command,
        char          * replyData,
        int           * replyLen,
        int             replyLenMax)
{
  return cn80ExecuteUtil ( vcontrol->dbname,
                           SQL_DIAGNOSE_VTRACE_CLEAR,
                           replyData,
                           replyLen );
} // end cn84TraceClear

/*
  -----------------------------------------------------------------------------
  function:     cn84TraceProtOpt
  -----------------------------------------------------------------------------
 */
tcn00_Error cn84TraceProtOpt
      ( VControlDataT * vcontrol,
        CommandT      * command,
        char          * replyData,
        int           * replyLen,
        int             replyLenMax)
{
  long                nIndex          = 0;
  tcn84TraceProtOpt   sTraceProtOpt[] = TRACE_PROTOPT;
  _TCHAR            * pCurrent        = replyData;

  // init OK Answer
  sprintf (pCurrent, "%s%s%s", ANSWER_OK_CN00, LINE_SEPSTRING_CN00, TRACE_PROTOPT_TITLE);
  pCurrent = pCurrent + _tcslen(pCurrent);

  while (sTraceProtOpt[nIndex].szOption != NULL) {
    _stprintf (pCurrent, "%s%s%s%s",
                         (_TCHAR *) sTraceProtOpt[nIndex].szOption,
                         VALUE_SEPSTRING_CN00,
                         (_TCHAR *) sTraceProtOpt[nIndex].szName,
                         LINE_SEPSTRING_CN00);
    pCurrent = pCurrent + _tcslen(pCurrent);

    nIndex++;
  }

  *replyLen = (int)_tcslen(replyData);

  return OK_CN00;
} // end cn84TraceProtOpt


/*
  -----------------------------------------------------------------------------
  function:     cn84TraceProt
  -----------------------------------------------------------------------------
 */
tcn00_Error cn84TraceProt
      ( VControlDataT * vcontrol,
        CommandT      * command,
        char          * replyData,
        int           * replyLen,
        int             replyLenMax)
{
  return cn40ExecXKernprot(vcontrol, command, replyData, replyLen, replyLenMax);
} // end cn84TraceProt


/*
  -----------------------------------------------------------------------------
  internal functions
  -----------------------------------------------------------------------------
 */

/*
  -----------------------------------------------------------------------------
  function:     cn84RestoreTrace
  -----------------------------------------------------------------------------
 */
tcn00_Error cn84RestoreTrace
      ( tsp00_DbNamec        szDbName )
{
  tcn84TraceProtList oProtList[] = TRACE_PROT_LIST; 
  tsp00_Namec        szTemp;
  int                nPos        = 0;
  char               szCommand[MAX_COMMANDLEN];
  char               szToken[MAX_TOKENLEN];

  // read from config file
  cn51DBMConfigValue::startBuffering(szDbName);
  nPos = 0;
  while (oProtList[nPos].szName != NULL) {
    szTemp.rawAssign(oProtList[nPos].szName);
    cn51DBMConfigValue aValue(szDbName, szTemp);
    oProtList[nPos].nLevel = aValue;
    ++nPos;
  } // end while
  cn51DBMConfigValue::endBuffering(szDbName);

  // build command
  SAPDB_strcpy(szCommand, SQL_DIAGNOSE_VTRACE);
  strcat(szCommand, " ");
  nPos = 0;
  while (oProtList[nPos].szSyntax != NULL) {
    if (oProtList[nPos].nLevel > LEVEL_OFF) {
      if (oProtList[nPos].bLevel) {
        sprintf(szToken, oProtList[nPos].szSyntax, oProtList[nPos].nLevel);
        strcat(szCommand, szToken);
      } else {
        strcat(szCommand, oProtList[nPos].szSyntax);
      } // end if
      strcat(szCommand, " ");
    } // end if
    ++nPos;
  } // end while
  strcat(szCommand, SQL_ON);

  // send to kernel
  return cn80ExecuteUtil (szDbName, szCommand);

} // end cn84RestoreTrace

/*
  -----------------------------------------------------------------------------
  function:     cn84SaveTrace
  -----------------------------------------------------------------------------
 */
tcn00_Error cn84SaveTrace
      ( tsp00_DbNamec        szDbName,
        char               * replyData,
        int                * replyLen )
{
  FUNCTION_DBG_MCN00_1("cn84TraceSave");

  tcn00_Error             nFuncReturn = OK_CN00;

  // check dbstate
  if (cn90DBState(szDbName) == STATE_ONLINE_CN00) {
    tin01_sql_session       SQLSession;
    tin110_SQLResultTable   aTable(&SQLSession);
    tin110_SQLRecord        aRecord;
    tsp00_Namec             szValue;
    tsp00_Namec             szDesc;
    tsp00_Namec             szTemp;
    int                     nPos        = 0;
    tcn84TraceProtList      oProtList[] = TRACE_PROT_LIST; 
    char                    l_replyData[1024];
    int                     l_replyLen;

    replyData = replyData == NULL ? &(l_replyData[0]) : replyData;
    replyLen  = replyLen  == NULL ? &l_replyLen       : replyLen;

    // read from config file
    cn51DBMConfigValue::startBuffering(szDbName);
    nPos = 0;
    while (oProtList[nPos].szName != NULL) {
      szTemp.rawAssign(oProtList[nPos].szName);
      cn51DBMConfigValue aValue(szDbName, szTemp);
      oProtList[nPos].nLevel = aValue;
      if (oProtList[nPos].szSysDDValue != NULL) {
        oProtList[nPos].nLevel = LEVEL_OFF;
      } // end if
      ++nPos;
    } // end while
    cn51DBMConfigValue::endBuffering(szDbName);

    // create sql session
    nFuncReturn = cn80ConnectSQL(szDbName, &SQLSession, replyData, replyLen);

    if (nFuncReturn == OK_CN00) {

      // select vtrace settings
      aTable.execute(SQL_SHOW_VTRACE);
      if (aTable.sqlRc() == cin01_db_ok) {

        // analyze records
        aRecord = aTable.record();
        while (aTable.sqlRc() == cin01_db_ok) {
          SAPDB_strcpy(szValue, aRecord.fieldAsChar(SQLF_VAL ));
          SAPDB_strcpy(szDesc,  aRecord.fieldAsChar(SQLF_DESC));
          nPos = 0;
          while (oProtList[nPos].szName != NULL) {
            if (oProtList[nPos].szSysDDValue != NULL) {
              if ((strcmp(szValue, oProtList[nPos].szSysDDValue) == 0) &&
                  (strcmp(szDesc,  oProtList[nPos].szSysDDDesc ) == 0)    ) {
                if (oProtList[nPos].bLevel) {
                  oProtList[nPos].nLevel = aRecord.fieldAsInt (SQLF_NUM);
                } else {
                  oProtList[nPos].nLevel = LEVEL_DEFAULT;
                } // end if

                break;
              } // end if
            } // end if
            ++nPos;
          } // while
          aRecord = aTable.nextRecord();
        } // end while

      } else if (aTable.sqlRc() != cin01_db_row_not_found) {
        // oops sql error
        teo200_EventList lEvtList(aTable.lastEvent(), FUNCTION_NAME_MCN00_1, ERR_SQL_CN00_1);
        nFuncReturn = cn90AnswerEvent(replyData, replyLen, lEvtList);
      } // end if

      // release session 
      cn80ReleaseSQL  ( &SQLSession, false);

    } // end if

    // save data to config file
    if (nFuncReturn == OK_CN00) {

      cn51DBMConfigValue::startBuffering(szDbName);

      nPos = 0;
      while (oProtList[nPos].szName != NULL) {
        szTemp.rawAssign(oProtList[nPos].szName);
        cn51DBMConfigValue aValue(szDbName, szTemp);
        aValue = oProtList[nPos].nLevel;
        ++nPos;
      } // end while

      cn51DBMConfigValue::endBuffering(szDbName);

    } // end if


  } // end if

  return nFuncReturn;
} // end cn84SaveTrace

/*
  -----------------------------------------------------------------------------
  function:     cn84_TraceSwitch
  -----------------------------------------------------------------------------
 */
static tcn00_Error cn84_TraceSwitch
      ( VControlDataT * vcontrol,
        const char    * szTokens,
        char          * replyData,
        int           * replyLen,
        int             replyLenMax,
        bool            bOn)
{
  tcn00_Error         nFuncReturn  = OK_CN00;
  tsp00_Namec         szKeyword;
  tsp00_Namec         szLevel;
  int                 nPos;
  int                 nToken;
  tcn84TraceProtList  oProtList[]  = TRACE_PROT_LIST; 
  bool                bConnect     = false;
  tin01_sql_session   aSQLSession;
  int                 nLevel = LEVEL_DEFAULT;
  char                szCommand[MAX_COMMANDLEN];
  char                szToken[MAX_TOKENLEN];
  tsp00_Namec         szTemp;
  tcn00_DBState       nState = STATE_UNKNOWN_CN00;

  // check dbstate
  if (nFuncReturn == OK_CN00) {
    nState = cn90DBState(vcontrol->dbname);
    if ((nState != STATE_ONLINE_CN00) && (nState != STATE_ADMIN_CN00) && (nState != STATE_STANDBY_CN00)) {
      nFuncReturn = cn90AnswerIError(replyData, replyLen, ERR_DBNORUN_CN00);
    } // end if
  } // end if

  // create session
  if (nFuncReturn == OK_CN00) {
    nFuncReturn = cn80ConnectSQL ( vcontrol->dbname, &aSQLSession, replyData,replyLen);
    bConnect = (nFuncReturn == OK_CN00);
  } // end if

  // read from config file
  if (nFuncReturn == OK_CN00) {
    cn51DBMConfigValue::startBuffering(vcontrol->dbname);
    nPos = 0;
    while (oProtList[nPos].szName != NULL) {
      szTemp.rawAssign(oProtList[nPos].szName);
      cn51DBMConfigValue aValue(vcontrol->dbname, szTemp);
      oProtList[nPos].nLevel = aValue;
      ++nPos;
    } // end while
    cn51DBMConfigValue::endBuffering(vcontrol->dbname);
  } // end if

  // iterate trough tokens and build command
  if (nFuncReturn == OK_CN00) {

    SAPDB_strcpy(szCommand, SQL_DIAGNOSE_VTRACE);
    strcat(szCommand, " ");

    nToken = 1;
    while (nFuncReturn == OK_CN00) {
      // extrakt token
      if (!cn90GetToken(szTokens, szKeyword, nToken, szKeyword.size())) {
        break;
      } // end if

      // find record
      nPos = 0;
      while (oProtList[nPos].szName != NULL) {
        if (stricmp(szKeyword, oProtList[nPos].szName) == 0) {
          nLevel = LEVEL_DEFAULT;
          // look for level parameter
          if (oProtList[nPos].bLevel && bOn) {
            if (cn90GetToken(szTokens, szLevel, nToken + 1, szLevel.size())) {
              if ((strlen(szLevel) ==  1 ) &&
                  (szLevel[0]      >= '1') &&
                  (szLevel[0]      <= '9')    ) {
                ++nToken;
                nLevel = atoi(szLevel);
              } // end if
            } // end if
          } // end if

          oProtList[nPos].nLevel = bOn ? nLevel : LEVEL_OFF;
          break;
        } // end if
        ++nPos;
      } // while

      // wrong parameter
      if (oProtList[nPos].szName == NULL) {
        nFuncReturn = cn90AnswerIError(replyData, replyLen, ERR_PARAM_CN00);
        break;
      } // end if

      // append keyword to command
      if (oProtList[nPos].bLevel ) {
        sprintf(szToken, oProtList[nPos].szSyntax, oProtList[nPos].nLevel); 
        strcat(szCommand, szToken);
      } else {
        strcat(szCommand, oProtList[nPos].szSyntax);
      } // end if
      strcat(szCommand, " ");

      ++nToken;
    } // end while

  } // end if

  // send command
  if (nFuncReturn == OK_CN00) {
    strcat(szCommand, bOn ? SQL_ON : SQL_OFF);
    nFuncReturn = cn80ExecuteSQL( &aSQLSession, szCommand, replyData, replyLenMax, *replyLen);
  } // end if

  // always disconnect (if autoconnect)
  if (bConnect) {
    cn80ReleaseSQL( &aSQLSession, true);
  } // end if

  // save configuration
  if (nFuncReturn == OK_CN00) {
    // save data to config file
    if (nFuncReturn == OK_CN00) {
      cn51DBMConfigValue::startBuffering(vcontrol->dbname);
      nPos = 0;
      while (oProtList[nPos].szName != NULL) {
        szTemp.rawAssign(oProtList[nPos].szName);
        cn51DBMConfigValue aValue(vcontrol->dbname, szTemp);
        aValue = oProtList[nPos].nLevel;
        ++nPos;
      } // end while
      cn51DBMConfigValue::endBuffering(vcontrol->dbname);
    } // end if
  } // end if

  // answer OK
  if (nFuncReturn == OK_CN00) {
    cn90AnswerOK(replyData, replyLen, NULL);
  } // end if

  return nFuncReturn;
} // end cn84_TraceSwitch

/*
  -----------------------------------------------------------------------------
  function:     cn84_TraceSwitchAll
  -----------------------------------------------------------------------------
 */
static tcn00_Error cn84_TraceSwitchAll
      ( VControlDataT * vcontrol,
        int             nLevel,
        char          * replyData,
        int           * replyLen,
        int             replyLenMax,
        bool            bOn)
{
  tcn00_Error         nFuncReturn  = OK_CN00;
  int                 nPos;

  tcn84TraceProtList  oProtList[]  = TRACE_PROT_LIST; 
  bool                bConnect     = false;
  tin01_sql_session   aSQLSession;
  char                szCommand[MAX_COMMANDLEN];
  char                szToken[MAX_TOKENLEN];
  tsp00_Namec         szTemp;
  tcn00_DBState       nState = STATE_UNKNOWN_CN00;

  // check dbstate
  if (nFuncReturn == OK_CN00) {
    nState = cn90DBState(vcontrol->dbname);
    if ((nState != STATE_ONLINE_CN00) && (nState != STATE_ADMIN_CN00) && (nState != STATE_STANDBY_CN00)) {
      nFuncReturn = cn90AnswerIError(replyData, replyLen, ERR_DBNORUN_CN00);
    } // end if
  } // end if

  // create session
  if (nFuncReturn == OK_CN00) {
    nFuncReturn = cn80ConnectSQL ( vcontrol->dbname, &aSQLSession, replyData,replyLen);
    bConnect = (nFuncReturn == OK_CN00);
  } // end if

  // iterate trough list entries and build command
  if (nFuncReturn == OK_CN00) {

    SAPDB_strcpy(szCommand, SQL_DIAGNOSE_VTRACE);
    strcat(szCommand, " ");

    nPos = 0;
    while (oProtList[nPos].szName != NULL) {

      // append keyword to command
      if (oProtList[nPos].bLevel ) {
        oProtList[nPos].nLevel = bOn ? nLevel : LEVEL_OFF;
        sprintf(szToken, oProtList[nPos].szSyntax, oProtList[nPos].nLevel); 
        strcat(szCommand, szToken);
      } else {
        oProtList[nPos].nLevel = bOn ? LEVEL_DEFAULT : LEVEL_OFF;
        strcat(szCommand, oProtList[nPos].szSyntax);
      } // end if
      strcat(szCommand, " ");

      ++nPos;
    } // end while

  } // end if

  // send command
  if (nFuncReturn == OK_CN00) {
    strcat(szCommand, bOn ? SQL_ON : SQL_OFF);
    nFuncReturn = cn80ExecuteSQL( &aSQLSession, szCommand, replyData, replyLenMax, *replyLen);
  } // end if

  // always disconnect (if autoconnect)
  if (bConnect) {
    cn80ReleaseSQL(&aSQLSession, true);
  } // end if

  // save configuration
  if (nFuncReturn == OK_CN00) {
    // save data to config file
    if (nFuncReturn == OK_CN00) {
      cn51DBMConfigValue::startBuffering(vcontrol->dbname);
      nPos = 0;
      while (oProtList[nPos].szName != NULL) {
        szTemp.rawAssign(oProtList[nPos].szName);
        cn51DBMConfigValue aValue(vcontrol->dbname, szTemp);
        aValue = oProtList[nPos].nLevel;
        ++nPos;
      } // end while
      cn51DBMConfigValue::endBuffering(vcontrol->dbname);
    } // end if
  } // end if

  // answer OK
  if (nFuncReturn == OK_CN00) {
    cn90AnswerOK(replyData, replyLen, NULL);
  } // end if

  return nFuncReturn;
} // end cn84_TraceSwitchAll
