首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

Oracle 透過 DBMS_PIPE 執行 OS 命令實作(下):C 守護進程完整程式碼

     編輯:Oracle 資料庫相關知識

架構回顧

採用雙進程協作模式:資料庫端透過 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;
}

關鍵設計要點

  • 管道命名:固定 'daemon' 為請求管道,回覆管道由呼叫端指定(DBMS_PIPE.UNIQUE_SESSION_NAME)
  • 訊息協定:第一個元素為指令類型(SYSTEM/STOP),後續元素為參數
  • 錯誤隔離:守護進程錯誤不影響資料庫,採續行模式
  • 同步阻塞:RECEIVE_MESSAGE 預設無限等待,配合 timeout 參數可實現心跳檢測

現代替代方案

Oracle 10g+ 建議使用:

  • DBMS_SCHEDULER.CREATE_JOB + job_type = 'EXECUTABLE'
  • Java 儲存程序 Runtime.getRuntime().exec()
  • External Table + PREPROCESSOR 指令碼

以上方案具備更完善的權限控制、審計與資源管理。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved