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

Pro*C 程序編程進階:數組批量操作、動態 SQL、存儲過程與編譯構建完整指南

     編輯:關於C語言

Pro*C 編程的精髓在於嵌入式 SQL 與 C 宿主語言的無縫融合。本文聚焦數組批量操作、動態 SQL 方法 2/3/4、存儲過程調用、編譯構建流程四大進階主題,提供可直接落地的代碼模式。

一、最小可行 Pro*C 程序骨架

#include 
#include           // SQL 通信區
EXEC SQL INCLUDE SQLCA;     // 預編譯器展開 sqlca 結構

// 全局預編譯選項(也可放 Makefile)
EXEC ORACLE OPTION (RELEASE_CURSOR=YES);
EXEC ORACLE OPTION (CHAR_MAP=STRING);  // 關鍵:char[n] 當作字符串處理

void main() {
    EXEC SQL BEGIN DECLARE SECTION;
    char uid[30] = "scott/tiger@orcl";
    char ename[21];  // VARCHAR2(20) + \0
    short ename_ind;
    EXEC SQL END DECLARE SECTION;

    EXEC SQL CONNECT :uid;
    if (sqlca.sqlcode != 0) { /* 錯誤處理 */ }

    EXEC SQL SELECT ename INTO :ename:ename_ind FROM emp WHERE empno = 7369;
    if (sqlca.sqlcode == 1403) { /* 無數據 */ }
    else if (sqlca.sqlcode < 0) { /* 錯誤 */ }
    else if (ename_ind == -1) { ename[0] = '\0'; }  // NULL 值處理

    printf("ENAME = %s\n", ename);
    EXEC SQL COMMIT WORK RELEASE;
}

二、數組批量操作:性能倍增器

1. 數組 FETCH(游標)

#define BATCH 500
struct { long empno; char ename[21]; double sal; short empno_i, ename_i, sal_i; } emp_arr[BATCH];
EXEC SQL DECLARE cur CURSOR FOR SELECT empno, ename, sal FROM emp;
EXEC SQL OPEN cur;
for (;;) {
    EXEC SQL FOR :BATCH FETCH cur INTO :emp_arr;
    int cnt = sqlca.sqlerrd[2];  // 累積行數,需自行計算增量
    if (cnt == 0) break;
    // 處理 emp_arr[0..cnt-1]
}
EXEC SQL CLOSE cur;

2. 數組 INSERT/UPDATE/DELETE

long ids[1000];
char names[1000][21];
for (int i=0; i<1000; i++) { ids[i]=i; sprintf(names[i], "EMP_%d", i); }
EXEC SQL FOR :1000 INSERT INTO temp_emp (id, name) VALUES (:ids, :names);

3. WHERE 子句中使用數組(批量刪除/更新)

long del_ids[100] = {7369, 7499, ...};
EXEC SQL FOR :100 DELETE FROM emp WHERE empno = :del_ids;

4. 動態 SQL 中使用數組

char *sql = "INSERT INTO log (msg) VALUES (:v)";
EXEC SQL PREPARE stmt FROM :sql;
EXEC SQL FOR :100 EXECUTE stmt USING :messages;

5. 結構體數組(最工程化)

struct Emp { long empno; char ename[21]; double sal; } emps[200];
Emp *p = emps;
EXEC SQL FOR :200 SELECT empno, ename, sal INTO :p FROM emp WHERE deptno = 10;
  • 結構體定義順序 = SELECT 列順序
  • 必須使用指針變量 p 指向數組首地址

三、動態 SQL 四大方法選型

方法適用場景核心語句複雜度
方法 1無輸入/輸出宿主變量的非查詢EXEC SQL EXECUTE IMMEDIATE :sql;最低
方法 2已知輸入宿主變量數/類型的非查詢PREPARE -> EXECUTE USING :vars低
方法 3已知輸出宿主變量數/類型的查詢PREPARE -> DECLARE CURSOR -> OPEN USING -> FETCH INTO中
方法 4輸入/輸出數量類型運行時才知DESCRIBE -> SQLDA -> 動態綁定最高

方法 2 實例(最常用)

char *sql = "UPDATE emp SET sal = sal * :ratio WHERE deptno = :dno";
float ratio = 1.1; int dno = 20;
EXEC SQL PREPARE stmt FROM :sql;
EXEC SQL EXECUTE stmt USING :ratio, :dno;
printf("Updated %ld rows\n", sqlca.sqlerrd[2]);

四、存儲過程調用規範

EXEC SQL EXECUTE
BEGIN
  pkg_emp.update_salary(
    :empno,        -- IN
    :new_sal,      -- IN
    :old_sal,      -- OUT
    :status,       -- OUT
    :err_msg       -- OUT
  );
END;
END-EXEC;
  • PL/SQL 匿名塊包裹
  • 宿主變量按位置綁定,IN/OUT/INOUT 均支援
  • 複雜類型 (Record/Collection) 需用 SQLDA (方法 4) 或定義對象類型

五、編譯構建流程標準化

1. 預編譯

proc iname=main.pc userid=scott/tiger \
     sqlcheck=SEMANTICS parse=FULL char_map=STRING \
     release_cursor=YES hold_cursor=NO maxopencursors=100
  • 生成 main.c (或 .cpp)
  • CODE=CPP 選項生成 C++ 兼容代碼

2. 編譯

gcc -c -I$ORACLE_HOME/precomp/public -I$ORACLE_HOME/rdbms/public main.c

3. 鏈接

gcc -o myapp main.o -L$ORACLE_HOME/lib -lclntsh

4. Makefile 關鍵規則

ORACLE_HOME = /opt/oracle/product/19c
PROC = $(ORACLE_HOME)/bin/proc
PROCFLAGS = userid=app/app parse=FULL sqlcheck=SEMANTICS char_map=STRING release_cursor=YES

CC = gcc
CFLAGS = -I$(ORACLE_HOME)/precomp/public -I$(ORACLE_HOME)/rdbms/public
LIBS = -L$(ORACLE_HOME)/lib -lclntsh -lm -lpthread

.SUFFIXES: .pc .c .o

.pc.c:
	$(PROC) $(PROCFLAGS) iname=$<

.c.o:
	$(CC) $(CFLAGS) -c $<

app: main.o db.o utils.o
	$(CC) -o $@ $^ $(LIBS)

六、避坑速查表

症狀原因對策
ORA-01000: maximum open cursors exceeded游標未 CLOSE/RELEASERELEASE_CURSOR=YES + 显式 CLOSE
字符串截斷/亂碼CHAR_MAP 預設 CHARZ 填充空格CHAR_MAP=STRING 或 VARCHAR 等價聲明
NULL 值導致 sqlcode < 0未使用指示變量INTO :var:ind (無逗號)
PREPARE 重複報錯MODE=ANSI 要求重新 PREPARE 前 CLOSE嚴格遵循 OPEN→FETCH→CLOSE→PREPARE 循環
多線程 sqlca 衝突共用 sql_contextENABLE THREADS + 每線程 CONTEXT ALLOCATE

總結

Pro*C 進階核心是數組批量化(減少網絡往返)、動態 SQL 方法 2(靈活構建語句)、存儲過程封裝業務邏輯、標準化構建流程。掌握這四大支柱,配合 CHAR_MAP=STRING、RELEASE_CURSOR=YES 兩大鐵律,即可駕馭百萬行級 Pro*C 核心系統。新架構請考慮 OCCI/ODPI-C/微服務化演進路徑。

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