採用雙進程協作模式:資料庫端透過 DBMS_PIPE 發送命令請求 → 獨立 C 守護進程接收並執行 OS 命令 → 將結果回傳資料庫。此為 Oracle 8i 時代無 DBMS_SCHEDULER、Java、External Table 等現代機制時的經典解法。
/* 連線錯誤處理 */
void connect_error() {
char msg_buffer[512];
int msg_length, buffer_size = 512;
EXEC SQL WHENEVER SQLERROR CONTINUE;
sqlglm(msg_buffer, &buffer_size, &msg_length);
printf("Daemon error while connecting:\n%.*s\nDaemon quitting.\n", msg_length, msg_buffer);
exit(1);
}
/* 執行期錯誤處理 */
void sql_error() {
char msg_buffer[512];
int msg_length, buffer_size = 512;
EXEC SQL WHENEVER SQLERROR CONTINUE;
sqlglm(msg_buffer, &buffer_size, &msg_length);
printf("Daemon error while executing:\n%.*s\nDaemon continuing.\n", msg_length, msg_buffer);
}
int main() {
EXEC SQL WHENEVER SQLERROR DO connect_error();
EXEC SQL CONNECT :uid;
printf("Daemon connected.\n");
EXEC SQL WHENEVER SQLERROR DO sql_error();
printf("Daemon waiting...\n");
while (1) {
/* 從 'daemon' 管道接收訊息 */
EXEC SQL EXECUTE
BEGIN
:status := DBMS_PIPE.RECEIVE_MESSAGE('daemon');
IF :status = 0 THEN
DBMS_PIPE.UNPACK_MESSAGE(:command);
END IF;
END;
END-EXEC;
IF (status == 0) {
command.arr[command.len] = '\0';
/* STOP 指令:優雅關閉 */
IF (!strcmp((char*)command.arr, "STOP")) {
printf("Daemon exiting.\n");
break;
}
/* SYSTEM 指令:執行 OS 命令 */
ELSE IF (!strcmp((char*)command.arr, "SYSTEM")) {
EXEC SQL EXECUTE
BEGIN
DBMS_PIPE.UNPACK_MESSAGE(:return_name);
DBMS_PIPE.UNPACK_MESSAGE(:value);
END;
END-EXEC;
value.arr[value.len] = '\0';
printf("Will execute system command '%s'\n", value.arr);
/* 核心執行點:system() 呼叫 */
status = system(value.arr);
/* 回傳結果 */
EXEC SQL EXECUTE
BEGIN
DBMS_PIPE.PACK_MESSAGE('done');
DBMS_PIPE.PACK_MESSAGE(:status);
:status := DBMS_PIPE.SEND_MESSAGE(:return_name);
END;
END-EXEC;
}
}
}
return 0;
}
DBMS_PIPE.UNIQUE_SESSION_NAME)RECEIVE_MESSAGE 預設無限等待,配合 timeout 參數可實現心跳檢測Oracle 10g+ 建議使用:
DBMS_SCHEDULER.CREATE_JOB + job_type = 'EXECUTABLE'Java 儲存程序 Runtime.getRuntime().exec()External Table + PREPROCESSOR 指令碼以上方案具備更完善的權限控制、審計與資源管理。