ページの先頭行へ戻る
Symfoware Server V10.0.0/V10.0.1 アプリケーション開発ガイド(埋込みSQL編)

A.2 日本語可変長文字列のデータ操作例

ここでは、ホスト変数の日本語可変長文字列をCプログラムで操作するプログラミング例を説明します。ホスト変数の日本語可変長文字列をCプログラムで操作する場合は、文字列の長さが必要です。このため、コンパイル時には、日本語可変長文字列の長さと日本語文字列を持つ構造体に変換します。Cプログラムは、変換された構造体の変数でデータ操作を行います。

以下に日本語可変長文字列を構造体形式に変換した例を示します。

アプリケーション中に以下のように宣言します。
  VARCHAR CHARACTER SET NCHAR hcomp_word[31];

                  ↓コンパイル時に構造体に変換します。

  struct  {
          short    sqllen;
          char     sqlvar[31];
  } hcomp_word;

SolarisLinuxプログラムの処理概要を図A.3 日本語可変長文字列のデータ操作の概要に示します。

SolarisLinux図A.3 日本語可変長文字列のデータ操作の概要

(1) 製品名を、ホスト変数の日本語可変長文字列に対話で入力します。

(2) CONNECT文により、データベース“DB01”の存在するサーバとコネクションを接続します。

(3) カーソル操作により、在庫表から入力された製品名に該当する在庫のデータを検索します。

(4) 在庫のデータを端末に出力します。

(5) DISCONNECT文により、データベース“DB01”の存在するサーバとのコネクションを切断します。


プログラミング例を以下に示します。

#include<stdio.h>
#include<string.h>


EXEC SQL BEGIN DECLARE SECTION;
        char  SQLSTATE[6];
        char  SQLMSG[256];
        VARCHAR CHARACTER SET NCHAR hcomp_word[31];                    …… (1)
        long  hnumber;
        char CHARACTER SET NCHAR        hproduct[31];
        long  hstock;
        long  hstorehouse;
EXEC SQL END   DECLARE SECTION;

void putmsgx();

main(void) {
            short   execute;
            short   count;
    EXEC SQL DECLARE 在庫 TABLE ON BUSINESS;                                 …… (2)
    EXEC SQL DECLARE CSR1 CURSOR FOR
                           SELECT * FROM 在庫 WHERE 製品名=:hcomp_word;   …… (3)

    printf("入力された製品名に該当する在庫のデータを取り出します.\n");

    for(;;){
            printf("日本語で製品名を入力してください >>");
            gets(hcomp_word.sqlvar);                                    …… (4)
            printf("\n");
            printf("製品\"%s\"のデータでよろしいですか?\n",hcomp_word.sqlvar);
            printf("よろしかったら(Y/y)を入力してください >>");
            execute=getchar();
            if(execute=='Y' || execute=='y'){
                    break;
            }
            printf("\n");
    }

    printf("\n");
    hcomp_word.sqllen = strlen(hcomp_word.sqlvar);                   …… (5)

    EXEC SQL WHENEVER SQLERROR GOTO :CONNECT_ERROR;

    EXEC SQL CONNECT TO 'DB01';                                             …… (6)
    EXEC SQL WHENEVER SQLERROR GOTO :STM_ERROR;
    EXEC SQL WHENEVER NOT FOUND GOTO :NOT_FOUND_ERROR;

    EXEC SQL OPEN CSR1;                                                     …… (7)

    printf("\n製品番号  製品名                  在庫数量  倉庫番号\n");
    for(count=0;;count++){
          memset(hproduct,'\0',sizeof(hproduct));                          …… (8)

          EXEC SQL FETCH CSR1 INTO :hnumber,:hproduct,:hstock,:hstorehouse;  …… (9)

          printf("%08ld  %-20s  %08ld  %08ld\n"                           …… (10)
                          ,hnumber,hproduct,hstock,hstorehouse);
    }
NOT_FOUND_ERROR:

        if(count != 0)  printf("\n該当データは%d件です.\n",count);         …… (11)
        else            printf("\n該当データなし\n");
        EXEC SQL WHENEVER SQLERROR CONTINUE;
        EXEC SQL ROLLBACK WORK;                                           …… (12)
        EXEC SQL DISCONNECT 'DB01';                                       …… (13)
        return 0;

STM_ERROR:
        putmsgx();
        EXEC SQL WHENEVER SQLERROR CONTINUE;                               …… (14)
        EXEC SQL ROLLBACK WORK;                                           …… (15)
        EXEC SQL DISCONNECT 'DB01';                                       …… (16)
        return 1;

CONNECT_ERROR:
        putmsgx();                                                       …… (17)
        return 1;
}

void putmsgx( void )  {                                                    …… (18)
    int i;
    for ( i = sizeof(SQLMSG) - 2 ; SQLMSG[i] == ' ' ; i-- );
    SQLMSG[++i] = '\0';
    SQLSTATE[5]='\0';
    printf( "SQLMSG:%s\n" , SQLMSG );
    printf( "SQLSTATE:%s\n" , SQLSTATE );
    return;
}

(1) 製品名を日本語可変長文字列のホスト変数として定義します。

(2) 在庫表を表宣言します。

(3) 在庫表のカーソル“CSR1”を宣言します。

(4) 対話処理で、製品名を入力します。入力領域は、日本語可変長文字列変数“hcomp_word”をコンパイル時に構造体に変換した変数“hcomp_word.sqlvar”に入力します。

(5) 入力した製品名の長さを、日本語可変長文字列変数“hcomp_word”をコンパイル時に構造体に変換した変数“hcomp_word.sqllen”に設定します。

(6) データベース“DB01”の存在するサーバとのコネクションを接続します。

(7) カーソル“CSR1”をオープンします。

(8) ホスト変数の“hproduct”をNULL文字で初期化します。

(9) 入力した製品名と等しい在庫表の製品名の行にカーソルを位置づけ、その行を読み込みます。

(10) 読み込んだ行をprintf関数で表示します。

(11) 在庫表のデータをすべて検索した場合は、検索結果をprintf関数で表示します。

(12) トランザクションをROLLBACK文により終了します。

(13) データベース“DB01”の存在するサーバとのコネクションを切断します。

(14) SQL文の実行でエラーの場合に、SQLMSGとSQLSTATEの内容を表示します。

(15) SQL文の実行でエラーの場合は、トランザクションをROLLBACK文により終了します。

(16) データベース“DB01”の存在するサーバとのコネクションを切断します。

(17) コネクションでエラーの場合に、SQLMSGとSQLSTATEの内容を表示します。

(18) SQLMSGとSQLSTATEの内容を表示する関数です。

Windowsプログラムの処理概要を図A.4 日本語可変長文字列のデータ操作の概要に示します。

Windows図A.4 日本語可変長文字列のデータ操作の概要

(1) CONNECT文により、データベースへコネクションを接続します。

(2) 製品名を、ホスト変数の日本語可変長文字列に対話で入力します。

(3) カーソル操作により、在庫表から入力された製品名に該当する在庫のデータを検索します。

(4) 在庫のデータを出力します。

(5) DISCONNECT文により、コネクションを切断します。


プログラミング例を以下に示します。

EXEC SQL INCLUDE sample4.h;
    :
long FAR PASCAL WsampleWndProc(hWnd, message, wParam, lParam)
    :
{
    FARPROC         lpProcAbout;
    HDC             hDC;
    PAINTSTRUCT     ps;
    EXEC SQL BEGIN DECLARE SECTION;                                          …… (1)
        char SQLSTATE[6];
        char SQLMSG[256];
        long hnumber;
        char CHARACTER SET IS NCHAR hproduct[21];
        long hstock;
        long hstorehouse;
        VARCHAR CHARACTER SET IS NCHAR hcomp_word[21];                       …… (2)
    EXEC SQL END DECLARE SECTION;
        short i;
        char msgno[5];

    EXEC SQL DECLARE  在庫 TABLE ON BUSINESS;                                …… (3)

    EXEC SQL WHENEVER SQLERROR GOTO :err_exit;

        switch (message) {
            case WM_CREATE:
                SQLMSG[255] = '\0';
                EXEC SQL CONNECT TO DEFAULT;                                 …… (4)
                DFlag2 = FALSE;
                count = 0;
                break;

            case WM_COMMAND:
                switch (wParam) {
                    case WIN_END:
                        PostMessage(hWnd, WM_CLOSE, 0, 0 );
                        break;
                    case WIN_INPUT:                                       …… (5)
                        lpProcAbout = MakeProcInstance(InputData, hInst);
                        DFlag = DialogBox(hInst,"InputData",hWnd,lpProcAbout);
                        FreeProcInstance(lpProcAbout);
                        break;

                    case WIN_EXEC:                                        …… (6)
                        count = 0;
                        InvalidateRect(hWnd,NULL,TRUE);
                        if (DFlag == FALSE) {
                            break;
                        }
                        EXEC SQL DECLARE CSR1 CURSOR FOR                  …… (7)
                                  SELECT * FROM 在庫 WHERE  製品名 = :hcomp_word;
                        EXEC SQL OPEN CSR1;                                 …… (8)

                        EXEC SQL WHENEVER NOT FOUND GOTO :atend;
                        hproduct[20]='\0';
                        for(count=0;;count++) {
                            EXEC SQL FETCH CSR1                             …… (9)
                                INTO :hnumber,:hproduct,:hstock,:hstorehouse;
                            wsprintf( hbuff, "%08ld  %-20s  %08ld  %08ld", hnumber,
                                (char far*)hproduct, hstock, hstorehouse ); …… (10)
                            DFlag2 = TRUE;
                        }

    atend:
                        EXEC SQL CLOSE CSR1;                               …… (11)
                        EXEC SQL COMMIT WORK;                              …… (12)
                        break;

                    default:
                        break;
                }
                break;
            case WM_PAINT:
                if (DFlag2==TRUE) {
                    hDC = BeginPaint (hWnd, &ps);
                    for( i = 0; i < count; i++ ) {
                        TextOut (hDC,10,10+(i*20),
                                        (LPSTR)hbuff,lstrlen((LPSTR)hbuff[i]));
                        EndPaint(hWnd, &ps);
                    }
                    UpdateWindow(hWnd);
                }
                break;
            case WM_DESTROY:
                EXEC SQL DISCONNECT ALL;                                   …… (13)
                PostQuitMessage(0);
                return(0);
    err_exit:
                memset(mes,'\0',512);
                SQLSTATE[5]='\0';
                SQLMSG[255]='\0';
                delspace( SQLMSG );
                wsprintf(mes,"SQL 文実行失敗\nSQLSTATE=%s\nSQLMSG=%s\n",  …… (14)
                    (LPSTR)SQLSTATE,(LPSTR)SQLMSG);
                MessageBox( 0, (LPSTR)mes, "MESSAGE", MB_OK );

                memcpy( msgno , SQLMSG+3 , 4 );
                msgno[4] = '\0';
                WinHelp( hWnd, HLP_PASS, HELP_CONTEXT, (DWORD)atol(msgno) );     (15)

                EXEC SQL WHENEVER SQLERROR CONTINUE;
                EXEC SQL ROLLBACK WORK;                                    …… (16)
                EXEC SQL DISCONNECT ALL;                                   …… (17)
                PostQuitMessage(0);
                return(0);

            default:
                break;
        }
        return (DefWindowProc(hWnd, message, wParam, lParam));
}
   

(1) ホスト変数を宣言します。

(2) 製品名が格納される日本語可変長文字列のホスト変数を宣言します。

(3) 在庫を表宣言します。

(4) 動作環境ファイルのDEFAULT_CONNECTIONで指定したサーバとコネクションを接続します。

(5) 選択されたメニューに従って、処理を行います。ここでは、製品名を入力するダイアログボックスを表示し、対話処理で入力します。“InputData”は、日本語可変長文字列変数“hcomp_word”をプレコンパイラが構造体に変換した変数“hcomp_word.sqlvar”および“hcomp_word.sqllen”にデータとその長さを入力する関数です。

(6) 選択されたメニューに従って、処理を行います。ここでは、SQL文の実行を開始します。

(7) 在庫表のすべての列に対するカーソル“CSR1”を宣言します。

(8) カーソル“CSR1”をオープンします。

(9) 入力した製品名と等しい在庫表の製品名の行にカーソルを位置づけ、その行を読み込みます。

(10) 検索結果を画面に出力します。

(11) カーソル“CSR1”をクローズします。

(12) トランザクションをCOMMIT文により終了します。

(13) すべてのコネクションを切断します。

(14) SQL 文の実行でエラーの場合は、SQLSTATEとSQLMSGの内容を出力します。

(15) エラーに対するヘルプメッセージを表示します。

(16) SQL 文の実行でエラーの場合は、トランザクションをROLLBACK文により終了します。

(17) すべてのコネクションを切断します。