Source for file oci8_class.php

Documentation is available at oci8_class.php

  1. <?php
  2. /**
  3.  * Oracle Database Class.
  4.  *
  5.  * Database Class provides a consistent API to communicate with MySQL or Oracle Databases.
  6.  * This one implements the OCI8 API.
  7.  * Requires dbdefs.inc.php for global access data (user,pw,host,appname)
  8.  *
  9.  * - Connect() / Disconnect()
  10.  * - Print_Error() / GetErrorText()
  11.  * - Query() / QueryResult() / FetchResult() / FreeResult()
  12.  * - Version() / GetClassVersion() / GetQueryCount()
  13.  * - Commit() / Rollback()
  14.  * - SetDebug() / PrintDebug() / SQLDebug()
  15.  * - GetBindVars() - PRIVATE!
  16.  * - DescTable()
  17.  * - Prepare() / Execute() / ExecuteHash()
  18.  * - SearchQueryCache() / RemoveFromQueryCache()
  19.  * - checkSock()
  20.  * - GetConnectionHandle() / SetConnectionHandle()
  21.  * - QueryHash() / QueryResultHash()
  22.  * - AffectedRows()
  23.  * - setErrorHandling() / getSQLError()
  24.  * - setPrefetch()
  25.  * - getOutputHash() / setOutputHash() / clearOutputHash()
  26.  * - SendEmailOnError()
  27.  * - setPConnect()
  28.  * - setConnectRetries() / getConnectRetries()
  29.  * @package db_oci8
  30.  * @author Sascha 'SieGeL' Pfalz <php@saschapfalz.de>
  31.  * @version 0.78 (28-Mar-2009)
  32.  *  $Id: oci8_class.php,v 1.14 2009/09/22 20:11:42 siegel Exp $
  33.  * @license http://opensource.org/licenses/bsd-license.php BSD License
  34.  * @filesource
  35.  */
  36. /**
  37.  * DEBUG: No Debug Info
  38.  */
  39. if(!defined('DBOF_DEBUGOFF'))
  40.   {
  41.   define('DBOF_DEBUGOFF'    (<< 0));
  42.   }
  43.  
  44. /**
  45.  * DEBUG: Debug on-screen
  46.  */
  47. if(!defined('DBOF_DEBUGSCREEN'))
  48.   {
  49.   define('DBOF_DEBUGSCREEN' (<< 1));
  50.   }
  51. /**
  52.  * DEBUG: Debug to error_log()
  53.  */
  54. if(!defined('DBOF_DEBUGFILE'))
  55.   {
  56.   define('DBOF_DEBUGFILE'   (<< 2));
  57.   }
  58.  
  59. /**#@+
  60.  * These defines are used in DescTable()
  61.  * @see DescTable
  62.  */
  63. define('DBOF_COLNAME'0);
  64. define('DBOF_COLTYPE'1);
  65. define('DBOF_COLSIZE'2);
  66. define('DBOF_COLPREC'3);
  67. /**#@-*/
  68.  
  69. /**#@+
  70.  * Used for Query Cache (V0.38+)
  71.  */
  72. if(!defined('DBOF_CACHE_QUERY'))
  73.   {
  74.   define('DBOF_CACHE_QUERY'     0);
  75.   }
  76. if(!defined('DBOF_CACHE_STATEMENT'))
  77.   {
  78.   define('DBOF_CACHE_STATEMENT' 1);
  79.   }
  80. /**#@-*/
  81.  
  82. /**#@+
  83.  * Connect and error handling (V0.57+).
  84.  * If NO_ERRORS is set and an error occures, the class still reports an
  85.  * an error of course but the error shown is reduced to avoid showing
  86.  * sensible informations in a productive environment.
  87.  * Set RETURN_ALL_ERRORS if you want to handle errors yourself.
  88.  */
  89. if(!defined('DBOF_SHOW_NO_ERRORS'))
  90.   {
  91.   define('DBOF_SHOW_NO_ERRORS'    0);
  92.   define('DBOF_SHOW_ALL_ERRORS'   1);
  93.   define('DBOF_RETURN_ALL_ERRORS' 2);
  94.   }
  95. /**#@-*/
  96.  
  97. /**
  98.  * OCI8 Database Class.
  99.  * @package db_oci8
  100.  */
  101. class db_oci8
  102.   {
  103.   /** @var mixed $sock Internal connection handle. */
  104.   var $sock;
  105.   /** @var string $host The TNS name of the target database. */
  106.   var $host;
  107.   /** @var string $user The username used to connect to database. */
  108.   var $user;
  109.   /** @var string $user The password used to connect to database. */
  110.   var $password;
  111.   /** @var string $database Currently not in use. */
  112.   var $database;
  113.   /** @var integer $querycounter Counts amount of queries executed. */
  114.   var $querycounter;
  115.   /** @var float $querytime Contains the total SQL execution time in microseconds. */
  116.   var $querytime;
  117.   /** @var mixed $stmt Stores active statement handle. */
  118.   var $stmt;
  119.   /** @var string $appname Name of application that uses this class. */
  120.   var $appname;
  121.   /** @var integer $debug Debugstate, default is OFF. */
  122.   var $debug;
  123.   /** @var string $sqlerr Contains possible SQL query that failed. */
  124.   var $sqlerr;
  125.   /** @var string $sqlerrmsg Contains ocierror['message'] info in case of an error. */
  126.   var $sqlerrmsg;
  127.   /** @var array $sqlcache Internal Cache for Prepare()/Execute() calls. */
  128.   var $sqlcache;
  129.   /** @var string All passed variables except QUERY and Flags. */
  130.   var $errvars;
  131.   /** @var integer Set to 1 to not auto-exit on error (Default is 0) */
  132.   var $no_exit;
  133.   /** @var integer How many SQL queries have been executed */
  134.   var $sqlcount;
  135.   /** @var integer How many Rows where affected by previous DML operation */
  136.   var $AffectedRows;
  137.   /** @var integer Flag indates level of error information shown */
  138.   var $showError;
  139.   /** @var string Email Address for the administrator of this project */
  140.   var $AdminEmail;
  141.   /** @var string The SAPI type of php (used to detect CLI sapi) */
  142.   var $SAPI_type;
  143.   /** @var array A hash array with all output parameters (used in QueryHash()) */
  144.   var $output_hash;
  145.   /** @var boolean TRUE = Connect() uses Persistant connection, else new one (Default) */
  146.   var $usePConnect;
  147.   /**
  148.    * @var integer How many connection retries we should try. Defaults to 1
  149.    * @since 0.75
  150.    */
  151.   var $connectRetries;
  152.  
  153.   /**
  154.    * Class Constructor.
  155.    * Whenever you instantiate this class the file dbdefs.inc.php will be included automatically.
  156.    * This file contains the default login data and other configuration options, see description
  157.    * inside this file for further informations.
  158.    * Since V0.72 you may optionally give an alternate file as configuration file. If no file is
  159.    * given inside the constructor the class still uses the file "dbdefs.inc.php" as default
  160.    * configuration file.
  161.    * @param string $extconfig Full path to dbdefs.inc.php, if empty class searches in current dir for dbdefs.inc.php
  162.    * @see dbdefs.inc.php
  163.    */
  164.   function db_oci8($extconfig='')
  165.     {
  166.     if($extconfig == '')
  167.       {
  168.       include_once('dbdefs.inc.php');
  169.       }
  170.     else
  171.       {
  172.       include($extconfig);
  173.       }
  174.     $this->classversion   '0.78';                   // Version of our class
  175.     $this->host           = '';                       // TNS Name of DB to connect to
  176.     $this->user           = '';                       // Username
  177.     $this->pass           '';                       // Password
  178.     $this->appname        = OCIAPPNAME;               // Name of our Application
  179.     $this->database       = '';                       // Oracle does not use this
  180.     $this->sock           = 0;                        // Internal database handle
  181.     $this->querycounter   = 0;                        // How many queries where executed
  182.     $this->querytime      = 0.000;                    // Time required for all queries
  183.     $this->stmt           = NULL;                     // Oracle Statement handler
  184.     $this->debug          = 0;                        // Debug is off per default
  185.     $this->sqlcache       = array();                  // Internal SQL cache for Prepare()/Execute()
  186.     $this->sqlerr         = '';                       // Contains possible SQL query that failed
  187.     $this->sqlerrmsg      = '';                       // Contains ocierror['message'] info
  188.     $this->errvars        = array();                  // All passed variables except QUERY and Flags
  189.     $this->no_exit        = 0;                        // Flag for Prepare/Execute pair to indicate if we should exit
  190.     $this->sqlcount       = 0;                        // Counter for Prepare/Execute pair to reference correct query
  191.     $this->AffectedRows   = 0;                        // Amount of rows processed during statement execution
  192.     $this->showError      = 0;                        // Flag for Error processing.
  193.     $this->AdminEmail     = (isset($_SERVER['SERVER_ADMIN'])) $_SERVER['SERVER_ADMIN'''// Defaults to Webadministrator of Server
  194.     $this->SAPI_type      = @php_sapi_name();         // May contain 'cli', in this case disable HTML errors!
  195.     $this->output_hash    = array();                  // Set to empty array in initial call
  196.     $this->usePConnect    = FALSE;                    // Set to TRUE to use Persistant connections
  197.     $this->connectRetries = 1;                        // How many retries we should perform when connecting to Oracle.
  198.  
  199.     if(!defined('OCIAPPNAME'))
  200.       {
  201.       $this->Print_Error('dbdefs.inc.php is wrong configured! Please check Class installation!');
  202.       }
  203.     if(defined('DB_ERRORMODE'))                     // You can set a default behavour for error handling in dbdefs.inc.php
  204.       {
  205.       $this->setErrorHandling(DB_ERRORMODE);
  206.       }
  207.     else
  208.       {
  209.       $this->setErrorHandling(DBOF_SHOW_NO_ERRORS)// Default is not to show too much informations
  210.       }
  211.     if(defined('OCIDB_ADMINEMAIL'))
  212.       {
  213.       $this->AdminEmail = OCIDB_ADMINEMAIL;         // If set use this address instead of default webmaster
  214.       }
  215.     if(defined('OCIDB_USE_PCONNECT'&& OCIDB_USE_PCONNECT != 0)
  216.       {
  217.       $this->usePConnect = TRUE;
  218.       }
  219.     if(defined('OCIDB_CONNECT_RETRIES'&& OCIDB_CONNECT_RETRIES 1)
  220.       {
  221.       $this->connectRetries = OCIDB_CONNECT_RETRIES;
  222.       }
  223.     }
  224.  
  225.   /**
  226.    * Performs the connection to Oracle.
  227.    * If anything goes wrong calls Print_Error().
  228.    * Also an Oracle procedure is called to register the Application name
  229.    * as defined in dbdefs.inc.php, This helps DBAs to better fine tune
  230.    * their databases according to application needs.
  231.    * @see dbdefs.inc.php
  232.    * @see Print_Error()
  233.    * @param string $user Username used to connect to DB
  234.    * @param string $pass Password to use for given username
  235.    * @param string $host Hostname of database to connect to
  236.    * @param integer $exit_on_error If set to 1 Class will automatically exit with error code, else return error array
  237.    * @return mixed Either the DB connection handle or an error array/exit, depending how $exit_on_error is set
  238.    * @see oci_logon
  239.    * @see oci_plogon
  240.    */
  241.   function Connect($user=NULL,$pass=NULL,$host=NULL,$exit_on_error 1)
  242.     {
  243.     $connquery '';
  244.     $connretry 0;
  245.  
  246.     if($this->sock)
  247.       {
  248.       return($this->sock);
  249.       }
  250.     if(isset($user&& $user!=NULL)
  251.       {
  252.       $this->user = $user;
  253.       }
  254.     else
  255.       {
  256.       $this->user = OCIDB_USER;
  257.       }
  258.     if(isset($pass&& $pass!=NULL)
  259.       {
  260.       $this->pass $pass;
  261.       }
  262.     else
  263.       {
  264.       $this->pass OCIDB_PASS;
  265.       }
  266.     if(isset($host&& $host!=NULL)
  267.       {
  268.       $this->host = $host;
  269.       }
  270.     else
  271.       {
  272.       $this->host = OCIDB_HOST;
  273.       }
  274.     $this->printDebug('OCILogon('.sprintf("%s/%s@%s",$this->user,$this->pass,$this->host).')');
  275.     $start $this->getmicrotime();
  276.     do
  277.       {
  278.       if($this->usePConnect == TRUE)
  279.         {
  280.         $this->sock = @OCIPLogon($this->user,$this->pass,$this->host);
  281.         }
  282.       else
  283.         {
  284.         $this->sock = @OCILogon($this->user,$this->pass,$this->host);
  285.         }
  286.       if(!$this->sock && $this->connectRetries > 1)
  287.         {
  288.         sleep(2);   // Wait short time and retry:
  289.         }
  290.       $connretry++;
  291.       }while($connretry $this->connectRetries);
  292.     if(!$this->sock)
  293.       {
  294.       $this->Print_Error('Connection to "'.$this->host.'" failed!',NULL,$exit_on_error);
  295.       return(0);
  296.       }
  297.     if(defined('DB_REGISTER'&& DB_REGISTER == 1)
  298.       {
  299.       $connquery.= " DBMS_APPLICATION_INFO.SET_MODULE('".$this->appname."',NULL); ";
  300.       }
  301.     if(defined('DB_SET_NUMERIC'&& DB_SET_NUMERIC == 1)
  302.       {
  303.       if(!defined('DB_NUM_DECIMAL'|| !defined('DB_NUM_GROUPING'))
  304.         {
  305.         $this->Disconnect();
  306.         $this->setErrorHandling(DBOF_SHOW_ALL_ERRORS);
  307.         $this->Print_Error('You have to define DB_NUM_DECIMAL/DB_NUM_GROUPING in dbdefs.inc.php first !!!');
  308.         exit;
  309.         }
  310.       $connquery.= " EXECUTE IMMEDIATE 'ALTER SESSION SET NLS_NUMERIC_CHARACTERS = ''".DB_NUM_DECIMAL.DB_NUM_GROUPING."'''; ";
  311.       }
  312.     if($connquery != "")
  313.       {
  314.       $dummy "BEGIN ";
  315.       $dummy.= $connquery;
  316.       $dummy.= " END;";
  317.       $this->Query($dummy,OCI_ASSOC,0);
  318.       }
  319.     $this->querytime+= ($this->getmicrotime($start);
  320.     return($this->sock);
  321.     }
  322.  
  323.   /**
  324.    * Disconnects from Oracle.
  325.    * You may optionally pass an external link identifier
  326.    * @param mixed $other_sock Optionally your own connection handle to close,
  327.    *  else internal socket will be used.
  328.    * @see OCI_Logoff
  329.    */
  330.   function Disconnect($other_sock=-1)
  331.     {
  332.     $start $this->getmicrotime();
  333.     if($other_sock!=-1)
  334.       {
  335.       @OCILogoff($other_sock);
  336.       }
  337.     else
  338.       {
  339.       if($this->sock)
  340.         {
  341.         @OCILogoff($this->sock);
  342.         $this->sock = 0;
  343.         }
  344.       }
  345.     $this->querytime+= ($this->getmicrotime($start);
  346.     $this->AffectedRows = 0;
  347.     $this->sqlerr       = 0;
  348.     $this->sqlerrmsg    = '';
  349.     }
  350.  
  351.   /**
  352.    * Prints out an Oracle error.
  353.    * Tries to highlight the buggy SQL part of the query and dumps out
  354.    * as much informations as possible. This may lead however to
  355.    * security problems, in this case you can set DBOF_SHOW_NO_ERRORS
  356.    * and the Error informations are returned to the callee instead of
  357.    * being displayed on-screen.
  358.    * Since V0.64 the class is able to send an email error message, see dbdefs.inc.php
  359.    *
  360.    * @param string $ustr Optional user-error string to be displayed
  361.    * @param mixed $var2dump Optional a variable to be dumped out via print_r()
  362.    * @param integer $exit_on_error If set to default of 1 this function terminates
  363.    *  execution of the script by calling exit, else it simply returns.
  364.    * @see print_r
  365.    * @see oci_error
  366.    */
  367.   function Print_Error($ustr='',$var2dump=NULL$exit_on_error 1)
  368.     {
  369.     if($this->stmt)
  370.       {
  371.       $earr @OCIError($this->stmt);
  372.       }
  373.     elseif($this->sock)
  374.       {
  375.       $earr @OCIError($this->sock);
  376.       }
  377.     else
  378.       {
  379.       $earr @OCIError();
  380.       }
  381.     $errstr   $earr['message'];
  382.     $errnum   $earr['code'];
  383.     $sqltext  $earr['sqltext'];
  384.     $sqlerrposintval($earr['offset']);
  385.     if($errnum == '')
  386.       {
  387.       $errnum = -1;
  388.       }
  389.     if($errstr == '')
  390.       {
  391.       $errstr 'N/A';
  392.       }
  393.     if($sqltext=="")
  394.       {
  395.       if($this->sqlerr!='')
  396.         {
  397.         $sqltext $this->sqlerr;
  398.         }
  399.       else
  400.         {
  401.         $sqltext 'N/A';
  402.         }
  403.       }
  404.     $this->sqlerrmsg = $errstr;
  405.     if($this->showError == DBOF_RETURN_ALL_ERRORS)
  406.       {
  407.       return($errnum);      // Return the error number
  408.       }
  409.     $this->SendMailOnError($earr);
  410.     $filename basename($_SERVER['SCRIPT_FILENAME']);
  411.     if($this->sock)
  412.       {
  413.       $this->Rollback();
  414.       $this->Disconnect();
  415.       }
  416.     $crlf "\n";
  417.     $space" ";
  418.     if($this->SAPI_type != 'cli')
  419.       {
  420.       $crlf "<br>\n";
  421.       $space"&nbsp;";
  422.       echo("<br>\n<div align=\"left\" style=\"background-color: #EEEEEE; color:#000000\" class=\"TB\">\n");
  423.       echo("<font color=\"red\" face=\"Arial, Sans-Serif\"><b>".$this->appname.": Database Error occured!</b></font><br>\n<br>\n<code>\n");
  424.       }
  425.     else
  426.       {
  427.       echo("\n!!! ".$this->appname.": Database Error occured !!!\n\n");
  428.       }
  429.     echo('CODE: '.$errnum.$crlf);
  430.     echo('DESC: '.rtrim($errstr).$crlf);
  431.     echo('FILE: '.$filename.$crlf);
  432.     if($this->showError == DBOF_SHOW_ALL_ERRORS)
  433.       {
  434.       if($ustr!='')
  435.         {
  436.         echo('INFO: '.$ustr.$crlf);
  437.         }
  438.       if($sqlerrpos)
  439.         {
  440.         if($this->SAPI_type != 'cli')
  441.           {
  442.           $dummy substr($sqltext,0,$sqlerrpos);
  443.           $dummy.='<font color="red">'.substr($sqltext,$sqlerrpos).'</font>';
  444.           $errquery $dummy;
  445.           }
  446.         else
  447.           {
  448.           $errquery $sqltext;
  449.           }
  450.         }
  451.       else
  452.         {
  453.         $errquery $sqltext;
  454.         }
  455.       echo($space."SQL: ".$errquery.$crlf);
  456.       echo($space."POS: ".$sqlerrpos.$crlf);
  457.       echo("QCNT: ".$this->querycounter.$crlf);
  458.       if(count($this->errvars))
  459.         {
  460.         echo("VALS: ");
  461.         reset($this->errvars);
  462.         $i 0;
  463.         $errbuf '';
  464.         while(list($key,$valeach($this->errvars))
  465.           {
  466.           if(!is_numeric($key))
  467.             {
  468.             $errbuf.=sprintf("P['%s']=>'%s' [%d]".$crlf,($key),$val,strlen($val));
  469.             }
  470.           else
  471.             {
  472.             $errbuf.=sprintf("P[%d]='%s'".$crlf,($i+1),$val);
  473.             }
  474.           $i++;
  475.           }
  476.         echo($errbuf.$crlf);
  477.         }
  478.       if(isset($var2dump))
  479.         {
  480.         if($this->SAPI_type != 'cli')
  481.           {
  482.           echo("DUMP: <pre>");
  483.           print_r($var2dump);
  484.           echo("</pre>");
  485.           }
  486.         else
  487.           {
  488.           echo("DUMP:\n");
  489.           print_r($var2dump);
  490.           }
  491.         }
  492.       }
  493.     if($this->SAPI_type != 'cli')
  494.       {
  495.       echo("<br>\nPlease inform <a href=\"mailto:".$this->AdminEmail."\">".$this->AdminEmail."</a> about this problem.");
  496.       echo("</code>\n");
  497.       echo("</div>\n");
  498.       echo("<div align=\"right\"><small>PHP V".phpversion()." / OCI8 Class v".$this->classversion."</small></div>\n");
  499.       @error_log($this->appname.': Error in '.$filename.': '.$ustr.' ('.chop($errstr).')',0);
  500.       }
  501.     else
  502.       {
  503.       echo("\nPlease inform ".$this->AdminEmail." about this problem.\n\nRunning on PHP V".phpversion()." / OCI8 Class v".$this->classversion."\n");
  504.       }
  505.     if($exit_on_errorexit;
  506.     }
  507.  
  508.   /**
  509.    * Performs a single row query with Bindvar support.
  510.    * Resflag can be OCI_NUM or OCI_ASSOC depending on what kind of array you want to be returned.
  511.    * Remember to pass all required variables for all defined bind vars after
  512.    * the $no_exit parameter, else you will recieve errors because of wrong parameter count!
  513.    * @param string $querystring The query to be executed against the RDBMS
  514.    * @param integer $resflag OCI_NUM for numeric array or OCI_ASSOC (default) for associative array result
  515.    * @param integer $no_exit 1 => Function returns errorcode instead of calling Print_Error() or 0 => Will always call Print_Error()
  516.    * @return array The result of the query as either associative or numeric array.
  517.    *  In case of an error can be also an assoc. array of error informations.
  518.    */
  519.   function Query($querystring$resflag OCI_ASSOC$no_exit 0)
  520.     {
  521.     $querystring        ltrim($querystring);    // Leading spaces seems to be a problem??
  522.     $resarr             array();
  523.     $this->errvars      = array();
  524.     $funcargs           @func_num_args();
  525.     $this->sqlerr       = $querystring;
  526.     $this->AffectedRows = 0;
  527.     $stmt               NULL;
  528.  
  529.     $this->checkSock();
  530.     if($querystring == '')
  531.       {
  532.       return($this->Print_Error('Query(): No querystring was supplied!'));
  533.       }
  534.     if($funcargs 3)
  535.       {
  536.       $this->errvars = array_slice(func_get_args(),3);
  537.       $res $this->GetBindVars($querystring);
  538.       if(($funcargs-3!= count($res))
  539.         {
  540.         return($this->Print_Error("Query(): Parameter count does not match bind var count in query! (Defined: ".count($res)." - Supplied: ".($funcargs).")",$res));
  541.         exit;
  542.         }
  543.       }
  544.     if($this->debug)
  545.       {
  546.       $this->PrintDebug($querystring);
  547.       }
  548.     $start $this->getmicrotime();
  549.     $stmt @OCIParse($this->sock,$querystring);
  550.     if(!$stmt)
  551.       {
  552.       return($this->Print_Error('Query(): Parse failed!'));
  553.       exit;
  554.       }
  555.     if($funcargs 3)
  556.       {
  557.       for($i 3$i $funcargs$i++)
  558.         {
  559.         $arg[$i@func_get_arg($i);
  560.         @OCIBindByName($stmt,$res[$i-3],$arg[$i],-1);
  561.         }
  562.       }
  563.     if(!@OCIExecute($stmt,OCI_DEFAULT))
  564.       {
  565.       if($no_exit)
  566.         {
  567.         $err @OCIError($stmt);
  568.         $this->sqlerrmsg = $err['message'];
  569.         return($err['code']);
  570.         }
  571.       else
  572.         {
  573.         $this->stmt = $stmt;
  574.         return($this->Print_Error('Query(): Execute failed!'));
  575.         exit;
  576.         }
  577.       }
  578.     $this->querycounter++;
  579.     if(StriStr(substr($querystring,0,6),"SELECT"))
  580.       {
  581.       @OCIFetchInto($stmt,$resarr,$resflag+OCI_RETURN_NULLS+OCI_RETURN_LOBS);
  582.       }
  583.     else
  584.       {
  585.       $res 0;
  586.       }
  587.     $this->AffectedRows = @OCIRowCount($stmt);
  588.     @OCIFreeStatement($stmt);
  589.     $this->querytime+= ($this->getmicrotime($start);
  590.     $this->errvars = array();
  591.     return($resarr);
  592.     }
  593.  
  594.   /**
  595.    * Performs a multirow-query and returns result handle.
  596.    * Required if you want to fetch many data rows. Does not return in case
  597.    * of error, so no further checking is required.
  598.    * Supports also binding, see Query() for further details.
  599.    * @param string $querystring SQL-Statement to be executed
  600.    * @return mixed Returns the statement handle or an error array in case of an error.
  601.    * @see Query
  602.    * @see FetchResult
  603.    * @see FreeResult
  604.    */
  605.   function QueryResult($querystring)
  606.     {
  607.     $querystring        ltrim($querystring);    // Leading spaces seems to be a problem??
  608.     $funcargs           @func_num_args();
  609.     $this->sqlerr       = $querystring;
  610.     $this->errvars      = array();
  611.     $this->AffectedRows = 0;
  612.     $stmt               NULL;
  613.  
  614.     $this->checkSock();
  615.     if($querystring == "")
  616.       {
  617.       return($this->Print_Error('QueryResult(): No querystring was supplied!'));
  618.       }
  619.     if($funcargs 1)
  620.       {
  621.       $this->errvars = array_slice(func_get_args(),1);
  622.       $res $this->GetBindVars($querystring);
  623.       if(($funcargs-1!= count($res))
  624.         {
  625.         return($this->Print_Error("QueryResult(): Parameter count does not match bind var count in query! (Defined:".count($res)." - Supplied: ".($funcargs).")",$res));
  626.         }
  627.       }
  628.     if($this->debug)
  629.       {
  630.       $this->PrintDebug($querystring);
  631.       }
  632.     $start $this->getmicrotime();
  633.     $stmt @OCIParse($this->sock,$querystring);
  634.     if(!$stmt)
  635.       {
  636.       return($this->Print_Error('QueryResult(): Parse failed!'));
  637.       }
  638.  
  639.     // Check if user wishes to set a default prefetching value:
  640.  
  641.     if(defined('DB_DEFAULT_PREFETCH'))
  642.       {
  643.       $this->setPrefetch(DB_DEFAULT_PREFETCH);
  644.       }
  645.  
  646.     // If we have any of the bind vars given, bind them NOW:
  647.  
  648.     if($funcargs 1)
  649.       {
  650.       for($i 1$i $funcargs$i++)
  651.         {
  652.         $arg[$i@func_get_arg($i);
  653.         @OCIBindByName($stmt,$res[$i-1],$arg[$i],-1);
  654.         }
  655.       }
  656.     if(!@OCIExecute($stmt,OCI_DEFAULT))
  657.       {
  658.       $this->stmt = $stmt;
  659.       return($this->Print_Error('QueryResult(): Execute failed!'));
  660.       }
  661.     $this->querycounter++;
  662.     $this->querytime+= ($this->getmicrotime($start);
  663.     $this->sqlcache[$this->sqlcount][DBOF_CACHE_QUERY]     $querystring;
  664.     $this->sqlcache[$this->sqlcount][DBOF_CACHE_STATEMENT$stmt;
  665.     $this->sqlcount++;
  666.     // Result set is returned, so we return it to the caller and also store it into internal class variable if another stmt isn't already stored there:
  667.     if(is_null($this->stmt))
  668.       {
  669.       $this->stmt = $stmt;
  670.       }
  671.     return($stmt);
  672.     }
  673.  
  674.   /**
  675.    * Fetches next datarow.
  676.    * Returns either numeric (OCI_NUM) or associative (OCI_ASSOC) array
  677.    * for one data row as pointed to by either internal or passed result var.
  678.    * @param integer $resflag OCI_ASSOC => Return associative array or OCI_NUM => Return numeric array
  679.    * @param mixed $extstmt If != -1 then we try to fetch from that passed handle, else the class uses
  680.    *  internal saved handle. Useful if you want to perform a lot of different queries.
  681.    * @return array The fetched datarow or NULL if no more data exist.
  682.    * @see QueryResult
  683.    * @see FreeResult
  684.    */
  685.   function FetchResult($resflag OCI_ASSOC,$extstmt = -1)
  686.     {
  687.     if($extstmt == -1)
  688.       {
  689.       $mystate $this->stmt;
  690.       }
  691.     else
  692.       {
  693.       $mystate $extstmt;
  694.       }
  695.     $start $this->getmicrotime();
  696.     @OCIFetchInto($mystate$res$resflag+OCI_RETURN_NULLS+OCI_RETURN_LOBS);
  697.     $this->querytime+= ($this->getmicrotime($start);
  698.     return($res);
  699.     }
  700.  
  701.   /**
  702.    * Frees result obtained by QueryResult().
  703.    * You may optionally pass external Result handle, if you omit this parameter
  704.    * the internal handle is freed. This function also checks the built-in statement
  705.    * cache for the handle and removes it from cache, too.
  706.    * @param mixed $extstmt Optional your external saved handle to be freed.
  707.    * @return mixed The result of OCIFreeStatement() is returned.
  708.    * @see QueryResult
  709.    * @see FetchResult
  710.    * @see SearchQueryCache
  711.    * @see RemoveFromQueryCache
  712.    * @see OCI_Free_Statement
  713.    */
  714.   function FreeResult($extstmt = -1)
  715.     {
  716.     if($extstmt == -1)
  717.       {
  718.       $mystate $this->stmt;
  719.       $this->stmt = NULL;
  720.       }
  721.     else
  722.       {
  723.       $mystate $extstmt;
  724.       $fq $this->SearchQueryCache($extstmt);
  725.       if($fq != -1)
  726.         {
  727.         $this->RemoveFromQueryCache($fq);
  728.         }
  729.       }
  730.     $this->errvars = array();
  731.     $this->no_exit = 0;
  732.     if($mystate)
  733.       {
  734.       $start $this->getmicrotime();
  735.       $this->AffectedRows = @OCIRowCount($mystate);
  736.       return(@OCIFreeStatement($mystate));
  737.       $this->querytime+= ($this->getmicrotime($start);
  738.       }
  739.     }
  740.  
  741.   /**
  742.    * Returns Oracle Server Version.
  743.    * Opens an own connection if no active one exists.
  744.    * @return string The Oracle Release Version string
  745.    */
  746.   function Version()
  747.     {
  748.     $weopen 0;
  749.     if(!$this->sock)
  750.       {
  751.       $this->Connect();
  752.       $weopen 1;
  753.       }
  754.     if($this->debug)
  755.       {
  756.       $this->PrintDebug('Version() called - Self-Connect: '.$weopen);
  757.       }
  758.     $start $this->getmicrotime();
  759.     $ver @OCIServerVersion($this->sock);
  760.     $ret explode("-",$ver);
  761.     if($weopen$this->Disconnect();
  762.     $this->querycounter++;
  763.     $this->querytime+= ($this->getmicrotime($start);
  764.     return(trim($ret[0]));
  765.     }
  766.  
  767.   /**
  768.    * Returns amount of queries executed by this class.
  769.    * @return integer How many queries are executed currently by this class.
  770.    */
  771.   function GetQueryCount()
  772.     {
  773.     if($this->debug)
  774.       {
  775.       $this->PrintDebug('GetQueryCount() called');
  776.       }
  777.     return(intval($this->querycounter));
  778.     }
  779.  
  780.   /**
  781.    * Returns amount of time spend on queries executed by this class.
  782.    * @return float Time in seconds.msecs spent in executing SQL statements.
  783.    * @since 0.68
  784.    */
  785.   function GetQueryTime()
  786.     {
  787.     return($this->querytime);
  788.     }
  789.  
  790.   /**
  791.    * Commits current transaction.
  792.    * @return integer The value of OCICommit() is returned.
  793.    * @see oci_commit
  794.    */
  795.   function Commit()
  796.     {
  797.     $this->checkSock();
  798.     if($this->debug)
  799.       {
  800.       $this->PrintDebug('COMMIT called');
  801.       }
  802.     $start $this->getmicrotime();
  803.     $rc @OCICommit($this->sock);
  804.     $this->querytime+= ($this->getmicrotime($start);
  805.     return($rc);
  806.     }
  807.  
  808.   /**
  809.    * Rollback current transaction.
  810.    * @return integer The value of OCIRollback() is returned.
  811.    * @see oci_rollback
  812.    */
  813.   function Rollback()
  814.     {
  815.     $this->checkSock();
  816.     if($this->debug)
  817.       {
  818.       $this->PrintDebug('ROLLBACK called');
  819.       }
  820.     $start $this->getmicrotime();
  821.     $rc @OCIRollback($this->sock);
  822.     $this->querytime+= ($this->getmicrotime($start);
  823.     return($rc);
  824.     }
  825.  
  826.   /**
  827.    * Function extracts all bind vars out of given query.
  828.    * To avoid wrong determined bind vars this function first kills out all TO_*() functions
  829.    * together with their (possible) format strings which results in a query
  830.    * containing only valid bind vars, format tags or other similar constructed
  831.    * tags are removed.
  832.    * @param string $query The query to check for bind vars.
  833.    * @return array Returns an array with all found bind vars in the order they are defined inside the query.
  834.    */
  835.   function GetBindVars($query)
  836.     {
  837.     $pattern array("/(TO_.*?\()(.*?)(,)(.*?\))/is","/(TO_.*?\('.*?'\))/is","/(TO_.*?\()(.*?\))/is");
  838.     $replace array("$2","","$2");
  839.     $mydummy $query;    // Make copy of current SQL
  840.  
  841.     $mydummy @preg_replace($pattern,$replace,$mydummy);
  842.     @preg_match_all('/[,|\W]?(:\w+)[,|\W]?/i',$mydummy,$res);
  843.     return($res[1]);
  844.     }
  845.  
  846.   /**
  847.    * Function allows debugging of SQL Queries.
  848.    * $state can have these values:
  849.    * - DBOF_DEBUGOFF    = Turn off debugging
  850.    * - DBOF_DEBUGSCREEN = Turn on debugging on screen (every Query will be dumped on screen)
  851.    * - DBOF_DEBUFILE    = Turn on debugging on PHP errorlog
  852.    * You can mix the debug levels by adding the according defines!
  853.    * @param integer $state The DEBUG level to set
  854.    */
  855.   function SetDebug($state)
  856.     {
  857.     $this->debug = $state;
  858.     }
  859.  
  860.   /**
  861.    * Handles debug output according to internal debug flag.
  862.    * @param string $msg The string to be send out to selected output.
  863.    */
  864.   function PrintDebug($msg)
  865.     {
  866.     if(!$this->debugreturn;
  867.     $errbuf '';
  868.     if($this->SAPI_type != 'cli')
  869.       {
  870.       $crlf   '<br>';
  871.       $header "<div align=\"left\" style=\"background-color:#ffffff; color:#000000\"><pre>DEBUG: %s%s</pre></div>\n";
  872.       }
  873.     else
  874.       {
  875.       $crlf   "\n";
  876.       $header "DEBUG: %s%s\n";
  877.       }
  878.     if($this->errvars)
  879.       {
  880.       $errbuf $crlf.'VARS: ';
  881.       reset($this->errvars);
  882.       while(list($key,$valeach($this->errvars))
  883.         {
  884.         if(!is_numeric($key))
  885.           {
  886.           $errbuf.=sprintf("P(%s)='%s' [%d]".$crlf,($key),$val,strlen($val));
  887.           }
  888.         else
  889.           {
  890.           $errbuf.=sprintf("P%d='%s'".$crlf,($i+1),$val);
  891.           }
  892.         $i++;
  893.         }
  894.       }
  895.     if($this->debug DBOF_DEBUGSCREEN)
  896.       {
  897.       printf($header,$msg,$errbuf);
  898.       }
  899.     if($this->debug DBOF_DEBUGFILE)
  900.       {
  901.       @error_log('DEBUG: '.$msg,0);
  902.       if($errbuf!="")
  903.         {
  904.         @error_log('DEBUG: '.strip_tags($errbuf),0);
  905.         }
  906.       }
  907.     }
  908.  
  909.   /**
  910.    * Allows to en- or disable the SQL_TRACE feature of Oracle.
  911.    * Pass TRUE to enable or FALSE to disable. When enabled all Statements of your
  912.    * session are saved in a tracefile stored in
  913.    * $ORACLE_BASE/admin/<DBNAME>/udump/*.trc
  914.    * After your session disconnects use the tkprof tool to generate
  915.    * Human-readable output from the tracefile, i.e.:
  916.    * $> tkprof oracle_ora_7527.trc out.txt
  917.    * Now read 'out.txt' and see what happen in Oracle!
  918.    * @param boolean $state TRUE to enable or FALSE to disable the SQL_TRACE feature.
  919.    */
  920.   function SQLDebug($state)
  921.     {
  922.     switch($state)
  923.       {
  924.       case  TRUE:   $sdebug 'TRUE';
  925.                     break;
  926.       case  FALSE:  $sdebug 'FALSE';
  927.                     break;
  928.       default:      return;
  929.       }
  930.     if($this->sock)
  931.       {
  932.       $this->Query('ALTER SESSION SET SQL_TRACE = '.$sdebug);
  933.       }
  934.     }
  935.  
  936.   /**
  937.    * Returns version of this class.
  938.    * @return string The version string in format "major.minor"
  939.    */
  940.   function GetClassVersion()
  941.     {
  942.     return($this->classversion);
  943.     }
  944.  
  945.   /**
  946.    * Describes a table by returning an array with all table info.
  947.    * @param string $tablename Name of table you want to describe.
  948.    * @return array A 2-dimensional array with table informations.
  949.    */
  950.   function DescTable($tablename)
  951.     {
  952.     $retarr array();
  953.     $weopen 0;
  954.     if(!$this->sock)
  955.       {
  956.       $this->Connect();
  957.       $weopen 1;
  958.       }
  959.     if($this->debug)
  960.       {
  961.       $this->PrintDebug('DescTable('.$tablename.') called - Self-Connect: '.$weopen);
  962.       }
  963.     $start $this->getmicrotime();
  964.     $stmt @OCIParse($this->sock,"SELECT * FROM ".$tablename." WHERE ROWNUM < 1");
  965.     @OCIExecute($stmt);
  966.     $this->querycounter++;
  967.     $ncols @OCINumCols($stmt);
  968.     for ($i 1$i <= $ncols$i++)
  969.       {
  970.       $retarr[$i-1][DBOF_COLNAME@OCIColumnName($stmt$i);
  971.       $retarr[$i-1][DBOF_COLTYPE@OCIColumnType($stmt$i);
  972.       $retarr[$i-1][DBOF_COLSIZE@OCIColumnSize($stmt$i);
  973.       $retarr[$i-1][DBOF_COLPREC@OCIColumnPrecision($stmt,$i);
  974.       }
  975.     @OCIFreeStatement($stmt);
  976.     if($weopen$this->Disconnect();
  977.     $this->querytime+= ($this->getmicrotime($start);
  978.     return($retarr);
  979.     }
  980.  
  981.   /**
  982.    * Preparses a query but do not execute it (yet).
  983.    * This allows to use a compiled query inside loops without having to parse it everytime
  984.    * Since 0.38 all prepared() queries will be put into our own QueryCache() so
  985.    * we can use the Prepare()/Execute()/ExecuteHash() pair for more than one query at once.
  986.    * @param string $querystring The Query you want to prepare (can contain bind variables).
  987.    * @param integer $no_exit 1 => Function returns errorcode instead of calling Print_Error() or 0 => Will always call Print_Error()
  988.    * @return mixed Either the statement handle on success or an error code / calling print_error().
  989.    */
  990.   function Prepare($querystring$no_exit 0)
  991.     {
  992.     $querystring    ltrim($querystring);    // Leading spaces seems to be a problem??
  993.     $this->no_exit  = $no_exit;
  994.     $this->sqlerr   = $querystring;
  995.  
  996.     $this->checkSock();
  997.     $start $this->getmicrotime();
  998.     $stmt @OCIParse($this->sock,$querystring);
  999.     if(!$stmt)
  1000.       {
  1001.       if($no_exit)
  1002.         {
  1003.         $err @OCIError($this->sock);
  1004.         $this->sqlerrmsg = $err['message'];
  1005.         return($err['code']);
  1006.         }
  1007.       else
  1008.         {
  1009.         return($this->Print_Error('Prepare(): Parse failed!'));
  1010.         }
  1011.       }
  1012.     if($this->debug)
  1013.       {
  1014.       $this->PrintDebug("PREPARE: #".$this->sqlcount." ".$this->sqlerr);
  1015.       }
  1016.     $this->sqlcache[$this->sqlcount][DBOF_CACHE_QUERY]     $querystring;
  1017.     $this->sqlcache[$this->sqlcount][DBOF_CACHE_STATEMENT$stmt;
  1018.     $this->sqlcount++;
  1019.     $this->querytime+= ($this->getmicrotime($start);
  1020.     return($stmt);
  1021.     }
  1022.  
  1023.   /**
  1024.    * Executes a prepare()d statement and returns the result.
  1025.    * You may then Fetch rows with FetchResult() or call FreeResult() to free your allocated result.
  1026.    * V0.38: Execute() searches first our QueryCache before executing, this
  1027.    * way we can use almost unlimited Queries at once in the Prepare/Execute pair
  1028.    * @param mixed $stmt The statement handle to be executed.
  1029.    * @return mixed Returns result set read for FetchResult() usage or an error state depending on class setting in case of an error.
  1030.    * @see Prepare
  1031.    */
  1032.   function Execute($stmt)
  1033.     {
  1034.     $f $this->SearchQueryCache($stmt);
  1035.     if($f == -1)
  1036.       {
  1037.       return($this->Print_Error("Cannot find query for given statement #".$stmt." inside query cache!!!"));
  1038.       }
  1039.     $this->sqlerr  = $this->sqlcache[$f][DBOF_CACHE_QUERY];
  1040.     $this->errvars = array();
  1041.     $funcargs @func_num_args();
  1042.     if($funcargs 1)
  1043.       {
  1044.       $this->errvars = @array_slice(@func_get_args(),1);
  1045.       $res $this->GetBindVars($this->sqlcache[$f][DBOF_CACHE_QUERY]);
  1046.       if(($funcargs-1!= count($res))
  1047.         {
  1048.         $this->stmt = $stmt;
  1049.         return($this->Print_Error("Execute(): Parameter count does not match bind var count in query! (Defined:".count($res)." - Supplied: ".($funcargs).")",$res));
  1050.         }
  1051.       }
  1052.     $start $this->getmicrotime();
  1053.     if($funcargs 1)
  1054.       {
  1055.       for($i 1$i $funcargs$i++)
  1056.         {
  1057.         $arg[$i@func_get_arg($i);
  1058.         @OCIBindByName($stmt,$res[$i-1],$arg[$i],-1);
  1059.         }
  1060.       }
  1061.     if($this->debug)
  1062.       {
  1063.       $this->PrintDebug($this->sqlerr);
  1064.       }
  1065.     if(!@OCIExecute($stmt,OCI_DEFAULT))
  1066.       {
  1067.       if($this->no_exit)
  1068.         {
  1069.         $err @OCIError($stmt);
  1070.         $this->sqlerrmsg = $err['message'];
  1071.         return($err['code']);
  1072.         }
  1073.       else
  1074.         {
  1075.         $this->stmt = $stmt;
  1076.         return($this->Print_Error('Execute(): Execute failed!'));
  1077.         }
  1078.       }
  1079.     $this->querycounter++;
  1080.     $this->querytime+= ($this->getmicrotime($start);
  1081.     return($stmt);
  1082.     }
  1083.  
  1084.   /**
  1085.    * Searches internal query cache for given statement id.
  1086.    * Returns index of found statement id or -1 to indicate an error.
  1087.    * This function is considered private and should NOT (!) be called from outside this class!
  1088.    * @param mixed $stmt The statement handle to search for
  1089.    * @return integer The index number of the found statement or -1 if no handle could be found.
  1090.    * @since 0.38
  1091.    */
  1092.   function SearchQueryCache($stmt)
  1093.     {
  1094.     $f 0;
  1095.     for($i 0$i $this->sqlcount$i++)
  1096.       {
  1097.       if($this->sqlcache[$i][DBOF_CACHE_STATEMENT=== $stmt)
  1098.         {
  1099.         return($i);
  1100.         }
  1101.       }
  1102.     return(-1);
  1103.     }
  1104.  
  1105.   /**
  1106.    * Removes query from cache.
  1107.    * Tries to remove a query from cache that was found by a previous call
  1108.    * to SearchQueryCache().
  1109.    * @param integer $nr Number of statement handle to be removed from cache.
  1110.    * @since 0.38
  1111.    */
  1112.   function RemoveFromQueryCache($nr)
  1113.     {
  1114.     $newdata array();
  1115.     $lv 0;
  1116.     for($i 0$i $this->sqlcount$i++)
  1117.       {
  1118.       if($i != $nr)
  1119.         {
  1120.         $newdata[$lv][DBOF_CACHE_QUERY]    $this->sqlcache[$i][DBOF_CACHE_QUERY];
  1121.         $newdata[$lv][DBOF_CACHE_STATEMENT]$this->sqlcache[$i][DBOF_CACHE_STATEMENT];
  1122.         $lv++;
  1123.         }
  1124.       }
  1125.     $this->sqlcache = $newdata;
  1126.     $this->sqlcount--;
  1127.     }
  1128.  
  1129.   /**
  1130.    * Checks if we are already connected to our database.
  1131.    * If not terminates by calling Print_Error().
  1132.    * @see Print_Error
  1133.    * @since 0.40
  1134.    */
  1135.   function checkSock()
  1136.     {
  1137.     if(!$this->sock)
  1138.       {
  1139.       return($this->Print_Error('<b>!!! NOT CONNECTED TO AN ORACLE DATABASE !!!</b>'));
  1140.       }
  1141.     }
  1142.  
  1143.   /**
  1144.    * Allows to save a file to a binary object field (BLOB).
  1145.    * Does not commit!
  1146.    * @param string $file_to_save Full path and filename of file to save
  1147.    * @param string $blob_table Name of Table where the blobfield resides
  1148.    * @param string $blob_field Name of BLOB field
  1149.    * @param string $where_clause Criteria to get the right row (i.e. WHERE ROWID=ABCDEF12345)
  1150.    * @return integer If all is okay returns 0 else an oracle error code.
  1151.    * @since 0.41
  1152.    */
  1153.   function SaveBLOB($file_to_save$blob_table$blob_field$where_clause)
  1154.     {
  1155.     $this->checkSock();
  1156.     if($where_clause == '')
  1157.       {
  1158.       return($this->Print_Error("SaveBLOB(): WHERE clause must be non-empty, else ALL rows would be updated!!!"));
  1159.       }
  1160.     $q1 "UPDATE ".$blob_table." SET ".$blob_field."=EMPTY_BLOB() ".$where_clause." RETURNING ".$blob_field." INTO :oralob";
  1161.     $this->sqlerr = $q1;
  1162.     $start $this->getmicrotime();
  1163.     $lobptr @OCINewDescriptor($this->sockOCI_D_LOB);
  1164.     if(!($lobstmt @OCIParse($this->sock,$q1)))
  1165.       {
  1166.       return($this->Print_Error("SaveBLOB(): Unable to parse query !!!"));
  1167.       }
  1168.     @OCIBindByName($lobstmt":oralob"$lobptr-1OCI_B_BLOB);
  1169.     if(!@OCIExecute($lobstmtOCI_DEFAULT))
  1170.       {
  1171.       @OCIFreeStatement($lobstmt);
  1172.       @OCIFreeDesc($lobptr);
  1173.       return($this->Print_Error("SaveBLOB(): Unable to retrieve empty LOB locator !!!"));
  1174.       }
  1175.     if(!$lobptr->savefile($file_to_save))
  1176.       {
  1177.       @OCIFreeStatement($lobstmt);
  1178.       @OCIFreeDesc($lobptr);
  1179.       return($this->Print_Error("SaveBLOB(): Cannot save LOB data !!!"));
  1180.       }
  1181.     @OCIFreeDesc($lobptr);
  1182.     @OCIFreeStatement($lobstmt);
  1183.     $this->query_counter++;
  1184.     $this->querytime+= ($this->getmicrotime($start);
  1185.     return(0);
  1186.     }
  1187.  
  1188.   /**
  1189.    * Returns current connection handle.
  1190.    * Returns either the internal connection socket or -1 if no active handle exists.
  1191.    * Useful if you want to work with OCI* functions in parallel to this class.
  1192.    * @return mixed Internal socket value
  1193.    * @since 0.42
  1194.    */
  1195.   function GetConnectionHandle()
  1196.     {
  1197.     return($this->sock);
  1198.     }
  1199.  
  1200.   /**
  1201.    * Allows to set internal socket to external value.
  1202.    * Note that the internal socket descriptor is only overriden if the class has
  1203.    * no active connection stored! If already a connection was performed the class
  1204.    * does not override it's internal handle to avoid problems!
  1205.    * @param mixed $extsock The connection handle as returned from OCILogon().
  1206.    * @since 0.49
  1207.    */
  1208.   function SetConnectionHandle($extsock)
  1209.     {
  1210.     if(!$this->sock$this->sock = $extsock;
  1211.     }
  1212.  
  1213.   /**
  1214.    * Executes a query with parameters passed as hash values.
  1215.    * Also IN/OUT and RETURNING INTO <...> clauses are supported.
  1216.    * You have to use FetchResult()/FreeResult() after using this function.
  1217.    * @param string $query The Query to be executed.
  1218.    * @param array &$inhash The bind vars as associative array (keys = bindvar names, values = bindvar values)
  1219.    * @return mixed Either the statement handle or an error code / calling Print_Error().
  1220.    * @see FetchResult
  1221.    * @see FreeResult
  1222.    * @since 0.44
  1223.    */
  1224.   function QueryResultHash($query,&$inhash)
  1225.     {
  1226.     $this->checkSock();
  1227.     $query        ltrim($query);    // Leading spaces seems to be a problem??
  1228.     $this->sqlerr = $query;
  1229.     if($this->debug)
  1230.       {
  1231.       $this->PrintDebug($query);
  1232.       }
  1233.     $start $this->getmicrotime();
  1234.     if(!($stmt @OCIParse($this->sock,$query)))
  1235.       {
  1236.       return($this->Print_Error("QueryResultHash(): Unable to parse query !!!"));
  1237.       }
  1238.     if(is_array($inhash))
  1239.       {
  1240.       $this->errvars = $inhash;
  1241.       reset($inhash);
  1242.       while(list($key,$valeach($inhash))
  1243.         {
  1244.         @OCIBindByName($stmt,$key,$inhash[$key],-1);
  1245.         }
  1246.       }
  1247.     if(!@OCIExecute($stmt,OCI_DEFAULT))
  1248.       {
  1249.       $this->stmt = $stmt;
  1250.       return($this->Print_Error("QueryResultHash(): Execute query failed!"));
  1251.       }
  1252.     $this->querycounter++;
  1253.     $this->querytime+= ($this->getmicrotime($start);
  1254.     if(is_null($this->stmt))
  1255.       {
  1256.       $this->stmt = $stmt;
  1257.       }
  1258.     return($stmt);
  1259.     }
  1260.  
  1261.   /**
  1262.    * This function tries to get the description for a given error message.
  1263.    * Simply pass the $err['message'] field to this function, it tries to
  1264.    * extract the required informations and call $ORACLE_HOME/bin/oerr to
  1265.    * get the error description. If either the exterr or the internal sqlerrmsg
  1266.    * variables are empty this function returns: "No error found."
  1267.    * @param string The error string from oracle. Maybe empty, in this case uses internal sqlerrmsg field.
  1268.    * @return string The extracted error text.
  1269.    */
  1270.   function GetErrorText($exterr "")
  1271.     {
  1272.     if($exterr != "")
  1273.       {
  1274.       $checkem $exterr;
  1275.       }
  1276.     else
  1277.       {
  1278.       $checkem $this->sqlerrmsg;
  1279.       }
  1280.     if($checkem=="")
  1281.       {
  1282.       return("No error found as error text is empty!");
  1283.       }
  1284.     $dummy explode(":",$checkem);   // Oracle stores errors as: XXX-YYYY: ZZZZZZZ
  1285.     if($dummy[0== $checkem)
  1286.       {
  1287.       return("No valid error description found! (".$checkem.")");
  1288.       }
  1289.     $test   str_replace("-"," ",$dummy[0]);
  1290.     $cmdstr "NLS_LANG=AMERICAN_AMERICA.WE8ISO8859P1; \$ORACLE_HOME/bin/oerr ".$test;
  1291.     $data   @exec($cmdstr,$retdata,$retcode);
  1292.     $dummy  @explode(",",$retdata[0]);     // Oracle stores: 01721, 00000, "..."
  1293.     return(@trim(@preg_replace("/\"/","",$dummy[2])));
  1294.     }
  1295.  
  1296.   /**
  1297.    * Returns count of affected rows.
  1298.    * Info is set in Query() and QueryResult() / FreeResult()
  1299.    * and should return the amount of rows affected by previous DML command
  1300.    * @return integer Number of affected rows of previous DML command
  1301.    */
  1302.   function AffectedRows()
  1303.     {
  1304.     return($this->AffectedRows);
  1305.     }
  1306.  
  1307.   /**
  1308.    * Returns hash with error informations from last query.
  1309.    * @return array Assoc. array with error informations.
  1310.    * @since 0.55
  1311.    */
  1312.   function getSQLError()
  1313.     {
  1314.     $ehash['err'$this->sqlerr;
  1315.     $ehash['msg'$this->sqlerrmsg;
  1316.     return($ehash);
  1317.     }
  1318.  
  1319.   /**
  1320.    * Allows to set the handling of errors.
  1321.    *
  1322.    * - DBOF_SHOW_NO_ERRORS    => Show no security-relevant informations
  1323.    * - DBOF_SHOW_ALL_ERRORS   => Show all errors (useful for develop)
  1324.    * - DBOF_RETURN_ALL_ERRORS => No error/autoexit, just return the mysql_error code.
  1325.    * @param integer $val The Error Handling mode you wish to use.
  1326.    * @since 0.57
  1327.    */
  1328.   function setErrorHandling($val)
  1329.     {
  1330.     $this->showError = $val;
  1331.     }
  1332.  
  1333.   /**
  1334.    * Allows to set the prefetch value when returning results.
  1335.    * Default is 1 which may lead to performance problems when data is transmitted via WAN.
  1336.    * @param integer $rows Amount of rows to be used for prefetching.
  1337.    * @param mixed $extstmt Optionally your own statement handle. If you omit this parameter the internal statement handle is used.
  1338.    * @return boolean Return value of OCISetPrefetch()
  1339.    * @see OCISetPrefetch()
  1340.    */
  1341.   function setPrefetch($rows,$extstmt=-1)
  1342.     {
  1343.     if($extstmt == -1)
  1344.       {
  1345.       $st $this->stmt;
  1346.       }
  1347.     else
  1348.       {
  1349.       $st $extstmt;
  1350.       }
  1351.     if($st 0return($st);
  1352.     return(@OCISetPrefetch($st,$rows));
  1353.     }
  1354.  
  1355.   /**
  1356.    * Performs a single row query with Bindvar support passed as associative hash.
  1357.    * Resflag can be OCI_NUM or OCI_ASSOC depending on what kind of array you want to be returned.
  1358.    * Remember to pass all required variables for all defined bind vars after the $no_exit parameter
  1359.    * as an assoc. array (Key = name of bindvar without ':', value = value to add).
  1360.    * @param string $querystring The query to be executed against the RDBMS
  1361.    * @param integer $resflag OCI_NUM for numeric array or OCI_ASSOC (default) for associative array result
  1362.    * @param integer $no_exit 1 => Function returns errorcode instead of calling Print_Error() or 0 => Will always call Print_Error()
  1363.    * @param array &$bindvarhash The bind vars as associative array (keys = bindvar names, values = bindvar values)
  1364.    * @return array The result of the query as either associative or numeric array.
  1365.    *  In case of an error can be also an assoc. array of error informations.
  1366.    * @see setOutputHash
  1367.    * @see getOutputHash
  1368.    * @see clearOutputHash
  1369.    * @since 0.62
  1370.    */
  1371.   function QueryHash($querystring$resflag OCI_ASSOC$no_exit 0&$bindvarhash)
  1372.     {
  1373.     $querystring        ltrim($querystring);    // Leading spaces seems to be a problem??
  1374.     $resarr             array();
  1375.     $this->errvars      = array();
  1376.     $funcargs           @func_num_args();
  1377.     $this->sqlerr       = $querystring;
  1378.     $this->AffectedRows = 0;
  1379.  
  1380.     $this->checkSock();
  1381.     if($querystring == '')
  1382.       {
  1383.       return($this->Print_Error('QueryHash(): No querystring was supplied!'));
  1384.       }
  1385.     if($this->debug)
  1386.       {
  1387.       $this->PrintDebug($querystring);
  1388.       }
  1389.     $start $this->getmicrotime();
  1390.     $stmt @OCIParse($this->sock,$querystring);
  1391.     if(!$stmt)
  1392.       {
  1393.       return($this->Print_Error('QueryHash(): Parse failed!'));
  1394.       exit;
  1395.       }
  1396.     if(is_array($bindvarhash))
  1397.       {
  1398.       reset($bindvarhash);
  1399.       $this->errvars = $bindvarhash;
  1400.       while(list($key,$valeach($bindvarhash))
  1401.         {
  1402.         @OCIBindByName($stmt,$key,$bindvarhash[$key],-1);
  1403.         }
  1404.       }
  1405.     if(count($this->output_hash))
  1406.       {
  1407.       reset($this->output_hash);
  1408.       while(list($key,$valeach($this->output_hash))
  1409.         {
  1410.         @OCIBindByName($stmt,$key,$this->output_hash[$key],$val);
  1411.         }
  1412.       }
  1413.     $ret @OCIExecute($stmt,OCI_DEFAULT);
  1414.     if($ret === FALSE)
  1415.       {
  1416.       if($no_exit)
  1417.         {
  1418.         $err @OCIError($stmt);
  1419.         $this->sqlerrmsg = $err['message'];
  1420.         return($err['code']);
  1421.         }
  1422.       else
  1423.         {
  1424.         $this->stmt = $stmt;
  1425.         return($this->Print_Error('QueryHash(): Execute failed!'));
  1426.         exit;
  1427.         }
  1428.       }
  1429.     $this->querycounter++;
  1430.     if(StriStr(substr($querystring,0,6),"SELECT"))
  1431.       {
  1432.       @OCIFetchInto($stmt,$resarr,$resflag+OCI_RETURN_NULLS+OCI_RETURN_LOBS);
  1433.       }
  1434.     else
  1435.       {
  1436.       $res 0;
  1437.       }
  1438.     $this->AffectedRows = @OCIRowCount($stmt);
  1439.     @OCIFreeStatement($stmt);
  1440.     $this->querytime+= ($this->getmicrotime($start);
  1441.     $this->errvars = array();
  1442.     return($resarr);
  1443.     }
  1444.  
  1445.   /**
  1446.    * Use this function to pass output hash data to QueryHash() function.
  1447.    * This is only required if you are using RETURNING INTO clauses or OUT variables,
  1448.    * if you only use the bind variables for input (IN) you do not need to set this.
  1449.    * WARNING: You are responsible to clear the array by using clearOutputHash()!
  1450.    * @param array &$outputhash The assoc. array to use for bind var return variables
  1451.    * @see getOutputHash
  1452.    */
  1453.   function setOutputHash(&$outputhash)
  1454.     {
  1455.     $this->output_hash = &$outputhash;
  1456.     }
  1457.  
  1458.   /**
  1459.    * Returns the contents of the output_hash variable.
  1460.    * @return array The contents of the internal output_hash variable.
  1461.    * @see setOutputHash
  1462.    */
  1463.   function getOutputHash()
  1464.     {
  1465.     return($this->output_hash);
  1466.     }
  1467.  
  1468.   /**
  1469.    * Clears the internal output hash array.
  1470.    * You are responsible to manage this yourself, the class only uses the variable!
  1471.    * @see setOutputHash
  1472.    * @see getOutputHash
  1473.    */
  1474.   function clearOutputHash()
  1475.     {
  1476.     $this->output_hash = array();
  1477.     }
  1478.  
  1479.   /**
  1480.    * Sends an error email.
  1481.    * If OCIDB_SENTMAILONERROR is defined and != 0 the class sent out an error report
  1482.    * to the configured email address in case of an error.
  1483.    * @param array $errarray The error array from Oracle as returned by getSQLError()
  1484.    * @see getSQLError
  1485.    */
  1486.   function SendMailOnError($errarray)
  1487.     {
  1488.     if(!defined('OCIDB_SENTMAILONERROR'|| OCIDB_SENTMAILONERROR == 0)
  1489.       {
  1490.       return;
  1491.       }
  1492.     $server  $_SERVER['SERVER_NAME']." (".$_SERVER['SERVER_ADDR'].")";
  1493.     if($server == '()' || $server == '')
  1494.       {
  1495.       $server 'n/a';
  1496.       }
  1497.     $uagent  (isset($_SERVER['HTTP_USER_AGENT'])) $_SERVER['HTTP_USER_AGENT''';
  1498.     if($uagent == '')
  1499.       {
  1500.       $uagent 'n/a';
  1501.       }
  1502.     $message "OCI8 Class: Error occured on ".date('r')." !!!\n\n";
  1503.     $message.= "  AFFECTED SERVER: ".$server."\n";
  1504.     $message.= "       USER AGENT: ".$uagent."\n";
  1505.     $message.= "       PHP SCRIPT: ".$_SERVER['SCRIPT_FILENAME']."\n";
  1506.     $message.= "   REMOTE IP ADDR: ".$_SERVER['REMOTE_ADDR']." (".@gethostbyaddr($_SERVER['REMOTE_ADDR']).")\n";
  1507.     $message.= "    DATABASE DATA: ".$this->user." @ ".$this->host."\n";
  1508.     $message.= "SQL ERROR MESSAGE: ".preg_replace("/\n|\r/","",$errarray['message'])."\n";
  1509.     $message.= "   SQL ERROR CODE: ".$errarray['code']."\n";
  1510.     $message.= "    QUERY COUNTER: ".$this->querycounter."\n";
  1511.     $message.= "        SQL QUERY:\n";
  1512.     $message.= "------------------------------------------------------------------------------------\n";
  1513.     $message.= $errarray['sqltext']."\n";
  1514.     $message.= "------------------------------------------------------------------------------------\n";
  1515.     if($this->sqlerr != $errarray['sqltext'])
  1516.       {
  1517.       $message.= "     THIS->SQLERR: ".$this->sqlerr."\n";
  1518.       }
  1519.     if(count($this->errvars))
  1520.       {
  1521.       $errbuf '';
  1522.       reset($this->errvars);
  1523.       $i 0;
  1524.       while(list($key,$valeach($this->errvars))
  1525.         {
  1526.         if(!is_numeric($key))
  1527.           {
  1528.           $errbuf.=sprintf("  P['%s'] => '%s'\n",($key),$val);
  1529.           }
  1530.         else
  1531.           {
  1532.           $errbuf.=sprintf("  P[%d] = '%s'\n",($i+1),$val);
  1533.           }
  1534.         $i++;
  1535.         }
  1536.       $errbuf substr($errbuf,0,strlen($errbuf)-1);
  1537.       $message.= "    THIS->ERRVARS: ".$errbuf."\n";
  1538.       }
  1539.     if(defined('OCIDB_MAIL_EXTRAARGS'&& OCIDB_MAIL_EXTRAARGS != '')
  1540.       {
  1541.       @mail($this->AdminEmail,'OCI8 Class v'.$this->classversion.' ERROR #'.$errarray['code'].' OCCURED!',$message,OCIDB_MAIL_EXTRAARGS);
  1542.       }
  1543.     else
  1544.       {
  1545.       @mail($this->AdminEmail,'OCI8 Class v'.$this->classversion.' ERROR #'.$errarray['code'].' OCCURED!',$message);
  1546.       }
  1547.     }
  1548.  
  1549.   /**
  1550.    * Returns microtime in format s.mmmmm.
  1551.    * Used to measure SQL execution time.
  1552.    * @return float the current time in microseconds.
  1553.    */
  1554.   function getmicrotime()
  1555.     {
  1556.     list($usec$secexplode(" ",microtime());
  1557.     return (floatval($usecfloatval($sec));
  1558.     }
  1559.  
  1560.   /**
  1561.    * Sets connection behavour.
  1562.    * If FALSE class uses oci_logon to connect.
  1563.    * If TRUE class uses oci_plogon to connect (Persistant connection)
  1564.    * @param boolean $conntype TRUE => Enable persistant connections, FALSE => Disable persistant connections
  1565.    * @return boolean The previous state
  1566.    * @since 0.73
  1567.    */
  1568.   function setPConnect($conntype)
  1569.    {
  1570.    if(is_bool($conntype)==FALSE)
  1571.      {
  1572.      return($this->usePConnect);
  1573.      }
  1574.    $oldtype $this->usePConnect;
  1575.    $this->usePConnect = $conntype;
  1576.    return($oldtype);
  1577.    }
  1578.  
  1579.   /**
  1580.    * Executes a prepare()d statement and returns the result.
  1581.    * You may then fetch rows with FetchResult() or call FreeResult() to free your allocated result.
  1582.    * This method is almost identical to "Execute()", however the bind variables used are passed as an associative array
  1583.    * instead of "guessing" them from query and given parameter. This is now the prefered way to use bind variables!
  1584.    * @param mixed $stmt The statement handle to be executed.
  1585.    * @param array &$bindvarhash The bind variables as associative array (key = bindvar name, value = bindvar value).
  1586.    * @return mixed Returns result set read for FetchResult() usage or an error state depending on class setting in case of an error.
  1587.    * @since 0.77
  1588.    * @see Prepare
  1589.    */
  1590.   function ExecuteHash($stmt,&$bindvarhash)
  1591.     {
  1592.     $f $this->SearchQueryCache($stmt);
  1593.     if($f == -1)
  1594.       {
  1595.       return($this->Print_Error("Cannot find query for given statement #".$stmt." inside query cache!!!"));
  1596.       }
  1597.     $this->sqlerr  = $this->sqlcache[$f][DBOF_CACHE_QUERY];
  1598.     $this->errvars = array();
  1599.     if(is_array($bindvarhash))
  1600.       {
  1601.       reset($bindvarhash);
  1602.       $this->errvars = $bindvarhash;
  1603.       while(list($key,$valeach($bindvarhash))
  1604.         {
  1605.         @OCIBindByName($stmt,$key,$bindvarhash[$key],-1);
  1606.         }
  1607.       }
  1608.     $start $this->getmicrotime();
  1609.     if($this->debug)
  1610.       {
  1611.       $this->PrintDebug($this->sqlerr);
  1612.       }
  1613.     if(!@OCIExecute($stmt,OCI_DEFAULT))
  1614.       {
  1615.       if($this->no_exit)
  1616.         {
  1617.         $err @OCIError($stmt);
  1618.         $this->sqlerrmsg = $err['message'];
  1619.         return($err['code']);
  1620.         }
  1621.       else
  1622.         {
  1623.         $this->stmt = $stmt;
  1624.         return($this->Print_Error('ExecuteHash(): Execute failed!'));
  1625.         }
  1626.       }
  1627.     $this->querycounter++;
  1628.     $this->querytime+= ($this->getmicrotime($start);
  1629.     return($stmt);
  1630.     }
  1631.  
  1632.   /**
  1633.    * Returns the number of retries in case of connection problems.
  1634.    * This value can be set globally inside the dbdefs.inc.php file
  1635.    * via the OCIDB_CONNECT_RETRIES define but may be changed run-time
  1636.    * also via the "setConnectRetries()" method.
  1637.    * @return integer The retry counter value currently set.
  1638.    * @since V0.78
  1639.    */
  1640.   function getConnectRetries()
  1641.     {
  1642.     return($this->connectRetries);
  1643.     }
  1644.  
  1645.   /**
  1646.    * Change the number of retries the class performs in case of connection problems.
  1647.    * This value is globally setable in the dbdefs.inc.php script (see define OCIDB_CONNECT_RETRIES)
  1648.    * but can be set also run-time via this method.
  1649.    * @param integer $retcnt The new number of connect retries.
  1650.    * @return integer The previous value
  1651.    * @since V0.78
  1652.    */
  1653.   function setConnectRetries($retcnt)
  1654.     {
  1655.     $oldval $this->getConnectRetries();
  1656.     $this->connectRetries = intval($retcnt);
  1657.     return($oldval);
  1658.     }
  1659.  
  1660.   // EOF
  1661. ?>

Documentation generated on Tue, 22 Sep 2009 22:17:38 +0200 by phpDocumentor 1.4.2