home *** CD-ROM | disk | FTP | other *** search
/ PC World 2003 March / PCWorld_2003-03_cd.bin / Software / Vyzkuste / phptriad / phptriad2-2-1.exe / php / pear / DB / mssql.php < prev    next >
Encoding:
PHP Script  |  2001-11-13  |  15.5 KB  |  496 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: Sterling Hughes <sterling@php.net>                          |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: mssql.php,v 1.24.2.3 2001/11/13 01:26:42 ssb Exp $
  20. //
  21. // Database independent query interface definition for PHP's Microsoft SQL Server
  22. // extension.
  23. //
  24.  
  25. require_once 'DB/common.php';
  26.  
  27. class DB_mssql extends DB_common
  28. {
  29.     var $connection;
  30.     var $phptype, $dbsyntax;
  31.     var $prepare_tokens = array();
  32.     var $prepare_types = array();
  33.     var $transaction_opcount = 0;
  34.     var $autocommit = true;
  35.  
  36.     function DB_mssql()
  37.     {
  38.         $this->DB_common();
  39.         $this->phptype = 'mssql';
  40.         $this->dbsyntax = 'mssql';
  41.         $this->features = array(
  42.             'prepare' => false,
  43.             'pconnect' => true,
  44.             'transactions' => true,
  45.             'limit' => 'emulate'
  46.         );
  47.         // XXX Add here error codes ie: 'S100E' => DB_ERROR_SYNTAX
  48.         $this->errorcode_map = array(
  49.  
  50.         );
  51.     }
  52.  
  53.     function connect($dsninfo, $persistent = false)
  54.     {
  55.         if (!DB::assertExtension('mssql') && !DB::assertExtension('sybase'))
  56.             return $this->raiseError(DB_ERROR_EXTENSION_NOT_FOUND);
  57.  
  58.         $this->dsn = $dsninfo;
  59.         $user = $dsninfo['username'];
  60.         $pw = $dsninfo['password'];
  61.         $dbhost = $dsninfo['hostspec'] ? $dsninfo['hostspec'] : 'localhost';
  62.  
  63.         $connect_function = $persistent ? 'mssql_pconnect' : 'mssql_connect';
  64.  
  65.         if ($dbhost && $user && $pw) {
  66.             $conn = @$connect_function($dbhost, $user, $pw);
  67.         } elseif ($dbhost && $user) {
  68.             $conn = @$connect_function($dbhost, $user);
  69.         } else {
  70.             $conn = @$connect_function($dbhost);
  71.         }
  72.         if (!$conn) {
  73.             return $this->raiseError(DB_ERROR_CONNECT_FAILED, null, null,
  74.                                          null, mssql_get_last_message());
  75.         }
  76.         if ($dsninfo['database']) {
  77.             if (!@mssql_select_db($dsninfo['database'], $conn)) {
  78.                 return $this->raiseError(DB_ERROR_NODBSELECTED, null, null,
  79.                                          null, mssql_get_last_message());
  80.             }
  81.         }
  82.         $this->connection = $conn;
  83.         return DB_OK;
  84.     }
  85.  
  86.     function disconnect()
  87.     {
  88.         $ret = @mssql_close($this->connection);
  89.         $this->connection = null;
  90.         return $ret;
  91.     }
  92.  
  93.     function simpleQuery($query)
  94.     {
  95.         $ismanip = DB::isManip($query);
  96.         $this->last_query = $query;
  97.         $query = $this->modifyQuery($query);
  98.         if (!$this->autocommit && $ismanip) {
  99.             if ($this->transaction_opcount == 0) {
  100.                 $result = @mssql_query('BEGIN TRAN', $this->connection);
  101.                 if (!$result) {
  102.                     return $this->mssqlRaiseError();
  103.                 }
  104.             }
  105.             $this->transaction_opcount++;
  106.         }
  107.         $result = @mssql_query($query, $this->connection);
  108.         if (!$result) {
  109.             return $this->mssqlRaiseError();
  110.         }
  111.         // Determine which queries that should return data, and which
  112.         // should return an error code only.
  113.         return $ismanip ? DB_OK : $result;
  114.     }
  115.  
  116.     // {{{ nextResult()
  117.  
  118.     /**
  119.      * Move the internal mssql result pointer to the next available result
  120.      *
  121.      * @param a valid fbsql result resource
  122.      *
  123.      * @access public
  124.      *
  125.      * @return true if a result is available otherwise return false
  126.      */
  127.     function nextResult($result)
  128.     {
  129.         return mssql_next_result($result);
  130.     }
  131.  
  132.     // }}}
  133.  
  134.     function &fetchRow($result, $fetchmode = DB_FETCHMODE_DEFAULT, $rownum=null)
  135.     {
  136.         if ($fetchmode == DB_FETCHMODE_DEFAULT) {
  137.             $fetchmode = $this->fetchmode;
  138.         }
  139.         $res = $this->fetchInto ($result, $arr, $fetchmode, $rownum);
  140.         if ($res !== DB_OK) {
  141.             return $res;
  142.         }
  143.         return $arr;
  144.     }
  145.  
  146.     function fetchInto($result, &$ar, $fetchmode, $rownum=null)
  147.     {
  148.         if ($rownum !== null) {
  149.             if (!@mssql_data_seek($result, $rownum)) {
  150.                 return null;
  151.             }
  152.         }
  153.         if ($fetchmode & DB_FETCHMODE_ASSOC) {
  154.             $ar = @mssql_fetch_array($result);
  155.         } else {
  156.             $ar = @mssql_fetch_row($result);
  157.         }
  158.         if (!$ar) {
  159.             if ($msg = mssql_get_last_message()) {
  160.                 return $this->raiseError($msg);
  161.             } else {
  162.                 return null;
  163.             }
  164.         }
  165.         return DB_OK;
  166.     }
  167.  
  168.     function freeResult($result)
  169.     {
  170.         if (is_resource($result)) {
  171.             return @mssql_free_result($result);
  172.         }
  173.         if (!isset($this->prepare_tokens[$result])) {
  174.             return false;
  175.         }
  176.         unset($this->prepare_tokens[$result]);
  177.         unset($this->prepare_types[$result]);
  178.         return true;
  179.     }
  180.  
  181.     function numCols($result)
  182.     {
  183.         $cols = @mssql_num_fields($result);
  184.         if (!$cols) {
  185.             return $this->mssqlRaiseError();
  186.         }
  187.         return $cols;
  188.     }
  189.  
  190.     function numRows($result)
  191.     {
  192.         $rows = @mssql_num_rows($result);
  193.         if ($rows === false) {
  194.             return $this->mssqlRaiseError();
  195.         }
  196.         return $rows;
  197.     }
  198.  
  199.     /**
  200.      * Enable/disable automatic commits
  201.      */
  202.     function autoCommit($onoff = false)
  203.     {
  204.         // XXX if $this->transaction_opcount > 0, we should probably
  205.         // issue a warning here.
  206.         $this->autocommit = $onoff ? true : false;
  207.         return DB_OK;
  208.     }
  209.  
  210.     // }}}
  211.     // {{{ commit()
  212.  
  213.     /**
  214.      * Commit the current transaction.
  215.      */
  216.     function commit()
  217.     {
  218.         if ($this->transaction_opcount > 0) {
  219.             $result = @mssql_query('COMMIT TRAN', $this->connection);
  220.             $this->transaction_opcount = 0;
  221.             if (!$result) {
  222.                 return $this->mssqlRaiseError();
  223.             }
  224.         }
  225.         return DB_OK;
  226.     }
  227.  
  228.     // }}}
  229.     // {{{ rollback()
  230.  
  231.     /**
  232.      * Roll back (undo) the current transaction.
  233.      */
  234.     function rollback()
  235.     {
  236.         if ($this->transaction_opcount > 0) {
  237.             $result = @mssql_query('ROLLBACK TRAN', $this->connection);
  238.             $this->transaction_opcount = 0;
  239.             if (!$result) {
  240.                 return $this->mssqlRaiseError();
  241.             }
  242.         }
  243.         return DB_OK;
  244.     }
  245.  
  246.     // }}}
  247.     // {{{ affectedRows()
  248.  
  249.     /**
  250.      * Gets the number of rows affected by the last query.
  251.      * if the last query was a select, returns 0.
  252.      *
  253.      * @return number of rows affected by the last query or DB_ERROR
  254.      */
  255.     function affectedRows()
  256.     {
  257.         if (DB::isManip($this->last_query)) {
  258.             $res = @mssql_query('select @@rowcount', $this->connection);
  259.             if (!$res) {
  260.                 return $this->mssqlRaiseError();
  261.             }
  262.             $ar = @mssql_fetch_row($res);
  263.             if (!$ar) {
  264.                 $result = 0;
  265.             } else {
  266.                 @mssql_free_result($res);
  267.                 $result = $ar[0];
  268.             }
  269.         } else {
  270.             $result = 0;
  271.         }
  272.         return $result;
  273.     }
  274.     // {{{ nextId()
  275.  
  276.     /**
  277.      * Get the next value in a sequence.  We emulate sequences
  278.      * for MSSQL.  Will create the sequence if it does not exist.
  279.      *
  280.      * @access public
  281.      *
  282.      * @param $seq_name the name of the sequence
  283.      *
  284.      * @param $ondemand whether to create the sequence table on demand
  285.      * (default is true)
  286.      *
  287.      * @return a sequence integer, or a DB error
  288.      */
  289.     function nextId($seq_name, $ondemand = true)
  290.     {
  291.         $sqn = preg_replace('/[^a-z0-9_]/i', '_', $seq_name);
  292.         $repeat = 0;
  293.         do {
  294.             $this->pushErrorHandling(PEAR_ERROR_RETURN);
  295.             $result = $this->query("INSERT INTO ${sqn}_seq (vapor) VALUES (0)");
  296.             $this->popErrorHandling();
  297.             if ($ondemand && DB::isError($result) &&
  298.                 ($result->getCode() == DB_ERROR || $result->getCode() == DB_ERROR_NOSUCHTABLE))
  299.             {
  300.                 $repeat = 1;
  301.                 $result = $this->createSequence($seq_name);
  302.                 if (DB::isError($result)) {
  303.                     return $result;
  304.                 }
  305.             } else {
  306.                 $result = $this->query("SELECT @@IDENTITY FROM ${sqn}_seq");
  307.                 $repeat = 0;
  308.             }
  309.         } while ($repeat);
  310.         if (DB::isError($result)) {
  311.             return $this->raiseError($result);
  312.         }
  313.         $result = $result->fetchRow(DB_FETCHMODE_ORDERED);
  314.         return $result[0];
  315.     }
  316.  
  317.     // }}}
  318.     // {{{ createSequence()
  319.  
  320.     function createSequence($seq_name)
  321.     {
  322.         $sqn = preg_replace('/[^a-z0-9_]/i', '_', $seq_name);
  323.         return $this->query("CREATE TABLE ${sqn}_seq".
  324.                             '([id] [int] IDENTITY (1, 1) NOT NULL ,' .
  325.                             '[vapor] [int] NULL)');
  326.     }
  327.     // }}}
  328.     // {{{ dropSequence()
  329.  
  330.     function dropSequence($seq_name)
  331.     {
  332.         $sqn = preg_replace('/[^a-z0-9_]/i', '_', $seq_name);
  333.         return $this->query("DROP TABLE ${sqn}_seq");
  334.     }
  335.     // }}}
  336.  
  337.     function errorCode()
  338.     {
  339.         $this->pushErrorHandling(PEAR_ERROR_RETURN);
  340.         $error_code = $this->getOne('select @@ERROR as ErrorCode');
  341.         $this->popErrorHandling();
  342.         // XXX Debug
  343.         if (!isset($this->errorcode_map[$error_code])) {
  344.             return DB_ERROR;
  345.         }
  346.         return $error_code;
  347.     }
  348.  
  349.     function mssqlRaiseError($code = null)
  350.     {
  351.         if ($code !== null) {
  352.             $code = $this->errorCode();
  353.             if (DB::isError($code)) {
  354.                 return $this->raiseError($code);
  355.             }
  356.         }
  357.         return $this->raiseError($code, null, null, null,
  358.                         mssql_get_last_message());
  359.     }
  360.  
  361.   /**
  362.  
  363.      * Returns information about a table or a result set
  364.      *
  365.      * NOTE: doesn't support table name and flags if called from a db_result
  366.      *
  367.      * @param  mixed $resource SQL Server result identifier or table name
  368.      * @param  int $mode A valid tableInfo mode (DB_TABLEINFO_ORDERTABLE or
  369.      *                   DB_TABLEINFO_ORDER)
  370.      *
  371.      * @return array An array with all the information
  372.      */
  373.  
  374.     function tableInfo($result, $mode = null)
  375.     {
  376.  
  377.         $count = 0;
  378.         $id    = 0;
  379.         $res   = array();
  380.  
  381.         /*
  382.          * depending on $mode, metadata returns the following values:
  383.          *
  384.          * - mode is false (default):
  385.          * $result[]:
  386.          *   [0]["table"]  table name
  387.          *   [0]["name"]   field name
  388.          *   [0]["type"]   field type
  389.          *   [0]["len"]    field length
  390.          *   [0]["flags"]  field flags
  391.          *
  392.          * - mode is DB_TABLEINFO_ORDER
  393.          * $result[]:
  394.          *   ["num_fields"] number of metadata records
  395.          *   [0]["table"]  table name
  396.          *   [0]["name"]   field name
  397.          *   [0]["type"]   field type
  398.          *   [0]["len"]    field length
  399.          *   [0]["flags"]  field flags
  400.          *   ["order"][field name]  index of field named "field name"
  401.          *   The last one is used, if you have a field name, but no index.
  402.          *   Test:  if (isset($result['meta']['myfield'])) { ...
  403.          *
  404.          * - mode is DB_TABLEINFO_ORDERTABLE
  405.          *    the same as above. but additionally
  406.          *   ["ordertable"][table name][field name] index of field
  407.          *      named "field name"
  408.          *
  409.          *      this is, because if you have fields from different
  410.          *      tables with the same field name * they override each
  411.          *      other with DB_TABLEINFO_ORDER
  412.          *
  413.          *      you can combine DB_TABLEINFO_ORDER and
  414.          *      DB_TABLEINFO_ORDERTABLE with DB_TABLEINFO_ORDER |
  415.          *      DB_TABLEINFO_ORDERTABLE * or with DB_TABLEINFO_FULL
  416.          */
  417.  
  418.         // if $result is a string, then we want information about a
  419.         // table without a resultset
  420.  
  421.         if (is_string($result)) {
  422.             $id = mssql_query("SELECT * FROM $result", $this->connection);
  423.             if (empty($id)) {
  424.                 return $this->mssqlRaiseError();
  425.             }
  426.         } else { // else we want information about a resultset
  427.             $id = $result;
  428.             if (empty($id)) {
  429.                 return $this->mssqlRaiseError();
  430.             }
  431.         }
  432.  
  433.         $count = @mssql_num_fields($id);
  434.  
  435.         // made this IF due to performance (one if is faster than $count if's)
  436.         if (empty($mode)) {
  437.  
  438.             for ($i=0; $i<$count; $i++) {
  439.                 $res[$i]['table'] = (is_string($result)) ? $result : '';
  440.                 $res[$i]['name']  = @mssql_field_name($id, $i);
  441.                 $res[$i]['type']  = @mssql_field_type($id, $i);
  442.                 $res[$i]['len']   = @mssql_field_length($id, $i);
  443.                 $res[$i]['flags'] = '';
  444.             }
  445.  
  446.         } else { // full
  447.             $res['num_fields']= $count;
  448.  
  449.             for ($i=0; $i<$count; $i++) {
  450.                 $res[$i]['table'] = (is_string($result)) ? $result : '';
  451.                 $res[$i]['name']  = @mssql_field_name($id, $i);
  452.                 $res[$i]['type']  = @mssql_field_type($id, $i);
  453.                 $res[$i]['len']   = @mssql_field_length($id, $i);
  454.                 $res[$i]['flags'] = '';
  455.                 if ($mode & DB_TABLEINFO_ORDER) {
  456.                     $res['order'][$res[$i]['name']] = $i;
  457.                 }
  458.                 if ($mode & DB_TABLEINFO_ORDERTABLE) {
  459.                     $res['ordertable'][$res[$i]['table']][$res[$i]['name']] = $i;
  460.                 }
  461.             }
  462.         }
  463.  
  464.         // free the result only if we were called on a table
  465.         if (is_string($result)) {
  466.             @mssql_free_result($id);
  467.         }
  468.         return $res;
  469.     }
  470.  
  471.     // {{{ getSpecialQuery()
  472.  
  473.     /**
  474.     * Returns the query needed to get some backend info
  475.     * @param string $type What kind of info you want to retrieve
  476.     * @return string The SQL query string
  477.     */
  478.     function getSpecialQuery($type)
  479.     {
  480.         switch ($type) {
  481.             case 'tables':
  482.                 $sql = "select name from sysobjects where type = 'U' order by name";
  483.                 break;
  484.             case 'views':
  485.                 $sql = "select name from sysobjects where type = 'V'";
  486.                 break;
  487.             default:
  488.                 return null;
  489.         }
  490.         return $sql;
  491.     }
  492.  
  493.     // }}}
  494.  
  495. }
  496. ?>