home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 June / ENTER.ISO / files / xampp-win32-1.4.5-installer.exe / xampp / adodb-oci8.inc.php < prev    next >
Encoding:
PHP Script  |  2004-03-20  |  34.1 KB  |  1,173 lines

  1. <?php
  2. /*
  3.  
  4.   version V4.21 20 Mar 2004 (c) 2000-2004 John Lim. All rights reserved.
  5.  
  6.   Released under both BSD license and Lesser GPL library license. 
  7.   Whenever there is any discrepancy between the two licenses, 
  8.   the BSD license will take precedence.
  9.  
  10.   Latest version is available at http://php.weblogs.com/
  11.   
  12.   Code contributed by George Fourlanos <fou@infomap.gr>
  13.   
  14.   13 Nov 2000 jlim - removed all ora_* references.
  15. */
  16.  
  17. /*
  18. NLS_Date_Format
  19. Allows you to use a date format other than the Oracle Lite default. When a literal
  20. character string appears where a date value is expected, the Oracle Lite database
  21. tests the string to see if it matches the formats of Oracle, SQL-92, or the value
  22. specified for this parameter in the POLITE.INI file. Setting this parameter also
  23. defines the default format used in the TO_CHAR or TO_DATE functions when no
  24. other format string is supplied.
  25.  
  26. For Oracle the default is dd-mon-yy or dd-mon-yyyy, and for SQL-92 the default is
  27. yy-mm-dd or yyyy-mm-dd.
  28.  
  29. Using 'RR' in the format forces two-digit years less than or equal to 49 to be
  30. interpreted as years in the 21st century (2000û2049), and years over 50 as years in
  31. the 20th century (1950û1999). Setting the RR format as the default for all two-digit
  32. year entries allows you to become year-2000 compliant. For example:
  33. NLS_DATE_FORMAT='RR-MM-DD'
  34.  
  35. You can also modify the date format using the ALTER SESSION command. 
  36. */
  37.  
  38. class ADODB_oci8 extends ADOConnection {
  39.     var $databaseType = 'oci8';
  40.     var $dataProvider = 'oci8';
  41.     var $replaceQuote = "''"; // string to use to replace quotes
  42.     var $concat_operator='||';
  43.     var $sysDate = "TRUNC(SYSDATE)";
  44.     var $sysTimeStamp = 'SYSDATE';
  45.     var $metaDatabasesSQL = "SELECT USERNAME FROM ALL_USERS WHERE USERNAME NOT IN ('SYS','SYSTEM','DBSNMP','OUTLN') ORDER BY 1";
  46.     var $_stmt;
  47.     var $_commit = OCI_COMMIT_ON_SUCCESS;
  48.     var $_initdate = true; // init date to YYYY-MM-DD
  49.     var $metaTablesSQL = "select table_name,table_type from cat where table_type in ('TABLE','VIEW')";
  50.     var $metaColumnsSQL = "select cname,coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno"; //changed by smondino@users.sourceforge. net
  51.     var $_bindInputArray = true;
  52.     var $hasGenID = true;
  53.     var $_genIDSQL = "SELECT (%s.nextval) FROM DUAL";
  54.     var $_genSeqSQL = "CREATE SEQUENCE %s START WITH %s";
  55.     var $_dropSeqSQL = "DROP SEQUENCE %s";
  56.     var $hasAffectedRows = true;
  57.     var $random = "abs(mod(DBMS_RANDOM.RANDOM,10000001)/10000000)";
  58.     var $noNullStrings = false;
  59.     var $connectSID = false;
  60.     var $_bind = false;
  61.     var $_hasOCIFetchStatement = false;
  62.     var $_getarray = false; // currently not working
  63.     var $leftOuter = '';  // oracle wierdness, $col = $value (+) for LEFT OUTER, $col (+)= $value for RIGHT OUTER
  64.     var $session_sharing_force_blob = false; // alter session on updateblob if set to true 
  65.     var $firstrows = true; // enable first rows optimization on SelectLimit()
  66.     var $selectOffsetAlg1 = 100; // when to use 1st algorithm of selectlimit.
  67.     var $NLS_DATE_FORMAT = 'YYYY-MM-DD';  // To include time, use 'RRRR-MM-DD HH24:MI:SS'
  68.      var $useDBDateFormatForTextInput=false;
  69.     var $datetime = false; // MetaType('DATE') returns 'D' (datetime==false) or 'T' (datetime == true)
  70.     
  71.     // var $ansiOuter = true; // if oracle9
  72.     
  73.     function ADODB_oci8() 
  74.     {
  75.         $this->_hasOCIFetchStatement = ADODB_PHPVER >= 0x4200;
  76.     }
  77.     
  78.     /*  Function &MetaColumns($table) added by smondino@users.sourceforge.net*/
  79.     function &MetaColumns($table) 
  80.     {
  81.     global $ADODB_FETCH_MODE;
  82.     
  83.         $save = $ADODB_FETCH_MODE;
  84.         $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
  85.         if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
  86.         
  87.         $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
  88.         
  89.         if (isset($savem)) $this->SetFetchMode($savem);
  90.         $ADODB_FETCH_MODE = $save;
  91.         if (!$rs) return false;
  92.         $retarr = array();
  93.         while (!$rs->EOF) { //print_r($rs->fields);
  94.             $fld = new ADOFieldObject();
  95.                $fld->name = $rs->fields[0];
  96.                $fld->type = $rs->fields[1];
  97.                $fld->max_length = $rs->fields[2];
  98.             $fld->scale = $rs->fields[3];
  99.             if ($rs->fields[1] == 'NUMBER' && $rs->fields[3] == 0) {
  100.                 $fld->type ='INT';
  101.                  $fld->max_length = $rs->fields[4];
  102.             }    
  103.                $fld->not_null = (strncmp($rs->fields[5], 'NOT',3) === 0);
  104.             $fld->binary = (strpos($fld->type,'BLOB') !== false);
  105.             $fld->default_value = $rs->fields[6];
  106.             
  107.             if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;    
  108.             else $retarr[strtoupper($fld->name)] = $fld;
  109.             $rs->MoveNext();
  110.         }
  111.         $rs->Close();
  112.         return $retarr;
  113.     }
  114.  
  115. /*
  116.  
  117.   Multiple modes of connection are supported:
  118.   
  119.   a. Local Database
  120.     $conn->Connect(false,'scott','tiger');
  121.   
  122.   b. From tnsnames.ora
  123.     $conn->Connect(false,'scott','tiger',$tnsname); 
  124.     $conn->Connect($tnsname,'scott','tiger'); 
  125.   
  126.   c. Server + service name
  127.     $conn->Connect($serveraddress,'scott,'tiger',$service_name);
  128.   
  129.   d. Server + SID
  130.       $conn->connectSID = true;
  131.     $conn->Connect($serveraddress,'scott,'tiger',$SID);
  132.  
  133.  
  134. Example TNSName:
  135. ---------------
  136. NATSOFT.DOMAIN =
  137.   (DESCRIPTION =
  138.     (ADDRESS_LIST =
  139.       (ADDRESS = (PROTOCOL = TCP)(HOST = kermit)(PORT = 1523))
  140.     )
  141.     (CONNECT_DATA =
  142.       (SERVICE_NAME = natsoft.domain)
  143.     )
  144.   )
  145.   
  146.   There are 3 connection modes, 0 = non-persistent, 1 = persistent, 2 = force new connection
  147.     
  148. */
  149.     function _connect($argHostname, $argUsername, $argPassword, $argDatabasename,$mode=0)
  150.     {
  151.         if (!function_exists('OCIPLogon')) return false;
  152.         
  153.         
  154.         $this->_errorMsg = false;
  155.         $this->_errorCode = false;
  156.         
  157.         if($argHostname) { // added by Jorma Tuomainen <jorma.tuomainen@ppoy.fi>
  158.             if (empty($argDatabasename)) $argDatabasename = $argHostname;
  159.             else {
  160.                 if(strpos($argHostname,":")) {
  161.                     $argHostinfo=explode(":",$argHostname);
  162.                        $argHostname=$argHostinfo[0];
  163.                     $argHostport=$argHostinfo[1];
  164.                  } else {
  165.                     $argHostport="1521";
  166.                    }
  167.                 
  168.                 if ($this->connectSID) {
  169.                     $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
  170.                     .")(PORT=$argHostport))(CONNECT_DATA=(SID=$argDatabasename)))";
  171.                 } else
  172.                     $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
  173.                     .")(PORT=$argHostport))(CONNECT_DATA=(SERVICE_NAME=$argDatabasename)))";
  174.             }
  175.         }
  176.                 
  177.          //if ($argHostname) print "<p>Connect: 1st argument should be left blank for $this->databaseType</p>";
  178.         if ($mode==1) {
  179.             $this->_connectionID = OCIPLogon($argUsername,$argPassword, $argDatabasename);
  180.             if ($this->_connectionID && $this->autoRollback)  OCIrollback($this->_connectionID);
  181.         } else if ($mode==2) {
  182.             $this->_connectionID = OCINLogon($argUsername,$argPassword, $argDatabasename);
  183.         } else {
  184.             $this->_connectionID = OCILogon($argUsername,$argPassword, $argDatabasename);
  185.         }
  186.         if ($this->_connectionID === false) return false;
  187.         if ($this->_initdate) {
  188.             $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='".$this->NLS_DATE_FORMAT."'");
  189.         }
  190.         
  191.         // looks like: 
  192.         // Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production With the Partitioning option JServer Release 8.1.7.0.0 - Production
  193.         // $vers = OCIServerVersion($this->_connectionID);
  194.         // if (strpos($vers,'8i') !== false) $this->ansiOuter = true;
  195.         return true;
  196.        }
  197.     
  198.     function ServerInfo()
  199.     {
  200.         $arr['compat'] = $this->GetOne('select value from sys.database_compatible_level');
  201.         $arr['description'] = @OCIServerVersion($this->_connectionID);
  202.         $arr['version'] = ADOConnection::_findvers($arr['description']);
  203.         return $arr;
  204.     }
  205.         // returns true or false
  206.     function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
  207.     {
  208.         return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,1);
  209.     }
  210.     
  211.     
  212.     
  213.     // returns true or false
  214.     function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
  215.     {
  216.         return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,2);
  217.     }
  218.     
  219.     function _affectedrows()
  220.     {
  221.         if (is_resource($this->_stmt)) return @OCIRowCount($this->_stmt);
  222.         return 0;
  223.     }
  224.     
  225.     function IfNull( $field, $ifNull ) 
  226.     {
  227.         return " NVL($field, $ifNull) "; // if Oracle
  228.     }
  229.     
  230.     // format and return date string in database date format
  231.     function DBDate($d)
  232.     {
  233.         if (empty($d) && $d !== 0) return 'null';
  234.         
  235.         if (is_string($d)) $d = ADORecordSet::UnixDate($d);
  236.         return "TO_DATE(".adodb_date($this->fmtDate,$d).",'".$this->NLS_DATE_FORMAT."')";
  237.     }
  238.  
  239.     
  240.     // format and return date string in database timestamp format
  241.     function DBTimeStamp($ts)
  242.     {
  243.         if (empty($ts) && $ts !== 0) return 'null';
  244.         if (is_string($ts)) $ts = ADORecordSet::UnixTimeStamp($ts);
  245.         return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'RRRR-MM-DD, HH:MI:SS AM')";
  246.     }
  247.     
  248.     function RowLock($tables,$where) 
  249.     {
  250.         if ($this->autoCommit) $this->BeginTrans();
  251.         return $this->GetOne("select 1 as ignore from $tables where $where for update");
  252.     }
  253.     
  254.     function &MetaTables($ttype=false,$showSchema=false,$mask=false) 
  255.     {
  256.         if ($mask) {
  257.             $save = $this->metaTablesSQL;
  258.             $mask = $this->qstr(strtoupper($mask));
  259.             $this->metaTablesSQL .= " AND table_name like $mask";
  260.         }
  261.         $ret =& ADOConnection::MetaTables($ttype,$showSchema);
  262.         
  263.         if ($mask) {
  264.             $this->metaTablesSQL = $save;
  265.         }
  266.         return $ret;
  267.     }
  268.     
  269.     function BeginTrans()
  270.     {    
  271.         if ($this->transOff) return true;
  272.         $this->transCnt += 1;
  273.         $this->autoCommit = false;
  274.         $this->_commit = OCI_DEFAULT;
  275.         return true;
  276.     }
  277.     
  278.     function CommitTrans($ok=true) 
  279.     { 
  280.         if ($this->transOff) return true;
  281.         if (!$ok) return $this->RollbackTrans();
  282.         
  283.         if ($this->transCnt) $this->transCnt -= 1;
  284.         $ret = OCIcommit($this->_connectionID);
  285.         $this->_commit = OCI_COMMIT_ON_SUCCESS;
  286.         $this->autoCommit = true;
  287.         return $ret;
  288.     }
  289.     
  290.     function RollbackTrans()
  291.     {
  292.         if ($this->transOff) return true;
  293.         if ($this->transCnt) $this->transCnt -= 1;
  294.         $ret = OCIrollback($this->_connectionID);
  295.         $this->_commit = OCI_COMMIT_ON_SUCCESS;
  296.         $this->autoCommit = true;
  297.         return $ret;
  298.     }
  299.     
  300.     
  301.     function SelectDB($dbName) 
  302.     {
  303.         return false;
  304.     }
  305.  
  306.     function ErrorMsg() 
  307.     {
  308.         if ($this->_errorMsg !== false) return $this->_errorMsg;
  309.  
  310.         if (is_resource($this->_stmt)) $arr = @OCIerror($this->_stmt);
  311.         if (empty($arr)) {
  312.             $arr = @OCIerror($this->_connectionID);
  313.             if ($arr === false) $arr = @OCIError();
  314.             if ($arr === false) return '';
  315.         }
  316.         $this->_errorMsg = $arr['message'];
  317.         $this->_errorCode = $arr['code'];
  318.         return $this->_errorMsg;
  319.     }
  320.  
  321.     function ErrorNo() 
  322.     {
  323.         if ($this->_errorCode !== false) return $this->_errorCode;
  324.         
  325.         if (is_resource($this->_stmt)) $arr = @OCIError($this->_stmt);
  326.         if (empty($arr)) {
  327.             $arr = @OCIError($this->_connectionID);
  328.             if ($arr == false) $arr = @OCIError();
  329.             if ($arr == false) return '';
  330.         }
  331.         
  332.         $this->_errorMsg = $arr['message'];
  333.         $this->_errorCode = $arr['code'];
  334.         
  335.         return $arr['code'];
  336.     }
  337.     
  338.     // Format date column in sql string given an input format that understands Y M D
  339.     function SQLDate($fmt, $col=false)
  340.     {    
  341.         if (!$col) $col = $this->sysTimeStamp;
  342.         $s = 'TO_CHAR('.$col.",'";
  343.         
  344.         $len = strlen($fmt);
  345.         for ($i=0; $i < $len; $i++) {
  346.             $ch = $fmt[$i];
  347.             switch($ch) {
  348.             case 'Y':
  349.             case 'y':
  350.                 $s .= 'YYYY';
  351.                 break;
  352.             case 'Q':
  353.             case 'q':
  354.                 $s .= 'Q';
  355.                 break;
  356.                 
  357.             case 'M':
  358.                 $s .= 'Mon';
  359.                 break;
  360.                 
  361.             case 'm':
  362.                 $s .= 'MM';
  363.                 break;
  364.             case 'D':
  365.             case 'd':
  366.                 $s .= 'DD';
  367.                 break;
  368.             
  369.             case 'H':
  370.                 $s.= 'HH24';
  371.                 break;
  372.                 
  373.             case 'h':
  374.                 $s .= 'HH';
  375.                 break;
  376.                 
  377.             case 'i':
  378.                 $s .= 'MI';
  379.                 break;
  380.             
  381.             case 's':
  382.                 $s .= 'SS';
  383.                 break;
  384.             
  385.             case 'a':
  386.             case 'A':
  387.                 $s .= 'AM';
  388.                 break;
  389.                 
  390.             default:
  391.             // handle escape characters...
  392.                 if ($ch == '\\') {
  393.                     $i++;
  394.                     $ch = substr($fmt,$i,1);
  395.                 }
  396.                 if (strpos('-/.:;, ',$ch) !== false) $s .= $ch;
  397.                 else $s .= '"'.$ch.'"';
  398.                 
  399.             }
  400.         }
  401.         return $s. "')";
  402.     }
  403.     
  404.     
  405.     /*
  406.     This algorithm makes use of
  407.     
  408.     a. FIRST_ROWS hint
  409.     The FIRST_ROWS hint explicitly chooses the approach to optimize response time, 
  410.     that is, minimum resource usage to return the first row. Results will be returned 
  411.     as soon as they are identified. 
  412.  
  413.     b. Uses rownum tricks to obtain only the required rows from a given offset.
  414.      As this uses complicated sql statements, we only use this if the $offset >= 100. 
  415.      This idea by Tomas V V Cox.
  416.      
  417.      This implementation does not appear to work with oracle 8.0.5 or earlier. Comment
  418.      out this function then, and the slower SelectLimit() in the base class will be used.
  419.     */
  420.     function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
  421.     {
  422.         // seems that oracle only supports 1 hint comment in 8i
  423.         if ($this->firstrows) {
  424.             if (strpos($sql,'/*+') !== false)
  425.                 $sql = str_replace('/*+ ','/*+FIRST_ROWS ',$sql);
  426.             else
  427.                 $sql = preg_replace('/^[ \t\n]*select/i','SELECT /*+FIRST_ROWS*/',$sql);
  428.         }
  429.         
  430.         if ($offset < $this->selectOffsetAlg1) {
  431.             if ($nrows > 0) {    
  432.                 if ($offset > 0) $nrows += $offset;
  433.                 //$inputarr['adodb_rownum'] = $nrows;
  434.                 if ($this->databaseType == 'oci8po') {
  435.                     $sql = "select * from ($sql) where rownum <= ?";
  436.                 } else {
  437.                     $sql = "select * from ($sql) where rownum <= :adodb_offset";
  438.                 } 
  439.                 $inputarr['adodb_offset'] = $nrows;
  440.                 $nrows = -1;
  441.             }
  442.             // note that $nrows = 0 still has to work ==> no rows returned
  443.  
  444.             $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
  445.             return $rs;
  446.             
  447.         } else {
  448.              // Algorithm by Tomas V V Cox, from PEAR DB oci8.php
  449.             
  450.              // Let Oracle return the name of the columns
  451.              $q_fields = "SELECT * FROM ($sql) WHERE NULL = NULL";
  452.              if (!$stmt = OCIParse($this->_connectionID, $q_fields)) {
  453.                  return false;
  454.              }
  455.              
  456.              if (is_array($inputarr)) {
  457.                  foreach($inputarr as $k => $v) {
  458.                     if (is_array($v)) {
  459.                         if (sizeof($v) == 2) // suggested by g.giunta@libero.
  460.                             OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);
  461.                         else
  462.                             OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);
  463.                     } else {
  464.                         $len = -1;
  465.                         if ($v === ' ') $len = 1;
  466.                         if (isset($bindarr)) {    // is prepared sql, so no need to ocibindbyname again
  467.                             $bindarr[$k] = $v;
  468.                         } else {                 // dynamic sql, so rebind every time
  469.                             OCIBindByName($stmt,":$k",$inputarr[$k],$len);
  470.                         }
  471.                     }
  472.                 }
  473.             }
  474.             
  475.              if (!OCIExecute($stmt, OCI_DEFAULT)) {
  476.                  OCIFreeStatement($stmt); 
  477.                  return false;
  478.              }
  479.              
  480.              $ncols = OCINumCols($stmt);
  481.              for ( $i = 1; $i <= $ncols; $i++ ) {
  482.                  $cols[] = '"'.OCIColumnName($stmt, $i).'"';
  483.              }
  484.              $result = false;
  485.             
  486.              OCIFreeStatement($stmt); 
  487.              $fields = implode(',', $cols);
  488.              $nrows += $offset;
  489.              $offset += 1; // in Oracle rownum starts at 1
  490.             
  491.             if ($this->databaseType == 'oci8po') {
  492.                      $sql = "SELECT $fields FROM".
  493.                       "(SELECT rownum as adodb_rownum, $fields FROM".
  494.                       " ($sql) WHERE rownum <= ?".
  495.                       ") WHERE adodb_rownum >= ?";
  496.                 } else {
  497.                      $sql = "SELECT $fields FROM".
  498.                       "(SELECT rownum as adodb_rownum, $fields FROM".
  499.                       " ($sql) WHERE rownum <= :adodb_nrows".
  500.                       ") WHERE adodb_rownum >= :adodb_offset";
  501.                 } 
  502.                 $inputarr['adodb_nrows'] = $nrows;
  503.                 $inputarr['adodb_offset'] = $offset;
  504.                 
  505.             if ($secs2cache>0) $rs =& $this->CacheExecute($secs2cache, $sql,$inputarr);
  506.             else $rs =& $this->Execute($sql,$inputarr);
  507.             return $rs;
  508.         }
  509.     
  510.     }
  511.     
  512.     /**
  513.     * Usage:
  514.     * Store BLOBs and CLOBs
  515.     *
  516.     * Example: to store $var in a blob
  517.     *
  518.     *    $conn->Execute('insert into TABLE (id,ablob) values(12,empty_blob())');
  519.     *    $conn->UpdateBlob('TABLE', 'ablob', $varHoldingBlob, 'ID=12', 'BLOB');
  520.     *    
  521.     *    $blobtype supports 'BLOB' and 'CLOB', but you need to change to 'empty_clob()'.
  522.     *
  523.     *  to get length of LOB:
  524.     *      select DBMS_LOB.GETLENGTH(ablob) from TABLE
  525.     *
  526.     * If you are using CURSOR_SHARING = force, it appears this will case a segfault
  527.     * under oracle 8.1.7.0. Run:
  528.     *     $db->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');
  529.     * before UpdateBlob() then...
  530.     */
  531.  
  532.     function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
  533.     {
  534.         
  535.         //if (strlen($val) < 4000) return $this->Execute("UPDATE $table SET $column=:blob WHERE $where",array('blob'=>$val)) != false;
  536.         
  537.         switch(strtoupper($blobtype)) {
  538.         default: ADOConnection::outp("<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;
  539.         case 'BLOB': $type = OCI_B_BLOB; break;
  540.         case 'CLOB': $type = OCI_B_CLOB; break;
  541.         }
  542.         
  543.         if ($this->databaseType == 'oci8po') 
  544.             $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";
  545.         else 
  546.             $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";
  547.         
  548.         $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);
  549.         $arr['blob'] = array($desc,-1,$type);
  550.         if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');
  551.         $commit = $this->autoCommit;
  552.         if ($commit) $this->BeginTrans();
  553.         $rs = ADODB_oci8::Execute($sql,$arr);
  554.         if ($rez = !empty($rs)) $desc->save($val);
  555.         $desc->free();
  556.         if ($commit) $this->CommitTrans();
  557.         if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=FORCE');
  558.         
  559.         if ($rez) $rs->Close();
  560.         return $rez;
  561.     }
  562.     
  563.     /**
  564.     * Usage:  store file pointed to by $var in a blob
  565.     */
  566.     function UpdateBlobFile($table,$column,$val,$where,$blobtype='BLOB')
  567.     {
  568.         switch(strtoupper($blobtype)) {
  569.         default: ADOConnection::outp( "<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;
  570.         case 'BLOB': $type = OCI_B_BLOB; break;
  571.         case 'CLOB': $type = OCI_B_CLOB; break;
  572.         }
  573.         
  574.         if ($this->databaseType == 'oci8po') 
  575.             $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";
  576.         else 
  577.             $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";
  578.         
  579.         $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);
  580.         $arr['blob'] = array($desc,-1,$type);
  581.         
  582.         $this->BeginTrans();
  583.         $rs = ADODB_oci8::Execute($sql,$arr);
  584.         if ($rez = !empty($rs)) $desc->savefile($val);
  585.         $desc->free();
  586.         $this->CommitTrans();
  587.         
  588.         if ($rez) $rs->Close();
  589.         return $rez;
  590.     }
  591.  
  592.     
  593.     /*
  594.         Example of usage:
  595.         
  596.         $stmt = $this->Prepare('insert into emp (empno, ename) values (:empno, :ename)');
  597.     */
  598.     function Prepare($sql,$cursor=false)
  599.     {
  600.     static $BINDNUM = 0;
  601.     
  602.         $stmt = OCIParse($this->_connectionID,$sql);
  603.  
  604.         if (!$stmt) return false;
  605.  
  606.         $BINDNUM += 1;
  607.         
  608.         if (@OCIStatementType($stmt) == 'BEGIN') {
  609.             return array($sql,$stmt,0,$BINDNUM, ($cursor) ? OCINewCursor($this->_connectionID) : false);
  610.         } 
  611.         
  612.         return array($sql,$stmt,0,$BINDNUM);
  613.     }
  614.     
  615.     /*
  616.         Call an oracle stored procedure and return a cursor variable. 
  617.         Convert the cursor variable into a recordset. 
  618.         Concept by Robert Tuttle robert@ud.com
  619.         
  620.         Example:
  621.             Note: we return a cursor variable in :RS2
  622.             $rs = $db->ExecuteCursor("BEGIN adodb.open_tab(:RS2); END;",'RS2');
  623.             
  624.             $rs = $db->ExecuteCursor(
  625.                 "BEGIN :RS2 = adodb.getdata(:VAR1); END;", 
  626.                 'RS2',
  627.                 array('VAR1' => 'Mr Bean'));
  628.             
  629.     */
  630.     function &ExecuteCursor($sql,$cursorName='rs',$params=false)
  631.     {
  632.         $stmt = ADODB_oci8::Prepare($sql,true); # true to allocate OCINewCursor
  633.             
  634.         if (is_array($stmt) && sizeof($stmt) >= 5) {
  635.             $this->Parameter($stmt, $ignoreCur, $cursorName, false, -1, OCI_B_CURSOR);
  636.             if ($params) {
  637.                 foreach($params as $k => $v) {
  638.                     $this->Parameter($stmt,$params[$k], $k);
  639.                 }
  640.             }
  641.         }
  642.         return $this->Execute($stmt);
  643.     }
  644.     
  645.     /*
  646.         Bind a variable -- very, very fast for executing repeated statements in oracle. 
  647.         Better than using
  648.             for ($i = 0; $i < $max; $i++) {    
  649.                 $p1 = ?; $p2 = ?; $p3 = ?;
  650.                 $this->Execute("insert into table (col0, col1, col2) values (:0, :1, :2)", 
  651.                     array($p1,$p2,$p3));
  652.             }
  653.         
  654.         Usage:
  655.             $stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:0, :1, :2)");
  656.             $DB->Bind($stmt, $p1);
  657.             $DB->Bind($stmt, $p2);
  658.             $DB->Bind($stmt, $p3);
  659.             for ($i = 0; $i < $max; $i++) {    
  660.                 $p1 = ?; $p2 = ?; $p3 = ?;
  661.                 $DB->Execute($stmt);
  662.             }
  663.             
  664.         Some timings:        
  665.             ** Test table has 3 cols, and 1 index. Test to insert 1000 records
  666.             Time 0.6081s (1644.60 inserts/sec) with direct OCIParse/OCIExecute
  667.             Time 0.6341s (1577.16 inserts/sec) with ADOdb Prepare/Bind/Execute
  668.             Time 1.5533s ( 643.77 inserts/sec) with pure SQL using Execute
  669.             
  670.         Now if PHP only had batch/bulk updating like Java or PL/SQL...
  671.     
  672.         Note that the order of parameters differs from OCIBindByName,
  673.         because we default the names to :0, :1, :2
  674.     */
  675.     function Bind(&$stmt,&$var,$size=4000,$type=false,$name=false)
  676.     {
  677.         if (!is_array($stmt)) return false;
  678.         
  679.         if (($type == OCI_B_CURSOR) && sizeof($stmt) >= 5) { 
  680.             return OCIBindByName($stmt[1],":".$name,$stmt[4],$size,$type);
  681.         }
  682.         
  683.         if ($name == false) {
  684.             if ($type !== false) $rez = OCIBindByName($stmt[1],":".$name,$var,$size,$type);
  685.             else $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size); // +1 byte for null terminator
  686.             $stmt[2] += 1;
  687.         } else {
  688.             if ($type !== false) $rez = OCIBindByName($stmt[1],":".$name,$var,$size,$type);
  689.             else $rez = OCIBindByName($stmt[1],":".$name,$var,$size); // +1 byte for null terminator
  690.         }
  691.         
  692.         return $rez;
  693.     }
  694.     
  695.     function Param($name)
  696.     {
  697.         return ':'.$name;
  698.     }
  699.     
  700.     /* 
  701.     Usage:
  702.         $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
  703.         $db->Parameter($stmt,$id,'myid');
  704.         $db->Parameter($stmt,$group,'group');
  705.         $db->Execute($stmt);
  706.         
  707.         @param $stmt Statement returned by Prepare() or PrepareSP().
  708.         @param $var PHP variable to bind to
  709.         @param $name Name of stored procedure variable name to bind to.
  710.         @param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in oci8.
  711.         @param [$maxLen] Holds an maximum length of the variable.
  712.         @param [$type] The data type of $var. Legal values depend on driver.
  713.         
  714.         See OCIBindByName documentation at php.net.
  715.     */
  716.     function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)
  717.     {
  718.             if  ($this->debug) {
  719.                 $prefix = ($isOutput) ? 'Out' : 'In';
  720.                 $ztype = (empty($type)) ? 'false' : $type;
  721.                 ADOConnection::outp( "{$prefix}Parameter(\$stmt, \$php_var='$var', \$name='$name', \$maxLen=$maxLen, \$type=$ztype);");
  722.             }
  723.             return $this->Bind($stmt,$var,$maxLen,$type,$name);
  724.     }
  725.     
  726.     /*
  727.     returns query ID if successful, otherwise false
  728.     this version supports:
  729.     
  730.        1. $db->execute('select * from table');
  731.        
  732.        2. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');
  733.           $db->execute($prepared_statement, array(1,2,3));
  734.           
  735.        3. $db->execute('insert into table (a,b,c) values (:a,:b,:c)',array('a'=>1,'b'=>2,'c'=>3));
  736.        
  737.        4. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');
  738.           $db->$bind($stmt,1); $db->bind($stmt,2); $db->bind($stmt,3); 
  739.           $db->execute($stmt);
  740.     */ 
  741.     function _query($sql,$inputarr)
  742.     {
  743.         
  744.         if (is_array($sql)) { // is prepared sql
  745.             $stmt = $sql[1];
  746.             
  747.             // we try to bind to permanent array, so that OCIBindByName is persistent
  748.             // and carried out once only - note that max array element size is 4000 chars
  749.             if (is_array($inputarr)) {
  750.                 $bindpos = $sql[3];
  751.                 if (isset($this->_bind[$bindpos])) {
  752.                 // all tied up already
  753.                     $bindarr = &$this->_bind[$bindpos];
  754.                 } else {
  755.                 // one statement to bind them all
  756.                     $bindarr = array();
  757.                     foreach($inputarr as $k => $v) {
  758.                         $bindarr[$k] = $v;
  759.                         OCIBindByName($stmt,":$k",$bindarr[$k],4000);
  760.                     }
  761.                     $this->_bind[$bindpos] = &$bindarr;
  762.                 }
  763.             }
  764.         } else {
  765.             $stmt=OCIParse($this->_connectionID,$sql);
  766.         }
  767.             
  768.         $this->_stmt = $stmt;
  769.         if (!$stmt) return false;
  770.     
  771.         if (defined('ADODB_PREFETCH_ROWS')) @OCISetPrefetch($stmt,ADODB_PREFETCH_ROWS);
  772.             
  773.         if (is_array($inputarr)) {
  774.             foreach($inputarr as $k => $v) {
  775.                 if (is_array($v)) {
  776.                     if (sizeof($v) == 2) // suggested by g.giunta@libero.
  777.                         OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);
  778.                     else
  779.                         OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);
  780.                     
  781.                     if ($this->debug==99) echo "name=:$k",' var='.$inputarr[$k][0],' len='.$v[1],' type='.$v[2],'<br>';
  782.                 } else {
  783.                     $len = -1;
  784.                     if ($v === ' ') $len = 1;
  785.                     if (isset($bindarr)) {    // is prepared sql, so no need to ocibindbyname again
  786.                         $bindarr[$k] = $v;
  787.                     } else {                 // dynamic sql, so rebind every time
  788.                         OCIBindByName($stmt,":$k",$inputarr[$k],$len);
  789.                     }
  790.                 }
  791.             }
  792.         }
  793.         
  794.         $this->_errorMsg = false;
  795.         $this->_errorCode = false;
  796.         if (OCIExecute($stmt,$this->_commit)) {
  797.         
  798.             switch (@OCIStatementType($stmt)) {
  799.                 case "SELECT":
  800.                     return $stmt;
  801.                     
  802.                 case "BEGIN":
  803.                     if (is_array($sql) && !empty($sql[4])) {
  804.                         $cursor = $sql[4];
  805.                         if (is_resource($cursor)) {
  806.                             $ok = OCIExecute($cursor);    
  807.                             return $cursor;
  808.                         }
  809.                         return $stmt;
  810.                     } else {
  811.                         if (is_resource($stmt)) {
  812.                             OCIFreeStatement($stmt);
  813.                             return true;
  814.                         }
  815.                         return $stmt;
  816.                     }
  817.                     break;
  818.                 default :
  819.                     // ociclose -- no because it could be used in a LOB?
  820.                     return true;
  821.             }
  822.         }
  823.         return false;
  824.     }
  825.     
  826.     // returns true or false
  827.     function _close()
  828.     {
  829.         if (!$this->autoCommit) OCIRollback($this->_connectionID);
  830.         OCILogoff($this->_connectionID);
  831.         $this->_stmt = false;
  832.         $this->_connectionID = false;
  833.     }
  834.     
  835.     function MetaPrimaryKeys($table, $owner=false,$internalKey=false)
  836.     {
  837.         if ($internalKey) return array('ROWID');
  838.         
  839.     // tested with oracle 8.1.7
  840.         $table = strtoupper($table);
  841.         if ($owner) {
  842.             $owner_clause = "AND ((a.OWNER = b.OWNER) AND (a.OWNER = UPPER('$owner')))";
  843.             $ptab = 'ALL_';
  844.         } else {
  845.             $owner_clause = '';
  846.             $ptab = 'USER_';
  847.         }
  848.         $sql = "
  849. SELECT /*+ RULE */ distinct b.column_name
  850.    FROM {$ptab}CONSTRAINTS a
  851.       , {$ptab}CONS_COLUMNS b
  852.   WHERE ( UPPER(b.table_name) = ('$table'))
  853.     AND (UPPER(a.table_name) = ('$table') and a.constraint_type = 'P')
  854.     $owner_clause
  855.     AND (a.constraint_name = b.constraint_name)";
  856.  
  857.          $rs = $this->Execute($sql);
  858.         if ($rs && !$rs->EOF) {
  859.             $arr =& $rs->GetArray();
  860.             $a = array();
  861.             foreach($arr as $v) {
  862.                 $a[] = reset($v);
  863.             }
  864.             return $a;
  865.         }
  866.         else return false;
  867.     }
  868.     
  869.     // http://gis.mit.edu/classes/11.521/sqlnotes/referential_integrity.html
  870.     function MetaForeignKeys($table, $owner=false)
  871.     {
  872.     global $ADODB_FETCH_MODE;
  873.     
  874.         $save = $ADODB_FETCH_MODE;
  875.         $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
  876.         $table = $this->qstr(strtoupper($table));
  877.         if (!$owner) {
  878.             $owner = $this->user;
  879.             $tabp = 'user_';
  880.         } else
  881.             $tabp = 'all_';
  882.             
  883.         $owner = ' and owner='.$this->qstr(strtoupper($owner));
  884.         
  885.         $sql = 
  886. "select constraint_name,r_owner,r_constraint_name 
  887.     from {$tabp}constraints
  888.     where constraint_type = 'R' and table_name = $table $owner";
  889.         
  890.         $constraints =& $this->GetArray($sql);
  891.         $arr = false;
  892.         foreach($constraints as $constr) {
  893.             $cons = $this->qstr($constr[0]);
  894.             $rowner = $this->qstr($constr[1]);
  895.             $rcons = $this->qstr($constr[2]);
  896.             $cols = $this->GetArray("select column_name from {$tabp}cons_columns where constraint_name=$cons $owner order by position");
  897.             $tabcol = $this->GetArray("select table_name,column_name from {$tabp}cons_columns where owner=$rowner and constraint_name=$rcons order by position");
  898.             
  899.             if ($cols && $tabcol) 
  900.                 for ($i=0, $max=sizeof($cols); $i < $max; $i++) {
  901.                     $arr[$tabcol[$i][0]] = $cols[$i][0].'='.$tabcol[$i][1];
  902.                 }
  903.         }
  904.         $ADODB_FETCH_MODE = $save;
  905.         
  906.         return $arr;
  907.     }
  908.  
  909.     
  910.     function CharMax()
  911.     {
  912.         return 4000;
  913.     }
  914.     
  915.     function TextMax()
  916.     {
  917.         return 4000;
  918.     }
  919.     
  920.     /**
  921.      * Quotes a string.
  922.      * An example is  $db->qstr("Don't bother",magic_quotes_runtime());
  923.      * 
  924.      * @param s            the string to quote
  925.      * @param [magic_quotes]    if $s is GET/POST var, set to get_magic_quotes_gpc().
  926.      *                This undoes the stupidity of magic quotes for GPC.
  927.      *
  928.      * @return  quoted string to be sent back to database
  929.      */
  930.     function qstr($s,$magic_quotes=false)
  931.     {    
  932.     $nofixquotes=false;
  933.     
  934.         if (is_array($s)) adodb_backtrace();
  935.         if ($this->noNullStrings && strlen($s)==0)$s = ' ';
  936.         if (!$magic_quotes) {    
  937.             if ($this->replaceQuote[0] == '\\'){
  938.                 $s = str_replace('\\','\\\\',$s);
  939.             }
  940.             return  "'".str_replace("'",$this->replaceQuote,$s)."'";
  941.         }
  942.         
  943.         // undo magic quotes for "
  944.         $s = str_replace('\\"','"',$s);
  945.         
  946.         if ($this->replaceQuote == "\\'")  // ' already quoted, no need to change anything
  947.             return "'$s'";
  948.         else {// change \' to '' for sybase/mssql
  949.             $s = str_replace('\\\\','\\',$s);
  950.             return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
  951.         }
  952.     }
  953.     
  954. }
  955.  
  956. /*--------------------------------------------------------------------------------------
  957.          Class Name: Recordset
  958. --------------------------------------------------------------------------------------*/
  959.  
  960. class ADORecordset_oci8 extends ADORecordSet {
  961.  
  962.     var $databaseType = 'oci8';
  963.     var $bind=false;
  964.     var $_fieldobjs;
  965.     //var $_arr = false;
  966.         
  967.     function ADORecordset_oci8($queryID,$mode=false)
  968.     {
  969.         if ($mode === false) { 
  970.             global $ADODB_FETCH_MODE;
  971.             $mode = $ADODB_FETCH_MODE;
  972.         }
  973.         switch ($mode)
  974.         {
  975.         default:
  976.         case ADODB_FETCH_NUM: $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
  977.         case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
  978.         case ADODB_FETCH_DEFAULT:
  979.         case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
  980.         }
  981.  
  982.         $this->_queryID = $queryID;
  983.     }
  984.  
  985.  
  986.     function Init()
  987.     {
  988.         if ($this->_inited) return;
  989.         
  990.         $this->_inited = true;
  991.         if ($this->_queryID) {
  992.             
  993.             $this->_currentRow = 0;
  994.             @$this->_initrs();
  995.             $this->EOF = !$this->_fetch();
  996.             
  997.             /*
  998.             // based on idea by Gaetano Giunta to detect unusual oracle errors
  999.             // see http://phplens.com/lens/lensforum/msgs.php?id=6771
  1000.             $err = OCIError($this->_queryID);
  1001.             if ($err && $this->connection->debug) ADOConnection::outp($err);
  1002.             */
  1003.             
  1004.             if (!is_array($this->fields)) {
  1005.                 $this->_numOfRows = 0;
  1006.                 $this->fields = array();
  1007.             }
  1008.         } else {
  1009.             $this->fields = array();
  1010.             $this->_numOfRows = 0;
  1011.             $this->_numOfFields = 0;
  1012.             $this->EOF = true;
  1013.         }
  1014.     }
  1015.     
  1016.     function _initrs()
  1017.     {
  1018.         $this->_numOfRows = -1;
  1019.         $this->_numOfFields = OCInumcols($this->_queryID);
  1020.         if ($this->_numOfFields>0) {
  1021.             $this->_fieldobjs = array();
  1022.             $max = $this->_numOfFields;
  1023.             for ($i=0;$i<$max; $i++) $this->_fieldobjs[] = $this->_FetchField($i);
  1024.         }
  1025.     }
  1026.  
  1027.       /*        Returns: an object containing field information.
  1028.               Get column information in the Recordset object. fetchField() can be used in order to obtain information about
  1029.               fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
  1030.               fetchField() is retrieved.        */
  1031.  
  1032.     function &_FetchField($fieldOffset = -1)
  1033.     {
  1034.         $fld = new ADOFieldObject;
  1035.         $fieldOffset += 1;
  1036.         $fld->name =OCIcolumnname($this->_queryID, $fieldOffset);
  1037.         $fld->type = OCIcolumntype($this->_queryID, $fieldOffset);
  1038.         $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset);
  1039.          if ($fld->type == 'NUMBER') {
  1040.              $p = OCIColumnPrecision($this->_queryID, $fieldOffset);
  1041.             $sc = OCIColumnScale($this->_queryID, $fieldOffset);
  1042.             if ($p != 0 && $sc == 0) $fld->type = 'INT';
  1043.             //echo " $this->name ($p.$sc) ";
  1044.          }
  1045.         return $fld;
  1046.     }
  1047.     
  1048.     /* For some reason, OCIcolumnname fails when called after _initrs() so we cache it */
  1049.     function &FetchField($fieldOffset = -1)
  1050.     {
  1051.         return $this->_fieldobjs[$fieldOffset];
  1052.     }
  1053.     
  1054.     
  1055.     // 10% speedup to move MoveNext to child class
  1056.     function MoveNext() 
  1057.     {
  1058.     //global $ADODB_EXTENSION;if ($ADODB_EXTENSION) return @adodb_movenext($this);
  1059.         
  1060.         if ($this->EOF) return false;
  1061.         
  1062.         $this->_currentRow++;
  1063.         if(@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode))
  1064.             return true;
  1065.         $this->EOF = true;
  1066.         
  1067.         return false;
  1068.     }    
  1069.     
  1070.     /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */
  1071.     function &GetArrayLimit($nrows,$offset=-1) 
  1072.     {
  1073.         if ($offset <= 0) {
  1074.             $arr =& $this->GetArray($nrows);
  1075.             return $arr;
  1076.         }
  1077.         for ($i=1; $i < $offset; $i++) 
  1078.             if (!@OCIFetch($this->_queryID)) return array();
  1079.             
  1080.         if (!@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) return array();
  1081.         $results = array();
  1082.         $cnt = 0;
  1083.         while (!$this->EOF && $nrows != $cnt) {
  1084.             $results[$cnt++] = $this->fields;
  1085.             $this->MoveNext();
  1086.         }
  1087.         
  1088.         return $results;
  1089.     }
  1090.  
  1091.     
  1092.     /* Use associative array to get fields array */
  1093.     function Fields($colname)
  1094.     {
  1095.         if (!$this->bind) {
  1096.             $this->bind = array();
  1097.             for ($i=0; $i < $this->_numOfFields; $i++) {
  1098.                 $o = $this->FetchField($i);
  1099.                 $this->bind[strtoupper($o->name)] = $i;
  1100.             }
  1101.         }
  1102.         
  1103.          return $this->fields[$this->bind[strtoupper($colname)]];
  1104.     }
  1105.     
  1106.  
  1107.  
  1108.     function _seek($row)
  1109.     {
  1110.         return false;
  1111.     }
  1112.  
  1113.     function _fetch() 
  1114.     {
  1115.         return @OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode);
  1116.     }
  1117.  
  1118.     /*        close() only needs to be called if you are worried about using too much memory while your script
  1119.             is running. All associated result memory for the specified result identifier will automatically be freed.        */
  1120.  
  1121.     function _close() 
  1122.     {
  1123.         if ($this->connection->_stmt === $this->_queryID) $this->connection->_stmt = false;
  1124.         OCIFreeStatement($this->_queryID);
  1125.          $this->_queryID = false;
  1126.         
  1127.     }
  1128.  
  1129.     function MetaType($t,$len=-1)
  1130.     {
  1131.         if (is_object($t)) {
  1132.             $fieldobj = $t;
  1133.             $t = $fieldobj->type;
  1134.             $len = $fieldobj->max_length;
  1135.         }
  1136.         switch (strtoupper($t)) {
  1137.          case 'VARCHAR':
  1138.          case 'VARCHAR2':
  1139.         case 'CHAR':
  1140.         case 'VARBINARY':
  1141.         case 'BINARY':
  1142.         case 'NCHAR':
  1143.         case 'NVARCHAR':
  1144.         case 'NVARCHAR2':
  1145.                  if (isset($this) && $len <= $this->blobSize) return 'C';
  1146.         
  1147.         case 'NCLOB':
  1148.         case 'LONG':
  1149.         case 'LONG VARCHAR':
  1150.         case 'CLOB':
  1151.         return 'X';
  1152.         
  1153.         case 'LONG RAW':
  1154.         case 'LONG VARBINARY':
  1155.         case 'BLOB':
  1156.             return 'B';
  1157.         
  1158.         case 'DATE': 
  1159.             return  ($this->connection->datetime) ? 'T' : 'D';
  1160.         
  1161.         
  1162.         case 'TIMESTAMP': return 'T';
  1163.         
  1164.         case 'INT': 
  1165.         case 'SMALLINT':
  1166.         case 'INTEGER': 
  1167.             return 'I';
  1168.             
  1169.         default: return 'N';
  1170.         }
  1171.     }
  1172. }
  1173. ?>