home *** CD-ROM | disk | FTP | other *** search
/ PC World 2001 August / PCWorld_2001-08_cd.bin / Komunikace / phptriad / phptriadsetup2-11.exe / php / pear / DB / mysql.php < prev    next >
PHP Script  |  2001-02-19  |  13KB  |  465 lines

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4.0                                                      |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2001 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: Stig Bakken <ssb@fast.no>                                   |
  17. // |                                                                      |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // Database independent query interface definition for PHP's MySQL
  21. // extension.
  22. //
  23.  
  24. //
  25. // XXX legend:
  26. //
  27. // XXX ERRORMSG: The error message from the mysql function should
  28. //                 be registered here.
  29. //
  30.  
  31. require_once "DB/common.php";
  32.  
  33. class DB_mysql extends DB_common
  34. {
  35.     // {{{ properties
  36.  
  37.     var $connection;
  38.     var $phptype, $dbsyntax;
  39.     var $prepare_tokens = array();
  40.     var $prepare_types = array();
  41.  
  42.     // }}}
  43.     // {{{ constructor
  44.  
  45.     /**
  46.      * DB_mysql constructor.
  47.      *
  48.      * @access public
  49.      */
  50.  
  51.     function DB_mysql()
  52.     {
  53.         $this->DB_common();
  54.         $this->phptype = "mysql";
  55.         $this->dbsyntax = "mysql";
  56.         $this->features = array(
  57.             "prepare" => false,
  58.             "pconnect" => true,
  59.             "transactions" => false
  60.         );
  61.         $this->errorcode_map = array(
  62.             1004 => DB_ERROR_CANNOT_CREATE,
  63.             1005 => DB_ERROR_CANNOT_CREATE,
  64.             1006 => DB_ERROR_CANNOT_CREATE,
  65.             1007 => DB_ERROR_ALREADY_EXISTS,
  66.             1008 => DB_ERROR_CANNOT_DROP,
  67.             1046 => DB_ERROR_NODBSELECTED,
  68.             1050 => DB_ERROR_ALREADY_EXISTS,
  69.             1051 => DB_ERROR_NOSUCHTABLE,
  70.             1054 => DB_ERROR_NOSUCHFIELD,
  71.             1062 => DB_ERROR_ALREADY_EXISTS,
  72.             1064 => DB_ERROR_SYNTAX,
  73.             1100 => DB_ERROR_NOT_LOCKED,
  74.             1136 => DB_ERROR_VALUE_COUNT_ON_ROW,
  75.             1146 => DB_ERROR_NOSUCHTABLE,
  76.         );
  77.     }
  78.  
  79.     // }}}
  80.  
  81.     // {{{ connect()
  82.  
  83.     /**
  84.      * Connect to a database and log in as the specified user.
  85.      *
  86.      * @param $dsn the data source name (see DB::parseDSN for syntax)
  87.      * @param $persistent (optional) whether the connection should
  88.      *        be persistent
  89.      * @access public
  90.      * @return int DB_OK on success, a DB error on failure
  91.      */
  92.     
  93.     function connect($dsn, $persistent = false)
  94.     {
  95.         if (is_array($dsn)) {
  96.             $dsninfo = &$dsn;
  97.         } else {
  98.             $dsninfo = DB::parseDSN($dsn);
  99.         }
  100.         
  101.         if (!$dsninfo || !$dsninfo["phptype"]) {
  102.             return $this->raiseError(); // XXX ERRORMSG
  103.         }
  104.     
  105.         $this->dsn = $dsninfo;
  106.  
  107.         $dbhost = $dsninfo["hostspec"] ? $dsninfo["hostspec"] : "localhost";
  108.         $user = $dsninfo["username"];
  109.         $pw = $dsninfo["password"];
  110.         
  111.         DB::assertExtension("mysql");
  112.         $connect_function = $persistent ? "mysql_pconnect" : "mysql_connect";
  113.         
  114.         if ($dbhost && $user && $pw) {
  115.             $conn = @$connect_function($dbhost, $user, $pw);
  116.         } elseif ($dbhost && $user) {
  117.             $conn = @$connect_function($dbhost, $user);
  118.         } elseif ($dbhost) {
  119.             $conn = @$connect_function($dbhost);
  120.         } else {
  121.             $conn = false;
  122.         }
  123.         
  124.         if ($conn == false) {
  125.             return $this->raiseError(); // XXX ERRORMSG
  126.         }
  127.         
  128.         if ($dsninfo["database"]) {
  129.             if (!mysql_select_db($dsninfo["database"], $conn)) {
  130.                 return $this->raiseError(); // XXX ERRORMSG
  131.             }
  132.         }
  133.         
  134.         $this->connection = $conn;
  135.         return DB_OK;
  136.     }
  137.  
  138.     // }}}
  139.     // {{{ disconnect()
  140.  
  141.     /**
  142.      * Log out and disconnect from the database.
  143.      *
  144.      * @access public
  145.      *
  146.      * @return bool TRUE on success, FALSE if not connected.
  147.      */
  148.     function disconnect()
  149.     {
  150.         return mysql_close($this->connection);
  151.     }
  152.  
  153.     // }}}
  154.     // {{{ simpleQuery()
  155.  
  156.     /**
  157.      * Send a query to MySQL and return the results as a MySQL resource
  158.      * identifier.
  159.      *
  160.      * @param the SQL query
  161.      *
  162.      * @access public
  163.      *
  164.      * @return mixed returns a valid MySQL result for successful SELECT
  165.      * queries, DB_OK for other successful queries.  A DB error is
  166.      * returned on failure.
  167.      */
  168.     function simpleQuery($query)
  169.     {
  170.         $this->last_query = $query;
  171.         $query = $this->modifyQuery($query);
  172.         $result = mysql_query($query, $this->connection);
  173.         if (!$result) {
  174.             return $this->mysqlRaiseError();
  175.         }
  176.         // Determine which queries that should return data, and which
  177.         // should return an error code only.
  178.         return DB::isManip($query) ? DB_OK : $result;
  179.     }
  180.  
  181.     // }}}
  182.     // {{{ fetchRow()
  183.  
  184.     /**
  185.      * Fetch a row and return as array.
  186.      *
  187.      * @param $result MySQL result identifier
  188.      * @param $fetchmode how the resulting array should be indexed
  189.      *
  190.      * @access public
  191.      *
  192.      * @return mixed an array on success, a DB error on failure, NULL
  193.      *               if there is no more data
  194.      */
  195.     function &fetchRow($result, $fetchmode = DB_FETCHMODE_DEFAULT)
  196.     {
  197.         if ($fetchmode == DB_FETCHMODE_DEFAULT) {
  198.             $fetchmode = $this->fetchmode;
  199.         }
  200.  
  201.         if ($fetchmode & DB_FETCHMODE_ASSOC) {
  202.             $row = mysql_fetch_array($result, MYSQL_ASSOC);
  203.         } else {
  204.             $row = mysql_fetch_row($result);
  205.         }
  206.     
  207.         if (!$row) {
  208.             $errno = mysql_errno($this->connection);
  209.  
  210.             if (!$errno) {
  211.                 return null;
  212.             }
  213.         
  214.             return $this->mysqlRaiseError($errno);
  215.         }
  216.     
  217.         return $row;
  218.     }
  219.  
  220.     // }}}
  221.     // {{{ fetchInto()
  222.  
  223.     /**
  224.      * Fetch a row and insert the data into an existing array.
  225.      *
  226.      * @param $result MySQL result identifier
  227.      * @param $arr (reference) array where data from the row is stored
  228.      * @param $fetchmode how the array data should be indexed
  229.      *
  230.      * @access public
  231.      *
  232.      * @return int DB_OK on success, a DB error on failure
  233.      */
  234.     function fetchInto($result, &$arr, $fetchmode = DB_FETCHMODE_DEFAULT)
  235.     {
  236.         if ($fetchmode == DB_FETCHMODE_DEFAULT) {
  237.             $fetchmode = $this->fetchmode;
  238.         }
  239.  
  240.         if ($fetchmode & DB_FETCHMODE_ASSOC) {
  241.             $arr = mysql_fetch_array($result, MYSQL_ASSOC);
  242.         } else {
  243.             $arr = mysql_fetch_row($result);
  244.         }
  245.  
  246.         if (!$arr) {
  247.             $errno = mysql_errno($this->connection);
  248.  
  249.             if (!$errno) {
  250.                 return NULL;
  251.             }
  252.  
  253.             return $this->mysqlRaiseError($errno);
  254.         }
  255.  
  256.         return DB_OK;
  257.     }
  258.  
  259.     // }}}
  260.     // {{{ freeResult()
  261.  
  262.     /**
  263.      * Free the internal resources associated with $result.
  264.      *
  265.      * @param $result MySQL result identifier or DB statement identifier
  266.      *
  267.      * @access public
  268.      *
  269.      * @return bool TRUE on success, FALSE if $result is invalid
  270.      */
  271.     function freeResult($result)
  272.     {
  273.         if (is_resource($result)) {
  274.             return mysql_free_result($result);
  275.         }
  276.  
  277.         if (!isset($this->prepare_tokens[$result])) {
  278.             return false;
  279.         }
  280.  
  281.         unset($this->prepare_tokens[$result]);
  282.         unset($this->prepare_types[$result]);
  283.  
  284.         return true; 
  285.     }
  286.  
  287.     // }}}
  288.     // {{{ numCols()
  289.  
  290.     /**
  291.      * Get the number of columns in a result set.
  292.      *
  293.      * @param $result MySQL result identifier
  294.      *
  295.      * @access public
  296.      *
  297.      * @return int the number of columns per row in $result
  298.      */
  299.     function numCols($result)
  300.     {
  301.         $cols = mysql_num_fields($result);
  302.  
  303.         if (!$cols) {
  304.             return $this->mysqlRaiseError();
  305.         }
  306.  
  307.         return $cols;
  308.     }
  309.  
  310.     // }}}
  311.     // {{{ numRows()
  312.  
  313.     /**
  314.      * Get the number of rows in a result set.
  315.      *
  316.      * @param $result MySQL result identifier
  317.      *
  318.      * @access public
  319.      *
  320.      * @return int the number of rows in $result
  321.      */
  322.     function numRows($result)
  323.     {
  324.         $rows = @mysql_num_rows($result);
  325.         if ($rows === null) {
  326.             return $this->mysqlRaiseError();
  327.         }
  328.  
  329.         return $rows;
  330.     }
  331.  
  332.     // }}}
  333.     // {{{ affectedRows()
  334.  
  335.     /**
  336.      * Gets the number of rows affected by the data manipulation
  337.      * query.  For other queries, this function returns 0.
  338.      *
  339.      * @return number of rows affected by the last query
  340.      */
  341.  
  342.     function affectedRows()
  343.     {
  344.         if (DB::isManip($this->last_query)) {
  345.             $result = mysql_affected_rows($this->connection);
  346.         } else {
  347.             $result = 0;
  348.         }
  349.         return $result;
  350.      }
  351.  
  352.     // }}}
  353.     // {{{ errorNative()
  354.  
  355.     /**
  356.      * Get the native error code of the last error (if any) that
  357.      * occured on the current connection.
  358.      *
  359.      * @access public
  360.      *
  361.      * @return int native MySQL error code
  362.      */
  363.  
  364.     function errorNative()
  365.     {
  366.         return mysql_errno($this->connection);
  367.     }
  368.  
  369.     // }}}
  370.     // {{{ nextId()
  371.  
  372.     /**
  373.      * Get the next value in a sequence.  We emulate sequences
  374.      * for MySQL.  Will create the sequence if it does not exist.
  375.      *
  376.      * @access public
  377.      *
  378.      * @param $seq_name the name of the sequence
  379.      * 
  380.      * @param $ondemand whether to create the sequence table on demand
  381.      * (default is true)
  382.      *
  383.      * @return a sequence integer, or a DB error
  384.      */
  385.     function nextId($seq_name, $ondemand = true)
  386.     {
  387.         $sqn = preg_replace('/[^a-z0-9_]/i', '_', $seq_name);
  388.         $repeat = 0;
  389.         do {
  390.             $result = $this->query("INSERT INTO ${sqn}_seq VALUES(NULL)");
  391.             if ($ondemand && DB::isError($result) &&
  392.                 $result->getCode() == DB_ERROR_NOSUCHTABLE) {
  393.                 $repeat = 1;
  394.                 $result = $this->createSequence($seq_name);
  395.                 if (DB::isError($result)) {
  396.                     return $result;
  397.                 }
  398.             } else {
  399.                 $repeat = 0;
  400.             }
  401.         } while ($repeat);
  402.         if (DB::isError($result)) {
  403.             return $result;
  404.         }
  405.         return mysql_insert_id($this->connection);
  406.     }
  407.         
  408.     // }}}
  409.     // {{{ createSequence()
  410.  
  411.     function createSequence($seq_name)
  412.     {
  413.         $sqn = preg_replace('/[^a-z0-9_]/i', '_', $seq_name);
  414.         return $this->query("CREATE TABLE ${sqn}_seq ".
  415.                             "(id INTEGER UNSIGNED AUTO_INCREMENT NOT NULL,".
  416.                             " PRIMARY KEY(id))");
  417.     }
  418.  
  419.     // }}}
  420.     // {{{ dropSequence()
  421.  
  422.     function dropSequence($seq_name)
  423.     {
  424.         $sqn = preg_replace('/[^a-z0-9_]/i', '_', $seq_name);
  425.         return $this->query("DROP TABLE ${sqn}_seq");
  426.     }
  427.  
  428.     // }}}
  429.     // {{{ modifyQuery()
  430.  
  431.     function modifyQuery($query)
  432.     {
  433.         if ($this->options['optimize'] == 'portability') {
  434.             // "DELETE FROM table" gives 0 affected rows in MySQL.
  435.             // This little hack lets you know how many rows were deleted.
  436.             if (preg_match('/^\s*DELETE\s+FROM\s+(\S+)\s*$/i', $query)) {
  437.                 $query = preg_replace('/^\s*DELETE\s+FROM\s+(\S+)\s*$/',
  438.                                       'DELETE FROM \1 WHERE 1=1', $query);
  439.             }
  440.         }
  441.         return $query;
  442.     }
  443.  
  444.     // }}}
  445.     // {{{ mysqlRaiseError()
  446.  
  447.     function mysqlRaiseError($errno = null)
  448.     {
  449.         if ($errno === null) {
  450.             return $this->raiseError($this->errorCode(mysql_errno($this->connection)));
  451.         }
  452.         return $this->raiseError($this->errorCode($errno));
  453.     }
  454.  
  455.     // }}}
  456.  
  457.     // TODO/wishlist:
  458.     // simpleFetch
  459.     // simpleGet
  460.     // longReadlen
  461.     // binmode
  462. }
  463.  
  464. ?>
  465.