RTA编程参考:核心功能与使用指南
1. 关键子例程介绍
-
SQL_string() 子例程
-
该子例程不返回任何值,原型为
void SQL_string(char *cmd, char *out, int *nout);。其中,cmd是包含 SQL 命令的缓冲区,out是保存返回给客户端响应的缓冲区,nout表示out缓冲区的可用字节数(进入时)和剩余可用字节数(退出时)。
-
该子例程不返回任何值,原型为
-
rta_config_dir() 子例程
-
此子例程用于设置保存文件目录的默认路径。输入参数
configdir指向的字符串会被保存,并在有保存文件的表的保存文件名前添加。在加载应用程序表之前,应该调用该子例程,以简化允许用户在命令行指定配置目录的应用程序。如果保存文件使用绝对路径(以/开头),则不会在前面添加配置目录。 -
原型:
int rta_config_dir(char *configdir); -
输入:
configdir为目标配置目录。 -
返回值:
-
RTA_SUCCESS:配置路径设置正确。 -
RTA_ERROR:由于错误(如无效目录)未设置路径。
-
-
此子例程用于设置保存文件目录的默认路径。输入参数
-
rta_save() 子例程
- 该子例程将表保存到指定路径和文件中,仅保存可保存到磁盘的列。生成的文件是包含所需数据的 UPDATE 命令列表,表中的每一行对应一个 UPDATE 命令。
-
为防止保存文件损坏,该子例程会在目标文件所在目录中打开一个临时文件,将数据保存到临时文件中,然后自动调用
rename()子例程将临时文件原子性地移动到保存文件。如果无法打开临时文件或无法使用rename()重命名临时文件,将生成错误。 -
原型:
int rta_save(TBLDEF *ptbl, char *fname); -
输入:
-
ptbl:指向要保存的表的TBLDEF结构的指针。 -
fname:包含存储数据的路径和文件名的以空字符结尾的字符串。
-
-
返回值:
-
RTA_SUCCESS:成功保存一个表。 -
RTA_ERROR:由于错误未保存表。
-
-
rta_load() 子例程
-
该子例程从包含 UPDATE 命令的文件中加载表,文件格式是一系列 UPDATE 命令,每行一个命令。每次执行 UPDATE 时,会执行任何写回调。当使用
rta_add_table()添加表时,会自动调用rta_load()。 -
原型:
int rta_load(TBLDEF *ptbl, char *fname); -
输入:
-
ptbl:指向要加载的表的指针。 -
fname:包含加载文件名的字符串。
-
-
返回值:
-
RTA_SUCCESS:成功加载一个表。 -
RTA_ERROR:无法打开指定的文件。
-
-
该子例程从包含 UPDATE 命令的文件中加载表,文件格式是一系列 UPDATE 命令,每行一个命令。每次执行 UPDATE 时,会执行任何写回调。当使用
2. SQL 命令语法
-
SELECT 命令
-
原型:
SELECT column_list FROM table [where_clause] [limit_clause] -
column_list可以包含*(表示所有列)、单个列名或用逗号分隔的列名列表。大多数NCMDCOLS列可以在column_list或WHERE子句中指定。 -
WHERE子句语法示例:col_name = value [AND col_name = value ..],所有col_name = value对都必须匹配,行才会匹配。可用的比较运算符有:=(等于)、!=(不等于)、>(大于)、<(小于)、>=(大于等于)、<=(小于等于)。 -
LIMIT关键字用于限制返回的行数,OFFSET关键字用于跳过指定数量的行并从下一行开始输出。 - 示例:
-
原型:
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
- 有八个保留字不能用作列名或表名:`AND`、`FROM`、`LIMIT`、`OFFSET`、`SELECT`、`SET`、`UPDATE`、`WHERE`,这些保留字不区分大小写。
- 字符串可以包含以下字符:`! @ # $ % ^ & * ( ) _ + - = { } [ ] \ | : ; < > ? , . / ~ \``。如果字符串包含双引号,使用单引号括起来;如果字符串包含单引号,使用双引号括起来。
-
UPDATE 命令
-
原型:
UPDATE table SET UPDATE_list [where_clause] [limit_clause] -
UPDATE_list格式:col_name = val [, col_name = val ...] -
WHERE子句语法:col_name = value [AND col_name = value ..] -
LIMIT子句语法:LIMIT n -
执行 UPDATE 时,会对受影响的列调用写回调,在调用回调之前会写入
UPDATE_list中的所有数据。UPDATE的LIMIT子句不是标准的 PostgreSQL 语法,但可用于逐行遍历表。例如,要更改表的第n行(n从 0 开始索引),可以使用LIMIT 1 OFFSET n。 - 示例:
-
原型:
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
3. 内部 RTA 表
-
当使用 RTA 库时,应用程序将包含以下四个 RTA 表:
| 表名 | 描述 |
| ---------- | ------------------------ |
| rta_tables | 包含所有表的表 |
| rta_columns| 包含所有列定义的表 |
| rta_dbg | 包含日志控制变量的表 |
| rta_stats | 包含使用情况和错误统计的表 | -
rta_tables 表
-
该表提供对所有内部和注册表的 SQL 访问,其数据与使用
rta_add_table()子例程注册的TBLDEF结构中的数据完全相同,用于应用程序调试。
| 列名 | 描述 |
| ---------- | ------------------------ |
| name | 表的名称 |
| address | 表在内存中的起始地址 |
| rowlen | 表中每行的字节数 |
| nrows | 表中的行数 |
| iterator | 用于从一行前进到下一行的子例程 |
| it_info | 迭代器的透明数据 |
-
该表提供对所有内部和注册表的 SQL 访问,其数据与使用
-
rta_columns 表
-
该表列出数据库中所有列的定义,其数据与使用
rta_add_table()子例程注册的COLDEF结构中的数据完全相同,用于通用表查看器和表编辑器应用程序,主要用于应用程序调试。
| 列名 | 描述 |
| ---------- | ------------------------ |
| table | 列所属表的名称 |
| name | 列的名称 |
| type | 列的数据类型 |
| length | 列数据类型的字节数 |
| offset | 从结构开始的字节数 |
| flags | 只读和保存到磁盘的位字段 |
| readcb | 读取前调用的子例程指针 |
| writecb | 写入后调用的子例程指针 |
| help | 列的描述 |
-
该表列出数据库中所有列的定义,其数据与使用
4. 调试配置
-
RTA 包不生成任何用户级日志消息,仅生成调试消息。
rta_dbgconfig表指定这些调试日志消息的处理方式,该表中的所有字段都是易失性的,需要在主程序中设置值以使其持久化。例如:SQL_string("UPDATE rta_dbgconfig SET target = 3")
| 列名 | 描述 |
| ---------- | ------------------------ |
| syserr | 整数,0 表示不记录,1 表示记录。记录操作系统调用错误(如malloc()失败),默认值为 1。 |
| rtaerr | 整数,0 表示不记录,1 表示记录。启用记录 RTA 包内部的错误,默认值为 1。 |
| sqlerr | 整数,0 表示不记录,1 表示记录。记录生成错误回复的 SQL 请求。如果 SQL 请求格式错误或请求不存在的表或列,则会出现错误回复,默认值为 1。 |
| trace | 整数,0 表示不记录,1 表示记录所有 SQL 请求,默认值为 0。 |
| target | 0:禁用所有调试日志记录;1:将调试消息记录到syslog();2:将调试消息记录到stderr;3:同时记录到syslog()和stderr。 |
| level | 整数,syslog()要求所有日志消息都有一个优先级。该整数指定发送 RTA 调试消息时使用的日志级别,更改此值直到更新dbg_target才会生效。默认值为 3。 |
| facility | 整数,syslog()要求所有日志消息都有一个设施。指定发送 RTA 调试消息时使用的设施,最好使用.../sys/syslog.h中的定义来设置,默认值为LOG_USER,更改此值直到更新dbg_target才会生效。 |
| ident | 字符串,syslog()要求所有日志消息都有一个标识字符串。指定发送 RTA 调试消息时使用的标识字符串,通常设置为进程或命令名,默认值为rta,更改此值直到更新dbg_target才会生效,最大长度为MXDBGIDENT字符。 |
5. 错误消息
-
SQL 请求错误
-
ERROR: Relation '%s' does not exist:表示SELECT或UPDATE语句中请求的表不存在,%s会被替换为请求的表名。 -
ERROR: Attribute '%s' not found:表示SELECT或UPDATE语句中请求的列不存在,%s会被替换为请求的列名。 -
ERROR: SQL parse error:表示 SQL 请求格式错误或WHERE子句或UPDATE列表中的数据类型不匹配。 -
ERROR: Output buffer full:表示请求的响应大小超过了输出缓冲区的大小,可通过增大输出缓冲区或使用LIMIT和OFFSET避免此错误。 -
ERROR: String too long for '%s':表示对字符串类型或字符串指针类型的列进行UPDATE时,字符串长度超过了列的宽度,%s会被替换为列名。 -
ERROR: Can not UPDATE read-only column '%s':表示尝试对标记为只读的列进行UPDATE,%s会被替换为列名。
-
-
内部调试消息
-
RTA 程序使用标准的
syslog()设施记录内部错误,默认的syslog()设施是LOG_USER,可以通过设置rta_dbg表中的facility更改默认值。可以修改syslogd进行后处理,如从这些调试消息生成 SNMP 陷阱。 -
RTA 程序以
rta[PID]: FILE LINE#: error_message的格式将所有内部调试错误消息发送到syslog(),其中PID、FILE和LINE#会被替换为进程 ID、源文件名和检测到错误的行号。
-
RTA 程序使用标准的
错误消息定义
// 系统错误
#define Er_No_Mem "%s %d: Cannot allocate memory"
#define Er_No_Save "%s %d: Table '%s' save failure. Cannot open %s"
#define Er_No_Load "%s %d: Table '%s' load failure. Cannot open %s"
// RTA 错误
#define Er_Max_Tbls "%s %d: Too many tables in DB"
#define Er_Max_Cols "%s %d: Too many columns in DB"
#define Er_Tname_Big "%s %d: Too many characters in table name: %s"
#define Er_Cname_Big "%s %d: Too many characters in column name: %s"
#define Er_Hname_Big "%s %d: Too many characters in help text: %s"
#define Er_Tbl_Dup "%s %d: DB already has table named: %s"
#define Er_Col_Dup "%s %d: Table '%s' already has column named: %s"
#define Er_Col_Type "%s %d: Column contains an unknown data type: %s"
#define Er_Col_Flag "%s %d: Column contains unknown flag data: %s"
#define Er_Col_Name "%s %d: Incorrect table in column definition: %s"
#define Er_Cmd_Cols "%s %d: Too many columns in table: %s"
#define Er_No_Space "%s %d: Not enough buffer space"
#define Er_Reserved "%s %d: Table or column is a reserved word: %s"
// SQL 错误
#define Er_Bad_SQL "%s %d: SQL parse error: %s"
#define Er_Readonly "%s %d: Attempt to UPDATE readonly column: %s"
// 跟踪消息
#define Er_Trace_SQL "%s %d: SQL command: %s (%s)"
6. 回调例程
-
读回调
- 读回调在使用列值之前执行,对于计算总和、平均值等值非常有用。如果可以仅在需要时计算这些值,就无需持续计算。
-
调用参数:
| 参数 | 描述 |
| ---------- | ------------------------ |
| char tblname | 引用的表的名称 |
| char colname | 引用的列的名称 |
| char sqlcmd | SQL 命令的文本 |
| void pr | 指向表中受影响行的指针 |
| int rowid | 正在读取或写入的行的从零开始的行号 |
-
写回调
- 写回调在所有列更新后调用,在与配置更改相关时最为适用,也是记录配置更改的好地方。
-
调用参数:
| 参数 | 描述 |
| ---------- | ------------------------ |
| char tblname | 引用的表的名称 |
| char colname | 引用的列的名称 |
| char sqlcmd | SQL 命令的文本 |
| void pr | 指向表中受影响行的指针 |
| int rowid | 正在读取或写入的行的从零开始的行号 |
| void *poldrow | 指向修改前行的副本的指针,用于检测行数据的更改 |
成功时回调返回 0,失败时返回非零值。失败时,表的行将恢复到初始值,并向客户端返回 SQL 错误
TRIGGERED ACTION EXCEPTION。
RTA编程参考:核心功能与使用指南
7. 操作流程示例
以下是一个使用上述子例程和 SQL 命令的简单操作流程示例,帮助更好地理解如何在实际应用中使用这些功能。
graph TD
A[开始] --> B[设置配置目录]
B --> C[添加表]
C --> D[加载表数据]
D --> E{是否需要更新数据?}
E -- 是 --> F[执行 UPDATE 命令]
E -- 否 --> G{是否需要查询数据?}
F --> G
G -- 是 --> H[执行 SELECT 命令]
G -- 否 --> I[保存表数据]
H --> I
I --> J[结束]
具体操作步骤如下:
1.
设置配置目录
:
c
char configdir[] = "/path/to/config/dir";
int result = rta_config_dir(configdir);
if (result == RTA_SUCCESS) {
// 配置目录设置成功
} else {
// 处理错误
}
2.
添加表
:使用
rta_add_table()
子例程添加表,这里省略具体实现。
3.
加载表数据
:
c
TBLDEF *ptbl; // 假设已经有指向表的指针
char fname[] = "/path/to/load/file";
result = rta_load(ptbl, fname);
if (result == RTA_SUCCESS) {
// 表数据加载成功
} else {
// 处理错误
}
4.
更新数据
:
sql
UPDATE conn SET lport = 0 WHERE fd != 0;
在代码中执行:
c
char cmd[] = "UPDATE conn SET lport = 0 WHERE fd != 0";
char out[1024];
int nout = sizeof(out);
SQL_string(cmd, out, &nout);
5.
查询数据
:
sql
SELECT destIP FROM conns WHERE fd != 0;
在代码中执行:
c
char cmd[] = "SELECT destIP FROM conns WHERE fd != 0";
char out[1024];
int nout = sizeof(out);
SQL_string(cmd, out, &nout);
6.
保存表数据
:
c
result = rta_save(ptbl, "/path/to/save/file");
if (result == RTA_SUCCESS) {
// 表数据保存成功
} else {
// 处理错误
}
8. 注意事项
- 磁盘 I/O 阻塞 :如前文所述,任何磁盘 I/O 操作都可能导致程序短暂阻塞,因此保存和加载表数据时,程序可能会暂停片刻。在设计应用程序时,需要考虑这种阻塞对程序性能和响应性的影响。
-
SQL 命令限制
:RTA 的 SQL 命令与 PostgreSQL 不完全相同,不允许使用
JOIN子句,WHERE子句仅支持布尔AND运算符,且没有锁和事务机制。在编写 SQL 命令时,务必遵循这些限制。 -
保留字使用
:不能使用
AND、FROM、LIMIT、OFFSET、SELECT、SET、UPDATE、WHERE作为列名或表名,否则会导致错误。 - 回调例程错误处理 :读回调和写回调在失败时会返回非零值,此时需要进行相应的错误处理,如恢复表的行到初始值,并向客户端返回错误信息。
9. 总结
RTA 提供了一系列强大的功能,包括表的保存、加载、SQL 查询和更新,以及调试配置和错误处理等。通过合理使用这些功能,可以方便地开发出高效、稳定的应用程序。在使用过程中,需要注意各个子例程的输入输出参数、SQL 命令的语法和限制,以及回调例程的使用和错误处理。同时,要充分考虑磁盘 I/O 操作可能带来的阻塞问题,确保程序的性能和响应性。
希望本文能帮助你更好地理解和使用 RTA 的相关功能,在实际开发中发挥其优势,实现所需的应用程序。如果你在使用过程中遇到任何问题,可以参考上述介绍和示例代码进行排查和解决。
超级会员免费看
1527

被折叠的 条评论
为什么被折叠?



