oracle彿創垂痕塀垂

  <?

  class DB_Sql {

  var $Debug = false;

  var $Home = "/u01/app/oracle/product/8.0.4";

  var $Remote = 1;

  /* This Query will be sent directly after the first connection

  Example:

  var $ConnectQuery="ALTER SESSION SET nls_date_language=german nls_date_format='DD.MM.RRRR'";

  -> Set the date format for this session, this is fine when your ora-role

  cannot be altered */

  var $ConnectQuery='';

  /* Due to a strange error with Oracle 8.0.5, Apache and PHP3.0.6

  you don't need to set the ENV - on my system Apache

  will change to a zombie, if I don't set this to FALSE!

  Instead I set these ENV-vars before the startup of apache.

  If unsure try it out, if it works. */

  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;

  /* copied from db_mysql for completeness */

  /* public: identification constant. never change this. */

  var $type = "oracle";

  var $revision = "Revision: 1.3";

  var $Halt_On_Error = "yes"; ## "yes" (halt with message), "no" (ignore errors quietly), "report" (ignore errror, but spit a warning)

  /* public: constructor */

  function DB_Sql($query = "") {

  $this->query($query);

  }

  /* public: some trivial reporting */

  function link_id() {

  return $this->Link_ID;

  }

  function query_id() {

  return $this->Query_ID;

  }

  function connect() {

  ## see above why we do this

  if ($this->OraPutEnv) {

  PutEnv("ORACLE_SID=$this->Database");

  PutEnv("ORACLE_HOME=$this->Home");

  }

  if ( 0 == $this->Link_ID ) {

  if($this->Debug) {

  printf("<br>Connect()ing to $this->Database...<br>n");

  }

  if($this->Remote) {

  if($this->Debug) {

  printf("<br>connect() $this->User/******@$this->Database<br>n");

  }

  $this->Link_ID=ora_plogon

  ("$this->User/$this->Password@$this->Database","");

  /************** (comment by SSilk)

  this dosn't work on my system:

  $this->Link_ID=ora_plogon

  ("$this->User@$this->Database.world","$this->Password");

  ***************/

  } else {

  if($this->Debug) {

  printf("<br>connect() $this->User, $this->Password <br>n");

  }

  $this->Link_ID=ora_plogon("$this->User","$this->Password");

  /* (comment by SSilk: don't know how this could work, but I leave this untouched!) */

  }

  if($this->Debug) {

  printf("<br>connect() Link_ID: $this->Link_ID<br>n");

  }

  if (!$this->Link_ID) {

  $this->halt("connect() Link-ID == false " .

  "($this->Link_ID), ora_plogon failed");

  } else {

  //echo "commit on<p>";

  ora_commiton($this->Link_ID);

  }

  if($this->Debug) {

  printf("<br>connect() Obtained the Link_ID: $this->Link_ID<br>n");

  }

  ## Execute Connect Query

  if ($this->ConnectQuery) {

  $this->query($this->ConnectQuery);

  }

  }

  }

  ## In order to increase the # of cursors per system/user go edit the

  ## init.ora file and increase the max_open_cursors parameter. Yours is on

  ## the default value, 100 per user.

  ## We tried to change the behaviour of query() in a way, that it tries

  ## to safe cursors, but on the other side be carefull with this, that you

  ## don't use an old result.

  ##

  ## You can also make extensive use of ->disconnect()!

  ## The unused QueryIDs will be recycled sometimes.

  function query($Query_String)

  {

  /* No empty query please. */

  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("Debug: query = %s<br>n", $Query_String);

  printf("<br>Debug: Query_ID: %d<br>n", $this->Query_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("<BR>ora_parse() failed:<BR>$Query_String<BR><small>Snap & paste this to sqlplus!</SMALL>");

  } elseif (!@ora_exec($this->Query_ID)) {

  $this->Errno=ora_errorcode($this->Query_ID);

  $this->Error=ora_error($this->Query_ID);

  $this->halt("<BR>n$Query_Stringn<BR><small>Snap & paste this to sqlplus!</SMALL>");

  }

  $this->Row=0;

  if(!$this->Query_ID) {

  $this->halt("Invalid 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("<br>next_record(): ID: %d Row: %d<br>n",

  $this->Query_ID,$this->Row+1);

  // more info for $this->Row+1 is $this->num_rows(),

  // but dosn't work in all cases (complicated selects)

  // and it is very slow here

  }

  $this->Row +=1;

  $errno=ora_errorcode($this->Query_ID);

  if(1403 == $errno) { # 1043 means no more records found

  $this->Errno=0;

  $this->Error="";

  $this->disconnect();

  $stat=0;

  } else {

  $this->Error=ora_error($this->Query_ID);

  $this->Errno=$errno;

  if($this->Debug) {

  printf("<br>%d Error: %s",

  $this->Errno,

  $this->Error);

  }

  $stat=0;

  }

  } else {

  $this->ora_no_next_fetch=false;

  for($ix=0;$ix<ora_numcols($this->Query_ID);$ix++) {

  $col=strtolower(ora_columnname($this->Query_ID,$ix));

  $value=ora_getcolumn($this->Query_ID,$ix);

  $this->Record[ "$col" ] = $value;

  $this->Record[ $ix ] = $value;

  #DBG echo"<b>[$col]</b>: $value <br>n";

  }

  $stat=1;

  }

  return $stat;

  }

  ## seek() works only for $pos - 1 and $pos

  ## Perhaps I make a own implementation, but my

  ## opinion is, that this should be done by PHP3

  function seek($pos) {

  if ($this->Row - 1 == $pos) {

  $this->ora_no_next_fetch=true;

  } elseif ($this->Row == $pos ) {

  ## do nothing

  } else {

  $this->halt("Invalid seek(): Position is cannot be handled by API.<BR>".

  "Only a seek to the last element is allowed in this version<BR>".

  "Difference too big. Wanted: $pos Current pos: $this->Row");

  }

  if ($this->Debug) echo "<BR>Debug: seek = $pos<BR>";

  $this->Row=$pos;

  }

  function lock($table, $mode = "write") {

  if ($mode == "write") {

  $result = ora_do($this->Link_ID, "lock table $table in row exclusive mode");

  } else {

  $result = 1;

  }

  return $result;

  }

  function unlock() {

  return ora_do($this->Link_ID, "commit");

  }

  // Important note: This function dosn't work with Oracle-Database-Links!

  // You are free to get a better method. :)

  function metadata($table,$full=false) {

  $count = 0;

  $id = 0;

  $res = array();

  /*

  * Due to compatibility problems with Table we changed the behavior

  * of metadata();

  * depending on $full, metadata returns the following values:

  *

  * - full is false (default):

  * $result[]:

  * [0]["table"] table name

  * [0]["name"] field name

  * [0]["type"] field type

  * [0]["len"] field length

  * [0]["flags"] field flags ("NOT NULL", "INDEX")

  * [0]["format"] precision and scale of number (eg. "10,2") or empty

  * [0]["index"] name of index (if has one)

  * [0]["chars"] number of chars (if any char-type)

  *

  * - full is true

  * $result[]:

  * ["num_fields"] number of metadata records

  * [0]["table"] table name

  * [0]["name"] field name

  * [0]["type"] field type

  * [0]["len"] field length

  * [0]["flags"] field flags ("NOT NULL", "INDEX")

  * [0]["format"] precision and scale of number (eg. "10,2") or empty

  * [0]["index"] name of index (if has one)

  * [0]["chars"] number of chars (if any char-type)

  * [0]["php_type"] the correspondig PHP-type

  * [0]["php_subtype"] the subtype of PHP-type

  * ["meta"][field name] index of field named "field name"

  * This could used, if you have the name, but no index-num - very fast

  * Test: if (isset($result['meta']['myfield'])) {} ...

  */

  $this->connect();

  ## This is a RIGHT OUTER JOIN: "(+)", if you want to see, what

  ## this query results try the following:

  ## $table = new Table; $db = new my_DB_Sql; # you have to make

  ## # your own class

  ## $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.column_id");

  $i=0;

  while ($this->next_record()) {

  $res[$i]["table"] = $this->Record[table_name];

  $res[$i]["name"] = strtolower($this->Record[column_name]);

  $res[$i]["type"] = $this->Record[data_type];

  $res[$i]["len"] = $this->Record[data_length];

  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->Record[data_scale];

  if ("0,0"==$res[$i]["format"]) $res[$i]["format"]='';

  $res[$i]["index"] = $this->Record[index_name];

  $res[$i]["chars"] = $this->Record[char_col_decl_length];

  if ($full) {

  $j=$res[$i]["name"];

  $res["meta"][$j] = $i;

  $res["meta"][strtoupper($j)] = $i;

  switch ($res[$i]["type"]) {

  case "VARCHAR2" :

  case "VARCHAR" :

  case "CHAR" :

  $res["php_type"]="string";

  $res["php_subtype"]="";

  break;

  case "DATE" :

  $res["php_type"]="string";

  $res["php_subtype"]="date";

  break;

  case "BLOB" :

  case "CLOB" :

  case "BFILE" :

  case "RAW" :

  case "LONG" :

  case "LONG RAW" :

  $res["php_type"]="string";

  $res["php_subtype"]="blob";

  break;

  case "NUMBER" :

  if ($res[$i]["format"]) {

  $res["php_type"]="double";

  $res["php_subtype"]="";

  } else {

  $res["php_type"]="int";

  $res["php_subtype"]="";

  }

  break;

  default :

  $this->halt("metadata(): Type is not a valid value: '$res[$i][type]'");

  break;

  }

  }

  if ($full) $res["meta"][$res[$i]["name"]] = $i;

  $i++;

  }

  if ($full) $res["num_fields"]=$i;

  # $this->disconnect();

  return $res;

  }

  ## THIS FUNCTION IS UNSTESTED!

  function affected_rows() {

  if ($this->Debug) echo "<BR>Debug: affected_rows=". ora_numrows($this->Query_ID)."<BR>";

  return ora_numrows($this->Query_ID);

  }

  ## Known bugs: It will not work for SELECT DISTINCT and any

  ## other constructs which are depending on the resulting rows.

  ## So you *really need* to check every query you make, if it

  ## will work with it!

  ##

  ## Also, for a qualified replacement you need to parse the

  ## selection, cause this will fail: "SELECT id, from FROM ...").

  ## "from" is - as far as I know a keyword in Oracle, so it can

  ## only be used in this way. But you have been warned.

  function num_rows() {

  $curs=ora_open($this->Link_ID);

  ## this is the important part and it is also the HACK!

  if (eregi("^[[:space:]]*SELECT[[:space:]]",$this->lastQuery) )

  {

  # This works for all?? cases, including SELECT DISTINCT case.

  # We just make select count(*) from original sql expression

  # and remove ORDER BY (if any) for speed

  # I like regular expressions too ;-)))

  $q = sprintf("SELECT COUNT(*) FROM (%s)",

  @eregi_Replace("ORDER[[:space:]]+BY[^)]*()*)", "\1",

  $this->lastQuery)

  );

  # works also for subselects:

  # 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 "<BR>Debug: num_rows: $q<BR>";

  ORA_parse($curs,$q);

  ORA_exec($curs);

  ORA_fetch($curs);

  $result = ORA_getcolumn($curs,0);

  ORA_close($curs);

  if ($this->Debug)

  {

  echo "<BR>Debug: ID ".$this->QueryID.

  " num_rows=". $result ."<BR>";

  }

  return $result;

  }

  else

  {

  $this->halt("Last Query was not a SELECT: $this->lastQuery");

  }

  }

  function num_fields() {

  if ($this->Debug) echo "<BR>Debug: num_fields=". ora_numcols($this->Query_ID) . "<BR>";

  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: sequence number */

  function nextid($seq_name)

  {

  $this->connect();

  /* Independent Query_ID */

  $Query_ID = ora_open($this->Link_ID);

  if(!@ora_parse($Query_ID,"SELECT $seq_name.NEXTVAL FROM DUAL"))

  {

  // There is no such sequence yet, then create it

  if(!@ora_parse($Query_ID,"CREATE SEQUENCE $seq_name")

  !@ora_exec($Query_ID)

  )

  {

  $this->halt("<BR> nextid() function - unable to create sequence");

  return 0;

  }

  @ora_parse($Query_ID,"SELECT $seq_name.NEXTVAL FROM DUAL");

  }

  if (!@ora_exec($Query_ID)) {

  $this->halt("<BR>ora_exec() failed:<BR>nextID function");

  }

  if (@ora_fetch($Query_ID) ) {

  $next_id = ora_getcolumn($Query_ID, 0);

  }

  else {

  $next_id = 0;

  }

  if ( $Query_ID > 0 ) {

  ora_close($Query_ID);

  }

  return $next_id;

  }

  function disconnect() {

  if($this->Debug) {

  echo "Debug: Disconnecting $this->Query_ID...<br>n";

  }

  if ( $this->Query_ID < 1 ) {

  echo "<B>Warning</B>: disconnect(): Cannot free ID $this->Query_IDn";

  # return();

  }

  ora_close($this->Query_ID);

  $this->Query_ID=0;

  }

  /* private: error handling */

  function halt($msg) {

  if ($this->Halt_On_Error == "no")

  return;

  $this->haltmsg($msg);

  if ($this->Halt_On_Error != "report")

  die("Session halted.");

  }

  function haltmsg($msg) {

  printf("</td></tr></table><br><b>Database error:</b> %s<br>n", $msg);

  printf("<b>Oracle Error</b>: %s (%s)<br>n",

  $this->Errno,

  $this->Error);

  }

  function table_names() {

  $this->connect();

  $this->query("

  SELECT table_name,tablespace_name

  FROM user_tables");

  $i=0;

  while ($this->next_record())

  {

  $info[$i]["table_name"] =$this->Record["table_name"];

  $info[$i]["tablespace_name"]=$this->Record["tablespace_name"];

  $i++;

  }

  return $info;

  }

  // Some transaction support

  // Methods are used in ct_oracle.inc

  function begin_transaction()

  {

  $this->connect();

  // Now, disable autocommit

  Ora_CommitOff($this->Link_ID);

  if ($this->Debug)

  {

  print "BEGIN TRANSACTION<BR>";

  }

  }

  function end_transaction()

  {

  if ($this->Debug)

  {

  print "BEGIN TRANSACTION<BR>";

  }

  $res = 1;

  if(!@Ora_Commit($this->Link_ID))

  {

  Ora_CommitOn($this->Link_ID);

  $this->halt("Unable to finish transaction");

  $res = 0;

  }

  // Enable autocommit again

  Ora_CommitOn($this->Link_ID);

  if ($this->Debug)

  {

  print "END TRANSACTION : $res<BR>";

  }

  return $res;

  }

  }

  ?>