/***************************************************************
 * 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.
 **************************************************************/

/***************************************************************
 * rta.h  -- DB API for your internal structures and tables
 **************************************************************/

/** ************************************************************
 * - Preamble:
 * "rta" is a specialized memory resident data base interface.
 * It is not a stand-alone server but a library which attaches
 * to a program and offers up the program's internal structures
 * and arrays as data base tables.  It uses a subset of the 
 * Postgres protocol and is compatible with the Postgres bindings
 * for "C", PHP, and the Postgres command line tool, psql.
 *
 *    This file contains the defines, structures, and function
 * prototypes for the 'rta' package.
 *
 * INDEX: 
 *        - Preamble
 *        - Introduction and Purpose
 *        - Limits
 *        - Data Structures
 *        - Subroutines
 *        - rta UPDATE and SELECT syntax
 *        - Internal DB tables
 *        - List of all error messages
 *        - How to write callback routines
 **************************************************************/

/** ************************************************************
 * - Introduction and Purpose:
 *    One of the problems facing Linux is the lack of real-time
 * access to status, statistics, and configuration of a service
 * once it has started.  We assume that to configure an
 * application we will be able to ssh into the box, vi the /etc
 * configuration file, and do a 'kill -1' on the process.  Real
 * time status and statistics are things Linux programmers don't
 * even think to ask for.  The problem of run time access is 
 * particularly pronounced for network appliances where ssh is
 * not available or might not be allowed.
 *    Another problem for appliance designers is that more than
 * one type of user interface may be required.  Sometimes
 * a customer requires that *no* configuration information be
 * sent over an Ethernet line which transports unsecured user
 * data.  In such a case the customer may turn off the web
 * interface and require that configuration, status, and
 * statistics be sent over an RS-232 serial line.  The VGA
 * console, SNMP MIBs,  and LDAP are also popular management
 * interfaces.
 *     The rta package helps solve these problems by giving
 * real-time access to the data structures and arrays inside a
 * running program.  With minimal effort, we make a program's
 * data structures appear as Postgres tables in a Postgres data
 * base.  
 *    For example, say you have a structure for TCP connections 
 * defined as:
 *    struct tcpconn {
 *      int   fd;       // conn's file descriptor
 *      int   lport;    // local port number
 *      int   dport;    // destination port number
 *      long  nsbytes;  // number of sent bytes
 *      long  nrbytes;  // number of received bytes
 *      long  nread;    // number of reads on the socket 
 *      long  nwrite;   // number of writes on the socket
 *    };
 *   
 * You might then define an array of these structures as:
 *    struct tcpconn Conns[MX_CONN];
 *
 *     The rta package allows any programming language with a 
 * Postgres binding to query your table of TCP connections....
 *    SELECT lport, dport FROM Conns WHERE fd != -1;
 *    UPDATE Conns SET dport = 0 WHERE fd = -1;
 *
 *     A data base API for all of your program's configuration,
 * status, and statistics makes debugging easier since you can
 * view much more of your program's state with simple Postgres
 * tools.  A data base API makes building user interface programs
 * easier since there are Postgres bindings for PHP, Tcl/Tk,
 * Perl, "C", as well as many more.
 *     A data base API can help speed development.  Carefully
 * defining the tables to be used by the UI programs lets the
 * core application team build the application while the UI
 * developers work on the web pages, wizards, and MIBs of the
 * various UI programs.  
 *
 *     Some effort is required.  In order to make your arrays
 * and structures available to the data base API, you need to
 * tell rta about the tables and columns in the data base. 
 * Table information includes things like the name, start
 * address, number of rows and the length of each row.  Column
 * information includes things like the associate table name,
 * the column name, the column's data type, and whether we want
 * any special functions called when the column is read or
 * written (callbacks).
 *
 *   This document describes the API offered by the rta package.
 **************************************************************/

#ifndef RTA_H
#define RTA_H 1

/***************************************************************
 * - Limits:
 *     Here are the defines which describe the internal limits
 * set in the rta package.  You are welcome to change these 
 * limits; just be sure to recompile the rta package using 
 * your new settings.
 **************************************************************/

#include <limits.h>             /* for PATH_MAX */
#include "list.h"
#include "hash.h"
        /** Maximum number of tables allowed in the system.
         * Your data base may not contain more than this number
         * of tables. */
#define MX_TBL        (500)

        /** Maximum number of columns allowed in the system.
         * Your data base may not contain more than this number
         * of columns. */
#define MX_COL       (2500)

        /** Maximum number of characters in a column name, table
         * name, and in help.  See TBLDEF and COLDEF below. */
#define MXCOLNAME      (30)
#define MXTBLNAME      (30)
#define MXHELPSTR    (1000)
#define MXFILENAME   PATH_MAX

        /** Maximum number of characters in the 'ident' field of
         * the openlog() call.  See the rta_dbg table below. */
#define MXDBGIDENT     (20)

        /** Maximum line size.  SQL commands in save files may
         * contain no more than MX_LN_SZ characters.  Lines with
         * more than MX_LN_SZ characters are silently truncated
         * to MX_LN_SZ characters. */
#define MX_LN_SZ     (1500)

    /* Maximum number of columns allowed in a table */
#define NCMDCOLS       (40)

          /** The column definition (COLDEF) structure describes
           * one column of a table.  A table description has an
           * array of COLDEFs to describe the columns in the
           * table. */
typedef struct
{

          /** The name of the table that has this column. */
  char    *table;

          /** The name of the column.  Must be at most MXCOLNAME
           * characters in length and must be unique within a
           * table.  The same column name may be used in more
           * than one table. */
  char    *name;

          /** The data type of the column.  Must be int, long,
           * string, pointer to void, pointer to int, pointer
           * to long, or pointer to string.  The DB types are
           * defined immediately following this structure. */
  int      type;

          /** The number of bytes in the string if the above
           * type is RTA_STR or RTA_PSTR. */
  int      length;

          /** Number of bytes from the start of the structure to
           * this column.  For example, a structure with an int,
           * a 20 character string, and a long, would have the
           * offset of the long set to 24.  Use of the function
           * offsetof() is encouraged.  If you have structure
           * members that do not start on word boundaries and
           * you do not want to use offsetof(), then consider
           * using -fpack-struct with gcc. */
  int      offset;

          /** Boolean flags which describe attributes of the
           * columns.  The flags are defined after this
           * structure and include a "read-only" flag and a
           * flag to indicate that updates to this column
           * should cause a table save.  (See table savefile
           * described below.)  */
  int      flags;

          /** Read callback.  This routine is called before the
           * column value is used.  Input values include the
           * table name, the column name, the input SQL
           * command, and the (zero indexed) row number for the
           * row that is being read.
           * This routine is called *each* time the column is
           * read so the following would produce two calls:
           * SELECT intime FROM inns WHERE intime >= 100;   */
  void    *(*readcb) (void *tbl, char *column, char *SQL, void *data);

          /** Write callback.  This routine is called after an
           * UPDATE in which the column is written. Input values
           * include the table name, the column name, the SQL
           * command, and the (zero indexed) row number of the
           * modified row.  See the callback section below.
           * This routine is called only once after all column
           * updates have occurred.  For example, if there were
           * a write callback attached to the addr column, the
           * following SQL statement would cause the execution
           * of the write callback once after both mask and addr
           * have been written:
           * UPDATE ethers SET mask="255.255.255.0", addr = \
           *     "192.168.1.10" WHERE name = "eth1";
           * The callback is called for each row modified. */
  void     (*writecb) (char *tbl, char *column, char *SQL, int row_num);

          /** A brief description of the column.  This should
           * include the meaning of the data in the column, the
           * limits, if any, and the default values.  Include
           * a brief description of the side effects of changes.
           * This field is particularly important for tables 
           * which are part of the "boundary" between the UI
           * developers and the application programmers.  */
  char    *help;
}
COLDEF;

/***************************************************************
 * - Data Structures:
 *     Each column and table in the data base must be described
 * in a data structure.  Here are the data structures and 
 * associated defines to describe tables and columns.
 **************************************************************/

        /** The data types.
         * String refers to an array of char.  The 'length' of
         * column must contain the number of bytes in the array.
         */
#define RTA_STR          0

        /** Pointer to void.  Use for generic pointers */
#define RTA_PTR          1

        /** Integer.  This is the compiler/architecture native
         * integer.  On Linux/gcc/Pentium an integer is 32 bits.
         */
#define RTA_INT          2

        /** Long.  This is the compiler/architecture native
         * long long.  On Linux/gcc/Pentium a long long is 64
         * bits.  */
#define RTA_LONG         3

        /** Pointer to string.  Pointer to an array of char, or
         * a (**char).  Note that the column length should be
         * the number of bytes in the string, not sizeof(char *).
         */
#define RTA_PSTR         4

        /** Pointers to int and long.  */
#define RTA_PINT         5
#define RTA_PLONG        6

        /** Float and pointer to float */
#define RTA_FLOAT        7
#define RTA_PFLOAT       8
#define MXCOLTYPE       (RTA_PFLOAT)

        /** The boolean flags.  
         * If the disksave bit is set any writes to the column
         * causes the table to be saved to the "savefile".  See
         * savefile described in the TBLDEF section below. */
#define RTA_DISKSAVE     (1<<0)

        /** If the readonly flag is set, any writes to the 
         * column will fail and a debug log message will be 
         * sent.  (For unit test you may find it very handy to
         * leave this bit clear to get better test coverage of
         * the corner cases.)   */
#define RTA_READONLY     (1<<1)

        /** The table definition (TBLDEF) structure describes
         * a table and is passed into the DB system by the
         * rta_add_table() subroutine.  */
typedef enum
{
  TBL_ARRAY = 0,
  TBL_LIST = 1,
  TBL_HASH = 2,
} RTA_TABLETYPE;

typedef struct
{

        /** The name of the table.  Must be less than than
         * MXTLBNAME characters in length.  Must be unique
         * within the DB.  */
  char    *name;

        /** Address of the first element of the first row of
         * the array of structs that make up the table.  */
  void    *address;

        /** The number of bytes in each row of the table.  
         * This is usually a sizeof() of the structure 
         * associated with the table.   (The idea is that we
         * can get to data element E in row R with ...
         *    data = *(address + (R * rowlen) + offset(E)) */
  int      rowlen;

        /** Number of rows in the table.   */
  int      nrows;

 /** the type of struct this points to? Hash, List or array */
  RTA_TABLETYPE tabletype;

        /** An array of COLDEF structures which describe each
         * column in the table.  These must be in statically
         * allocated memory since the rta system references
         * them while running.  */
  COLDEF  *cols;

        /** The number of columns in the table.  That is, the
         * number of COLDEFs defined by 'cols'.  */
  int      ncol;

        /**  Save file.  Path and name of a file which stores
         * the non-volatile part of the table.  The file has
         * all of the UPDATE statements needed to rebuild the
         * table.  The file is rewritten in its entirety each
         * time a 'savetodisk' column is updated.  No file
         * save is attempted if the savefile is blank. */
  char    *savefile;

        /**  Help text.  A description of the table, how it is
         * used, and what its intent is.  A brief note to
         * describe how it relate to other parts of the system
         * and description of important callbacks is nice 
         * thing to include here.  */
  char    *help;
}
TBLDEF;

/***************************************************************
 * - Subroutines
 * Here is a summary of the few routines in the rta API:
 *    rta_init()      - initialize internal tables
 *    dbcommand()     - I/F to Postgres clients
 *    egp_add_table() - add a table and its columns to the DB
 *    SQL_string()    - execute an SQL statement in the DB
 *    rta_save()      - save a table to a file
 *    rta_load()      - load a table from a file
 *
 * The FUSE based virtual filesystem adds the following:
 *    rtafs_init()    - mount FS and get file descriptor for it
 *    do_rtafs()      - handle all virtual file system IO
 * The above two routines are in the rtafs library.  Their 
 * inclusion in this include file cause no harm if you are
 * using only the rtadb library.  Note that the rtafs library
 * requires the rtadb library.
 **************************************************************/

/** ************************************************************
 * dbcommand():  - Depacketize and execute Postgres commands.
 *
 * The main application accepts TCP connections from Postgres
 * clients and passes the stream of bytes (encoded SQL requests)
 * from the client into the rta system via this routine.  If the
 * input buffer contains a complete command, it is executed, nin
 * is decrement by the number of bytes consumed, and RTA_SUCCESS
 * is returned.  If there is not a complete command, RTA_NOCMD
 * is returned and no bytes are removed from the input buffer.
 * If a command is executed, the results are encoded into the
 * Postgres protocol and placed in the output buffer.  When the
 * routine is called the input variable, nout, has the number of
 * free bytes available in the output buffer, out.  When the
 * routine returns nout has been decremented by the size of the
 * response placed in the output buffer.  An error message is
 * generated if the number of available bytes in the output 
 * buffer is too small to hold the response from the SQL command.
 * 
 * Input:  cmd - the buffer with the Postgres packet
 *         nin - on entry, the number of bytes in 'cmd',
 *               on exit, the number of bytes remaining in cmd
 *         out - the buffer to hold responses back to client
 *         nout - on entry, the number of free bytes in 'out'
 *               on exit, the number of remaining free bytes
 * Return: RTA_SUCCESS   - executed one command
 *         RTA_NOCMD     - input did not have a full cmd
 *         RTA_CLOSE     - client requests an orderly close
 **************************************************************/
int      dbcommand(char *, int *, char *, int *, int );
void     deldbconnection(int connid);

/** ************************************************************
 * rta_add_table():  - Register a table for inclusion in the
 * DB interface.  Adding a table allows external Postgres
 * clients access to the table's content.
 *     Note that the TBLDEF structure must be statically
 * allocated.  The DB system keeps just the pointer to the table
 * and does not copy the information.  This means that you can
 * change the contents of the table definition by changing the
 * contents of the TBLDEF structure.  This might be useful if
 * you need to allocate more memory for the table and change its
 * row count and address.
 *    An error is returned if another table by the same name 
 * already exists in the DB or if the table is defined without
 * any columns.
 *    If a 'savefile' is specified, it is loaded.  (See the
 * rta_load() command below for more details.)
 * 
 * Input:  ptbl          - pointer to the TBLDEF to add
 * Return: RTA_SUCCESS   - table added
 *         RTA_ERROR     - error
 **************************************************************/
int      rta_add_table(TBLDEF *);

/*
 * Logging function callback 
 */
typedef void (*logcb) (char *logmsg);

/** ************************************************************
 * rta_init():  - Initialize all internal variables and tables
 * This may be called more than once.
 * 
 * Input:  None
 * Return: None
 **************************************************************/
void     rta_init(logcb);

/* change the uname/password for authentication */
void rta_change_auth(char *uname, char *pass);

/** ************************************************************
 * SQL_string():  - Execute single SQL command
 *
 * Executes the SQL command placed in the null-terminated string,
 * cmd.  The results are encoded into the Postgres protocol and
 * placed in the output buffer.  When the routine is called the
 * input variable, nout, has the number of free bytes available
 * in the output buffer, out.  When the routine returns nout has
 * been decremented by the size of the response placed in the
 * output buffer.  An error message is generated if the number
 * of available bytes in the output buffer is too small to hold
 * the response from the SQL command.
 *     This routine may be most useful when updating a table
 * value in order to invoke the write callbacks.  (The output
 * buffer has the results encoded in the Postgres protocol and
 * might not be too useful directly.)
 *
 * Input:  cmd - the buffer with the SQL command,
 *         out - the buffer to hold responses back to client,
 *         nout - on entry, the number of free bytes in 'out'
 *               on exit, the number of remaining free bytes
 * Return: 
 **************************************************************/
void     SQL_string(char *, char *, int *);

/** ************************************************************
 * rta_save():  - Save table to file.   Saves all "savetodisk"
 * columns to the path/file specified.  Only savetodisk columns
 * are saved.  The resultant file is a list of UPDATE commands
 * containing the desired data.  There is one UPDATE command for
 * each row in the table.
 *     This routine tries to minimize exposure to corrupted 
 * save files by opening a temp file in the same directory as
 * the target file.  The data is saved to the temp file and the
 * system call rename() is called to atomically move the temp
 * to the save file.  Errors are generated if rta_save can not
 * open the temp file or is unable to rename() it.
 *     As a general warning, note that any disk I/O can cause
 * a program to block briefly and so saving and loading tables
 * might cause your program to block.
 * 
 * Input:  ptbl   - pointer to the TBLDEF structure for the 
 *                  table to save
 *         fname  - null terminated string with the path and
 *                  file name for the stored data.
 * Return: RTA_SUCCESS   - table saved
 *         RTA_ERROR     - some kind of error
 **************************************************************/
int      rta_save(TBLDEF *, char *);

/** ************************************************************
 * rta_load():  - Load a table from a file of UPDATE commands.
 * The file format is a series of UPDATE commands with one 
 * command per line.  Any write callbacks are executed as the
 * update occurs.  
 * 
 * Input:  ptbl   - pointer to the table to be loaded
 *         fname  - string with name of the load file
 *
 * Return: RTA_SUCCESS   - table loaded
 *         RTA_ERROR     - could not open the file specified
 **************************************************************/
int      rta_load(TBLDEF *, char *);

    /* successfully executed request or command */
#define RTA_SUCCESS   (0)

    /* input did not have a full command */
#define RTA_NOCMD     (1)

    /* encountered an internal error */
#define RTA_ERROR     (2)

    /* DB client requests a session close */
#define RTA_CLOSE     (3)

/** ************************************************************
 * rtafs_init():  - Initialize the virtual file system interface
 * to RTA.  The single input parameter is the mount point for
 * the VFS.  On success, the return value is a file descriptor
 * to the VFS.  On failure, a -1 is returned and errno is set.
 * This file descriptor should be used in subsequent select() or
 * poll() calls to notify your program of file system activity.
 * An important SIDE EFFECT is that the signal handlers for
 * SIGHUP, SIGINT, and SIGTERM are set.  The signal handler
 * tries to unmount the virtual file system.  This routine
 * is part of the librtafs library.
 *   Note that FUSE requires that the owner and group of the
 * mount point be the same as the owner and group of the program
 * that does the mount.  For example, if your mount point is
 * owned by Apache, then your the UID of your program must be
 * Apache as well.
 *
 * Input:  char *mountpoint - desired mount point
 *
 * Return: int fd        - file descriptor on success.
 **************************************************************/
int      rtafs_init(char *);

/** ************************************************************
 * do_rtafs():  - Handle all actual virtual file system IO. 
 * This routine handles all file system IO for the virtual file
 * system mounted by the rtafs_init() call.  This routine should
 * be called when there is activity on the file descriptor
 * returned from rtafs_init().  It has no input or output
 * parameters.  This routine is part of the librtafs library.
 * 
 * Input:  (none)
 *
 * Return: (none)
 **************************************************************/
void     do_rtafs();

/** ************************************************************
 * - rta UPDATE and SELECT syntax
 *     rta IS AN API, *NOT* A DATABASE!
 * Neither the rta UPDATE nor the rta SELECT adhere to the
 * Postgres equivalents.  Joins are not allowed, and the WHERE
 * clause supports only the AND relation.  There are no locks
 * or transactions.
 *
 * SELECT:
 *    SELECT column_list FROM table [where_clause] [limit_clause]
 *
 *    SELECT supports multiple columns, '*', LIMIT, and OFFSET.
 * At most MXCMDCOLS columns can be specified in the select list
 * or in the WHERE clause.  LIMIT restricts the number of rows
 * returned to the number specified.  OFFSET skips the number of
 * rows specified and begins output with the next row.
 * 'column_list' is a '*' or 'column_name [, column_name ...]'.
 * 'where_clause' is 'col_name = value [AND col_name = value ..]'
 * in which all col=val pairs must match for a row to match.
 *     LIMIT and OFFSET are very useful to prevent a buffer
 * overflow on the output buffer of dbcommand().  They are also
 * very useful for web based user interfaces in which viewing
 * the data a page-at-a-time is desirable.
 *     Column and table names are case sensitive.  If a column
 * or table name is one of the reserved words it must be placed
 * in quotes when used.  The reserved words are: AND, FROM, 
 * LIMIT, OFFSET, SELECT, SET, UPDATE, and WHERE.  Reserved 
 * words are *not* case sensitive.  You may use lower case
 * reserved words in your 
 *    Comparison operator in the WHERE clause include =, >=,
 * <=, >, and <.
 *    You can use a reserved word, like OFFSET, as a column name
 * but you will need to quote it whenever you reference it in an
 * SQL command (SELECT "offset" FROM tunings ...).   Strings 
 * may contain any of the !@#$%^&*()_+-={}[]\|:;<>?,./~`
 * characters.  If a string contains a double quote, use a 
 * single quote to wrap it (eg 'The sign say "Hi mom!"'), and
 * use double quotes to wrap string with embedded single quotes.
 *
 *     Examples:
 * SELECT * FROM rta_tables
 *
 * SELECT destIP FROM conns WHERE fd != 0
 *
 * SELECT destIP FROM conns WHERE fd != 0 AND lport = 80
 *
 * SELECT destIP, destPort FROM conns \
 *       WHERE fd != 0 \
 *       LIMIT 100 OFFSET 0
 * 
 * SELECT destIP, destPort FROM conns \
 *       WHERE fd != 0 \
 *       LIMIT 100 OFFSET 0
 *
 *
 * UPDATE:
 *    UPDATE table SET update_list [where_clause] [limit_clause]
 *
 *    UPDATE writes values into a table.  The update_list is of
 * the form 'col_name = val [, col_name = val ...].  The WHERE
 * and LIMIT clauses are as described above.  
 *    An update invokes write callbacks on the affected columns.
 * All data in the row is written before the callbacks are 
 * called.  
 *    The LIMIT clause for updates is not standard Postgres SQL,
 * but can be really useful for stepping through a table one row
 * at a time.  To change only the n'th row of a table, use a
 * limit clause like 'LIMIT 1 OFFSET n' (n is zero-indexed).
 *
 *    Examples:
 * UPDATE conn SET lport = 0;
 *
 * UPDATE ethers SET mask = "255.255.255.0", \ 
 *                   addr = "192.168.1.10"   \ 
 *       WHERE name = "eth0"
 *
 * UPDATE conn SET usecount = 0 WHERE fd != 0 AND lport = 21
 *
 **************************************************************/

/** ************************************************************
 * - Internal DB tables
 *     rta has five tables visible to the application:
 *  rta_tables:      - a table of all tables in the DB
 *  rta_columns:     - a table of all columns in the DB
 *  pg_user:         - spoof of Postgres table needed to log on
 *  rta_logconfig:   - controls what gets logged from rta
 *  egp_stats:       - simple usage and error statistics
 *
 *     The rta_tables table gives SQL access to all internal and
 * registered tables.  The data in the table is exactly that of
 * the TBLDEF structures registered with rta_add_table().  This
 * table is used for the generic table viewer and table editor 
 * applications used mostly for application debugging.  The
 * columns of rta_tables are:
 *     name      - the name of the table
 *     address   - the start address of the table in memory
 *     rowlen    - number of bytes in each row of the table
 *     nrows     - number of rows in the table
 *     cols      - pointer to array of column definitions
 *     ncol      - number of columns in the table
 *     savefile  - the file used to store non-volatile columns
 *     help      - a description of the table
 *
 *     The rta_columns table has the column definitions of all
 * columns in the DB.  The data in the table is exactly that of
 * the COLDEF structures registered with rta_add_table().  This
 * table is used for the generic table viewer and table editor
 * applications used mostly for application debugging.  The
 * columns of rta_columns are:
 *     table     - the name of the column's table
 *     name      - name of the column
 *     type      - column's data type
 *     length    - number of bytes columns data type
 *     offset    - number of bytes from start of structure
 *     flags     - Bit field for 'read-only' and 'savetodisk'
 *     readcb    - pointer to subroutine called before reads
 *     writecb   - pointer to subroutine called after writes
 *     help      - a description of the column
 *
 *     The pg_user table is provided to complete the connection
 * protocol between Postgres clients and the rta package.  It
 * authenticates the connecting user.  We spoof the protocol by
 * using a read callback to add the user into the table before
 * checking if the user is valid.  In this way *any* user who
 * connects is in the table and so is authenticated.  (One
 * future enhancement to rta might be to do real Postgres style 
 * authentication.)   The columns of pg_user are:
 *     usename     - spoofed to match any requested name
 *     usesysid    - 100
 *     usecreatedb - 'f'
 *     usetrace    - 'f'
 *     usesuper    - 'f'
 *     usecatupd   - 'f'
 *     passwd      - "******"
 *     valuntil    - ""
 *
 *     The rta_dbgconfig table controls which errors generate
 * debug log messages.  See the logging section below for the
 * exact mapping.  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 ....").)
 * The columns of rta_dbgconfig are:
 *     syserr - integer, 0 means no log, 1 means log.
 *              This logs OS call errors like malloc()
 *              failures.  Default is 1.
 *     rtaerr - integer, 0 means no log, 1 means log.
 *              Enables logging of errors internal to the
 *              rta package itself.  Default is 1.
 *     sqlerr - integer, 0 means no log, 1 means log.
 *              Log any SQL request which generates an
 *              error reply.  Error replies occur if an SQL
 *              request is malformed or if it requests a
 *              non-existent table or column.  Default is 1.
 *              (SQL errors are usually client programming
 *               errors.)
 *     trace  - integer, 0 means no log, 1 means log all
 *              SQL requests.  Default is 0.
 *     target - 0:  disable all debug logging
 *              1:  log debug messages to syslog()
 *              2:  log debug messages to stderr
 *              3:  log to both syslog() and stderr
 *              The default is 1.  Setting the facility
 *              causes a close and an open of syslog().
 *     priority - integer.  Syslog() requires a priority as
 *              part of all log messages.  This specifies
 *              the priority to use when sending rta debug
 *              messages.  Changes to this do not take
 *              effect until dbg_target is updated.
 *              0:  LOG_EMERG
 *              1:  LOG_ALERT
 *              2:  LOG_CRIT
 *              3:  LOG_ERR
 *              4:  LOG_WARNING
 *              5:  LOG_NOTICE
 *              6:  LOG_INFO
 *              7:  LOG_DEBUG
 *              Default is 3.
 *     facility - integer.  Syslog() requires a facility as
 *              part of all log messages.  This specifies
 *              the facility to use when sending rta debug
 *              messages.  It is best to use the defines in
 *              .../sys/syslog.h to set this.  The default
 *              is LOG_USER.  Changes to this do not take
 *              effect until dbg_target is updated.
 *     ident  - string.  Syslog() requires an 'ident' string as
 *              part of all log messages.  This specifies
 *              the ident string to use when sending rta debug
 *              messages.  This is normally set to the process
 *              or command name.  The default is "rta".  Changes
 *              to this do not take effect until dbg_target
 *              is updated.  This can be at most MXDBGIDENT
 *              characters in length.
 *
 *     The rta_stat 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().  The columns of rta_stats are:
 *     nsyserr    - count of failed OS calls. 
 *     nrtaerr    - count of internal rta failures.
 *     nsqlerr    - count of SQL failures.
 *     nauth      - count of authorizations. (==#connections)
 *     nupdate    - count of UPDATE or file write requests
 *     nselect    - count of SELECT or file read requests
 *
 **************************************************************/

/** ************************************************************
 * - List of all messages
 *      There are two types of error messages available in the
 * rta package.  The first type is the error messages returned
 * as part of an SQL request.  The messages of this type are:
 *
 * 1) "ERROR:  Relation '%s' does not exist"
 *      This reply indicates that a table requested in a SELECT
 *      UPDATE, or where clause does not exist.  The %s is 
 *      replaced by the name of the requested table.
 * 2) "ERROR:  Attribute '%s' not found\n"
 *      This reply indicates that a column requested in a SELECT
 *      UPDATE, or where clause does not exist.  The %s is 
 *      replaced by the name of the requested column.
 * 3) "ERROR:  SQL parse error"
 *      This reply indicates a mal-formed SQL request or a
 *      mis-match in the types of data in a where clause or in 
 *      an update list.
 * 4) "ERROR:  Output buffer full"
 *      This reply indicates that the size of the response to
 *      a request exceeds the size of the output buffer.  See
 *      dbcommand() and the 'out' and 'nout' parameters.  This
 *      error can be avoided with a large enough output buffer
 *      or, preferably, with the use of LIMIT and OFFSET.
 * 5) "ERROR:  String too long for '%s'
 *      This reply indicates that an update to a column of type
 *      string or pointer to string would have exceeded the
 *      width of the column.  The %s is replaced by the column
 *      name.
 * 6) "ERROR:  Can not update read-only column '%s'
 *      This reply indicates that an attempt to update a column
 *      marked as read-only.  The %s is replaced by the column
 *      name.
 *
 *     The other type of error messages are internal debug
 * messages.  Debug messages are logged using the standard
 * syslog() facility available on all Linux systems.  The
 * default syslog "facility" used is LOG_USER but this can be
 * changed by setting 'facility' in the rta_dbg table.
 *     You are welcome to modify syslogd in order to do post
 * processing such as generating SNMP traps off these debug
 * messages.  All error messages of this type are send to
 * syslog() as:    "egp[PID]: FILE LINE#: error_message",
 * where PID, FILE, and LINE# are replaced by the process ID,
 * the source file name, and the line number where the error
 * was detected.
 *     Following are the defines used to generate these debug
 * and error messages.   The "%s %d" at the start of each 
 * error string is replaced by the file name and line number
 * where the error is detected.  */

        /** "System" errors */
#define Er_No_Mem       "%s %d: Can not allocate memory\n"
#define Er_No_Save      "%s %d: Table save failure.  Can not open %s\n"
#define Er_No_Load      "%s %d: Table load failure.  Can not open %s\n"

        /** "RTA" errors */
#define Er_Max_Tbls     "%s %d: Too many tables in DB\n"
#define Er_Max_Cols     "%s %d: Too many columns in DB\n"
#define Er_Tname_Big    "%s %d: Too many characters in table name: %s\n"
#define Er_Cname_Big    "%s %d: Too many characters in column name: %s\n"
#define Er_Hname_Big    "%s %d: Too many characters in help text: %s\n"
#define Er_Tbl_Dup      "%s %d: DB already has table named: %s\n"
#define Er_Col_Dup      "%s %d: Table already has column named: %s\n"
#define Er_Col_Type     "%s %d: Column contains an unknown data type: %s\n"
#define Er_Col_Flag     "%s %d: Column contains unknown flag data: %s\n"
#define Er_Cmd_Cols     "%s %d: Too many columns in table: %s\n"
#define Er_No_Space     "%s %d: Not enough buffer space\n"

        /** "SQL" errors */
#define Er_Bad_SQL      "%s %d: SQL parse error: %s\n"
#define Er_Readonly     "%s %d: Attempt to update readonly column: %s\n"
#define Er_BadPass	"%s %d: Bad Username/Password\n"
        /** "Trace" messages */
#define Er_Trace_SQL    "%s %d: SQL command: %s  (%s)\n"

/*************************************************************/

/** ************************************************************
 * - How to write callback routines
 *     As mentioned above, read callbacks are executed before a
 * column value is used and write callbacks are called after all
 * columns have been updated.  Both read and write callbacks
 * return nothing (are of type void) and have the same calling
 * parameters:
 *   - char *tblname:  the name of the table referenced
 *   - char *colname:  the name of the column referenced
 *   - char *sqlcmd:   the text of the SQL command 
 *   - int   rowid:    the zero-indexed row number of the row
 *                     being read or written
 *
 *     Read callbacks are particularly useful to compute things
 * like sums and averages; things that aren't worth the effort
 * compute continuously if it's possible to compute it just 
 * when it is used.
 *     Write callbacks can form the real engine driving the
 * application.  These are most applicable when tied to 
 * configuration changes.   Write callbacks are also a useful 
 * place to log configuration changes.
 **************************************************************/

/***************************************************************
 * - Future enhancements:
 *    Several enhancements are possible for the rta package:
 * - printf format string in the column definition
 * - ability to register more than one trigger per column
 * - secure login maintaining Postgres compatibility
 * - IPC and support for shared tables in shared memory
 * - specify pre or post for the write callback
 * - table save callback (to save file to flash?)
 * - execution times for table access, update
 * - count(*) function
 * - model output buffer mgmt on zlib to allow output streams
 * - add a column data type of "table" to allow nested tables
 * - add internationalization support
 **************************************************************/

#endif
