ヘッダーをスキップ
Oracle Application Serverグローバリゼーション・ガイド
10gリリース3(10.1.3.1.0)
B31838-01
  目次
目次
索引
索引

戻る
戻る
次へ
次へ
 

5 集中型データベースの使用

この章の項目は次のとおりです。

5.1 集中型データベースの使用およびデータベース・サーバーへの接続

Unicodeの集中型データベースは、グローバル・インターネット・アプリケーションを開発するためのアプローチの機能として、単一言語と多言語の両方に共通しています。集中型データベースの使用には、次のメリットがあります。

データベース・キャラクタ・セットは、Unicodeである必要があります。Unicodeを使用して、データをいくつかの言語で格納および操作できます。Unicodeは、世界中のほぼすべての言語において文字を定義するユニバーサル・キャラクタ・セットです。Oracleデータベースは、次のいずれかのエンコーディング形式でUnicodeデータを格納できます。


関連項目:


インターネット・アプリケーションからOracle Application Serverを介してデータベース・サーバーに接続するには、いくつかの方法があります。Javaサーブレット、JSP、EJBなどのテクノロジを使用するJavaベースのインターネット・アプリケーションの場合、データベースの接続性のためにOracle JDBCドライバを使用します。

Java文字列は常にUnicodeでエンコードされているので、JDBCはテキスト・データをデータベース・キャラクタ・セットとUnicodeとの間で透過的に変換します。Oracleデータベースと通信するJavaサーブレットとJSPでは、必ず次のことを確認する必要があります。

Perl、PL/SQL、C/C++などのプログラミング・テクノロジを使用する非Javaインターネット・アプリケーションの場合、データベースから検索したりデータベースに挿入されたテキスト・データは、NLS_LANGパラメータで指定したキャラクタ・セットでエンコードされます。POSIXロケールで使用するキャラクタ・セットは、アプリケーション内のPOSIXロケールに依存する関数でデータベースのデータを直接処理するために、NLS_LANGキャラクタ・セットと一致する必要があります。

多言語アプリケーションの場合、NLS_LANGキャラクタ・セットとページ・エンコーディングは、キャラクタ・セットが変換されデータ損失が発生する可能性を回避するために、両方ともUTF-8にする必要があります。

5.2 データベース接続のためのJDBCの使用

JSPとJavaサーブレットを使用する場合は、Oracle Application ServerでOracleデータベースへの接続用に提供されているOracle JDBCドライバを使用します。Oracle Application Serverには、中間層アプリケーションに配置可能なクライアント側JDBCドライバが2種類あります。

Oracle JDBCドライバは、文字データをデータベース・キャラクタ・セットからSQL CHARデータ型とSQL NCHARデータ型のUnicodeに透過的に変換します。この透過的な変換の結果、Oracle JDBCドライバをコールするJSPとJavaサーブレットは、データベース列をJava文字列にバインドおよび定義し、SQL実行の結果セットからJava文字列にデータをフェッチできます。

Java文字列を使用すると、カスタマ表のNAMEおよびADDRESS列をバインドできます。それぞれVARCHAR2データ型とNVARCHAR2データ型として列を定義します。たとえば、次のように設定します。

String cname = request.getParameter("cname")
String caddr = request.getParameter("caddress");
OraclePreparedStatement pstmt = conn.prepareStatement("insert into" +
        "CUSTOMERS (NAME, ADRESS) values (?, ?) ");
pstmt.setString(1, cname);
pstmt.setFormOfUse(2, OraclePreparedStatement.FORM_NCHAR);
pstmt.setString(2, caddr);
pstmt.execute();

Java文字列変数をNVARCHAR2として定義されたADDRESS列にバインドするには、setString()メソッドの前にsetFormOfUse()メソッドをコールする必要があります。

Oracle JDBCドライバは、データベース・セッションが初期化されたときに、デフォルトのJavaロケールに該当する値に対してNLS_LANGUAGEおよびNLS_TERRITORYセッション・パラメータの値を設定します。単一言語アプリケーションの場合、Javaのデフォルト・ロケールは、ユーザーのロケールと一致するように構成されます。このため、データベース接続は必ずユーザーのロケールと一致しています。


関連項目:

Oracle Databaseドキュメント・ライブラリ内の『Oracle Database JDBC開発者ガイドおよびリファレンス』

5.3 データベース接続のためのPL/SQLの使用

PL/SQLプロシージャおよびPSPは、SQLを使用して、ローカルのOracleデータベースのデータにアクセスします。また、SQLおよびデータベース・リンクを使用して、リモートのOracleデータベースのデータにアクセスします。

たとえば、次に示すmod_plsqlモジュールのPL/SQLプロシージャをコールできます。これは、VARCHAR2として定義された顧客名列とNVARCHAR2として定義された顧客アドレス列からなるカスタマ表にレコードを挿入します。

procedure addcustomer( cname varchar2 default NULL, caddress nvarchar2 default NULL) is
begin
   ....
   if (cname is not null) then
        caddr :=TO_NCHAR(address);
        insert into customers (name, address) values (cname, caddr);
        commit;
   end if;
end;

Apache mod_plsqlでは、NVARCHAR引数の受け渡しをサポートしていません。その結果、PL/SQLプロシージャで引数に対してVARCHAR2を使用して、NVARCHARに明示的に変換してからINSERT文を実行する必要があります。

例では、静的SQLを使用してカスタマ表に接続しています。また、DBMS_SQL PL/SQLパッケージを使用し、動的SQLによってデータベース内のデータにアクセスすることもできます。


関連項目:

Oracle Databaseドキュメント・ライブラリ内の『PL/SQLパッケージ・プロシージャおよびタイプ・リファレンス』

5.4 データベース接続のためのPerlの使用

Perlスクリプトは、Oracle用のDBI/DBDドライバによってOracleデータベースに接続します。DBI/DBDドライバは、Oracle Application Serverの一部です。このドライバは、Oracle Call Interface(OCI)をコールしてデータベースに接続します。データベースから検索したデータやデータベースに挿入したデータは、NLS_LANGキャラクタ・セットでエンコードされます。Perlスクリプトでは、次の項目を実行できる必要があります。

これによって、データベースから検索したデータをPOSIX文字列操作関数で処理できるようになります。

次のコードは、DBI/DBDドライバによってOracleデータベースのカスタマ表に行を挿入する方法を示しています。

Use Apache::DBI;
...
# Connect to the database
$constr = 'host=dlsun1304.us.oracle.com;sid=icachedb;port=1521' ;
$usr = 'system' ;
$pwd = 'manager' ;
$dbh = DBI->onnect("dbi:Oracle:$constr", $usr, $pwd, {AutoCommit=>1} ) ||
       $r->rint("Failed to connect to Oracle: " . DBI->rrstr );

# prepare the statement
$sql = 'insert into customers (name, address) values (:n, :a)';
$sth = $dbh->repare( $sql );
$sth->ind_param(':n' , $cname);
$sth->ind_param(':a', $caddress);
$sth->xecute();
$sth->inish();
$dbh->isconnect();

ターゲット列がSQL NCHARデータ型である場合は、各バインド変数の使用フラグのフォームを指定する必要があります。たとえば、アドレス列がNVARCHAR2データ型である場合は、SQL文を実行する前に$sth->func()関数を追加する必要があります。

use DBD::Oracle qw(:ora_forms);
...
$sql = 'insert into customers (name, address) values (:n, :a)';
$sth = $dbh->repare($sql);
$sth->ind_param(':n', $cname);
$sth->ind_param(':a', $caddress);
$sth->func( { ':a' => ORA_NCHAR }, 'set_form');
$sth->xecute();
$sth->inish();
$dbh->isconnect();

多言語アプリケーションでUTF-8データを適切に処理するために、Perlスクリプトは次のことを行います。

5.5 データベース接続のためのC/C++の使用

C/C++アプリケーションは、OCIまたはPRO*C/C++によってOracleデータベースに接続します。OCIを直接コールするか、PRO*C/C++インタフェースを使用することによって、Unicodeデータの取得および格納をUTF-8データベースおよびSQL NCHARデータ型において実行できます。

通常、データベースから検索したデータやデータベースに挿入したデータは、NLS_LANGキャラクタ・セットでエンコードされます。C/C++プログラムでは、NLS_LANGキャラクタ・セットと同じキャラクタ・セットをPOSIXロケールに使用する必要があります。そうしないと、POSIX文字列関数は、データベースから検索した文字データを使用できず、データベースに挿入されたときにPOSIXロケールでエンコードされた文字データが破損する場合があります。

多言語アプリケーションの場合、NLS_LANGキャラクタ・セットではなく、OCIライブラリに提供されたUnicode APIを使用することがあります。この代替策は、UTF-16 Unicodeによってwchar_tデータ型を実装するMicrosoft Windowsなどのプラットフォーム用に記述されたアプリケーションにとって好都合です。これらのプラットフォームでUnicode APIを使用すると、通常のOCI APIの使用時に必要なデータ変換が不要になります。

この項の項目は次のとおりです。

5.5.1 データベース接続のためのOCI APIの使用

次の例は、カスタマ表のVARCHAR2列とNVARCHAR2列をC/C++でバインドおよび定義する方法を示しています。この例は、OCIを使用し、NLS_LANGキャラクタ・セットに基づいています。textデータ型がunsigned charへのマクロであることに注意してください。

text *sqlstmt= (text *)"SELECT name, address FROM customers
                        WHERE id = :cusid";
text cname[100];                      /* Customer Name */
text caddr[200];                      /* Customer Address */
text custid[10] = "9876";             /* Customer ID */
ub2 cform = SQLCS_NCHAR;              /* Form of Use for NCHAR types */
...
OCIStmtPrepare (stmthp, errhp, sqlstmt,
                (ub4)strlen ((char *)sqlstmt),
                (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT));
/* Bind the custid buffer */
OCIBindByName(stmthp, &bnd1p, errhp, (text*)":custid",
              (sb4)strlen((char *)":custid"),
              (dvoid *) custid, sizeof(cust_id), SQLT_STR,
              (dvoid *)&insname_ind, (ub2 *) 0, (ub2 *) 0,
              (ub4) 0,(ub4 *)0, OCI_DEFAULT);

/* Define the cname buffer for VARCHAR */
OCIDefineByPos (stmthp, &dfn1p, errhp, (ub4)1, (dvoid *)cname,
                (sb4)sizeof(cname), SQLT_STR,
                (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT);

/* Define the caddr buffer for the address column in NVARCHAR2 */
OCIDefineByPos (stmthp, &dfn2p, errhp, (ub4)2, (dvoid *)caddr,
                (sb4)sizeof(caddr), SQLT_STR,
                (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT);
OCIAttrSet((void *) dfn2p, (ub4) OCI_HTYPE_DEFINE, (void *) &cform, (ub4) 0,
           (ub4)OCI_ATTR_CHARSET_FORM, errhp);
...

5.5.2 データベース接続のためのOCI付属Unicode APIの使用

OCIライブラリで多言語アプリケーション用に提供するUnicode APIを使用することができます。

OCI環境ハンドルを作成するときにUnicodeモードを指定することによって、Unicode APIを使用します。OCI環境ハンドルから継承されたハンドルは、すべて自動的にUnicodeモードに設定されます。Unicodeモードに変更することによって、OCI関数へのすべてのテキスト・データ引数は、Unicodeテキスト(utext*)データ型でUTF-16エンコーディングであることが前提になります。バインドおよび定義を行う場合、データ・バッファにおいてutextバッファがUTF-16エンコーディングであることが前提になります。

Unicode APIのプログラム・コードは、次の点を除いて、非Unicode OCI API用のコードと類似しています。

  • すべてのtextデータ型は、unsigned shortデータ型のマクロであるutextデータ型に変更されます。

  • すべてのリテラル文字列は、Unicodeリテラル文字列に変更されます。

  • すべてのstrlen()関数は、文字列長をバイトではなくUnicode文字数で計算するwcslen()関数に変更されます。

次のタスクを実行する方法を、その後のMicrosoft Windowsプログラムの例に示します。

  • Unicodeモードにして、OCI環境ハンドルを作成します。

  • customers表のVARCHAR2の名前列とNVARCHAR2のアドレス列をバインドおよび定義します。

utext *sqlstmt= (text *)L"SELECT name, address FROM customers
                        WHERE id = :cusid";
utext cname[100];                     /* Customer Name */
utext caddr[200];                     /* Customer Address */
text custid[10] = "9876";             /* Customer ID */
ub1 cform = SQLCS_NCHAR;              /* Form of Use for NCHAR types */
...
/* Use Unicode OCI API by specifying UTF-16 mode */
status = OCIEnvCreate((OCIEnv **)&envhp, OCI_UTF16, (void *)0,
                      (void *(*) ()) 0, (void *(*) ()) 0, (void(*) ()) 0,
                      (size_t) 0, (void **)0);
...
OCIStmtPrepare (stmthp, errhp, sqlstmt,
                (ub4)wcslen ((char *)sqlstmt),
                (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT));

/* Bind the custid buffer */
OCIBindByName(stmthp, &bnd1p, errhp, (constant text*) L":custid",
              (sb4)wcslen(L":custid"),
              (dvoid *) custid, sizeof(cust_id), SQLT_STR,
              (dvoid *)&insname_ind, (ub2 *) 0, (ub2 *) 0,
              (ub4) 0,(ub4 *)0, OCI_DEFAULT);

/* Define the cname buffer for the name column in VARCHAR2 */
OCIDefineByPos (stmthp, &dfn1p, errhp, (ub4)1, (dvoid *)cname,
                (sb4)sizeof(cname), SQLT_STR,
                (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT);

/* Define the caddr buffer for the address column in NVARCHAR2 */
OCIDefineByPos (stmthp, &dfn2p, errhp, (ub4)2, (dvoid *)caddr,
                (sb4)sizeof(caddr), SQLT_STR,
                (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT);
OCIAttrSet((void *) dfn2p, (ub4) OCI_HTYPE_DEFINE, (void *) &cform, (ub4) 0,
           (ub4)OCI_ATTR_CHARSET_FORM, errhp);
...

5.5.3 データベース接続のためのPro*C/C++でのUnicodeバインドと定義の使用

多言語アプリケーションの場合、Unicodeのバインドと定義をPro*C/C++で使用することができます。

Pro*C/C++によって、バインドおよび定義の操作用にUTF-16 Unicodeバッファを指定できるようになります。UTF-16バッファをPro*C/C++で指定するには、2種類の方法があります。

  • C/C++のunsigned shortデータ型の別名であるutextデータ型を使用します。

  • Pro*C/C++で提供されるuvarcharデータ型を使用します。このデータ型は、lengthフィールドとutextバッファ・フィールドからなるstructに前処理されます。

struct uvarchar
{
   ub2 len;         /* length of arr */
   utext arr[1] ;   /* UTF-16 buffer */
};
typedef struct uvarchar uvarchar ;

次の例では、cnamecaddrという2種類のホスト変数が使用されています。cnameホスト変数は、100のUTF-16コード・ユニット(unsigned short)で構成されるutextバッファとして、VARCHAR2データ型の顧客名列に対して宣言されます。caddrホスト変数は、50のUCS2文字で構成されるuvarcharバッファとして、NVARCHAR2データ型の顧客アドレス列に対して宣言されます。lenarrのフィールドはstructのフィールドとしてアクセス可能です。

#include <sqlca.h>
#include <sqlucs2.h>

main()
{
   ...
   /* Change to STRING datatype:    */
   EXEC ORACLE OPTION (CHAR_MAP=STRING) ;
   utext cname[100] ;              /* unsigned short type */
   uvarchar caddr[200] ;           /* Pro*C/C++ uvarchar type */
   ...
   EXEC SQL SELECT name, address INTO :cname, :caddr FROM customers;
   /* cname is NULL-terminated */
   wprintf(L"ENAME = %s, ADDRESS = %.*s\n", cname, caddr.len, caddr.arr);
   ...
}