ProCプログラムのOracleプリコンパイル

Oracleプリコンパイラとは、高水準ソース・プログラムで埋込みSQL文を使用可能にするプログラミング・ツールです。図1-1のように、プリコンパイラはソース・プログラムを入力として受け入れ、埋込みSQL文を標準Oracleランタイム・ライブラリ・コールに変換して、通常の方法でコンパイル、リンクおよび実行できる変更済ソース・プログラムを生成します。

Oracleデータベースからempテーブルのデータをフェッチするサンプル例

test_p1.pc

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

/* SQLアクセス用定数(テスト用のためハードコーディング)*/
#define ORAUSER    "hr"
#define ORAPASSWD  "hr"
#define ORASYSID_T "atp_low"


/* SQLアクセス用変数(いわゆるホスト変数)宣言部 */
/* "h_"始まりの変数はselectに利用 */
EXEC SQL BEGIN DECLARE SECTION;
    varchar username[20];
    varchar password[20];
    varchar systemid[20];
    int deptno;             /* 部署番号 */
    int empno;              /* 従業員番号 */
    char ename[50];         /* 従業員名 */
    float sal;              /* 給与 */
EXEC SQL END DECLARE SECTION;

/* ProCプリコンパイラ用ヘッダファイル宣言 */
EXEC SQL INCLUDE sqlca.h;

/******************************/
/* ここからメイン関数 */
/* メイン関数内での流れ */
/* 1.変数定義(ホスト変数についてはグローバル定義) */
/* 2.値の初期化 */
/* 3.DBコネクト */
/* 4.select文の発行 */
/* 5.カーソルオープン */
/* 6.フェッチ実行 */
/* 7.カーソルクローズ */
/* 8.DB切断(コミット) */
/******************************/
int main(int argc, char *argv[])
{
    /* フェッチ時のカーソルループ用変数 */
    int i;

    /* ホスト変数初期化 */
    memset(&username, 0x00, sizeof(username));
    memset(&password, 0x00, sizeof(password));
    memset(&systemid, 0x00, sizeof(systemid));
    deptno = 0;
    empno  = 0;
    sal    = 0.0;
    memset(&ename, 0x00, sizeof(ename));

    /* oracleへの接続(SQLアクセス用変数に定数をセット) */
    strcpy(username.arr, ORAUSER);
    username.len = strlen(username.arr);
    strcpy(password.arr, ORAPASSWD);
    password.len = strlen(password.arr);
    strcpy(systemid.arr, ORASYSID_T);
    systemid.len = strlen(systemid.arr);

    /* 例外宣言→errorptへ飛ぶ */
    EXEC SQL WHENEVER SQLERROR GOTO errorpt;


    printf("user: %s, password: %s 接続開始します\n",
    username.arr,password.arr);

    /* 接続 */
    EXEC SQL CONNECT :username
      IDENTIFIED BY :password
      AT :systemid;
    if (sqlca.sqlcode != 0) {
        printf("接続エラー: %s\n", sqlca.sqlerrm.sqlerrmc);
        return 1;
    }
    printf("データベースに接続しました。\n");

    /* カーソルを宣言 */
    EXEC SQL AT :systemid DECLARE emp_cursor CURSOR FOR 
      SELECT empno, ename, sal FROM EMP WHERE deptno = 60;

    /* ユーザー入力: 部署番号 
    printf("部署番号を入力してください: ");
    scanf("%d", &deptno);*/

    /* カーソルをオープン */
    EXEC SQL OPEN emp_cursor;

    if (sqlca.sqlcode != 0) {
        printf("カーソルのオープンに失敗しました: %s\n", sqlca.sqlerrm.sqlerrmc);
        EXEC SQL ROLLBACK WORK RELEASE;
        return 1;
    }

    /* カーソルからデータをFETCH */
    while (1) {
        EXEC SQL FETCH emp_cursor INTO :empno, :ename, :sal;

        if (sqlca.sqlcode == 100) {
            /* データがもう存在しない場合 */
            printf("すべてのデータを取得しました。\n");
            break;
        } else if (sqlca.sqlcode != 0) {
            printf("FETCHエラー: %s\n", sqlca.sqlerrm.sqlerrmc);
            EXEC SQL CLOSE emp_cursor;
            // EXEC SQL ROLLBACK WORK RELEASE;
            return 1;
        }

        /* データの表示 */
        printf("従業員番号: %d, 名前: %s, 給与: %.2f\n", empno, ename, sal);
    }

    /* カーソルをクローズ */
    EXEC SQL CLOSE emp_cursor;

    /* トランザクションをコミット */
    //EXEC SQL COMMIT WORK RELEASE;

    printf("処理が完了しました。\n");

    return 0;
    /* error時の処理 */
errorpt:
    printf("\n\n%-79s \n",sqlca.sqlerrm.sqlerrmc);
    EXEC SQL WHENEVER SQLERROR CONTINUE;
}

ハンドでコンパイル

1)プリコンパイル(pcファイルをcファイルにする) 
proc iname=test_p1.pc oname=test_p1.c sqlcheck=full

2)オブジェクトファイルを生成する 
gcc -c test_p1.c -I $ORACLE_HOME/precomp/public

3)実行ファイル作成 
gcc -o test_p1 test_p1.o -L$ORACLE_HOME/lib -lclntsh


4)実行
./test_p1

makeファイルでコンパイル

MakeTestP1.mk

# Oracle環境の設定
#ORACLE_HOME = /u01/app/oracle/product/19.3/db1  # Oracleのインストールパス
PROC = $(ORACLE_HOME)/bin/proc      # Pro*Cプリコンパイラ
CC = gcc                            # Cコンパイラ
CFLAGS = -I$(ORACLE_HOME)/rdbms/public -L$(ORACLE_HOME)/lib -lclntsh 
#LDLIBS = -loracle                   # Oracleライブラリリンクオプション

# ターゲットプログラム名
TARGET = test_p1

# ソースファイル
PC_SRC = $(TARGET).pc               # Pro*Cソース
C_SRC = $(TARGET).c                 # Pro*Cから生成されるCソース

# 生成物
OBJ = $(TARGET).o

all: $(TARGET)

# Pro*Cプリコンパイル
$(C_SRC): $(PC_SRC)
	$(PROC) iname=$(PC_SRC) oname=$(C_SRC)

# Cコンパイルとリンク
$(TARGET): $(C_SRC) $(OBJ)
	$(CC) $(C_SRC) -o $(TARGET) $(CFLAGS) 

# クリーンアップ
clean:
	rm -f $(TARGET) $(C_SRC) $(OBJ) test_p1.c *.lis

Follow me!