home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 April / CMCD0404.ISO / Software / Freeware / Programare / groupoffice-com-2.01 / database / oracle.class.inc < prev    next >
Text File  |  2004-03-08  |  14KB  |  439 lines

  1. <?php
  2. /*
  3.  * Oracle accessor based on Session Management for PHP3
  4.  *
  5.  * Copyright (c) 1998-2000 Luis Francisco Gonzalez Hernandez
  6.  *
  7.  * $Id: oracle.class.inc,v 1.1.1.1 2003/07/03 15:04:02 mschering Exp $
  8.  *
  9.  */
  10.  
  11. class db {
  12.   var $Debug    =  false;
  13.   var $Home     = "/u01/app/oracle/product/8.0.4";
  14.   var $Remote   =  1;
  15.   /* Due to a strange error with Oracle 8.0.5, Apache and PHP3.0.6
  16.      you don't need to set the ENV - on my system Apache
  17.      will change to a zombie, if I don't set this to FALSE!
  18.      If unsure try it out, if it works. */
  19.   var $OraPutEnv   = true;
  20.  
  21.   var $Database = "";
  22.   var $User     = "";
  23.   var $Password = "";
  24.  
  25.   var $Link_ID    = 0;
  26.   var $Query_ID  = 0;
  27.   var $Record    = array();
  28.   var $Row;
  29.  
  30.   var $Errno     = 0;
  31.   var $Error     = "";
  32.   var $ora_no_next_fetch=false;
  33.  
  34.  
  35.   /* copied from db_mysql for completeness */
  36.   /* public: identification constant. never change this. */
  37.   var $type     = "oracle";
  38.   var $revision = "1.2";
  39.  
  40.   var $Halt_On_Error = "yes"; ## "yes" (halt with message), "no" (ignore errors quietly), "report" (ignore errror, but spit a warning)
  41.  
  42.   /* public: constructor */
  43.   function db($query = "") {
  44.       global $GO_CONFIG;
  45.       $this->Host = $GO_CONFIG->db_host;
  46.       $this->Database = $GO_CONFIG->db_name;
  47.       $this->User = $GO_CONFIG->db_user;
  48.         $this->Password = $GO_CONFIG->db_pass;
  49.       $this->query($query);
  50.   }
  51.  
  52.   /* public: some trivial reporting */
  53.   function link_id() {
  54.     return $this->Link_ID;
  55.   }
  56.  
  57.   function query_id() {
  58.     return $this->Query_ID;
  59.   }
  60.  
  61.   function connect() {
  62.       ## see above why we do this
  63.       if ($this->OraPutEnv) {
  64.         PutEnv("ORACLE_SID=$this->Database");
  65.         PutEnv("ORACLE_HOME=$this->Home");
  66.       }
  67.       if ( 0 == $this->Link_ID ) {
  68.         if($this->Debug) {
  69.           printf("<br>Connect()ing to $this->Database...<br>\n");
  70.         }
  71.         if($this->Remote) {
  72.           if($this->Debug) {
  73.             printf("<br>connect() $this->User/******@$this->Database.world<br>\n");
  74.           }
  75.           $this->Link_ID=ora_plogon
  76.                  ("$this->User/$this->Password@$this->Database","");
  77.           /************** (comment by SSilk)
  78.            this dosn't work on my system:
  79.           $this->Link_ID=ora_plogon
  80.                  ("$this->User@$this->Database.world","$this->Password");
  81.           ***************/
  82.         } else {
  83.           if($this->Debug) {
  84.             printf("<br>connect() $this->User, $this->Password <br>\n");
  85.           }
  86.           $this->Link_ID=ora_plogon("$this->User","$this->Password");
  87.           /* (comment by SSilk: don't know how this could work, but I leave this untouched!) */
  88.         }
  89.         if($this->Debug) {
  90.           printf("<br>connect() Link_ID: $this->Link_ID<br>\n");
  91.         }
  92.         if (!$this->Link_ID) {
  93.           $this->halt("connect() Link-ID == false " .
  94.                  "($this->Link_ID), ora_plogon failed");
  95.         } else {
  96.             //echo "commit on<p>";
  97.           ora_commiton($this->Link_ID);
  98.         }
  99.         if($this->Debug) {
  100.           printf("<br>connect() Obtained the Link_ID: $this->Link_ID<br>\n");
  101.         }
  102.       }
  103.   }
  104.  
  105.   ## In order to increase the # of cursors per system/user go edit the
  106.   ## init.ora file and increase the max_open_cursors parameter. Yours is on
  107.   ## the default value, 100 per user.
  108.   ## We tried to change the behaviour of query() in a way, that it tries
  109.   ## to safe cursors, but on the other side be carefull with this, that you
  110.   ## don't use an old result.
  111.   ##
  112.   ## You can also make extensive use of ->disconnect()!
  113.   ## The unused QueryIDs will be recycled sometimes.
  114.  
  115.   function query($Query_String) {
  116.  
  117.     /* No empty queries, please, since PHP4 chokes on them. */
  118.     if ($Query_String == "")
  119.       /* The empty query string is passed on from the constructor,
  120.        * when calling the class without a query, e.g. in situations
  121.        * like these: '$db = new DB_Sql_Subclass;'
  122.        */
  123.       return 0;
  124.  
  125.       $this->connect();
  126.       $this->lastQuery=$Query_String;
  127.  
  128.       if (!$this->Query_ID) {
  129.           $this->Query_ID= ora_open($this->Link_ID);
  130.       }
  131.       if($this->Debug) {
  132.         printf("Debug: query = %s<br>\n", $Query_String);
  133.         printf("<br>Debug: Query_ID: %d<br>\n", $this->Query_ID);
  134.       }
  135.  
  136.       if(!@ora_parse($this->Query_ID,$Query_String)) {
  137.         $this->Errno=ora_errorcode($this->Query_ID);
  138.         $this->Error=ora_error($this->Query_ID);
  139.         $this->halt("<BR>ora_parse() failed:<BR>$Query_String<BR><small>Snap & paste this to sqlplus!</SMALL>");
  140.       } elseif (!@ora_exec($this->Query_ID)) {
  141.         $this->Errno=ora_errorcode($this->Query_ID);
  142.         $this->Error=ora_error($this->Query_ID);
  143.         $this->halt("<BR>\n$Query_String\n<BR><small>Snap & paste this to sqlplus!</SMALL>");
  144.       }
  145.  
  146.       $this->Row=0;
  147.  
  148.       if(!$this->Query_ID) {
  149.         $this->halt("Invalid SQL: ".$Query_String);
  150.       }
  151.  
  152.       return $this->Query_ID;
  153.   }
  154.  
  155.   function next_record() {
  156.       if (!$this->no_next_fetch &&
  157.           0 == ora_fetch($this->Query_ID)) {
  158.           if ($this->Debug) {
  159.             printf("<br>next_record(): ID: %d,Rows: %d<br>\n",
  160.             $this->Query_ID,$this->num_rows());
  161.           }
  162.           $this->Row    +=1;
  163.  
  164.           $errno=ora_errorcode($this->Query_ID);
  165.           if(1403 == $errno) { # 1043 means no more records found
  166.               $this->Errno=0;
  167.               $this->Error="";
  168.               $this->disconnect();
  169.               $stat=0;
  170.           } else {
  171.               $this->Error=ora_error($this->Query_ID);
  172.               $this->Errno=$errno;
  173.               if($this->Debug) {
  174.                   printf("<br>%d Error: %s",
  175.                          $this->Errno,
  176.                          $this->Error);
  177.               }
  178.               $stat=0;
  179.           }
  180.       } else {
  181.         $this->no_next_fetch=false;
  182.           for($ix=0;$ix<ora_numcols($this->Query_ID);$ix++) {
  183.               $col=strtolower(ora_columnname($this->Query_ID,$ix));
  184.               $value=ora_getcolumn($this->Query_ID,$ix);
  185.               $this->Record[ "$col" ] = $value;
  186. #              echo"<b>[$col]</b>: $value <br>\n";
  187.           }
  188.           $stat=1;
  189.       }
  190.  
  191.   return $stat;
  192.   }
  193.  
  194.   ## seek() works only for $pos - 1 and $pos
  195.   ## Perhaps I make a own implementation, but my
  196.   ## opinion is, that this should be done by PHP3
  197.   function seek($pos) {
  198.       if       ($this->Row - 1 == $pos) {
  199.         $this->no_next_fetch=true;
  200.       } elseif ($this->Row == $pos ) {
  201.     ## do nothing
  202.       } else {
  203.         $this->halt("Invalid seek(): Position is cannot be handled by API.<BR>".
  204.               "Difference too big. Wanted: $pos Current pos: $this->Row");
  205.       }
  206.       if ($Debug) echo "<BR>Debug: seek = $pos<BR>";
  207.       $this->Row=$pos;
  208.   }
  209.  
  210.   function lock($table, $mode = "write") {
  211.     if ($mode == "write") {
  212.       $result = ora_do($this->Link_ID, "lock table $table in row exclusive mode");
  213.     } else {
  214.       $result = 1;
  215.     }
  216.     return $result;
  217.   }
  218.  
  219.   function unlock() {
  220.     return ora_do($this->Link_ID, "commit");
  221.   }
  222.  
  223.   function metadata($table,$full=false) {
  224.       $count = 0;
  225.       $id    = 0;
  226.       $res   = array();
  227.  
  228.     /*
  229.      * Due to compatibility problems with Table we changed the behavior
  230.      * of metadata();
  231.      * depending on $full, metadata returns the following values:
  232.      *
  233.      * - full is false (default):
  234.      * $result[]:
  235.      *   [0]["table"]  table name
  236.      *   [0]["name"]   field name
  237.      *   [0]["type"]   field type
  238.      *   [0]["len"]    field length
  239.      *   [0]["flags"]  field flags ("NOT NULL", "INDEX")
  240.      *   [0]["format"] precision and scale of number (eg. "10,2") or empty
  241.      *   [0]["index"]  name of index (if has one)
  242.      *   [0]["chars"]  number of chars (if any char-type)
  243.      *
  244.      * - full is true
  245.      * $result[]:
  246.      *   ["num_fields"] number of metadata records
  247.      *   [0]["table"]  table name
  248.      *   [0]["name"]   field name
  249.      *   [0]["type"]   field type
  250.      *   [0]["len"]    field length
  251.      *   [0]["flags"]  field flags ("NOT NULL", "INDEX")
  252.      *   [0]["format"] precision and scale of number (eg. "10,2") or empty
  253.      *   [0]["index"]  name of index (if has one)
  254.      *   [0]["chars"]  number of chars (if any char-type)
  255.      *   ["meta"][field name]  index of field named "field name"
  256.      *   The last one is used, if you have a field name, but no index.
  257.      *   Test:  if (isset($result['meta']['myfield'])) {} ...
  258.      */
  259.  
  260.       $this->connect();
  261.  
  262.       ## This is a RIGHT OUTER JOIN: "(+)", if you want to see, what
  263.       ## this query results try the following:
  264.       ## $table = new Table; $db = new my_DB_Sql; # you have to make
  265.       ##                                          # your own class
  266.       ## $table->show_results($db->query(see query vvvvvv))
  267.       ##
  268.       $this->query("SELECT T.table_name,T.column_name,T.data_type,".
  269.            "T.data_length,T.data_precision,T.data_scale,T.nullable,".
  270.            "T.char_col_decl_length,I.index_name".
  271.            " FROM ALL_TAB_COLUMNS T,ALL_IND_COLUMNS I".
  272.            " WHERE T.column_name=I.column_name (+)".
  273.            " AND T.table_name=I.table_name (+)".
  274.            " AND T.table_name=UPPER('$table') ORDER BY T.column_id");
  275.  
  276.       $i=0;
  277.       while ($this->next_record()) {
  278.         $res[$i]["table"] =  $this->Record[table_name];
  279.         $res[$i]["name"]  =  strtolower($this->Record[column_name]);
  280.         $res[$i]["type"]  =  $this->Record[data_type];
  281.         $res[$i]["len"]   =  $this->Record[data_length];
  282.         if ($this->Record[index_name]) $res[$i]["flags"] = "INDEX ";
  283.         $res[$i]["flags"] .= ( $this->Record[nullable] == 'N') ? '' : 'NOT NULL';
  284.         $res[$i]["format"]=  (int)$this->Record[data_precision].",".
  285.                              (int)$this->Record[data_scale];
  286.         if ("0,0"==$res[$i]["format"]) $res[$i]["format"]='';
  287.         $res[$i]["index"] =  $this->Record[index_name];
  288.         $res[$i]["chars"] =  $this->Record[char_col_decl_length];
  289.         if ($full) {
  290.             $j=$res[$i]["name"];
  291.             $res["meta"][$j] = $i;
  292.             $res["meta"][strtoupper($j)] = $i;
  293.         }
  294.         if ($full) $res["meta"][$res[$i]["name"]] = $i;
  295.         $i++;
  296.       }
  297.       if ($full) $res["num_fields"]=$i;
  298. #      $this->disconnect();
  299.       return $res;
  300.   }
  301.  
  302.   ## THIS FUNCTION IS UNSTESTED!
  303.   function affected_rows() {
  304.     if ($Debug) echo "<BR>Debug: affected_rows=". ora_numrows($this->Query_ID)."<BR>";
  305.     return ora_numrows($this->Query_ID);
  306.   }
  307.  
  308.   ## Known bugs: It will not work for SELECT DISTINCT and any
  309.   ## other constructs which are depending on the resulting rows.
  310.   ## So you *really need* to check every query you make, if it
  311.   ## will work with it.
  312.   ##
  313.   ## Also, for a qualified replacement you need to parse the
  314.   ## selection, cause this will fail: "SELECT id, from FROM ...").
  315.   ## "FROM" is - as far as I know a keyword in Oracle, so it can
  316.   ## only be used in this way. But you have been warned.
  317.   function num_rows() {
  318.     $curs=ora_open($this->Link_ID);
  319.  
  320.     ## this is the important part and it is also the HACK!
  321.     if (eregi("^[[:space:]]*SELECT[[:space:]]",$this->lastQuery) ) {
  322.       $from_pos = strpos(strtoupper($this->lastQuery),"FROM");
  323.       $q = "SELECT count(*) ". substr($this->lastQuery, $from_pos);
  324.  
  325.       ORA_parse($curs,$q);
  326.       ORA_exec($curs);
  327.       ORA_fetch($curs);
  328.       if ($Debug) echo "<BR>Debug: num_rows=". ORA_getcolumn($curs,0)."<BR>";
  329.       return(ORA_getcolumn($curs,0));
  330.     } else {
  331.       $this->halt("Last Query was not a SELECT: $this->lastQuery");
  332.     }
  333.   }
  334.  
  335.   function num_fields() {
  336.       if ($Debug) echo "<BR>Debug: num_fields=". ora_numcols($this->Query_ID) . "<BR>";
  337.       return ora_numcols($this->Query_ID);
  338.   }
  339.  
  340.   function nf() {
  341.     return $this->num_rows();
  342.   }
  343.  
  344.   function np() {
  345.     print $this->num_rows();
  346.   }
  347.  
  348.   function f($Name) {
  349.     return $this->Record[$Name];
  350.   }
  351.  
  352.   function p($Name) {
  353.     print $this->Record[$Name];
  354.   }
  355.  
  356.   /* public: sequence number */
  357.   function nextid($seq_name)
  358.   {
  359.       $this->connect();
  360.  
  361.       /* Independent Query_ID */
  362.       $Query_ID = ora_open($this->Link_ID);
  363.  
  364.       if(!@ora_parse($Query_ID,"SELECT $seq_name.NEXTVAL FROM DUAL"))
  365.       {
  366.         // There is no such sequence yet, then create it
  367.         if(!@ora_parse($Query_ID,"CREATE SEQUENCE $seq_name")
  368.            ||
  369.            !@ora_exec($Query_ID)
  370.            )
  371.         {
  372.             $this->halt("<BR> nextid() function - unable to create sequence");
  373.             return 0;
  374.         }
  375.         @ora_parse($Query_ID,"SELECT $seq_name.NEXTVAL FROM DUAL");
  376.       }
  377.       if (!@ora_exec($Query_ID)) {
  378.         $this->halt("<BR>ora_exec() failed:<BR>nextID function");
  379.       }
  380.       if (@ora_fetch($Query_ID) ) {
  381.         $next_id =  ora_getcolumn($Query_ID, 0);
  382.       }
  383.       else {
  384.         $next_id = 0;
  385.       }
  386.       if ( Query_ID > 0 ) {
  387.         ora_close(Query_ID);
  388.       }
  389.  
  390.       return $next_id;
  391.   }
  392.  
  393.   function disconnect() {
  394.       if($this->Debug) {
  395.           echo "Debug: Disconnecting $this->Query_ID...<br>\n";
  396.       }
  397.       if ( $this->Query_ID < 1 ) {
  398.         echo "<B>Warning</B>: disconnect(): Cannot free ID $this->Query_ID\n";
  399. #        return();
  400.       }
  401.       ora_close($this->Query_ID);
  402.       $this->Query_ID=0;
  403.   }
  404.  
  405.   /* private: error handling */
  406.   function halt($msg) {
  407.     if ($this->Halt_On_Error == "no")
  408.       return;
  409.  
  410.     $this->haltmsg($msg);
  411.  
  412.     if ($this->Halt_On_Error != "report")
  413.       die("Session halted.");
  414.   }
  415.  
  416.   function haltmsg($msg) {
  417.     printf("</td></tr></table><b>Database error:</b> %s<br>\n", $msg);
  418.     printf("<b>Oracle Error</b>: %s (%s)<br>\n",
  419.       $this->Errno,
  420.       $this->Error);
  421.   }
  422.  
  423.   function table_names() {
  424.    $this->connect();
  425.    $this->query("
  426.    SELECT table_name,tablespace_name
  427.      FROM user_tables");
  428.    $i=0;
  429.    while ($this->next_record())
  430.    {
  431.    $info[$i]["table_name"]     =$this->Record["table_name"];
  432.    $info[$i]["tablespace_name"]=$this->Record["tablespace_name"];
  433.    $i++;
  434.    }
  435.   return $info;
  436.   }
  437. }
  438. ?>
  439.