librta:   Access Your Running Program

Live Demo
Bash
Table Editor


Support
FAQ
Contact Us!

librta API Specification

- Preamble

Librta is a specialized memory resident database interface. It is not a stand-alone database but a library which attaches to your program and offers up your program's internal structures and arrays as database 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 page contains the defines, structures, and function prototypes for librta. The information in this page is taken from the rta.h file in the librta package. The rta.h file is the authoritative reference to the API.

INDEX:
- Preamble
- Limits
- Data Structures
- Subroutines
- librta UPDATE and SELECT syntax
- librta INSERT and DELETE syntax
- Internal DB tables
- List of all error messages
- How to write callback routines

- Limits

Here are the defines which describe the internal limits set in the librta library. You are welcome to change these limits; just be sure to recompile librta package using your new settings.

#define Value Description
RTA_MX_TBL 500 Maximum number of tables allowed in the system. Your database may not contain more than this number of tables.
RTA_MX_COL 2500 Maximum number of columns allowed in the system. Your database may not contain more than this number of columns.
RTA_MXCOLNAME 30 Maximum number of characters in a column name, table name, help text, and path to the save file. See RTA_TBLDEF and RTA_COLDEF below.
RTA_MXTBLNAME 30
RTA_MXHELPSTR 1000
RTA_MXFILENAME PATH_MAX
RTA_MXDBGIDENT 20 Maximum number of characters in the 'ident' field of the openlog() call. See the rta_dbg table below.
RTA_MX_LN_SZ 1500 Maximum line size. SQL commands in save files may contain no more than RTA_MX_LN_SZ characters. Lines with more than RTA_MX_LN_SZ characters are silently truncated to RTA_MX_LN_SZ characters.
RTA_NCMDCOLS 40 Maximum number of columns allowed in a table.

- Data Structures

Each column and table in the database must be described in a data structure. Here are the data structures and associated defines to describe tables and columns.

The column definition (RTA_COLDEF) structure describes one column of a table. A table description has an array of RTA_COLDEFs to describe the columns in the table.

The RTA_COLDEF Structure
Type/Name Description
char *table The name of the table that has this column.
char *name The name of the column. Must be at most RTA_MXCOLNAME characters in length and must be unique within a table. The same column name may be used in more than one table.
int type 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 length The number of bytes in the string if the above type is RTA_STR or RTA_PSTR.
int offset 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 flags 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 (*readcb) () 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, a pointer to the row, and the (zero indexed) row number for the row that is being read. On success, a zero should be returned. This routine is called *each* time the column is read so the following would produce two calls:
SELECT intime FROM inns WHERE intime >= 100;
int (*writecb) () 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, a pointer to the row, the (zero indexed) row number of the the row that changed, and a pointer to the row before any changes were made. 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.

If an error is detected during the callback, a non-zero value can be returned. This returns an error to the client and restores the table row to its original value.

char *help 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.
RTA_COLDEF Types and Flags
RTA_STR String refers to an array of char. The 'length' of column must contain the number of bytes in the array.
RTA_PSTR 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 a sizeof(char *).
RTA_INT Integer. This is the compiler/architecture native integer. On Linux/gcc/Pentium an integer is 32 bits.
RTA_PINT Pointer to integer.
RTA_LONG Long. This is the compiler/architecture native long long. On Linux/gcc/Pentium a long long is 64 bits.
RTA_PLONG Pointer to long.
RTA_FLOAT Float. This is the compiler/architecture native float.
RTA_PFLOAT Pointer to float.
RTA_PTR Pointer to void. Use for generic pointers
RTA_DISKSAVE Flag: 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 RTA_TBLDEF section below.
RTA_READONLY Flag: 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.)


The table definition (RTA_TBLDEF) structure describes a table and is passed into the DB system by the rta_add_table() subroutine.

The RTA_TBLDEF Structure
Type/Name Description
char *name The name of the table. Must be less than than RTA_MXTLBNAME characters in length. Must be unique within the DB.
void *address Address of the first element of the first row of the array of struct that make up the table. This may be set to zero if an iterator is defined for the table.
int rowlen 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 nrows Number of rows in the table. This may be set to zero if an iterator is defined for the table.
void *iterator A function which, given a pointer to one row, return a pointer to the next row. The iterator is called as iterator(void *prow, void *it_info, int rowid);
An prow of NULL should return the first row of the table. The function should return NULL when asked for the row after the last row in the table. As a convenience, the row number being requested is also passed. That is, the first call will have rowid equal to zero. You may use either the current row pointer or the requested row number in determining the pointer to the row. The iterator function also passes the it_info void pointer described below.
If an iterator is defined, the RTA_TBLDEF values for table address and number of rows are ignored.
The iterator function provides a way to make linked lists and other data arrangements appear as database tables. See the sample application for an example. You might also look at the implementation of rta_tables and rta_columns, since they use an iterator as well.
void *it_info The value of it_info defined in the RTA_TBLDEF is passed each time the iterator is called on this table. This lets you define, for example, one iterator function for all of your linked lists. Inside your iterator function you can use it_info to determine which table the iterator should use.
int insertcb() INSERT callback. This routine is called to insert a a new row into a table. This routine should only be used for tables in which the rows are malloc'ed one at a time. The insert callback is given the name of the table, the SQL of the original INSERT command, and a pointer to a newly allocated row for that table. The callback needs to attach the row to the table using the technique (linked list, b-tree) suitable for that table. On success, the callback should return the zero-indexed row number for the new row or, on failure, the callback should return -1.
void deletecb() DELETE callback. This routine is called to delete a row from a table. This routine is appropriate for tables that have rows that are malloc'ed. It is up to the delete callback to unlink the row from the table and to FREE ALL MEMORY MALLOC'ED for the row. This callback has no return value and always succeeds. */
RTA_COLDEF *cols An array of RTA_COLDEF structures which describe the columns in the table. These must be in statically allocated memory since librta references them while running.
int ncol The number of columns in the table. That is, the number of RTA_COLDEFs defined by 'cols'.
char *savefile 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 *help 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.

- Subroutines

Here is a summary of the few routines in the librta API:

rta_dbcommand() process data stream from Postgres clients
rta_add_table() add a table and its columns to the DB
rta_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


rta_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 librta 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.

int
rta_dbcommand(char *cmd  - the buffer with the Postgres packet
              int  *nin  - on entry, the number of bytes in 'cmd',
                           on exit, the number of bytes remaining in cmd
              char *out  - the buffer to hold responses back to client
              int  *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 a orderly close
        RTA_NOBUF     - insufficient space in output buffer


rta_add_table() - Add table to DB
Registers a table for inclusion in the DB interface. Adding a table allows external Postgres clients access to the table's content. Note that the RTA_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 RTA_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.)

int
rta_add_table(RTA_TBLDEF *ptbl - pointer to the RTA_TBLDEF to add);
Return: RTA_SUCCESS   - table added
        RTA_ERROR     - error


rta_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.)

void
rta_SQL_string(char *cmd - the buffer with the SQL command
               char *out - the buffer to hold responses back to client,
               int *nout - on entry, the number of free bytes in 'out'
                           on exit, the number of remaining free bytes);


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.

int
rta_save(RTA_TBLDEF *ptbl - pointer to the RTA_TBLDEF structure for the
                            table to save,
             char *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


rta_load() - Load table from file
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.

int
rta_load(RTA_TBLDEF *ptbl   - pointer to the table to be loaded,
         char *fname        - string with name of the load file);
Return: RTA_SUCCESS   - table loaded
        RTA_ERROR     - could not open the file specified


rta_config_dir() - Set directory prefix for file save/load
The string pointed to by configdir is saved and is prepended to the savefile names for tables with savefiles. This call should be used before loading your application tables. It is intended to make it simpler for applications which let the user specify an configuration directory on the command line.

If the savefile uses an absolute path (ie. one starting with '/') it is not prepended with the configuration directory.

This call is optional. If it is not used the current working directory is used instead.

int
rta_config_dir(char *configdir - path to the configuration files);
Return: RTA_SUCCESS   - config path set
        RTA_ERROR     - error, (not a valid directory?)



- librta UPDATE and SELECT syntax

LIBRTA IS AN API, *NOT* A DATABASE!

Neither the librta UPDATE nor the librta 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 RTA_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 rta_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 names.

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 says "Hi mom!"'), and use double quotes to wrap a 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

- librta INSERT and DELETE syntax

LIBRTA IS AN API, *NOT* A DATABASE!

Neither the librta INSERT nor the librta DELETE adhere to the Postgres equivalents. An insert requires both the column list and the values section and does not support "default" specified in the command. The librta DELETE does not support "ONLY" or "USING" clauses, and the WHERE clause supports only the AND relation. There are no locks or transactions.

INSERT:
    INSERT INTO table ( column_list ) VALUES ( value_list )

INSERT is used to allocate and add a new row into a table. Only the syntax given above is supported, and an error is returned if the number or type of columns in the column_list do not match the number and types of value in the value_list.

INSERT and DELETE require callback routines. The syntax for the callbacks and some general guidelines for callback routines is given later in this document.

INSERT Examples:

 // Insert a new row letting the insert callback set the values
 INSERT INTO demotbl ( ) VALUES ( )
 
 // Insert a new row setting the dlplong column to 5.
 INSERT INTO demotbl ( dlplong ) VALUES ( 5 )
 
 // As above but also set dlstr to "hello, world"
 INSERT INTO demotbl ( dlstr, dlplong ) VALUES ( "hello,world", 5 )
DELETE:
    DELETE FROM table [where_clause] [limit_clause]

DELETE removes rows from a table and frees any memory allocated for the rows. The WHERE and LIMIT clauses are as described in the select section above.

DELETE Examples:

// Delete all rows in the demotbl table.
DELETE FROM demotbl

// Delete all rows where the dlplong is equal to 5
DELETE FROM demotbl WHERE dlplong = 5

// Delete the fourth and fifth rows.  (Table are zero indexed.)
DELETE FROM demotbl LIMIT 2 OFFSET 3

- Internal DB tables

The librta API 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
rta_dbg: - 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 RTA_TBLDEF structures registered with rta_add_table(). This table is used for the generic table editor application. 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
iterator - callback function to get a pointer to the next row
it_info - transparently passed in each call to the iterator
insertcb - callback used to insert a row in the table
deletecb - callback used to delete a row from a 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 RTA_COLDEF structures registered with rta_add_table(). This table is used for the generic table editor. 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 rta_dbgconfig table controls which errors generate debug log messages. See the logging section below for the exact mapping. The librta library 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 "rta_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 librta 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 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 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 librta 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 RTA_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 the first time a table is added with rta_add_table(). The columns of rta_stats are:

    nsyserr - count of failed OS calls.
nrtaerr - count of internal librta failures.
nsqlerr - count of SQL failures.
nauth - count of authorizations. (==#connections)
nupdate - count of UPDATE requests
nselect - count of SELECT requests
ninsert - count of INSERT requests
ndelete - count of DELETE requests



- List of all error messages

There are two types of error messages available in librta. The first type is the error messages returned in response to a failed 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 rta_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.
7) "ERROR: Failed callback on column '%s'"
This indicates that a read or write callback (trigger) has has failed. If a write update failed, the table remain unmodified.
8) "ERROR: DELETE not available on relation '%s'"
This indicates that an attempt was made to delete a row on a table that does not have a delete callback.
9) "ERROR: INSERT not available on relation '%s'"
This indicates that an attempt was made to add a row to a table that does not have an insert callback.
10) "ERROR: Failed INSERT on relation '%s'"
The insert of a row has failed. Syntax errors are usually captured by other error messages leaving this message to imply that the application itself found something wrong with the values in the INSERT request.

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 sent to syslog() as: "rta[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. These are the messages that will appear in the syslog and on the stderr output. 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 
"%s %d: Can not allocate memory\n"
"%s %d: Table save failure.  Can not open %s\n"
"%s %d: Table load failure.  Can not open %s\n"

         "RTA" errors 
"%s %d: Too many tables in DB\n"
"%s %d: Too many columns in DB\n"
"%s %d: Too many characters in table name: %s\n"
"%s %d: Too many characters in column name: %s\n"
"%s %d: Too many characters in help text: %s\n"
"%s %d: DB already has table named: %s\n"
"%s %d: Table already has column named: %s\n"
"%s %d: Column contains an unknown data type: %s\n"
"%s %d: Column contains unknown flag data: %s\n"
"%s %d: Too many columns in table: %s\n"
"%s %d: Not enough buffer space\n"

         "SQL" errors 
"%s %d: SQL parse error: %s\n"
"%s %d: Attempt to update readonly column: %s\n"

         "Trace" messages 
"%s %d: SQL command: %s  (%s)\n"



- How to write callback routines

Callback (or "trigger") routines are available for read, write, insert, and delete.

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 an integer which is zero on success and non-zero on failure. Read callbacks have the following 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
void *pr   pointer to the row being read or written
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 to compute continuously if it's possible to compute it just when it is used. A returned value of zero indicates that the read callback was successful.


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.

Write callbacks have the same parameters as read callbacks with the addition of a pointer to a copy of the row before it was modified. Access to a copy of the unmodified row is useful to detect actual changes and not just updates with the same value.

Your write callback can also perform sanity checking on the values about to be entered in the table. If the values are in error, the callback can return a non-zero value. This error is propagated back to the client, and the table row is restored to its original value.

Write callbacks are passed the following 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
void *pr   pointer to the row being read or written
int     rowid   the zero-indexed row number of the row being read or written
void *poldrow   pointer to a copy of the row before any changes


Insert and delete callbacks are invoked to add or remove a row from a table. These routines are used (along with an iterator) to manage tables in which the rows are allocated dynamically and appear in a linked list or B-tree.

The librta processing of INSERT allocates memory for the row itself as well as memory for any librta pointer types in the row. Thus a row with a single integer pointer (RTA_PINT) would have two memory allocations -- one for the PINT and one for the row.

Use an insert callback to attach the new row into the table and to do application specific initialization of the row. Write callbacks are called for the row after the insert callback returns so you don't need to replicate that code in the insert callback.

If your insert callback detects a problem that values passed in with the INSERT, have it return a negative value and librta will free the memory allocated for the new row and will return an error to the user. The text of the error is defined above as the E_BADINSERT error. If your insert callback succeeds, have it return the zero-indexed row number of the new row in your table. This value is returned to the user as the OID. That is, the PostgreSQL response to an insert looks like:
  INSERT <OID> <ROWS>
The number of rows inserted is alway one and the OID, while normally the index of the new row, can actually be any non-negative value you want.

The parameters to a insert callback are:

char *tblname   the name of the table referenced
char *sqlcmd   the text of the SQL command
void *pr   pointer to the row being read or written


The delete callback is used to remove a row from a table. This usually involves unlinking the row from a linked list and freeing any memory allocated for the row. If you are using insert and delete be sure to FREE THE MEMORY of the row. Be sure to free all of the memory allocated for the pointer types which were also allocated.

The delete callback does not have a return value and its calling parameters are the same as the insert callback:

char *tblname   the name of the table referenced
char *sqlcmd   the text of the SQL command
void *pr   pointer to the row being read or written

Downloads

Download Page

Source Code
  Source Tarball
  
Debian
  PPA Repository
  Debian Packages
  
RPM
  RPM Packages