home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 June / ENTER.ISO / files / xampp-win32-1.4.5-installer.exe / xampp / sybase.php < prev    next >
Encoding:
PHP Script  |  2004-03-24  |  24.9 KB  |  838 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 foldmethod=marker: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Sterling Hughes <sterling@php.net>                          |
  17. // |          Ant⌠nio Carlos VenΓncio J·nior <floripa@php.net>            |
  18. // | Maintainer: Daniel Convissor <danielc@php.net>                       |
  19. // +----------------------------------------------------------------------+
  20. //
  21. // $Id: sybase.php,v 1.50 2004/03/05 01:46:53 danielc Exp $
  22.  
  23.  
  24. // TODO
  25. //    - This driver may fail with multiple connections under the same
  26. //      user/pass/host and different databases
  27.  
  28.  
  29. require_once 'DB/common.php';
  30.  
  31. /**
  32.  * Database independent query interface definition for PHP's Sybase
  33.  * extension.
  34.  *
  35.  * @package  DB
  36.  * @version  $Id: sybase.php,v 1.50 2004/03/05 01:46:53 danielc Exp $
  37.  * @category Database
  38.  * @author   Sterling Hughes <sterling@php.net>
  39.  * @author   Ant⌠nio Carlos VenΓncio J·nior <floripa@php.net>
  40.  */
  41. class DB_sybase extends DB_common
  42. {
  43.     // {{{ properties
  44.  
  45.     var $connection;
  46.     var $phptype, $dbsyntax;
  47.     var $prepare_tokens = array();
  48.     var $prepare_types = array();
  49.     var $transaction_opcount = 0;
  50.     var $autocommit = true;
  51.  
  52.     // }}}
  53.     // {{{ constructor
  54.  
  55.     /**
  56.      * DB_sybase constructor.
  57.      *
  58.      * @access public
  59.      */
  60.     function DB_sybase()
  61.     {
  62.         $this->DB_common();
  63.         $this->phptype = 'sybase';
  64.         $this->dbsyntax = 'sybase';
  65.         $this->features = array(
  66.             'prepare' => false,
  67.             'pconnect' => true,
  68.             'transactions' => false,
  69.             'limit' => 'emulate'
  70.         );
  71.         $this->errorcode_map = array(
  72.         );
  73.     }
  74.  
  75.     // }}}
  76.     // {{{ connect()
  77.  
  78.     /**
  79.      * Connect to a database and log in as the specified user.
  80.      *
  81.      * @param $dsn the data source name (see DB::parseDSN for syntax)
  82.      * @param $persistent (optional) whether the connection should
  83.      *        be persistent
  84.      * @access public
  85.      * @return int DB_OK on success, a DB error on failure
  86.      */
  87.     function connect($dsninfo, $persistent = false)
  88.     {
  89.         if (!DB::assertExtension('sybase') &&
  90.             !DB::assertExtension('sybase_ct'))
  91.         {
  92.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  93.         }
  94.  
  95.         $this->dsn = $dsninfo;
  96.  
  97.         $interface = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost';
  98.         $connect_function = $persistent ? 'sybase_pconnect' : 'sybase_connect';
  99.  
  100.         if ($interface && $dsninfo['username'] && $dsninfo['password']) {
  101.             $conn = @$connect_function($interface, $dsninfo['username'],
  102.                                        $dsninfo['password']);
  103.         } elseif ($interface && $dsninfo['username']) {
  104.             /*
  105.              * Using false for pw as a workaround to avoid segfault.
  106.              * See PEAR bug 631
  107.              */
  108.             $conn = @$connect_function($interface, $dsninfo['username'],
  109.                                        false);
  110.         } else {
  111.             $conn = false;
  112.         }
  113.  
  114.         if (!$conn) {
  115.             return $this->raiseError(DB_ERROR_CONNECT_FAILED);
  116.         }
  117.  
  118.         if ($dsninfo['database']) {
  119.             if (!@sybase_select_db($dsninfo['database'], $conn)) {
  120.                 return $this->raiseError(DB_ERROR_NODBSELECTED, null,
  121.                                          null, null, @sybase_get_last_message());
  122.             }
  123.             $this->_db = $dsninfo['database'];
  124.         }
  125.  
  126.         $this->connection = $conn;
  127.         return DB_OK;
  128.     }
  129.  
  130.     // }}}
  131.     // {{{ disconnect()
  132.  
  133.     /**
  134.      * Log out and disconnect from the database.
  135.      *
  136.      * @access public
  137.      *
  138.      * @return bool true on success, false if not connected.
  139.      */
  140.     function disconnect()
  141.     {
  142.         $ret = @sybase_close($this->connection);
  143.         $this->connection = null;
  144.         return $ret;
  145.     }
  146.  
  147.     // }}}
  148.     // {{{ errorNative()
  149.  
  150.     /**
  151.      * Get the last server error messge (if any)
  152.      *
  153.      * @return string sybase last error message
  154.      */
  155.     function errorNative()
  156.     {
  157.         return @sybase_get_last_message();
  158.     }
  159.  
  160.     // }}}
  161.     // {{{ errorCode()
  162.  
  163.     /**
  164.      * Determine PEAR::DB error code from the database's text error message.
  165.      *
  166.      * @param  string  $errormsg  error message returned from the database
  167.      * @return integer  an error number from a DB error constant
  168.      */
  169.     function errorCode($errormsg)
  170.     {
  171.         static $error_regexps;
  172.         if (!isset($error_regexps)) {
  173.             $error_regexps = array(
  174.                 '/Incorrect syntax near/'
  175.                     => DB_ERROR_SYNTAX,
  176.                 '/^Unclosed quote before the character string [\"\'].*[\"\']\./'
  177.                     => DB_ERROR_SYNTAX,
  178.                 '/Implicit conversion from datatype [\"\'].+[\"\'] to [\"\'].+[\"\'] is not allowed\./'
  179.                     => DB_ERROR_INVALID_NUMBER,
  180.                 '/Cannot drop the table [\"\'].+[\"\'], because it doesn\'t exist in the system catalogs\./'
  181.                     => DB_ERROR_NOSUCHTABLE,
  182.                 '/Only the owner of object [\"\'].+[\"\'] or a user with System Administrator \(SA\) role can run this command\./'
  183.                     => DB_ERROR_ACCESS_VIOLATION,
  184.                 '/^.+ permission denied on object .+, database .+, owner .+/'
  185.                     => DB_ERROR_ACCESS_VIOLATION,
  186.                 '/^.* permission denied, database .+, owner .+/'
  187.                     => DB_ERROR_ACCESS_VIOLATION,
  188.                 '/[^.*] not found\./'
  189.                     => DB_ERROR_NOSUCHTABLE,
  190.                 '/There is already an object named/'
  191.                     => DB_ERROR_ALREADY_EXISTS,
  192.                 '/Invalid column name/'
  193.                     => DB_ERROR_NOSUCHFIELD,
  194.                 '/does not allow null values/'
  195.                     => DB_ERROR_CONSTRAINT_NOT_NULL,
  196.                 '/Command has been aborted/'
  197.                     => DB_ERROR_CONSTRAINT,
  198.             );
  199.         }
  200.  
  201.         foreach ($error_regexps as $regexp => $code) {
  202.             if (preg_match($regexp, $errormsg)) {
  203.                 return $code;
  204.             }
  205.         }
  206.         return DB_ERROR;
  207.     }
  208.  
  209.     // }}}
  210.     // {{{ sybaseRaiseError()
  211.  
  212.     /**
  213.      * Gather information about an error, then use that info to create a
  214.      * DB error object and finally return that object.
  215.      *
  216.      * @param  integer  $errno  PEAR error number (usually a DB constant) if
  217.      *                          manually raising an error
  218.      * @return object  DB error object
  219.      * @see errorNative()
  220.      * @see errorCode()
  221.      * @see DB_common::raiseError()
  222.      */
  223.     function sybaseRaiseError($errno = null)
  224.     {
  225.         $native = $this->errorNative();
  226.         if ($errno === null) {
  227.             $errno = $this->errorCode($native);
  228.         }
  229.         return $this->raiseError($errno, null, null, null, $native);
  230.     }
  231.  
  232.     // }}}
  233.     // {{{ simpleQuery()
  234.  
  235.     /**
  236.      * Send a query to Sybase and return the results as a Sybase resource
  237.      * identifier.
  238.      *
  239.      * @param the SQL query
  240.      *
  241.      * @access public
  242.      *
  243.      * @return mixed returns a valid Sybase result for successful SELECT
  244.      * queries, DB_OK for other successful queries.  A DB error is
  245.      * returned on failure.
  246.      */
  247.     function simpleQuery($query)
  248.     {
  249.         $ismanip = DB::isManip($query);
  250.         $this->last_query = $query;
  251.         if (!@sybase_select_db($this->_db, $this->connection)) {
  252.             return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
  253.         }
  254.         $query = $this->modifyQuery($query);
  255.         if (!$this->autocommit && $ismanip) {
  256.             if ($this->transaction_opcount == 0) {
  257.                 $result = @sybase_query('BEGIN TRANSACTION', $this->connection);
  258.                 if (!$result) {
  259.                     return $this->sybaseRaiseError();
  260.                 }
  261.             }
  262.             $this->transaction_opcount++;
  263.         }
  264.         $result = @sybase_query($query, $this->connection);
  265.         if (!$result) {
  266.             return $this->sybaseRaiseError();
  267.         }
  268.         if (is_resource($result)) {
  269.             $numrows = $this->numRows($result);
  270.             if (is_object($numrows)) {
  271.                 return $numrows;
  272.             }
  273.             $this->num_rows[(int)$result] = $numrows;
  274.             return $result;
  275.         }
  276.         // Determine which queries that should return data, and which
  277.         // should return an error code only.
  278.         return $ismanip ? DB_OK : $result;
  279.     }
  280.  
  281.     // }}}
  282.     // {{{ nextResult()
  283.  
  284.     /**
  285.      * Move the internal sybase result pointer to the next available result
  286.      *
  287.      * @param a valid sybase result resource
  288.      *
  289.      * @access public
  290.      *
  291.      * @return true if a result is available otherwise return false
  292.      */
  293.     function nextResult($result)
  294.     {
  295.         return false;
  296.     }
  297.  
  298.     // }}}
  299.     // {{{ fetchInto()
  300.  
  301.     /**
  302.      * Fetch a row and insert the data into an existing array.
  303.      *
  304.      * Formating of the array and the data therein are configurable.
  305.      * See DB_result::fetchInto() for more information.
  306.      *
  307.      * @param resource $result    query result identifier
  308.      * @param array    $arr       (reference) array where data from the row
  309.      *                            should be placed
  310.      * @param int      $fetchmode how the resulting array should be indexed
  311.      * @param int      $rownum    the row number to fetch
  312.      *
  313.      * @return mixed DB_OK on success, null when end of result set is
  314.      *               reached or on failure
  315.      *
  316.      * @see DB_result::fetchInto()
  317.      * @access private
  318.      */
  319.     function fetchInto($result, &$arr, $fetchmode, $rownum=null)
  320.     {
  321.         if ($rownum !== null) {
  322.             if (!@sybase_data_seek($result, $rownum)) {
  323.                 return null;
  324.             }
  325.         }
  326.         if ($fetchmode & DB_FETCHMODE_ASSOC) {
  327.             if (function_exists('sybase_fetch_assoc')) {
  328.                 $arr = @sybase_fetch_assoc($result);
  329.             } else {
  330.                 if ($arr = @sybase_fetch_array($result)) {
  331.                     foreach ($arr as $key => $value) {
  332.                         if (is_int($key)) {
  333.                             unset($arr[$key]);
  334.                         }
  335.                     }
  336.                 }
  337.             }
  338.             if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE && $arr) {
  339.                 $arr = array_change_key_case($arr, CASE_LOWER);
  340.             }
  341.         } else {
  342.             $arr = @sybase_fetch_row($result);
  343.         }
  344.         if (!$arr) {
  345.             // reported not work as seems that sybase_get_last_message()
  346.             // always return a message here
  347.             //if ($errmsg = @sybase_get_last_message()) {
  348.             //    return $this->sybaseRaiseError($errmsg);
  349.             //} else {
  350.                 return null;
  351.             //}
  352.         }
  353.         if ($this->options['portability'] & DB_PORTABILITY_RTRIM) {
  354.             $this->_rtrimArrayValues($arr);
  355.         }
  356.         if ($this->options['portability'] & DB_PORTABILITY_NULL_TO_EMPTY) {
  357.             $this->_convertNullArrayValuesToEmpty($arr);
  358.         }
  359.         return DB_OK;
  360.     }
  361.  
  362.     // }}}
  363.     // {{{ freeResult()
  364.  
  365.     /**
  366.      * Free the internal resources associated with $result.
  367.      *
  368.      * @param $result Sybase result identifier
  369.      *
  370.      * @access public
  371.      *
  372.      * @return bool true on success, false if $result is invalid
  373.      */
  374.     function freeResult($result)
  375.     {
  376.         unset($this->num_rows[(int)$result]);
  377.         return @sybase_free_result($result);
  378.     }
  379.  
  380.     // }}}
  381.     // {{{ numCols()
  382.  
  383.     /**
  384.      * Get the number of columns in a result set.
  385.      *
  386.      * @param $result Sybase result identifier
  387.      *
  388.      * @access public
  389.      *
  390.      * @return int the number of columns per row in $result
  391.      */
  392.     function numCols($result)
  393.     {
  394.         $cols = @sybase_num_fields($result);
  395.         if (!$cols) {
  396.             return $this->sybaseRaiseError();
  397.         }
  398.         return $cols;
  399.     }
  400.  
  401.     // }}}
  402.     // {{{ numRows()
  403.  
  404.     /**
  405.      * Get the number of rows in a result set.
  406.      *
  407.      * @param $result Sybase result identifier
  408.      *
  409.      * @access public
  410.      *
  411.      * @return int the number of rows in $result
  412.      */
  413.     function numRows($result)
  414.     {
  415.         $rows = @sybase_num_rows($result);
  416.         if ($rows === false) {
  417.             return $this->sybaseRaiseError();
  418.         }
  419.         return $rows;
  420.     }
  421.  
  422.     // }}}
  423.     // {{{ affectedRows()
  424.  
  425.     /**
  426.      * Gets the number of rows affected by the data manipulation
  427.      * query.  For other queries, this function returns 0.
  428.      *
  429.      * @return number of rows affected by the last query
  430.      */
  431.     function affectedRows()
  432.     {
  433.         if (DB::isManip($this->last_query)) {
  434.             $result = @sybase_affected_rows($this->connection);
  435.         } else {
  436.             $result = 0;
  437.         }
  438.         return $result;
  439.      }
  440.  
  441.     // }}}
  442.     // {{{ nextId()
  443.  
  444.     /**
  445.      * Returns the next free id in a sequence
  446.      *
  447.      * @param string  $seq_name  name of the sequence
  448.      * @param boolean $ondemand  when true, the seqence is automatically
  449.      *                           created if it does not exist
  450.      *
  451.      * @return int  the next id number in the sequence.  DB_Error if problem.
  452.      *
  453.      * @internal
  454.      * @see DB_common::nextID()
  455.      * @access public
  456.      */
  457.     function nextId($seq_name, $ondemand = true)
  458.     {
  459.         $seqname = $this->getSequenceName($seq_name);
  460.         if (!@sybase_select_db($this->_db, $this->connection)) {
  461.             return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
  462.         }
  463.         $repeat = 0;
  464.         do {
  465.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  466.             $result = $this->query("INSERT INTO $seqname (vapor) VALUES (0)");
  467.             $this->popErrorHandling();
  468.             if ($ondemand && DB::isError($result) &&
  469.                 ($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE))
  470.             {
  471.                 $repeat = 1;
  472.                 $result = $this->createSequence($seq_name);
  473.                 if (DB::isError($result)) {
  474.                     return $this->raiseError($result);
  475.                 }
  476.             } elseif (!DB::isError($result)) {
  477.                 $result =& $this->query("SELECT @@IDENTITY FROM $seqname");
  478.                 $repeat = 0;
  479.             } else {
  480.                 $repeat = false;
  481.             }
  482.         } while ($repeat);
  483.         if (DB::isError($result)) {
  484.             return $this->raiseError($result);
  485.         }
  486.         $result = $result->fetchRow(DB_FETCHMODE_ORDERED);
  487.         return $result[0];
  488.     }
  489.  
  490.     /**
  491.      * Creates a new sequence
  492.      *
  493.      * @param string $seq_name  name of the new sequence
  494.      *
  495.      * @return int  DB_OK on success.  A DB_Error object is returned if
  496.      *              problems arise.
  497.      *
  498.      * @internal
  499.      * @see DB_common::createSequence()
  500.      * @access public
  501.      */
  502.     function createSequence($seq_name)
  503.     {
  504.         $seqname = $this->getSequenceName($seq_name);
  505.         return $this->query("CREATE TABLE $seqname ".
  506.                             '(id numeric(10,0) IDENTITY NOT NULL ,' .
  507.                             'vapor int NULL)');
  508.     }
  509.  
  510.     // }}}
  511.     // {{{ dropSequence()
  512.  
  513.     /**
  514.      * Deletes a sequence
  515.      *
  516.      * @param string $seq_name  name of the sequence to be deleted
  517.      *
  518.      * @return int  DB_OK on success.  DB_Error if problems.
  519.      *
  520.      * @internal
  521.      * @see DB_common::dropSequence()
  522.      * @access public
  523.      */
  524.     function dropSequence($seq_name)
  525.     {
  526.         $seqname = $this->getSequenceName($seq_name);
  527.         return $this->query("DROP TABLE $seqname");
  528.     }
  529.  
  530.     // }}}
  531.     // {{{ getSpecialQuery()
  532.  
  533.     /**
  534.      * Returns the query needed to get some backend info
  535.      * @param string $type What kind of info you want to retrieve
  536.      * @return string The SQL query string
  537.      */
  538.     function getSpecialQuery($type)
  539.     {
  540.         switch ($type) {
  541.             case 'tables':
  542.                 return "select name from sysobjects where type = 'U' order by name";
  543.             case 'views':
  544.                 return "select name from sysobjects where type = 'V'";
  545.             default:
  546.                 return null;
  547.         }
  548.     }
  549.  
  550.     // }}}
  551.     // {{{ autoCommit()
  552.  
  553.     /**
  554.      * Enable/disable automatic commits
  555.      */
  556.     function autoCommit($onoff = false)
  557.     {
  558.         // XXX if $this->transaction_opcount > 0, we should probably
  559.         // issue a warning here.
  560.         $this->autocommit = $onoff ? true : false;
  561.         return DB_OK;
  562.     }
  563.  
  564.     // }}}
  565.     // {{{ commit()
  566.  
  567.     /**
  568.      * Commit the current transaction.
  569.      */
  570.     function commit()
  571.     {
  572.         if ($this->transaction_opcount > 0) {
  573.             if (!@sybase_select_db($this->_db, $this->connection)) {
  574.                 return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
  575.             }
  576.             $result = @sybase_query('COMMIT', $this->connection);
  577.             $this->transaction_opcount = 0;
  578.             if (!$result) {
  579.                 return $this->sybaseRaiseError();
  580.             }
  581.         }
  582.         return DB_OK;
  583.     }
  584.  
  585.     // }}}
  586.     // {{{ rollback()
  587.  
  588.     /**
  589.      * Roll back (undo) the current transaction.
  590.      */
  591.     function rollback()
  592.     {
  593.         if ($this->transaction_opcount > 0) {
  594.             if (!@sybase_select_db($this->_db, $this->connection)) {
  595.                 return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
  596.             }
  597.             $result = @sybase_query('ROLLBACK', $this->connection);
  598.             $this->transaction_opcount = 0;
  599.             if (!$result) {
  600.                 return $this->sybaseRaiseError();
  601.             }
  602.         }
  603.         return DB_OK;
  604.     }
  605.  
  606.     // }}}
  607.     // {{{ tableInfo()
  608.  
  609.     /**
  610.      * Returns information about a table or a result set.
  611.      *
  612.      * NOTE: only supports 'table' and 'flags' if <var>$result</var>
  613.      * is a table name.
  614.      *
  615.      * @param object|string  $result  DB_result object from a query or a
  616.      *                                string containing the name of a table
  617.      * @param int            $mode    a valid tableInfo mode
  618.      * @return array  an associative array with the information requested
  619.      *                or an error object if something is wrong
  620.      * @access public
  621.      * @internal
  622.      * @since 1.6.0
  623.      * @see DB_common::tableInfo()
  624.      */
  625.     function tableInfo($result, $mode = null)
  626.     {
  627.         if (isset($result->result)) {
  628.             /*
  629.              * Probably received a result object.
  630.              * Extract the result resource identifier.
  631.              */
  632.             $id = $result->result;
  633.             $got_string = false;
  634.         } elseif (is_string($result)) {
  635.             /*
  636.              * Probably received a table name.
  637.              * Create a result resource identifier.
  638.              */
  639.             if (!@sybase_select_db($this->_db, $this->connection)) {
  640.                 return $this->sybaseRaiseError(DB_ERROR_NODBSELECTED);
  641.             }
  642.             $id = @sybase_query("SELECT * FROM $result WHERE 1=0",
  643.                                 $this->connection);
  644.             $got_string = true;
  645.         } else {
  646.             /*
  647.              * Probably received a result resource identifier.
  648.              * Copy it.
  649.              * Depricated.  Here for compatibility only.
  650.              */
  651.             $id = $result;
  652.             $got_string = false;
  653.         }
  654.  
  655.         if (!is_resource($id)) {
  656.             return $this->sybaseRaiseError(DB_ERROR_NEED_MORE_DATA);
  657.         }
  658.  
  659.         if ($this->options['portability'] & DB_PORTABILITY_LOWERCASE) {
  660.             $case_func = 'strtolower';
  661.         } else {
  662.             $case_func = 'strval';
  663.         }
  664.  
  665.         $count = @sybase_num_fields($id);
  666.  
  667.         // made this IF due to performance (one if is faster than $count if's)
  668.         if (!$mode) {
  669.  
  670.             for ($i=0; $i<$count; $i++) {
  671.                 $f = @sybase_fetch_field($id, $i);
  672.  
  673.                 // column_source is often blank
  674.                 if ($got_string) {
  675.                     $res[$i]['table'] = $case_func($result);
  676.                 } else {
  677.                     $res[$i]['table'] = $case_func($f->column_source);
  678.                 }
  679.                 $res[$i]['name']  = $case_func($f->name);
  680.                 $res[$i]['type']  = $f->type;
  681.                 $res[$i]['len']   = $f->max_length;
  682.                 if ($res[$i]['table']) {
  683.                     $res[$i]['flags'] = $this->_sybase_field_flags(
  684.                             $res[$i]['table'], $res[$i]['name']);
  685.                 } else {
  686.                     $res[$i]['flags'] = '';
  687.                 }
  688.             }
  689.  
  690.         } else {
  691.             // get full info
  692.  
  693.             $res['num_fields'] = $count;
  694.  
  695.             for ($i=0; $i<$count; $i++) {
  696.                 $f = @sybase_fetch_field($id, $i);
  697.  
  698.                 // column_source is often blank
  699.                 if ($got_string) {
  700.                     $res[$i]['table'] = $case_func($result);
  701.                 } else {
  702.                     $res[$i]['table'] = $case_func($f->column_source);
  703.                 }
  704.                 $res[$i]['name']  = $case_func($f->name);
  705.                 $res[$i]['type']  = $f->type;
  706.                 $res[$i]['len']   = $f->max_length;
  707.                 if ($res[$i]['table']) {
  708.                     $res[$i]['flags'] = $this->_sybase_field_flags(
  709.                             $res[$i]['table'], $res[$i]['name']);
  710.                 } else {
  711.                     $res[$i]['flags'] = '';
  712.                 }
  713.  
  714.                 if ($mode & DB_TABLEINFO_ORDER) {
  715.                     $res['order'][$res[$i]['name']] = $i;
  716.                 }
  717.                 if ($mode & DB_TABLEINFO_ORDERTABLE) {
  718.                     $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  719.                 }
  720.             }
  721.         }
  722.  
  723.         // free the result only if we were called on a table
  724.         if ($got_string) {
  725.             @sybase_free_result($id);
  726.         }
  727.         return $res;
  728.     }
  729.  
  730.     // }}}
  731.     // {{{ _sybase_field_flags()
  732.  
  733.     /**
  734.      * Get the flags for a field.
  735.      *
  736.      * Currently supports:
  737.      *  + <samp>unique_key</samp>    (unique index, unique check or primary_key)
  738.      *  + <samp>multiple_key</samp>  (multi-key index)
  739.      *
  740.      * @param string  $table   table name
  741.      * @param string  $column  field name
  742.      * @return string  space delimited string of flags.  Empty string if none.
  743.      * @access private
  744.      */
  745.     function _sybase_field_flags($table, $column)
  746.     {
  747.         static $tableName = null;
  748.         static $flags = array();
  749.  
  750.         if ($table != $tableName) {
  751.             $flags = array();
  752.             $tableName = $table;
  753.  
  754.             // get unique/primary keys
  755.             $res = $this->getAll("sp_helpindex $table", DB_FETCHMODE_ASSOC);
  756.  
  757.             if (!isset($res[0]['index_description'])) {
  758.                 return '';
  759.             }
  760.  
  761.             foreach ($res as $val) {
  762.                 $keys = explode(', ', trim($val['index_keys']));
  763.  
  764.                 if (sizeof($keys) > 1) {
  765.                     foreach ($keys as $key) {
  766.                         $this->_add_flag($flags[$key], 'multiple_key');
  767.                     }
  768.                 }
  769.  
  770.                 if (strpos($val['index_description'], 'unique')) {
  771.                     foreach ($keys as $key) {
  772.                         $this->_add_flag($flags[$key], 'unique_key');
  773.                     }
  774.                 }
  775.             }
  776.  
  777.         }
  778.  
  779.         if (array_key_exists($column, $flags)) {
  780.             return(implode(' ', $flags[$column]));
  781.         }
  782.  
  783.         return '';
  784.     }
  785.  
  786.     // }}}
  787.     // {{{ _add_flag()
  788.  
  789.     /**
  790.      * Adds a string to the flags array if the flag is not yet in there
  791.      * - if there is no flag present the array is created.
  792.      *
  793.      * @param array  $array  reference of flags array to add a value to
  794.      * @param mixed  $value  value to add to the flag array
  795.      * @access private
  796.      */
  797.     function _add_flag(&$array, $value)
  798.     {
  799.         if (!is_array($array)) {
  800.             $array = array($value);
  801.         } elseif (!in_array($value, $array)) {
  802.             array_push($array, $value);
  803.         }
  804.     }
  805.  
  806.     // }}}
  807.     // {{{ quoteIdentifier()
  808.  
  809.     /**
  810.      * Quote a string so it can be safely used as a table / column name
  811.      *
  812.      * Quoting style depends on which database driver is being used.
  813.      *
  814.      * @param string $str  identifier name to be quoted
  815.      *
  816.      * @return string  quoted identifier string
  817.      *
  818.      * @since 1.6.0
  819.      * @access public
  820.      */
  821.     function quoteIdentifier($str)
  822.     {
  823.         return '[' . str_replace(']', ']]', $str) . ']';
  824.     }
  825.  
  826.     // }}}
  827.  
  828. }
  829.  
  830. /*
  831.  * Local variables:
  832.  * tab-width: 4
  833.  * c-basic-offset: 4
  834.  * End:
  835.  */
  836.  
  837. ?>
  838.