クラス DB_Sql {
var $Debug = false;
var $Home = "/u01/app/oracle/product/8.0.4";
var $Remote = 1;
/* このクエリは最初の接続後に直接送信されます
例:
var $ConnectQuery="ALTER SESSION SET nls_date_ language=german nls_date_format='DD.MM.RRRR'";
->このセッションの日付形式を設定します。これは、ora ロール
を変更できない場合に問題ありません */
var $ConnectQuery='';
/* Oracle 8.0.5、Apache、および PHP3.0.6 での奇妙なエラーのため
ENV を設定する必要はありません - 私のシステムでは Apache
これを FALSE に設定しないとゾンビに変わります!
代わりに、Apache の起動前にこれらの ENV 変数を設定します。
不明な場合は、うまくいくかどうか試してください。 */
var $OraPutEnv = true;
var $Database = "";
var $User = "";
var $Password = "";
var $Link_ID = 0;
var $Query_ID = 0;
var $Record = array();
var $Row;
var $Errno = 0;
var $Error = "";
var $ora_no_next_fetch=false;
/* 完全を期すために db_mysql からコピー */
/* public: 識別定数。これを決して変更しないでください。 */
var $type = "オラクル";
var $revision = "リビジョン: 1.3";
var $Halt_On_Error = "はい"; ## "yes" (メッセージを表示して停止)、"no" (エラーを静かに無視)、"report" (エラーを無視しますが、警告を吐きます)
/* public:constructor */
function DB_Sql($query = "" ) {
$this->クエリ($クエリ);
}
/* public: 些細なレポート */
function link_id() {
return $this->Link_ID;
}
function query_id() {
return $this->Query_ID;
}
function connect() {
## これを行う理由は上記を参照
if ($this->OraPutEnv) {
PutEnv("ORACLE_SID=$this->Database");
PutEnv("ORACLE_HOME=$this->ホーム");
}
if ( 0 == $this->Link_ID ) {
if($this->Debug) {
printf("
$this->データベースに接続中...< ;br>n");
}
if($this->Remote) {
if($this->Debug) {
printf("
connect() $this->User/******@$this->データベース
n");
}
$this->Link_ID=ora_plogon
("$this->ユーザー/$this->パスワード@$this-> ;Database","");
/************** (SSilk によるコメント)
これは私のシステムでは動作しません:
$this->Link_ID=ora_plogon
( "$this->ユーザー@$this->Database.world","$this->パスワード");*/
} else {
if($this->Debug) {
printf("
connect() $this->ユーザー, $this->パスワード
n");
}
$ this->Link_ID=ora_plogon("$this->User","$this->Password");
/* (SSilk によるコメント: これがどのように機能するかわかりませんが、これはそのままにしておきます。 ) */
}
if($this->Debug) {
printf("
connect() Link_ID: $this->Link_ID
n");
}
if (!$this ->Link_ID) {
$this->halt("connect() Link-ID == false " .
"($this->Link_ID), ora_plogon が失敗しました")
} else {
//echo "commit on
";
ora_commiton($this->Link_ID);
if($this->Debug) {
printf("
connect() Link_ID を取得しました: $this- >Link_ID
n");
}
## 接続クエリを実行
if ($this->ConnectQuery) {
$this->query($this->ConnectQuery);
}
}
## システム/ユーザーごとのカーソルの数を増やすには、
## init.ora ファイルを編集して、max_open_cursors パラメータを増やします。
## はデフォルト値で、ユーザーごとに 100 です。
## 私たちは、カーソルを安全にするために
## を試みるという方法で query() の動作を変更しようとしましたが、その一方で、古い結果を使用しないように
## する必要があることに注意してください。
##
## ->disconnect() を広範囲に使用することもできます。
## 未使用の QueryID は時々リサイクルされます。
function query($Query_String)
{
/* 空のクエリは使用しないでください。 */
if (empty($Query_String))
{
return 0;
}
$this->connect();
$this->lastQuery=$Query_String;
if (!$this->Query_ID) {
$this->Query_ID= ora_open($this->Link_ID);
}
if($this->Debug) {
printf("デバッグ: クエリ = %s
n", $Query_String);
printf("
デバッグ: クエリ ID: %d
n", $this->クエリ ID);
}
if(!@ora_parse($this->Query_ID,$Query_String)) {
$this->Errno=ora_errorcode($this->Query_ID);
$this->Error=ora_error($this->Query_ID);
$this->halt("
ora_parse() が失敗しました:
$Query_String
これをスナップして sqlplus に貼り付けます!");
} elseif (!@ora_exec($this->Query_ID)) {
$this->Errno=ora_errorcode($this->Query_ID);
$this->Error=ora_error($this->Query_ID);
$this->halt("
n$Query_Stringn
これをスナップして sqlplus に貼り付けます!");
}
$this->行=0;
if(!$this->Query_ID) {
$this->halt("無効な SQL: ".$Query_String);
}
return $this->Query_ID;
}
function next_record() {
if (!$this->ora_no_next_fetch &&
0 == ora_fetch($this->Query_ID)) {
if ($this->Debug) {
printf("
next_record(): ID: %d 行: %d
n",
$this->Query_ID,$this->Row+1);
// $this->Row+1 の詳細は $this->num_rows() です
// しかし、すべてのケースで機能するとは限りません (複雑な選択)
// ここでは非常に遅いです
}
$this->行 +=1;
$errno=ora_errorcode($this->Query_ID);
if(1403 == $errno) { # 1043 は、これ以上レコードが見つからないことを意味します
$this->Errno=0;
$this->エラー="";
$this->disconnect();
$stat=0;
} else {
$this->Error=ora_error($this->Query_ID);
$this->Errno=$errno;
if($this->Debug) {
printf("
%d エラー: %s",
$this->Errno,
$this->Error);
}
$stat=0;
}
} else {
$this->ora_no_next_fetch=false;
for($ix=0;$ix
$col=strto lower(ora_columnname($this->Query_ID,$ix));
$value=ora_getcolumn($this->Query_ID,$ix);
$this->レコード[ "$col" ] = $value;
$this->レコード[ $ix ] = $value;
#DBG echo"[$col]: $value
n";
}
$stat=1;
}
$stat を返す;
}
## look() は $pos - 1 と $pos に対してのみ機能します
## おそらく独自の実装を作成しますが、私の
## 意見は、これは PHP3 で行うべきであるということです
function look($pos ) {
if ($this->Row - 1 == $pos) {
$this->ora_no_next_fetch=true;
} elseif ($this->Row == $pos ) {
## 何もしない
} else {
$this->halt("無効なシーク(): 位置は API で処理できません。
"このバージョンでは最後の要素へのシークのみが許可されています
".
"差が大きすぎます。募集: $pos 現在の位置: $this->Row");
}
if ($this->Debug) echo "
Debug: Seek = $pos
";
$this->Row=$pos;
}
function lock($table, $mode = "write") {
if ($mode == "write") {
$result = ora_do($this->Link_ID, "行のテーブル $table をロック排他モード");
} else {
$result = 1;
}
$result を返します。
}
functionunlock() {
return ora_do($this->Link_ID, "commit");
}
// 重要な注意: この関数は Oracle-Database-Links では機能しません。
// より良い方法を自由に入手できます。 :)
関数メタデータ($table,$full=false) {
$count = 0;
$id = 0;
$res = 配列();
/*
* Table との互換性の問題のため、metadata(); の動作
* を変更しました。
* $full に応じて、メタデータは次の値を返します:
*
* - full は false (デフォルト):
* $result[]:
* [0]["table"] テーブル名
* [0][ "name"] フィールド名
* [0]["type"] フィールドタイプ
* [0]["len"] フィールド長
* [0]["flags"] フィールドフラグ ("NOT NULL"、"INDEX") ")
* [0]["format"] 数値の精度とスケール (例: "10,2") または空
* [0]["index"] インデックスの名前 (ある場合)
* [0 ]["chars"] 文字の数 (char 型がある場合)
*
* - full が true
* $result[]:
* ["num_fields"] メタデータ レコードの数
* [0]["table "] テーブル名
* [0]["name"] フィールド名
* [0]["type"] フィールドタイプ
* [0]["len"] フィールド長
* [0]["flags"]フィールド フラグ ("NOT NULL"、"INDEX")
* [0]["format"] 数値の精度と位取り (例: "10,2") または空
* [0]["index"] の名前インデックス (ある場合)
* [0]["chars"] 文字の数 (char-type がある場合)
* [0]["php_type"] 対応する PHP タイプ
* [0]["php_subtype" ] PHP タイプのサブタイプ
* ["meta"][field name] "field name" という名前のフィールドのインデックス
* これは、名前はあるが、index-num がない場合に使用できます - 非常に高速です
* テスト: if (isset($result['meta']['myfield'])) {} ...
*/
$this->connect();
## これは RIGHT OUTER JOIN: "(+)" です。このクエリの結果を確認したい場合は、
## 次のことを試してください。
## $table = new Table; $db = 新しい my_DB_Sql; #
## # 独自のクラスを作成する必要があります
## $table->show_results($db->query(see query vvvvvv))
##
$this->query("SELECT T.table_name ,T.column_name,T.data_type,".
"T.data_length,T.data_precision,T.data_scale,T.nullable,".
"T.char_col_decl_length,I.index_name".
" FROM ALL_TAB_COLUMNS T,ALL_IND_COLUMNS I ".
" WHERE T.column_name=I.column_name (+)".
" AND T.table_name=I.table_name (+)".
" AND T.table_name=UPPER('$table') ORDER BY T.列ID");
$i=0;
while ($this->next_record()) {
$res[$i]["テーブル"] = $this->Record[テーブル名];
$res[$i]["name"] = strto lower($this->Record[column_name]);
$res[$i]["type"] = $this->Record[data_type];
$res[$i]["len"] = $this->レコード[データ長];
if ($this->Record[index_name]) $res[$i]["flags"] = "INDEX ";
$res[$i]["flags"] .= ( $this->Record[nullable] == 'N') ? '' : 'NOT NULL';
$res[$i]["format"]= (int)$this->Record[data_precision].",".
(int)$this->レコード[データスケール];
if ("0,0"==$res[$i]["フォーマット"]) $res[$i]["フォーマット"]='';
$res[$i]["インデックス"] = $this->レコード[インデックス名];
$res[$i]["chars"] = $this->Record[char_col_decl_length];
if ($full) {
$j=$res[$i]["名前"];
$res["メタ"][$j] = $i;
$res["meta"][strtoupper($j)] = $i;
switch ($res[$i]["type"]) {
case "VARCHAR2" :
case "VARCHAR" :
case "CHAR" :
$res["php_type"]="string";
$res["php_subtype"]="";
休憩;
ケース "DATE" :
$res["php_type"]="string";
$res["php_subtype"]="日付";
休憩;
case "BLOB" :
case "CLOB" :
case "BFILE" :
case "RAW" :
case "LONG" :
case "LONG RAW" :
$res["php_type"]="string";
$res["php_subtype"]="blob";
休憩;
case "NUMBER" :
if ($res[$i]["format"]) {
$res["php_type"]="double";
$res["php_subtype"]="";
} else {
$res["php_type"]="int";
$res["php_subtype"]="";
}
休憩;
デフォルト :
$this->halt("metadata(): タイプが有効な値ではありません: '$res[$i][type]'");
休憩;
}
}
if ($full) $res["meta"][$res[$i]["name"]] = $i;
$i++;
}
if ($full) $res["num_fields"]=$i;
# $this->disconnect();
$res を返す;
}
## この機能はテストされていません!
functionaffected_rows() {
if ($this->Debug) echo "
Debug:affected_rows=". ora_numrows($this->Query_ID)."
";
return ora_numrows($this->Query_ID);
}
## 既知のバグ: SELECT DISTINCT および結果の行に依存する
## 他の構造では機能しません。
## したがって、作成したすべてのクエリが機能するかどうかを *本当に確認する必要があります *
##!
##
## また、修飾された置換の場合、
## 選択を解析する必要があります。これは失敗します: "SELECT id, from FROM ...")。
## "from" は、私が知る限り Oracle のキーワードであるため、
## この方法でのみ使用できます。しかし、あなたは警告を受けています。
function num_rows() {
$curs=ora_open($this->Link_ID);
## これは重要な部分であり、ハックでもあります。
if (eregi("^[[:space:]]*SELECT[[:space:]]",$this->lastQuery) )
{
# これはすべてに機能しますか?? SELECT DISTINCT の場合を含む。
# 元の SQL 式から select count(*) を作成するだけです
# 速度を上げるために ORDER BY (ある場合) を削除します
# 正規表現も好きです ;-)))
$q = sprintf("SELECT COUNT(*) FROM (%s)",
@eregi_Replace("ORDER[[:space:]]+BY[^)]*()*)", "1",
$this->lastQuery)
);
# は副選択にも機能します:
# if (eregi("[[:space:]]+FROM([[:space:]]]+.*[[:space:]]+FROM)",$this- >lastQuery,$r))
# $areplace=$r[1];
# $q=eregi_Replace("^[[:space:]]*SELECT[[:space:]]+".
# ".*[[:space:]]+FROM",
# "SELECT COUNT( *) FROM$areplace",
# $this->lastQuery);
if ($this->Debug) echo "
Debug: num_rows: $q
";
ORA_parse($curs,$q);
ORA_exec($curs);
ORA_fetch($curs);
$result = ORA_getcolumn($curs,0);
ORA_close($curs);
if ($this->Debug)
{
echo "
Debug: ID ".$this->QueryID。
「num_rows=」。 $result ."
";
}
$result を返します。
}
else
{
$this->halt("最後のクエリは SELECT ではありませんでした: $this->lastQuery");
}
}
function num_fields() {
if ($this->Debug) echo "
Debug: num_fields="。 ora_numcols($this->Query_ID) 。 "
";
return ora_numcols($this->Query_ID);
}
function nf() {
return $this->num_rows();
}
function np() {
print $this->num_rows();
}
function f($Name) {
return $this->Record[$Name];
}
function p($Name) {
print $this->Record[$Name];
}
/* public: シーケンス番号 */
function nextid($seq_name)
{
$this->connect();
/* 独立したクエリ ID */
$Query_ID = ora_open($this->Link_ID);
if(!@ora_parse($Query_ID,"SELECT $seq_name.NEXTVAL FROM DUAL"))
{
// そのようなシーケンスはまだないので、作成します
if(!@ora_parse($Query_ID,"CREATE SEQUENCE) $seq_name")
!@ora_exec($Query_ID)
)
{
$this->halt("
nextid() 関数 - シーケンスを作成できません");
0を返します;
}
@ora_parse($Query_ID,"SELECT $seq_name.NEXTVAL FROM DUAL");
}
if (!@ora_exec($Query_ID)) {
$this->halt("
ora_exec() が失敗しました:
nextID 関数");
}
if (@ora_fetch($Query_ID) ) {
$next_id = ora_getcolumn($Query_ID, 0);
}
else {
$next_id = 0;
}
if ( $Query_ID > 0 ) {
ora_close($Query_ID);
}
$next_id を返す;
}
functiondetach() {
if($this->Debug) {
echo "デバッグ: $this->Query_ID...
n の接続を切断しています";
}
if ( $this->Query_ID echo "警告:切断(): ID $this->Query_IDn を解放できません";
# return();
}
ora_close($this->Query_ID);
$this->Query_ID=0;
}
/* private: エラー処理 */
function halt($msg) {
if ($this->Halt_On_Error == "no")
return;
$this->haltmsg($msg);
if ($this->Halt_On_Error != "レポート")
die("セッションが停止しました。");
}
function haltmsg($msg) {
printf("
データベースエラー: %s
n "、$msg);
printf("Oracle エラー: %s (%s)
n",
$this->Errno,
$this->Error);
}
関数 table_names() {
$this->connect();
$this->query("
SELECT テーブル名,テーブルスペース名
FROM user_tables");
$i=0;
while ($this->next_record())
{
$info[$i]["テーブル名"] =$this->Record["テーブル名"];
$info[$i]["テーブルスペース名"]=$this->Record["テーブルスペース名"];
$i++;
}
$info を返します。
}
// 一部のトランザクションのサポート
// メソッドは ct_oracle.inc で使用されます
function begin_transaction()
{
$this->connect();
// 次に、自動コミットを無効にします
Ora_CommitOff($this->Link_ID);
if ($this->Debug)
{
print "BEGIN TRANSACTION
";
}
}
function end_transaction()
{
if ($this->Debug)
{
print "BEGIN TRANSACTION
";
}
$res = 1;
if(!@Ora_Commit($this->Link_ID))
{
Ora_CommitOn($this->Link_ID);
$this->halt("トランザクションを終了できません");
$res = 0;
}
// 自動コミットを再度有効にする
Ora_CommitOn($this->Link_ID);
if ($this->Debug)
{
print "END TRANSACTION : $res
";
}
$res を返す;
}
}
?>