この章の項目は次のとおりです。
Unicodeの集中型データベースは、グローバル・インターネット・アプリケーションを開発するためのアプローチの機能として、単一言語と多言語の両方に共通しています。集中型データベースの使用には、次のメリットがあります。
データの完全ビューが実現します。たとえば、全世界の顧客数や、製品の全世界的な在庫レベルを問い合せることができます。
1つの集中型データベースの管理は、複数の分散データベースの管理よりも容易です。
データベース・キャラクタ・セットは、Unicodeである必要があります。Unicodeを使用して、データをいくつかの言語で格納および操作できます。Unicodeは、世界中のほぼすべての言語において文字を定義するユニバーサル・キャラクタ・セットです。Oracleデータベースは、次のいずれかのエンコーディング形式でUnicodeデータを格納できます。
|
関連項目:
|
インターネット・アプリケーションからOracle Application Serverを介してデータベース・サーバーに接続するには、いくつかの方法があります。Javaサーブレット、JSP、EJBなどのテクノロジを使用するJavaベースのインターネット・アプリケーションの場合、データベースの接続性のためにOracle JDBCドライバを使用します。
Java文字列は常にUnicodeでエンコードされているので、JDBCはテキスト・データをデータベース・キャラクタ・セットとUnicodeとの間で透過的に変換します。Oracleデータベースと通信するJavaサーブレットとJSPでは、必ず次のことを確認する必要があります。
データベースから返されたJava文字列は、構成されたHTMLページのエンコーディングに変換されます。
フォーム入力は、JDBCドライバのコールで使用する前に、HTMLフォームのエンコーディングからUnicodeに変換されます。
Perl、PL/SQL、C/C++などのプログラミング・テクノロジを使用する非Javaインターネット・アプリケーションの場合、データベースから検索したりデータベースに挿入されたテキスト・データは、NLS_LANGパラメータで指定したキャラクタ・セットでエンコードされます。POSIXロケールで使用するキャラクタ・セットは、アプリケーション内のPOSIXロケールに依存する関数でデータベースのデータを直接処理するために、NLS_LANGキャラクタ・セットと一致する必要があります。
多言語アプリケーションの場合、NLS_LANGキャラクタ・セットとページ・エンコーディングは、キャラクタ・セットが変換されデータ損失が発生する可能性を回避するために、両方ともUTF-8にする必要があります。
JSPとJavaサーブレットを使用する場合は、Oracle Application ServerでOracleデータベースへの接続用に提供されているOracle JDBCドライバを使用します。Oracle Application Serverには、中間層アプリケーションに配置可能なクライアント側JDBCドライバが2種類あります。
Oracleクライアント・ライブラリを必要とするJDBC OCIドライバ
Pure JavaドライバであるJDBC Thinドライバ
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開発者ガイドおよびリファレンス』 |
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パッケージ・プロシージャおよびタイプ・リファレンス』 |
Perlスクリプトは、Oracle用のDBI/DBDドライバによってOracleデータベースに接続します。DBI/DBDドライバは、Oracle Application Serverの一部です。このドライバは、Oracle Call Interface(OCI)をコールしてデータベースに接続します。データベースから検索したデータやデータベースに挿入したデータは、NLS_LANGキャラクタ・セットでエンコードされます。Perlスクリプトでは、次の項目を実行できる必要があります。
POSIXロケールをLC_ALL環境変数で指定されたロケールで初期化します。
NLS_LANGキャラクタ・セットで使用されているキャラクタ・セットを使用します。
これによって、データベースから検索したデータを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スクリプトは次のことを行います。
UTF-8キャラクタ・セットに関連付けられたPOSIXロケールを使用します。
UTF-8のPerlモジュールを使用して、Perl文字列内のすべての文字列がUTF-8であることを示します。
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の使用時に必要なデータ変換が不要になります。
この項の項目は次のとおりです。
データベース接続のためのPro*C/C++でのUnicodeバインドと定義の使用
|
注意: OCIライブラリは、Oracle Application Serverの一部です。このライブラリを使用するために、Oracleデータベース・クライアントをインストールする必要はありません。 |
次の例は、カスタマ表の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);
...
OCIライブラリで多言語アプリケーション用に提供するUnicode APIを使用することができます。
OCI環境ハンドルを作成するときにUnicodeモードを指定することによって、Unicode APIを使用します。OCI環境ハンドルから継承されたハンドルは、すべて自動的にUnicodeモードに設定されます。Unicodeモードに変更することによって、OCI関数へのすべてのテキスト・データ引数は、Unicodeテキスト(utext*)データ型でUTF-16エンコーディングであることが前提になります。バインドおよび定義を行う場合、データ・バッファにおいてutextバッファがUTF-16エンコーディングであることが前提になります。
Unicode APIのプログラム・コードは、次の点を除いて、非Unicode OCI API用のコードと類似しています。
次のタスクを実行する方法を、その後の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);
...
多言語アプリケーションの場合、Unicodeのバインドと定義をPro*C/C++で使用することができます。
Pro*C/C++によって、バインドおよび定義の操作用にUTF-16 Unicodeバッファを指定できるようになります。UTF-16バッファをPro*C/C++で指定するには、2種類の方法があります。
struct uvarchar
{
ub2 len; /* length of arr */
utext arr[1] ; /* UTF-16 buffer */
};
typedef struct uvarchar uvarchar ;
次の例では、cnameとcaddrという2種類のホスト変数が使用されています。cnameホスト変数は、100のUTF-16コード・ユニット(unsigned short)で構成されるutextバッファとして、VARCHAR2データ型の顧客名列に対して宣言されます。caddrホスト変数は、50のUCS2文字で構成されるuvarcharバッファとして、NVARCHAR2データ型の顧客アドレス列に対して宣言されます。lenとarrのフィールドは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);
...
}