/***************************************************************
 * Run Time Access
 * Copyright (C) 2003 Robert W Smith (bsmith@linuxtoys.org)
 *
 *  This program is distributed under the terms of the GNU LGPL.
 *  See the file COPYING file.
 **************************************************************/

/***************************************************************
 * Overview:
 *    The "rta" package provides a Postgres-like API into our
 * system tables and variables.  We need to describe each of our
 * tables as if it were a data base table.  We describe each
 * table in general in an array of TBLDEF structures with one
 * structure per table, and each column of each table in an
 * array of COLDEF strustures with one COLDEF structure per
 * column.
 **************************************************************/

#include <stdio.h>              /* for printf prototypes */
#include <stddef.h>             /* for 'offsetof' */
#include <syslog.h>             /* for LOG_ERR, LOG_USER */
#include <string.h>             /* for strncmp prototypes */
#include <time.h>
#include "rta.h"                /* for TBLDEF and COLDEF */
#include "do_sql.h"             /* for struct Sql_Cmd */

/* Forward reference for read callbacks */
void    *spoof_user(void *, char *, char *, void *);
void    *compute_time(void *, char *col, char *sql, void *);

/***************************************************************
 * One of the tables we need to maintain compatibility with the
 * various Postgres front-ends is 'pg_user'.  So here we define
 * a pg_user data structure, allocate a 1 row table for users,
 * define the table using COLDEF and TBLDEF, and give a read
 * callback which makes the first table entry look like whoever
 * appears in the WHERE clause.  So a query like ....
 *    SELECT usesuper FROM pg_user WHERE usename = "Any Name"
 * will always return 'f' regardless of the usename requested.
 * This is also a resonable demonstration of a read callback.
 * (Clearly this defeats the security model of Postgres.  If you
 * _want_ to use a real pg_user table you can remove the read
 * callback, allocate more rows, and save the data to disk.)
 **************************************************************/

#define   MX_PGNAMELEN   (32)
#define   FT_LEN          (2)

/* Define the structure */
struct Pg_User
{
  char     usename[MX_PGNAMELEN]; /* user name */
  int      usesysid;   /* user ID */
  char     usecreatedb[FT_LEN]; /* creat DB */
  char     usetrace[FT_LEN]; /* trace execution */
  char     usesuper[FT_LEN]; /* super user */
  char     usecatupd[FT_LEN];
  char     passwd[MX_PGNAMELEN]; /* the password */
  char     valuntil[MX_PGNAMELEN]; /* valid until .... */
};

/* Allocate and initialize the table */
struct Pg_User pg_user[] = {
  {
      "master",                   /* user name */
      100,                      /* user ID */
      "f",                      /* creat DB */
      "f",                      /* trace execution */
      "f",                      /* super user */
      "f",
      "password",                   /* the password */
      ""                        /* valid until .... */
    }
};

void rta_change_auth(char *uname, char *pass) {
	strncpy(pg_user[0].usename, uname, MX_PGNAMELEN);
	strncpy(pg_user[0].passwd, pass, MX_PGNAMELEN);
}



/* Define the table columns */
COLDEF   pg_userCols[] = {
  {
      "pg_user",                /* table name */
      "usename",                /* column name */
      RTA_STR,                  /* type of data */
      MX_PGNAMELEN,             /* #bytes in col data */
      offsetof(struct Pg_User, usename), /* offset from col strt */
      0,               /* =1 to save on disk */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The name of the Postgres user.  We overwrite this column "
      "with whatever string is in the WHERE clause.  In this way "
      "there is always a match when looking up a user name in the "
      "DB"},
  {
      "pg_user",                /* table name */
      "usesysid",               /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(struct Pg_User, usesysid), /* offset from col strt */
      0,               /* =1 to save on disk */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The user ID of the user.  Currently fixed at 100."},
  {
      "pg_user",                /* table name */
      "usecreatedb",            /* column name */
      RTA_STR,                  /* type of data */
      FT_LEN,                   /* #bytes in col data */
      offsetof(struct Pg_User, usecreatedb), /* offset from strt */
      0,               /* =1 to save on disk */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "Bool flag ('t' or 'f') to indicate whether the user can "
      "create new data bases.  Always 'f' in our system,"},
  {
      "pg_user",                /* table name */
      "usetrace",               /* column name */
      RTA_STR,                  /* type of data */
      FT_LEN,                   /* #bytes in col data */
      offsetof(struct Pg_User, usetrace), /* offset from col strt */
      0,               /* =1 to save on disk */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "Bool flag ('t' or 'f') to indicate whether the user can "
      "use the trace capability.  Always 'f' in our system,"},
  {
      "pg_user",                /* table name */
      "usesuper",               /* column name */
      RTA_STR,                  /* type of data */
      FT_LEN,                   /* #bytes in col data */
      offsetof(struct Pg_User, usesuper), /* offset from col strt */
      0,               /* =1 to save on disk */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "Bool flag ('t' or 'f') to indicate whether the user has "
      "super-user capability.  Always 'f' in our system,"},
  {
      "pg_user",                /* table name */
      "usecatupd",              /* column name */
      RTA_STR,                  /* type of data */
      FT_LEN,                   /* #bytes in col data */
      offsetof(struct Pg_User, usecatupd), /* offset from strt */
      0,               /* =1 to save on disk */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "Bool flag ('t' or 'f').  Always 'f' in our system,"},
  {
      "pg_user",                /* table name */
      "passwd",                 /* column name */
      RTA_STR,                  /* type of data */
      MX_PGNAMELEN,             /* #bytes in col data */
      offsetof(struct Pg_User, passwd), /* offset from col strt */
      0,               /* =1 to save on disk */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The encrypted password of the user.  Not implemented in "
      "the current system."},
  {
      "pg_user",                /* table name */
      "valuntil",               /* column name */
      RTA_STR,                  /* type of data */
      MX_PGNAMELEN,             /* #bytes in col data */
      offsetof(struct Pg_User, valuntil), /* offset from col strt */
      0,               /* =1 to save on disk */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The expiration date of the password.  Not implemented in "
      "the current system."},
};

/* Define the table */
TBLDEF   pg_userTable = {
  "pg_user",                    /* table name */
  (void *) pg_user,             /* address of table */
  sizeof(struct Pg_User),       /* length of each row */
  1,                            /* # rows in table */
  TBL_ARRAY,
  pg_userCols,                  /* Column definitions */
  sizeof(pg_userCols) / sizeof(COLDEF), /* # columns */
  "",                           /* save file name */
  "The table of Postgres users.  We spoof this table so that "
    "any user name in a WHERE clause appears in the table as a "
    "legitimate user with no super, createDB, trace or catupd "
    "capability."
};

/* spoof_user(): - Routine to copy user name from WHERE clause
 * to 'usename' in order to spoof the system into accepting
 * any user name as a valid user.  We normally expect a command
 * of the form:
 * SELECT usesuper FROM gp_user WHERE usename = 'XXXXXXX'
 *    What we want to do is to copy XXXXXX into the usename
 * field so there is always a match.  We do some basic checks
 * to be sure the command is of the above form.
 *
 * Input:        Name of the table 
 *               Name of the column
 *               Text of the SQL command itself
 *               Index of row used (zero indexed)
 * Output:       
 * Effects:      Copies user name to 'usename' field
 ***************************************************************/
void    *
spoof_user(void *tblname, char *colname, char *sqlcmd, void *rowid)
{
  extern struct Sql_Cmd cmd;

  /* Verify that the column of interest is 'usename'. Verify that there 
     is one WHERE clause. Verify that the WHERE relation is equality. */
  if ((strcmp(colname, "usename")) ||
    (cmd.nwhrcols != 1) || (cmd.whrrel[0] != RTA_EQ))
    return NULL;

  /* It seems OK.  Copy the WHERE string */
//  strncpy(pg_user[0].usename, cmd.whrvals[0], MX_PGNAMELEN);
  strncpy(pg_user[0].usename, "harhar", MX_PGNAMELEN);
  return NULL;
}

/***************************************************************
 * One of the tables we want to present to the UI is the table
 * of UI connections.  It is defined in app.h as ....
 *  typedef struct {
    int   fd;          // FD of TCP conn (=-1 if not in use)
    int   cmdindx;     // Index of next location in cmd buffer
    char  cmd[MXCMD];  // SQL command from UI program
    int   rspfree;     // Number of free bytes in rsp buffer
    char  rsp[MXRSP];  // SQL response to the UI program
    int   o_port;      // Other-end TCP port number
    int   o_ip;        // Other-end IP address 
    long long nbytin;  // number of bytes read in
    long long nbytout; // number of bytes sent out
    int   ctm;         // connect time (==time();)
    int   cdur;        // duration time (== now()-ctm;)
 *  } UI;
 * The following array of COLDEF describes this structure with
 * one COLDEF for each element in the UI strucure.
 **************************************************************/
COLDEF   PG_ConnCols[] = {
  {
      "pg_conn",                /* table name */
      "id",                     /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(EpgConn, id),    /* offset from col start */
      RTA_READONLY,             /* Flags for read-only/disksave */
      NULL,                     /* called before read */
      (void (*)()) 0,           /* called after write */
    "int ID of the connection"},
  {
      "pg_conn",                /* table name */
      "username",               /* column name */
      RTA_STR,                  /* type of data */
      33,                       /* #bytes in col data */
      offsetof(EpgConn, username), /* offset from col start */
      RTA_READONLY,             /* Flags for read-only/disksave */
      NULL,                     /* called before read */
      (void (*)()) 0,           /* called after write */
    "the Username"},
  {
      "pg_conn",                /* table name */
      "cmd",                    /* column name */
      RTA_STR,                  /* type of data */
      1000,                     /* #bytes in col data */
      offsetof(EpgConn, cmd),   /* offset from col start */
      RTA_READONLY,             /* Flags for read-only/disksave */
      NULL,                     /* called before read */
      (void (*)()) 0,           /* called after write */
    "Input command from the user interface program.  This"
      " is an SQL command which is executed against the data"
      " in the application."},
  {
      "pg_conn",                /* table name */
      "rspfree",                /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(EpgConn, rspfree), /* offset from col start */
      RTA_READONLY,             /* Flags for read-only/disksave */
      NULL,                     /* called before read */
      (void (*)()) 0,           /* called after write */
    "Index of the next free byte in the response string, rsp"},
  {
      "pg_conn",                /* table name */
      "rsp",                    /* column name */
      RTA_STR,                  /* type of data */
      50,                       /* first 50 bytes of response field */
      offsetof(EpgConn, rsp),   /* offset from col start */
      RTA_READONLY,             /* Flags for read-only/disksave */
      NULL,                     /* called before read */
      (void (*)()) 0,           /* called after write */
    "Response back to the calling program.  This is used to"
      " store the result so that the write() does not need to"
      " block"},
  {
      "pg_conn",                /* table name */
      "ctm",                    /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(EpgConn, ctm),   /* offset from col start */
      RTA_READONLY,             /* Flags for read-only/disksave */
      NULL,                     /* called before read */
      (void (*)()) 0,           /* called after write */
    "Connect TiMe.  The unix style time() when the connection"
      " was established.  This is used to decide which connection"
      " to drop when the connection table is full and a new UI"
      " connection request arrives."},
  {
      "pg_conn",                /* table name */
      "cdur",                   /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(EpgConn, cdur),  /* offset from col start */
      RTA_READONLY,             /* Flags for read-only/disksave */
      compute_time,             /* called before read */
      NULL,                     /* called after write */
    "Connect DURation.  The number of seconds the connection"
      " has been open.  A read callback computes this each time"
      " the value is used."},
};

void    *
compute_time(void *tbl, char *col, char *sql, void *rowid)
{
  EpgConn *data = rowid;

  data->cdur = time(NULL) - data->ctm;
  return &data->cdur;
}

TBLDEF   pg_connTable = {
  "pg_conn",                    /* table name */
  0,                            /* address of table */
  0,                            /* length of each row */
  0,                            /* # rows in table */
  TBL_LIST,
  PG_ConnCols,                  /* Column definitions */
  sizeof(PG_ConnCols) / sizeof(COLDEF), /* # columns */
  "",                           /* save file name */
  "Data about connections from frontend programs"
};

/***************************************************************
 * We define a table which contains the column definitions of
 * all columns in the system.  This is a pseudo table in that
 * there is not an array of structures like other tables.
 * Instead, pointers to each column definition is placed in a
 * table.  This table requires special handling in do_sql.c.
 * The table definition for "rta_columns" must appear as the
 * second entry in the array of table definition pointers.
 **************************************************************/

/* Define the table columns */
COLDEF   rta_columnsCols[] = {
  {
      "rta_columns",            /* table name */
      "table",                  /* column name */
      RTA_PSTR,                 /* type of data */
      MXTBLNAME,                /* #bytes in col data */
      offsetof(COLDEF, table), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The name of the table that this column belongs to."},
  {
      "rta_columns",            /* table name */
      "name",                   /* column name */
      RTA_PSTR,                 /* type of data */
      MXCOLNAME,                /* #bytes in col data */
      offsetof(COLDEF, name), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The name of the column.  Must be unique within a table "
      "definition but may be replicated in other tables.  The "
      "maximum string length of the column name is set by "
      "MXCOLNAME defined in the rta.h file."},
  {
      "rta_columns",            /* table name */
      "type",                   /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(COLDEF, type), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The data type of the column.  Types include string, "
      "integer, long, pointer, pointer to string, pointer to "
      "integer, and pointer to long.  See rta.h for more details."},
  {
      "rta_columns",            /* table name */
      "length",                 /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(COLDEF, length), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The length of the string in bytes if the column data "
      "type is a string or a pointer to a string."},
  {
      "rta_columns",            /* table name */
      "offset",                 /* column name */
      RTA_PTR,                  /* type of data */
      sizeof(void *),           /* #bytes in col data */
      offsetof(COLDEF, offset), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The number of bytes from the start of the structure "
      "to the member element defined in this entry.  Be careful "
      "in setting the offset with non word-aligned elements like "
      "single characters.  If you do no use offsetof() consider "
      "using -fpack-struct"},
  {
      "rta_columns",            /* table name */
      "flags",                  /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(COLDEF, flags), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "Flags associated with the column include flags to indicate "
      "read-only status and whether or not the data should be "
      "included in the save file.  See rta.h for the associated "
      "defines and details."},
  {
      "rta_columns",            /* table name */
      "readcb",                 /* column name */
      RTA_PTR,                  /* type of data */
      sizeof(void *),           /* #bytes in col data */
      offsetof(COLDEF, readcb), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "A pointer to a function that returns an integer.  If "
      "defined, the function is called before the column is "
      "read.  This function is useful to compute values only "
      "when needed."},
  {
      "rta_columns",            /* table name */
      "writecb",                /* column name */
      RTA_PTR,                  /* type of data */
      sizeof(void *),           /* #bytes in col data */
      offsetof(COLDEF, writecb), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "A pointer to a function that returns and integer.  If "
      "defined, the function is called after an UPDATE command "
      "modifies the column.  All columns in an UPDATE are "
      "modified before any write callbacks are executed.  This "
      "function is useful to effect changes requested or implied "
      "by the column definition."},
  {
      "rta_columns",            /* table name */
      "help",                   /* column name */
      RTA_PSTR,                 /* type of data */
      MXHELPSTR,                /* #bytes in col data */
      offsetof(COLDEF, help), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "A brief description of the column.  Should include "
      "limits, default value, and a description of how to set "
      "it.  Can contain at most MXHELPSTR characters."},
};

/* Define the table */
TBLDEF   rta_columnsTable = {
  "rta_columns",                /* table name */
  (void *) 0,                   /* address of table */
  sizeof(COLDEF),               /* length of each row */
  0,                            /* incremented as tables are added */
  TBL_ARRAY,
  rta_columnsCols,              /* Column definitions */
  sizeof(rta_columnsCols) / sizeof(COLDEF), /* # columns */
  "",                           /* save file name */
  "The list of all columns in all tables along with their "
    "attributes."
};

/***************************************************************
 * We define a table which contains the table definition of all
 * tables in the system.  This is a pseudo table in that there
 * is not an array of structures like other tables.  Use of this
 * table requires special handling in do_sql.
 **************************************************************/

/* Define the table columns */
COLDEF   rta_tablesCols[] = {
  {
      "rta_tables",             /* table name */
      "name",                   /* column name */
      RTA_PSTR,                 /* type of data */
      MXTBLNAME,                /* #bytes in col data */
      offsetof(TBLDEF, name), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The name of the table.  This must be unique in the system. "
      " Table names can be at most MXTBLNAME characters in length."
      "  See rta.h for details.  Note that some table names are "
      "reserved for internal use."},
  {
      "rta_tables",             /* table name */
      "address",                /* column name */
      RTA_PTR,                  /* type of data */
      sizeof(void *),           /* #bytes in col data */
      offsetof(TBLDEF, address), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The start address of the array of structs that makes up "
      "the table."},
  {
      "rta_tables",             /* table name */
      "tabletype",              /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(TBLDEF, tabletype), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The type of table this is"},
  {
      "rta_tables",             /* table name */
      "rowlen",                 /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(TBLDEF, rowlen), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The length of each struct in the array of structs that "
      "makes up the table."},
  {
      "rta_tables",             /* table name */
      "nrows",                  /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(TBLDEF, nrows), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The number of rows in the table."},
  {
      "rta_tables",             /* table name */
      "cols",                   /* column name */
      RTA_PTR,                  /* type of data */
      sizeof(void *),           /* #bytes in col data */
      offsetof(TBLDEF, cols), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "A pointer to an array of COLDEF structures.  There is one "
      "COLDEF for each column in the table."},
  {
      "rta_tables",             /* table name */
      "ncol",                   /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(TBLDEF, ncol), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The number of columns in the table."},
  {
      "rta_tables",             /* table name */
      "savefile",               /* column name */
      RTA_PSTR,                 /* type of data */
      MXFILENAME,               /* #bytes in col data */
      offsetof(TBLDEF, savefile), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The name of the file with the non-volatile contents of "
      "the table.  This file is read when the table is "
      "initialized and is written any time a column with the "
      "non-volatile flag set is modified."},
  {
      "rta_tables",             /* table name */
      "help",                   /* column name */
      RTA_PSTR,                 /* type of data */
      MXHELPSTR,                /* #bytes in col data */
      offsetof(TBLDEF, help), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "A description of the table."},
};

/* Define the table */
TBLDEF   rta_tablesTable = {
  "rta_tables",                 /* table name */
  (void *) 0,                   /* address of table */
  sizeof(TBLDEF),               /* length of each row */
  0,                            /* It's a pseudo table */
  TBL_ARRAY,
  rta_tablesCols,               /* Column definitions */
  sizeof(rta_tablesCols) / sizeof(COLDEF), /* # columns */
  "",                           /* save file name */
  "The table of all tables in the system.  This is a pseudo "
    "table and not an array of structures like other tables."
};

/***************************************************************
 *     The rta_dbg table controls which errors generate
 * debug log messages, the priority, and the facility of the
 * syslog() messages sent.  The rta package generates no user
 * level log * messages, only debug messages.  All of the fields
 * in this table are volatile.  You will need to set the values
 * in your main program to make them seem persistent.
 * (Try something like
 *    "SQL_string("UPDATE rta_dbgconfig SET dbg ....").)
 * A callback attached to dbg_facility causes a close/reopen of
 * syslog().
 **************************************************************/

/* Allocate and initialize the table */
struct EpgDbg rtadbg = {
  1,                            /* log system errors */
  1,                            /* log rta errors */
  1,                            /* log SQL errors */
  0,                            /* no log of SQL cmds */
  0,                            /* log to syslog() only */
  LOG_ERR,                      /* see sys/syslog.h */
  LOG_USER,                     /* see sys/syslog.h */
  "rta"                         /* see 'man openlog' */
};
#ifdef SHWDBGTBL
/* Define the table columns */
COLDEF   rta_dbgCols[] = {
  {
      "rta_dbg",                /* table name */
      "syserr",                 /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(struct EpgDbg, syserr), /* offset 2 col strt */
      0,               /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "A non-zero value causes a call to syslog() for all system "
      "errors such as failed malloc() or save file read failures."},
  {
      "rta_dbg",                /* table name */
      "rtaerr",                 /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(struct EpgDbg, rtaerr), /* offset 2 col strt */
      0,               /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "A non-zero value causes a call to syslog() for all errors "
      "internal to the rta package."},
  {
      "rta_dbg",                /* table name */
      "sqlerr",                 /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(struct EpgDbg, sqlerr), /* offset 2 col strt */
      0,               /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "A non-zero value causes a call to syslog() for all SQL "
      "errors.  Such errors usually indicate a programming error "
      "in one of the user interface programs."},
  {
      "rta_dbg",                /* table name */
      "trace",                  /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(struct EpgDbg, trace), /* offset 2 col strt */
      0,               /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "A non-zero value causes all SQL commands to be logged.  "
      "If the command is UPDATE, the number of rows affected is "
      "also logged."},
  {
      "rta_dbg",                /* table name */
      "target",                 /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(struct EpgDbg, target), /* offset 2 col strt */
      0,               /* Flags for read-only/disksave */
      NULL,            /* called before read */
      restart_syslog,  /* called after write */
    "Sets destination of log messages.  Zero turns off all "
      "logging of errors.  One sends log messages to syslog()."
      "  Two sends log messages to stderr.  Three sends error "
      "messages to both syslog() and to stderr.  Default is one."},
  {
      "rta_dbg",                /* table name */
      "priority",               /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(struct EpgDbg, priority), /* offset 2 col strt */
      0,               /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The syslog() priority.  Please see .../sys/syslog.h for "
      "the possible values.  Default is LOG_ERR."},
  {
      "rta_dbg",                /* table name */
      "facility",               /* column name */
      RTA_INT,                  /* type of data */
      sizeof(int),              /* #bytes in col data */
      offsetof(struct EpgDbg, facility), /* offset 2 col strt */
      0,               /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The syslog() facility.  Please see .../sys/syslog.h for "
      "the possible values.  Default is LOG_USER."},
  {
      "rta_dbg",                /* table name */
      "ident",                  /* column name */
      RTA_STR,                  /* type of data */
      MXDBGIDENT,               /* #bytes in col data */
      offsetof(struct EpgDbg, ident), /* offset 2 col strt */
      0,               /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "The syslog() 'ident'.  Please see 'man openlog' for "
      "details.  Default is 'rta'.  An update of the target "
      "field is required for this to take effect."},
};

/***************************************************************
 * restart_syslog(): - Routine to restart or reconfigure the
 * logging facility.  Syslog is always closed and (if enabled)
 * reopened with the priority and facility sepcified in the
 * rtadbg structure.
 *
 * Input:        Name of the table 
 *               Name of the column
 *               Text of the SQL command itself
 *               Index of row used (zero indexed)
 * Output:       
 * Effects:      Copies user name to 'usename' field
 **************************************************************/
void
restart_syslog(char *tblname, char *colname, char *sqlcmd, int rowid)
{
  extern struct EpgDbg rtadbg;

  closelog();

  if (rtadbg.target == 1 || rtadbg.target == 3)
  {
    openlog(rtadbg.ident, LOG_ODELAY | LOG_PID, rtadbg.facility);
  }

  return;
}

/* Define the table */
TBLDEF   rta_dbgTable = {
  "rta_dbg",                    /* table name */
  (void *) &rtadbg,             /* address of table */
  sizeof(struct EpgDbg),        /* length of each row */
  1,                            /* # rows in table */
  TBL_ARRAY,
  rta_dbgCols,                  /* Column definitions */
  sizeof(rta_dbgCols) / sizeof(COLDEF), /* # columns */
  "",                           /* save file name */
  "Configure of debug logging.  A callback on the 'target' "
    "field closes and reopens syslog().  None of the values "
    "in this table are saved to disk.  If you want non-default "
    "values you need to change the rta source or do an "
    "SQL_string() to set the values when you initialize your "
    "program."
};
#endif
/***************************************************************
 *     The rta_stats table contains usage and error statistics
 * which might be of interest to developers.  All fields are
 * of type long, are read-only, and are set to zero by
 * rta_init(). 
 **************************************************************/

/* Allocate and initialize the table */
struct EpgStat rtastat = {
  (long long) 0,                /* count of failed OS calls. */
  (long long) 0,                /* count of internal rta failures. */
  (long long) 0,                /* count of SQL failures. */
  (long long) 0,                /* count of authorizations. */
  (long long) 0,                /* count of UPDATE requests */
  (long long) 0,                /* count of SELECT requests */
};

/* Define the table columns */
COLDEF   rta_statCols[] = {
  {
      "rta_stat",               /* table name */
      "nsyserr",                /* column name */
      RTA_LONG,                 /* type of data */
      sizeof(long long),        /* #bytes in col data */
      offsetof(struct EpgStat, nsyserr), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "Count of failed OS calls."},
  {
      "rta_stat",               /* table name */
      "nrtaerr",                /* column name */
      RTA_LONG,                 /* type of data */
      sizeof(long long),        /* #bytes in col data */
      offsetof(struct EpgStat, nrtaerr), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "Count of internal rta failures."},
  {
      "rta_stat",               /* table name */
      "nsqlerr",                /* column name */
      RTA_LONG,                 /* type of data */
      sizeof(long long),        /* #bytes in col data */
      offsetof(struct EpgStat, nsqlerr), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "Count of SQL failures."},
  {
      "rta_stat",               /* table name */
      "nauth",                  /* column name */
      RTA_LONG,                 /* type of data */
      sizeof(long long),        /* #bytes in col data */
      offsetof(struct EpgStat, nauth), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "Count of DB authorizations.  This is a good estimate "
      "to the total number of connections."},
  {
      "rta_stat",               /* table name */
      "nselect",                /* column name */
      RTA_LONG,                 /* type of data */
      sizeof(long long),        /* #bytes in col data */
      offsetof(struct EpgStat, nselect), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "Count of SELECT commands."},
  {
      "rta_stat",               /* table name */
      "nupdate",                /* column name */
      RTA_LONG,                 /* type of data */
      sizeof(long long),        /* #bytes in col data */
      offsetof(struct EpgStat, nupdate), /* offset 2 col strt */
      RTA_READONLY,    /* Flags for read-only/disksave */
      NULL,            /* called before read */
      (void (*)()) 0,  /* called after write */
    "Count of UPDATE commands."},
};

/* Define the table */
TBLDEF   rta_statTable = {
  "rta_stat",                   /* table name */
  (void *) &rtastat,            /* address of table */
  sizeof(struct EpgStat),       /* length of each row */
  1,                            /* # rows in table */
  TBL_ARRAY,
  rta_statCols,                 /* Column definitions */
  sizeof(rta_statCols) / sizeof(COLDEF), /* # columns */
  "",                           /* save file name */
  "Usage and error counts for the rta package."
};


