首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Pro*C WHENEVER 錯誤處理作用域規則詳解:預編譯器視角的局部性

     編輯:關於C語言

Pro*C EXEC SQL WHENEVER 指令的作用域規則常被誤解。本文從預編譯器生成代碼角度,揭示其文件級局部性、類型獨立性與後定義覆蓋三大核心規則。

三大核心規則

  1. 類型獨立:SQLERROR、NOT FOUND、SQLWARNING 三類錯誤處理互不干擾
  2. 同類覆蓋:同類型新 WHENEVER 覆蓋舊定義,作用域至文件末尾或下一同類定義
  3. 文件級局部:作用域跨越函數邊界,從定義處延伸至文件結尾(非塊級、非函數級)

預編譯器展開機制

預編譯器掃描源文件,對每條 EXEC SQL 語句,根據當前生效的 WHENEVER 規則插入檢查代碼:

實戰案例推演

案例 1:不同類型獨立生效

EXEC SQL WHENEVER SQLERROR DO sql_error("msg");  // 定義1
// ... 多條 SQL ...
EXEC SQL WHENEVER NOT FOUND DO break;           // 定義2
// ... SELECT/FETCH ...
EXEC SQL WHENEVER NOT FOUND CONTINUE;           // 定義3 覆蓋定義2
  • 定義1:作用域從此處至文件末尾(無同類覆蓋)
  • 定義2:作用域至定義3前
  • 定義3:作用域至文件末尾
  • 後續發生 SQLERROR 仍按定義1處理,不受 2/3 影響

案例 2:同類覆蓋鏈

EXEC SQL WHENEVER SQLERROR DO sql_error();  // A
EXEC SQL WHENEVER NOT FOUND GOTO exit_label; // B
EXEC SQL WHENEVER SQLERROR CONTINUE;        // C 覆蓋 A
EXEC SQL SELECT ...;  // 此處 SQLERROR→CONTINUE, NOT FOUND→GOTO
EXEC SQL WHENEVER SQLERROR STOP;            // D 覆蓋 C
EXEC SQL FETCH ...;   // 此處 SQLERROR→STOP, NOT FOUND→GOTO

案例 3:跨函數影響(關鍵陷阱)

// file.pc
void helper() {
    EXEC SQL WHENEVER SQLERROR STOP;  // 影響 main 中後續 SQL!
}

int main() {
    EXEC SQL WHENEVER SQLERROR DO handle();
    EXEC SQL CONNECT ...;  // 這裡用 handle()
    helper();              // 調用 helper,但 helper 內無 SQL
    EXEC SQL SELECT ...;   // 這裡用 STOP!因 helper 內的定義生效
}

教訓: WHENEVER 不遵循 C 語言作用域規則,勿在函數內定義 WHENEVER,應集中在文件開頭或模塊邊界管理。

生成代碼對比(簡化)

/* 原始 Pro*C */
EXEC SQL WHENEVER SQLERROR DO sql_error("msg");
EXEC SQL CONNECT :usr;

/* 預編譯後 C */
{ if (sqlca.sqlcode < 0) sql_error("msg"); }  // CONNECT 後插入
EXEC SQL WHENEVER NOT FOUND GOTO exit;
EXEC SQL SELECT ...;
/* 生成 */
{ if (sqlca.sqlcode == 1403) goto exit;
  if (sqlca.sqlcode < 0) sql_error("msg"); }  // 兩類檢查並存

最佳實踐建議

  1. 統一錯誤策略:項目規範統一用 WHENEVER SQLERROR GOTO error_label 或 DO 回調,避免混用
  2. 集中定義:文件頂部定義全局策略,極少數局部場景用 CONTINUE 臨時屏蔽並緊接恢復
  3. 禁用函數內定義:防止跨函數污染
  4. 檢查生成代碼:編譯保留 .c 文件 (proc ... CODE=C),核實插入邏輯
  5. 配合 sqlca 手動檢查:關鍵操作顯式判斷 sqlca.sqlcode,不完全依賴 WHENEVER

總結

WHENEVER 是預編譯器層面的文件級宏替換指令,非運行時機制。理解其「類型隔離、同類覆蓋、文件局部」三大規則,配合查看生成的 C 代碼,即可精準控制 SQL 錯誤處理流程,避免「明明定義了 CONTINUE 卻跳轉到錯誤標籤」等離譜 Bug。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
WHENEVER 類型觸發條件插入代碼模式
SQLERRORsqlca.sqlcode < 0if (sqlca.sqlcode < 0) { action; }
NOT FOUNDsqlca.sqlcode == 1403 (ORA-01403)if (sqlca.sqlcode == 1403) { action; }
SQLWARNINGsqlca.sqlwarn[0] == 'W'if (sqlca.sqlwarn[0] == 'W') { action; }