MDB2
[ class tree: MDB2 ] [ index: MDB2 ] [ all elements ]

Source for file sqlsrv.php

Documentation is available at sqlsrv.php

  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PHP versions 4 and 5                                                 |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1998-2008 Manuel Lemos, Tomas V.V.Cox,                 |
  6. // | Stig. S. Bakken, Lukas Smith                                         |
  7. // | All rights reserved.                                                 |
  8. // +----------------------------------------------------------------------+
  9. // | MDB2 is a merge of PEAR DB and Metabases that provides a unified DB  |
  10. // | API as well as database abstraction for PHP applications.            |
  11. // | This LICENSE is in the BSD license style.                            |
  12. // |                                                                      |
  13. // | Redistribution and use in source and binary forms, with or without   |
  14. // | modification, are permitted provided that the following conditions   |
  15. // | are met:                                                             |
  16. // |                                                                      |
  17. // | Redistributions of source code must retain the above copyright       |
  18. // | notice, this list of conditions and the following disclaimer.        |
  19. // |                                                                      |
  20. // | Redistributions in binary form must reproduce the above copyright    |
  21. // | notice, this list of conditions and the following disclaimer in the  |
  22. // | documentation and/or other materials provided with the distribution. |
  23. // |                                                                      |
  24. // | Neither the name of Manuel Lemos, Tomas V.V.Cox, Stig. S. Bakken,    |
  25. // | Lukas Smith nor the names of his contributors may be used to endorse |
  26. // | or promote products derived from this software without specific prior|
  27. // | written permission.                                                  |
  28. // |                                                                      |
  29. // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS  |
  30. // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT    |
  31. // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS    |
  32. // | FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE      |
  33. // | REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,          |
  34. // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
  35. // | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS|
  36. // |  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED  |
  37. // | AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT          |
  38. // | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY|
  39. // | WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE          |
  40. // | POSSIBILITY OF SUCH DAMAGE.                                          |
  41. // +----------------------------------------------------------------------+
  42. // | Authors: Frank M. Kromann <frank@kromann.info>                       |
  43. // |          David Coallier <davidc@php.net>                             |
  44. // |          Lorenzo Alberton <l.alberton@quipo.it>                      |
  45. // +----------------------------------------------------------------------+
  46.  
  47. require_once 'MDB2/Driver/Manager/Common.php';
  48.  
  49. // {{{ class MDB2_Driver_Manager_sqlsrv
  50.  
  51. /**
  52.  * MDB2 MSSQL driver for the management modules
  53.  *
  54.  * @package MDB2
  55.  * @category Database
  56.  * @author  Frank M. Kromann <frank@kromann.info>
  57.  * @author  David Coallier <davidc@php.net>
  58.  * @author  Lorenzo Alberton <l.alberton@quipo.it>
  59.  */
  60. class MDB2_Driver_Manager_sqlsrv extends MDB2_Driver_Manager_Common
  61. {
  62.     // {{{ createDatabase()
  63.     /**
  64.      * create a new database
  65.      *
  66.      * @param string $name    name of the database that should be created
  67.      * @param array  $options array with collation info
  68.      *
  69.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  70.      * @access public
  71.      */
  72.     function createDatabase($name$options = array())
  73.     {
  74.         $db $this->getDBInstance();
  75.         if (MDB2::isError($db)) {
  76.             return $db;
  77.         }
  78.  
  79.         $name $db->quoteIdentifier($nametrue);
  80.         $query = "CREATE DATABASE $name";
  81.         if ($db->options['database_device']{
  82.             $query.= ' ON '.$db->options['database_device'];
  83.             $query.= $db->options['database_size''=' .
  84.                      $db->options['database_size''';
  85.         }
  86.         if (!empty($options['collation'])) {
  87.             $query .= ' COLLATE ' $options['collation'];
  88.         }
  89.         return $db->standaloneQuery($querynulltrue);
  90.     }
  91.  
  92.     // }}}
  93.     // {{{ alterDatabase()
  94.  
  95.     /**
  96.      * alter an existing database
  97.      *
  98.      * @param string $name    name of the database that is intended to be changed
  99.      * @param array  $options array with name, collation info
  100.      *
  101.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  102.      * @access public
  103.      */
  104.     function alterDatabase($name$options = array())
  105.     {
  106.         $db $this->getDBInstance();
  107.         if (MDB2::isError($db)) {
  108.             return $db;
  109.         }
  110.  
  111.         $query '';
  112.         if (!empty($options['name'])) {
  113.             $query .= ' MODIFY NAME = ' .$db->quoteIdentifier($options['name']true);
  114.         }
  115.         if (!empty($options['collation'])) {
  116.             $query .= ' COLLATE ' $options['collation'];
  117.         }
  118.         if (!empty($query)) {
  119.             $query 'ALTER DATABASE '$db->quoteIdentifier($nametrue$query;
  120.             return $db->standaloneQuery($querynulltrue);
  121.         }
  122.         return MDB2_OK;
  123.     }
  124.  
  125.     // }}}
  126.     // {{{ dropDatabase()
  127.  
  128.     /**
  129.      * drop an existing database
  130.      *
  131.      * @param string $name name of the database that should be dropped
  132.      *
  133.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  134.      * @access public
  135.      */
  136.     function dropDatabase($name)
  137.     {
  138.         $db $this->getDBInstance();
  139.         if (MDB2::isError($db)) {
  140.             return $db;
  141.         }
  142.  
  143.         $name $db->quoteIdentifier($nametrue);
  144.         return $db->standaloneQuery("DROP DATABASE $name"nulltrue);
  145.     }
  146.  
  147.     // }}}
  148.     // {{{ dropTable()
  149.  
  150.     /**
  151.      * drop an existing table
  152.      *
  153.      * @param string $name name of the table that should be dropped
  154.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  155.      * @access public
  156.      */
  157.     function dropTable($name)
  158.     {
  159.         $db $this->getDBInstance();
  160.         if (MDB2::isError($db)) {
  161.             return $db;
  162.         }
  163.         $name $db->quoteIdentifier($nametrue);
  164.         $result $db->exec("IF EXISTS (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME='$name') DROP TABLE $name");
  165.         if (MDB2::isError($result)) {
  166.             return $result;
  167.         }
  168.         return MDB2_OK;
  169.     }
  170.  
  171.     // }}}
  172.     // {{{ _getTemporaryTableQuery()
  173.  
  174.     /**
  175.      * Override the parent method.
  176.      *
  177.      * @return string The string required to be placed between "CREATE" and "TABLE"
  178.      *                 to generate a temporary table, if possible.
  179.      */
  180.     function _getTemporaryTableQuery()
  181.     {
  182.         return '';
  183.     }
  184.  
  185.     // }}}
  186.     // {{{ _getAdvancedFKOptions()
  187.  
  188.     /**
  189.      * Return the FOREIGN KEY query section dealing with non-standard options
  190.      * as MATCH, INITIALLY DEFERRED, ON UPDATE, ...
  191.      *
  192.      * @param array $definition 
  193.      *
  194.      * @return string 
  195.      * @access protected
  196.      */
  197.     function _getAdvancedFKOptions($definition)
  198.     {
  199.         $query '';
  200.         if (!empty($definition['onupdate'])) {
  201.             $query .= ' ON UPDATE '.$definition['onupdate'];
  202.         }
  203.         if (!empty($definition['ondelete'])) {
  204.             $query .= ' ON DELETE '.$definition['ondelete'];
  205.         }
  206.         return $query;
  207.     }
  208.  
  209.     // }}}
  210.     // {{{ createTable()
  211.  
  212.     /**
  213.      * create a new table
  214.      *
  215.      * @param string $name   Name of the database that should be created
  216.      * @param array  $fields Associative array that contains the definition of each field of the new table
  217.      *                        The indexes of the array entries are the names of the fields of the table an
  218.      *                        the array entry values are associative arrays like those that are meant to be
  219.      *                        passed with the field definitions to get[Type]Declaration() functions.
  220.      *
  221.      *                       Example
  222.      *                         array(
  223.      *
  224.      *                             'id' => array(
  225.      *                                 'type' => 'integer',
  226.      *                                 'unsigned' => 1,
  227.      *                                 'notnull' => 1,
  228.      *                                 'default' => 0,
  229.      *                             ),
  230.      *                             'name' => array(
  231.      *                                 'type' => 'text',
  232.      *                                 'length' => 12,
  233.      *                             ),
  234.      *                             'description' => array(
  235.      *                                 'type' => 'text',
  236.      *                                 'length' => 12,
  237.      *                             )
  238.      *                         );
  239.      * @param array $options An associative array of table options:
  240.      *                           array(
  241.      *                               'comment' => 'Foo',
  242.      *                               'temporary' => true|false,
  243.      *                           );
  244.      *
  245.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  246.      * @access public
  247.      */
  248.     function createTable($name$fields$options = array())
  249.     {
  250.         /*if (!empty($options['temporary'])) {
  251.             $name = '#'.$name;//would make subsequent calls fail because it would go out ot scope and be destroyed already
  252.         }*/
  253.         return parent::createTable($name$fields$options);
  254.     }
  255.  
  256.     // }}}
  257.     // {{{ truncateTable()
  258.  
  259.     /**
  260.      * Truncate an existing table (if the TRUNCATE TABLE syntax is not supported,
  261.      * it falls back to a DELETE FROM TABLE query)
  262.      *
  263.      * @param string $name name of the table that should be truncated
  264.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  265.      * @access public
  266.      */
  267.     function truncateTable($name)
  268.     {
  269.         $db $this->getDBInstance();
  270.         if (MDB2::isError($db)) {
  271.             return $db;
  272.         }
  273.  
  274.         $name $db->quoteIdentifier($nametrue);
  275.         $result $db->exec("TRUNCATE TABLE $name");
  276.         if (MDB2::isError($result)) {
  277.             return $result;
  278.         }
  279.         return MDB2_OK;
  280.     }
  281.  
  282.     // }}}
  283.     // {{{ vacuum()
  284.  
  285.     /**
  286.      * Optimize (vacuum) all the tables in the db (or only the specified table)
  287.      * and optionally run ANALYZE.
  288.      *
  289.      * @param string $table table name (all the tables if empty)
  290.      * @param array  $options an array with driver-specific options:
  291.      *                - timeout [int] (in seconds) [mssql-only]
  292.      *                - analyze [boolean] [pgsql and mysql]
  293.      *                - full [boolean] [pgsql-only]
  294.      *                - freeze [boolean] [pgsql-only]
  295.      *
  296.      *  NB: you have to run the NSControl Create utility to enable VACUUM
  297.      *
  298.      * @return mixed MDB2_OK success, a MDB2 error on failure
  299.      * @access public
  300.      */
  301.     function vacuum($table = null$options = array())
  302.     {
  303.         $db $this->getDBInstance();
  304.         if (MDB2::isError($db)) {
  305.             return $db;
  306.         }
  307.         $timeout = isset($options['timeout']? (int)$options['timeout': 300;
  308.  
  309.         $query 'NSControl Create';
  310.         $result $db->exec($query);
  311.         if (MDB2::isError($result)) {
  312.             return $result;
  313.         }
  314.  
  315.         $result $db->exec('EXEC NSVacuum '.$timeout);
  316.         if (MDB2::isError($result)) {
  317.             return $result;
  318.         }
  319.         return MDB2_OK;
  320.     }
  321.  
  322.     // }}}
  323.     // {{{ alterTable()
  324.  
  325.     /**
  326.      * alter an existing table
  327.      *
  328.      * @param string  $name    name of the table that is intended to be changed.
  329.      * @param array   $changes associative array that contains the details of each type
  330.      *                          of change that is intended to be performed. The types of
  331.      *                          changes that are currently supported are defined as follows:
  332.      *
  333.      *                              name
  334.      *
  335.      *                                 New name for the table.
  336.      *
  337.      *                             add
  338.      *
  339.      *                                 Associative array with the names of fields to be added as
  340.      *                                  indexes of the array. The value of each entry of the array
  341.      *                                  should be set to another associative array with the properties
  342.      *                                  of the fields to be added. The properties of the fields should
  343.      *                                  be the same as defined by the MDB2 parser.
  344.      *
  345.      *
  346.      *                             remove
  347.      *
  348.      *                                 Associative array with the names of fields to be removed as indexes
  349.      *                                  of the array. Currently the values assigned to each entry are ignored.
  350.      *                                  An empty array should be used for future compatibility.
  351.      *
  352.      *                             rename
  353.      *
  354.      *                                 Associative array with the names of fields to be renamed as indexes
  355.      *                                  of the array. The value of each entry of the array should be set to
  356.      *                                  another associative array with the entry named name with the new
  357.      *                                  field name and the entry named Declaration that is expected to contain
  358.      *                                  the portion of the field declaration already in DBMS specific SQL code
  359.      *                                  as it is used in the CREATE TABLE statement.
  360.      *
  361.      *                             change
  362.      *
  363.      *                                 Associative array with the names of the fields to be changed as indexes
  364.      *                                  of the array. Keep in mind that if it is intended to change either the
  365.      *                                  name of a field and any other properties, the change array entries
  366.      *                                  should have the new names of the fields as array indexes.
  367.      *
  368.      *                                 The value of each entry of the array should be set to another associative
  369.      *                                  array with the properties of the fields to that are meant to be changed as
  370.      *                                  array entries. These entries should be assigned to the new values of the
  371.      *                                  respective properties. The properties of the fields should be the same
  372.      *                                  as defined by the MDB2 parser.
  373.      *
  374.      *                             Example
  375.      *                                 array(
  376.      *                                     'name' => 'userlist',
  377.      *                                     'add' => array(
  378.      *                                         'quota' => array(
  379.      *                                             'type' => 'integer',
  380.      *                                             'unsigned' => 1
  381.      *                                         )
  382.      *                                     ),
  383.      *                                     'remove' => array(
  384.      *                                         'file_limit' => array(),
  385.      *                                         'time_limit' => array()
  386.      *                                     ),
  387.      *                                     'change' => array(
  388.      *                                         'name' => array(
  389.      *                                             'length' => '20',
  390.      *                                             'definition' => array(
  391.      *                                                 'type' => 'text',
  392.      *                                                 'length' => 20,
  393.      *                                             ),
  394.      *                                         )
  395.      *                                     ),
  396.      *                                     'rename' => array(
  397.      *                                         'sex' => array(
  398.      *                                             'name' => 'gender',
  399.      *                                             'definition' => array(
  400.      *                                                 'type' => 'text',
  401.      *                                                 'length' => 1,
  402.      *                                                 'default' => 'M',
  403.      *                                             ),
  404.      *                                         )
  405.      *                                     )
  406.      *                                 )
  407.      *
  408.      * @param boolean $check   indicates whether the function should just check if the DBMS driver
  409.      *                          can perform the requested table alterations if the value is true or
  410.      *                          actually perform them otherwise.
  411.      *
  412.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  413.      * @access public
  414.      */
  415.     function alterTable($name$changes$check)
  416.     {
  417.         $db $this->getDBInstance();
  418.         if (MDB2::isError($db)) {
  419.             return $db;
  420.         }
  421.         $name_quoted $db->quoteIdentifier($nametrue);
  422.  
  423.         foreach ($changes as $change_name => $change{
  424.             switch ($change_name{
  425.             case 'remove':
  426.             case 'rename':
  427.             case 'add':
  428.             case 'change':
  429.             case 'name':
  430.                 break;
  431.             default:
  432.                 return $db->raiseError(MDB2_ERROR_CANNOT_ALTERnullnull,
  433.                     'change type "'.$change_name.'" not yet supported'__FUNCTION__);
  434.             }
  435.         }
  436.  
  437.         if ($check{
  438.             return MDB2_OK;
  439.         }
  440.  
  441.         $idxname_format $db->getOption('idxname_format');
  442.         $db->setOption('idxname_format''%s');
  443.  
  444.         if (!empty($changes['remove']&& is_array($changes['remove'])) {
  445.             $result $this->_dropConflictingIndices($namearray_keys($changes['remove']));
  446.             if (MDB2::isError($result)) {
  447.                 $db->setOption('idxname_format'$idxname_format);
  448.                 return $result;
  449.             }
  450.             $result $this->_dropConflictingConstraints($namearray_keys($changes['remove']));
  451.             if (MDB2::isError($result)) {
  452.                 $db->setOption('idxname_format'$idxname_format);
  453.                 return $result;
  454.             }
  455.  
  456.             $query '';
  457.             foreach ($changes['remove'as $field_name => $field{
  458.                 if ($query{
  459.                     $query.= ', ';
  460.                 }
  461.                 $field_name $db->quoteIdentifier($field_nametrue);
  462.                 $query.= 'COLUMN ' $field_name;
  463.             }
  464.  
  465.             $result $db->exec("ALTER TABLE $name_quoted DROP $query");
  466.             if (MDB2::isError($result)) {
  467.                 $db->setOption('idxname_format'$idxname_format);
  468.                 return $result;
  469.             }
  470.         }
  471.  
  472.         if (!empty($changes['rename']&& is_array($changes['rename'])) {
  473.             foreach ($changes['rename'as $field_name => $field{
  474.                 $field_name $db->quoteIdentifier($field_nametrue);
  475.                 $result $db->exec("sp_rename '$name_quoted.$field_name', '".$field['name']."', 'COLUMN'");
  476.                 if (MDB2::isError($result)) {
  477.                     $db->setOption('idxname_format'$idxname_format);
  478.                     return $result;
  479.                 }
  480.             }
  481.         }
  482.  
  483.         if (!empty($changes['add']&& is_array($changes['add'])) {
  484.             $query '';
  485.             foreach ($changes['add'as $field_name => $field{
  486.                 if ($query{
  487.                     $query.= ', ';
  488.                 else {
  489.                     $query.= 'ADD ';
  490.                 }
  491.                 $query.= $db->getDeclaration($field['type']$field_name$field);
  492.             }
  493.  
  494.             $result $db->exec("ALTER TABLE $name_quoted $query");
  495.             if (MDB2::isError($result)) {
  496.                 $db->setOption('idxname_format'$idxname_format);
  497.                 return $result;
  498.             }
  499.         }
  500.  
  501.         $dropped_indices     = array();
  502.         $dropped_constraints = array();
  503.  
  504.         if (!empty($changes['change']&& is_array($changes['change'])) {
  505.             $dropped $this->_dropConflictingIndices($namearray_keys($changes['change']));
  506.             if (MDB2::isError($dropped)) {
  507.                 $db->setOption('idxname_format'$idxname_format);
  508.                 return $dropped;
  509.             }
  510.             $dropped_indices array_merge($dropped_indices$dropped);
  511.             $dropped $this->_dropConflictingConstraints($namearray_keys($changes['change']));
  512.             if (MDB2::isError($dropped)) {
  513.                 $db->setOption('idxname_format'$idxname_format);
  514.                 return $dropped;
  515.             }
  516.             $dropped_constraints array_merge($dropped_constraints$dropped);
  517.  
  518.             foreach ($changes['change'as $field_name => $field{
  519.                 //MSSQL doesn't allow multiple ALTER COLUMNs in one query
  520.                 $query 'ALTER COLUMN ';
  521.  
  522.                 //MSSQL doesn't allow changing the DEFAULT value of a field in altering mode
  523.                 if (array_key_exists('default'$field['definition'])) {
  524.                     unset($field['definition']['default']);
  525.                 }
  526.  
  527.                 $query .= $db->getDeclaration($field['definition']['type']$field_name$field['definition']);
  528.                 $result $db->exec("ALTER TABLE $name_quoted $query");
  529.                 if (MDB2::isError($result)) {
  530.                     $db->setOption('idxname_format'$idxname_format);
  531.                     return $result;
  532.                 }
  533.             }
  534.         }
  535.  
  536.         // restore the dropped conflicting indices and constraints
  537.         foreach ($dropped_indices as $index_name => $index{
  538.             $result $this->createIndex($name$index_name$index);
  539.             if (MDB2::isError($result)) {
  540.                 $db->setOption('idxname_format'$idxname_format);
  541.                 return $result;
  542.             }
  543.         }
  544.         foreach ($dropped_constraints as $constraint_name => $constraint{
  545.             $result $this->createConstraint($name$constraint_name$constraint);
  546.             if (MDB2::isError($result)) {
  547.                 $db->setOption('idxname_format'$idxname_format);
  548.                 return $result;
  549.             }
  550.         }
  551.  
  552.         $db->setOption('idxname_format'$idxname_format);
  553.  
  554.         if (!empty($changes['name'])) {
  555.             $new_name $db->quoteIdentifier($changes['name']true);
  556.             $result $db->exec("sp_rename '$name_quoted', '$new_name'");
  557.             if (MDB2::isError($result)) {
  558.                 return $result;
  559.             }
  560.         }
  561.  
  562.         return MDB2_OK;
  563.     }
  564.  
  565.     // }}}
  566.     // {{{ _dropConflictingIndices()
  567.  
  568.     /**
  569.      * Drop the indices that prevent a successful ALTER TABLE action
  570.      *
  571.      * @param string $table  table name
  572.      * @param array  $fields array of names of the fields affected by the change
  573.      *
  574.      * @return array dropped indices definitions
  575.      */
  576.     function _dropConflictingIndices($table$fields)
  577.     {
  578.         $db $this->getDBInstance();
  579.         if (MDB2::isError($db)) {
  580.             return $db;
  581.         }
  582.  
  583.         $dropped = array();
  584.         $index_names $this->listTableIndexes($table);
  585.         if (MDB2::isError($index_names)) {
  586.             return $index_names;
  587.         }
  588.         $db->loadModule('Reverse');
  589.         $indexes = array();
  590.         foreach ($index_names as $index_name{
  591.             $idx_def $db->reverse->getTableIndexDefinition($table$index_name);
  592.             if (!MDB2::isError($idx_def)) {
  593.                 $indexes[$index_name$idx_def;
  594.             }
  595.         }
  596.         foreach ($fields as $field_name{
  597.             foreach ($indexes as $index_name => $index{
  598.                 if (!isset($dropped[$index_name]&& array_key_exists($field_name$index['fields'])) {
  599.                     $dropped[$index_name$index;
  600.                     $result $this->dropIndex($table$index_name);
  601.                     if (MDB2::isError($result)) {
  602.                         return $result;
  603.                     }
  604.                 }
  605.             }
  606.         }
  607.  
  608.         return $dropped;
  609.     }
  610.  
  611.     // }}}
  612.     // {{{ _dropConflictingConstraints()
  613.  
  614.     /**
  615.      * Drop the constraints that prevent a successful ALTER TABLE action
  616.      *
  617.      * @param string $table  table name
  618.      * @param array  $fields array of names of the fields affected by the change
  619.      *
  620.      * @return array dropped constraints definitions
  621.      */
  622.     function _dropConflictingConstraints($table$fields)
  623.     {
  624.         $db $this->getDBInstance();
  625.         if (MDB2::isError($db)) {
  626.             return $db;
  627.         }
  628.  
  629.         $dropped = array();
  630.         $constraint_names $this->listTableConstraints($table);
  631.         if (MDB2::isError($constraint_names)) {
  632.             return $constraint_names;
  633.         }
  634.         $db->loadModule('Reverse');
  635.         $constraints = array();
  636.         foreach ($constraint_names as $constraint_name{
  637.             $cons_def $db->reverse->getTableConstraintDefinition($table$constraint_name);
  638.             if (!MDB2::isError($cons_def)) {
  639.                 $constraints[$constraint_name$cons_def;
  640.             }
  641.         }
  642.         foreach ($fields as $field_name{
  643.             foreach ($constraints as $constraint_name => $constraint{
  644.                 if (!isset($dropped[$constraint_name]&& array_key_exists($field_name$constraint['fields'])) {
  645.                     $dropped[$constraint_name$constraint;
  646.                     $result $this->dropConstraint($table$constraint_name);
  647.                     if (MDB2::isError($result)) {
  648.                         return $result;
  649.                     }
  650.                 }
  651.             }
  652.             // also drop implicit DEFAULT constraints
  653.             $default $this->_getTableFieldDefaultConstraint($table$field_name);
  654.             if (!MDB2::isError($default&& !empty($default)) {
  655.                 $result $this->dropConstraint($table$default);
  656.                 if (MDB2::isError($result)) {
  657.                     return $result;
  658.                 }
  659.             }
  660.         }
  661.  
  662.         return $dropped;
  663.     }
  664.  
  665.     // }}}
  666.     // {{{ _getTableFieldDefaultConstraint()
  667.  
  668.     /**
  669.      * Get the default constraint for a table field
  670.      *
  671.      * @param string $table name of table that should be used in method
  672.      * @param string $field name of field that should be used in method
  673.      *
  674.      * @return mixed name of default constraint on success, a MDB2 error on failure
  675.      * @access private
  676.      */
  677.     function _getTableFieldDefaultConstraint($table$field)
  678.     {
  679.         $db $this->getDBInstance();
  680.         if (MDB2::isError($db)) {
  681.             return $db;
  682.         }
  683.  
  684.         $table $db->quoteIdentifier($tabletrue);
  685.         $field $db->quote($field'text');
  686.         $query = "SELECT OBJECT_NAME(syscolumns.cdefault)
  687.                     FROM syscolumns
  688.                    WHERE syscolumns.id = object_id('$table')
  689.                      AND syscolumns.name = $field
  690.                      AND syscolumns.cdefault <> 0";
  691.         return $db->queryOne($query);
  692.     }
  693.  
  694.     // }}}
  695.     // {{{ listTables()
  696.  
  697.     /**
  698.      * list all tables in the current database
  699.      *
  700.      * @return mixed array of table names on success, a MDB2 error on failure
  701.      * @access public
  702.      */
  703.     function listTables()
  704.     {
  705.         $db $this->getDBInstance();
  706.  
  707.         if (MDB2::isError($db)) {
  708.             return $db;
  709.         }
  710.  
  711.         $query 'EXEC sp_tables @table_type = "\'TABLE\'"';
  712.         $table_names $db->queryCol($querynull2);
  713.         if (MDB2::isError($table_names)) {
  714.             return $table_names;
  715.         }
  716.         $result = array();
  717.         foreach ($table_names as $table_name{
  718.             if (!$this->_fixSequenceName($table_nametrue)) {
  719.                 $result[$table_name;
  720.             }
  721.         }
  722.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  723.             $result array_map(($db->options['field_case'== CASE_LOWER ?
  724.                         'strtolower' 'strtoupper')$result);
  725.         }
  726.         return $result;
  727.     }
  728.  
  729.     // }}}
  730.     // {{{ listTableFields()
  731.  
  732.     /**
  733.      * list all fields in a table in the current database
  734.      *
  735.      * @param string $table name of table that should be used in method
  736.      *
  737.      * @return mixed array of field names on success, a MDB2 error on failure
  738.      * @access public
  739.      */
  740.     function listTableFields($table)
  741.     {
  742.         $db $this->getDBInstance();
  743.         if (MDB2::isError($db)) {
  744.             return $db;
  745.         }
  746.  
  747.         $table $db->quoteIdentifier($tabletrue);
  748.         $columns $db->queryCol("SELECT c.name
  749.                                     FROM syscolumns c
  750.                                LEFT JOIN sysobjects o ON c.id = o.id
  751.                                    WHERE o.name = '$table'");
  752.         if (MDB2::isError($columns)) {
  753.             return $columns;
  754.         }
  755.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  756.             $columns array_map(($db->options['field_case'== CASE_LOWER ? 'strtolower' 'strtoupper')$columns);
  757.         }
  758.         return $columns;
  759.     }
  760.  
  761.     // }}}
  762.     // {{{ listTableIndexes()
  763.  
  764.     /**
  765.      * list all indexes in a table
  766.      *
  767.      * @param string $table name of table that should be used in method
  768.      *
  769.      * @return mixed array of index names on success, a MDB2 error on failure
  770.      * @access public
  771.      */
  772.     function listTableIndexes($table)
  773.     {
  774.         $db $this->getDBInstance();
  775.         if (MDB2::isError($db)) {
  776.             return $db;
  777.         }
  778.  
  779.         $key_name 'INDEX_NAME';
  780.         $pk_name 'PK_NAME';
  781.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  782.             if ($db->options['field_case'== CASE_LOWER{
  783.                 $key_name strtolower($key_name);
  784.                 $pk_name  strtolower($pk_name);
  785.             else {
  786.                 $key_name strtoupper($key_name);
  787.                 $pk_name  strtoupper($pk_name);
  788.             }
  789.         }
  790.         $table $db->quote($table'text');
  791.         $query = "EXEC sp_statistics @table_name=$table";
  792.         $indexes $db->queryCol($query'text'$key_name);
  793.         if (MDB2::isError($indexes)) {
  794.             return $indexes;
  795.         }
  796.         $query = "EXEC sp_pkeys @table_name=$table";
  797.         $pk_all $db->queryCol($query'text'$pk_name);
  798.         $result = array();
  799.         foreach ($indexes as $index{
  800.             if (!in_array($index$pk_all&& ($index $this->_fixIndexName($index))) {
  801.                 $result[$index= true;
  802.             }
  803.         }
  804.  
  805.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  806.             $result array_change_key_case($result$db->options['field_case']);
  807.         }
  808.         return array_keys($result);
  809.     }
  810.  
  811.     // }}}
  812.     // {{{ listDatabases()
  813.  
  814.     /**
  815.      * list all databases
  816.      *
  817.      * @return mixed array of database names on success, a MDB2 error on failure
  818.      * @access public
  819.      */
  820.     function listDatabases()
  821.     {
  822.         $db $this->getDBInstance();
  823.         if (MDB2::isError($db)) {
  824.             return $db;
  825.         }
  826.  
  827.         $result $db->queryCol('SELECT name FROM sys.databases');
  828.         if (MDB2::isError($result)) {
  829.             return $result;
  830.         }
  831.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  832.             $result array_map(($db->options['field_case'== CASE_LOWER ? 'strtolower' 'strtoupper')$result);
  833.         }
  834.         return $result;
  835.     }
  836.  
  837.     // }}}
  838.     // {{{ listUsers()
  839.  
  840.     /**
  841.      * list all users
  842.      *
  843.      * @return mixed array of user names on success, a MDB2 error on failure
  844.      * @access public
  845.      */
  846.     function listUsers()
  847.     {
  848.         $db $this->getDBInstance();
  849.         if (MDB2::isError($db)) {
  850.             return $db;
  851.         }
  852.  
  853.         $result $db->queryCol('SELECT DISTINCT loginame FROM master..sysprocesses');
  854.         if (MDB2::isError($result|| empty($result)) {
  855.             return $result;
  856.         }
  857.         foreach (array_keys($resultas $k{
  858.             $result[$ktrim($result[$k]);
  859.         }
  860.         return $result;
  861.     }
  862.  
  863.     // }}}
  864.     // {{{ listFunctions()
  865.  
  866.     /**
  867.      * list all functions in the current database
  868.      *
  869.      * @return mixed array of function names on success, a MDB2 error on failure
  870.      * @access public
  871.      */
  872.     function listFunctions()
  873.     {
  874.         $db $this->getDBInstance();
  875.         if (MDB2::isError($db)) {
  876.             return $db;
  877.         }
  878.  
  879.         $query "SELECT name
  880.                     FROM sysobjects
  881.                    WHERE objectproperty(id, N'IsMSShipped') = 0
  882.                     AND (objectproperty(id, N'IsTableFunction') = 1
  883.                      OR objectproperty(id, N'IsScalarFunction') = 1)";
  884.         /*
  885.         SELECT ROUTINE_NAME
  886.           FROM INFORMATION_SCHEMA.ROUTINES
  887.          WHERE ROUTINE_TYPE = 'FUNCTION'
  888.         */
  889.         $result $db->queryCol($query);
  890.         if (MDB2::isError($result)) {
  891.             return $result;
  892.         }
  893.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  894.             $result array_map(($db->options['field_case'== CASE_LOWER ? 'strtolower' 'strtoupper')$result);
  895.         }
  896.         return $result;
  897.     }
  898.  
  899.     // }}}
  900.     // {{{ listTableTriggers()
  901.  
  902.     /**
  903.      * list all triggers in the database that reference a given table
  904.      *
  905.      * @param string table for which all referenced triggers should be found
  906.      *
  907.      * @return mixed array of trigger names on success,  otherwise, false which
  908.      *                could be a db error if the db is not instantiated or could
  909.      *                be the results of the error that occured during the
  910.      *                querying of the sysobject module.
  911.      * @access public
  912.      */
  913.     function listTableTriggers($table = null)
  914.     {
  915.         $db $this->getDBInstance();
  916.         if (MDB2::isError($db)) {
  917.             return $db;
  918.         }
  919.  
  920.         $table $db->quote($table'text');
  921.         $query "SELECT o.name
  922.                     FROM sysobjects o
  923.                    WHERE xtype = 'TR'
  924.                      AND OBJECTPROPERTY(o.id, 'IsMSShipped') = 0";
  925.         if (null !== $table{
  926.             $query .= " AND object_name(parent_obj) = $table";
  927.         }
  928.  
  929.         $result $db->queryCol($query);
  930.         if (MDB2::isError($result)) {
  931.             return $result;
  932.         }
  933.  
  934.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE &&
  935.             $db->options['field_case'== CASE_LOWER)
  936.         {
  937.             $result array_map(($db->options['field_case'== CASE_LOWER ?
  938.                 'strtolower' 'strtoupper')$result);
  939.         }
  940.         return $result;
  941.     }
  942.  
  943.     // }}}
  944.     // {{{ listViews()
  945.  
  946.     /**
  947.      * list all views in the current database
  948.      *
  949.      * @param string database, the current is default
  950.      *
  951.      * @return mixed array of view names on success, a MDB2 error on failure
  952.      * @access public
  953.      */
  954.     function listViews()
  955.     {
  956.         $db $this->getDBInstance();
  957.         if (MDB2::isError($db)) {
  958.             return $db;
  959.         }
  960.  
  961.         $query "SELECT name
  962.                     FROM sysobjects
  963.                    WHERE xtype = 'V'";
  964.         /*
  965.         SELECT *
  966.           FROM sysobjects
  967.          WHERE objectproperty(id, N'IsMSShipped') = 0
  968.            AND objectproperty(id, N'IsView') = 1
  969.         */
  970.  
  971.         $result $db->queryCol($query);
  972.         if (MDB2::isError($result)) {
  973.             return $result;
  974.         }
  975.  
  976.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE &&
  977.             $db->options['field_case'== CASE_LOWER)
  978.         {
  979.             $result array_map(($db->options['field_case'== CASE_LOWER ?
  980.                           'strtolower' 'strtoupper')$result);
  981.         }
  982.         return $result;
  983.     }
  984.  
  985.     // }}}
  986.     // {{{ dropIndex()
  987.  
  988.     /**
  989.      * drop existing index
  990.      *
  991.      * @param string $table name of table that should be used in method
  992.      * @param string $name  name of the index to be dropped
  993.      *
  994.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  995.      * @access public
  996.      */
  997.     function dropIndex($table$name)
  998.     {
  999.         $db $this->getDBInstance();
  1000.         if (MDB2::isError($db)) {
  1001.             return $db;
  1002.         }
  1003.  
  1004.         $table $db->quoteIdentifier($tabletrue);
  1005.         $name $db->quoteIdentifier($db->getIndexName($name)true);
  1006.         $result $db->exec("DROP INDEX $table.$name");
  1007.         if (MDB2::isError($result)) {
  1008.             return $result;
  1009.         }
  1010.         return MDB2_OK;
  1011.     }
  1012.  
  1013.     // }}}
  1014.     // {{{ listTableConstraints()
  1015.  
  1016.     /**
  1017.      * list all constraints in a table
  1018.      *
  1019.      * @param string $table name of table that should be used in method
  1020.      *
  1021.      * @return mixed array of constraint names on success, a MDB2 error on failure
  1022.      * @access public
  1023.      */
  1024.     function listTableConstraints($table)
  1025.     {
  1026.         $db $this->getDBInstance();
  1027.         if (MDB2::isError($db)) {
  1028.             return $db;
  1029.         }
  1030.         $query = "SELECT c.constraint_name
  1031.                     FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS c
  1032.                    WHERE c.constraint_catalog = DB_NAME()
  1033.                      AND c.table_name = '$table'";
  1034.         $constraints $db->queryCol($query);
  1035.         if (MDB2::isError($constraints)) {
  1036.             return $constraints;
  1037.         }
  1038.  
  1039.         $result = array();
  1040.         foreach ($constraints as $constraint{
  1041.             $constraint $this->_fixIndexName($constraint);
  1042.             if (!empty($constraint)) {
  1043.                 $result[$constraint= true;
  1044.             }
  1045.         }
  1046.  
  1047.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  1048.             $result array_change_key_case($result$db->options['field_case']);
  1049.         }
  1050.         return array_keys($result);
  1051.     }
  1052.  
  1053.     // }}}
  1054.     // {{{
  1055.  
  1056.     /**
  1057.      * Create a basic SQL query for a new table creation
  1058.      *
  1059.      * @param string $name   Name of the database that should be created
  1060.      * @param array $fields  Associative array that contains the definition of each field of the new table
  1061.      * @param array $options An associative array of table options
  1062.      *                           Supported options are:
  1063.      *                           'primary'   An array of column names in the array keys
  1064.      *                                       that form the primary key of the table
  1065.      *                           'temporary' If true, creates the table as a temporary table
  1066.      * @return mixed string  The SQL query on success, or MDB2 error on failure
  1067.      * @see createTable()
  1068.      */
  1069.     function _getCreateTableQuery($name$fields$options = array())
  1070.     {
  1071.         $db $this->getDBInstance();
  1072.         if (MDB2::isError($db)) {
  1073.             return $db;
  1074.         }
  1075.  
  1076.         if (!$name{
  1077.             return $db->raiseError(MDB2_ERROR_CANNOT_CREATEnullnull,
  1078.                 'no valid table name specified'__FUNCTION__);
  1079.         }
  1080.         if (empty($fields)) {
  1081.             return $db->raiseError(MDB2_ERROR_CANNOT_CREATEnullnull,
  1082.                 'no fields specified for table "'.$name.'"'__FUNCTION__);
  1083.         }
  1084.         $query_fields $this->getFieldDeclarationList($fields);
  1085.         if (MDB2::isError($query_fields)) {
  1086.             return $query_fields;
  1087.         }
  1088.         /*Removed since you can't get the PK name from Schema here, will result in a redefinition of PK index error
  1089.         if (!empty($options['primary'])) {
  1090.             $query_fields.= ', PRIMARY KEY ('.implode(', ', array_keys($options['primary'])).')';
  1091.         }*/
  1092.  
  1093.         $name $db->quoteIdentifier($nametrue);
  1094.         $result 'CREATE ';
  1095.         if (!empty($options['temporary']&& $options['temporary']{
  1096.             $result .= $this->_getTemporaryTableQuery(' ';
  1097.         }
  1098.         $result .= "TABLE $name ($query_fields)";
  1099.         return $result;
  1100.     }
  1101.  
  1102.     // }}}
  1103.     // {{{ createSequence()
  1104.  
  1105.     /**
  1106.      * create sequence
  1107.      *
  1108.      * @param string $seq_name name of the sequence to be created
  1109.      * @param string $start    start value of the sequence; default is 1
  1110.      *
  1111.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  1112.      * @access public
  1113.      */
  1114.     function createSequence($seq_name$start = 1)
  1115.     {
  1116.         $db $this->getDBInstance();
  1117.         if (MDB2::isError($db)) {
  1118.             return $db;
  1119.         }
  1120.  
  1121.         $sequence_name $db->quoteIdentifier($db->getSequenceName($seq_name)true);
  1122.         $seqcol_name $db->quoteIdentifier($db->options['seqcol_name']true);
  1123.         $query = "CREATE TABLE $sequence_name ($seqcol_name " .
  1124.                  "INT PRIMARY KEY CLUSTERED IDENTITY($start,1) NOT NULL)";
  1125.  
  1126.         $res $db->exec($query);
  1127.         if (MDB2::isError($res)) {
  1128.             return $res;
  1129.         }
  1130.  
  1131.         $query = "SET IDENTITY_INSERT $sequence_name ON ".
  1132.                  "INSERT INTO $sequence_name ($seqcol_name) VALUES ($start)";
  1133.         $res $db->exec($query);
  1134.  
  1135.         if (!MDB2::isError($res)) {
  1136.             return MDB2_OK;
  1137.         }
  1138.  
  1139.         $result $db->exec("DROP TABLE $sequence_name");
  1140.         if (MDB2::isError($result)) {
  1141.             return $db->raiseError($resultnullnull,
  1142.                 'could not drop inconsistent sequence table'__FUNCTION__);
  1143.         }
  1144.  
  1145.         return $db->raiseError($resnullnull,
  1146.             'could not create sequence table'__FUNCTION__);
  1147.     }
  1148.  
  1149.     // }}}
  1150.     // {{{ dropSequence()
  1151.  
  1152.     /**
  1153.      * This function drops an existing sequence
  1154.      *
  1155.      * @param string $seq_name name of the sequence to be dropped
  1156.      *
  1157.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  1158.      * @access public
  1159.      */
  1160.     function dropSequence($seq_name)
  1161.     {
  1162.         $db $this->getDBInstance();
  1163.         if (MDB2::isError($db)) {
  1164.             return $db;
  1165.         }
  1166.  
  1167.         $sequence_name $db->quoteIdentifier($db->getSequenceName($seq_name)true);
  1168.         $result $db->exec("DROP TABLE $sequence_name");
  1169.         if (MDB2::isError($result)) {
  1170.             return $result;
  1171.         }
  1172.         return MDB2_OK;
  1173.     }
  1174.  
  1175.     // }}}
  1176.     // {{{ listSequences()
  1177.  
  1178.     /**
  1179.      * list all sequences in the current database
  1180.      *
  1181.      * @return mixed array of sequence names on success, a MDB2 error on failure
  1182.      * @access public
  1183.      */
  1184.     function listSequences()
  1185.     {
  1186.         $db $this->getDBInstance();
  1187.         if (MDB2::isError($db)) {
  1188.             return $db;
  1189.         }
  1190.  
  1191.         $query "SELECT name FROM sysobjects WHERE xtype = 'U'";
  1192.         $table_names $db->queryCol($query);
  1193.         if (MDB2::isError($table_names)) {
  1194.             return $table_names;
  1195.         }
  1196.         $result = array();
  1197.         foreach ($table_names as $table_name{
  1198.             if ($sqn $this->_fixSequenceName($table_nametrue)) {
  1199.                 $result[$sqn;
  1200.             }
  1201.         }
  1202.         if ($db->options['portability'MDB2_PORTABILITY_FIX_CASE{
  1203.             $result array_map(($db->options['field_case'== CASE_LOWER ?
  1204.                           'strtolower' 'strtoupper')$result);
  1205.         }
  1206.         return $result;
  1207.     }
  1208.  
  1209.     // }}}
  1210.     /**
  1211.      * New OPENX method to check table name according to specifications:
  1212.      *  http://msdn.microsoft.com/en-us/library/aa258255(SQL.80).aspx
  1213.      *
  1214.      *  Table names must conform to the rules for identifiers. The combination of owner.table_name
  1215.      *  must be unique within the database. table_name can contain a maximum of 128 characters,
  1216.      *  except for local temporary table names (names prefixed with a single number sign (#)) that
  1217.      *  cannot exceed 116 characters.
  1218.      *
  1219.      * @param string $name table name to check
  1220.      * @return true if name is correct and PEAR error on failure
  1221.      */
  1222.     function validateTableName($name)
  1223.     {
  1224.         // Table name maximum length is 128
  1225.         if (strlen($name> 128{
  1226.             return PEAR::raiseError(
  1227.                'SQL Server table names are limited to 128 characters in length');
  1228.         }
  1229.         return true;
  1230.     }
  1231.  
  1232.     /**
  1233.      * New OpenX method
  1234.      *
  1235.      * @param string $table 
  1236.      * @return array 
  1237.      */
  1238.     function getTableStatus($table)
  1239.     {
  1240.         $db $this->getDBInstance();
  1241.         if (MDB2::isError($db)) {
  1242.             return $db;
  1243.         }
  1244.  
  1245.         $query      = "exec sp_spaceused '{$table}'";
  1246.         $result     $db->queryAll($querynullMDB2_FETCHMODE_ASSOC);
  1247.         if (MDB2::isError($result))
  1248.         {
  1249.             return array();
  1250.         }
  1251.         $result[0]['data_length'(isset($result[0]['data'])) $result[0]['data': 0;
  1252.         $result[0]['data_free'(isset($result[0]['unused'])) $result[0]['unused': 0;
  1253.         //data_length,rows,auto_increment,data_free
  1254.         $query      = "SELECT IDENT_CURRENT ('{$table}') + IDENT_INCR ('{$table}') AS auto_increment";
  1255.         $resultIdentity     $db->queryAll($querynullMDB2_FETCHMODE_ASSOC);
  1256.         $result[0]['auto_increment'(isset($resultIdentity[0]['auto_increment'])) $resultIdentity[0]['auto_increment': 0;
  1257.         return $result;
  1258.     }
  1259.  
  1260.     function checkTable($tableName)
  1261.     {
  1262.         $db $this->getDBInstance();
  1263.         if (MDB2::isError($db)) {
  1264.             return $db;
  1265.         }
  1266.         $query  'CHECK TABLE '.$tableName;
  1267.         $result $db->queryRow($querynullMDB2_FETCHMODE_ASSOC);
  1268.         if (MDB2::isError($result))
  1269.         {
  1270.             return array('msg_text' => $result->getUserInfo());
  1271.         }
  1272.         return $result;
  1273.     }
  1274.  
  1275.     /**
  1276.      * New OPENX method to check database name according to specifications:
  1277.      *  Mysql specification: http://dev.mysql.com/doc/refman/4.1/en/identifiers.html
  1278.      *  Mysql specification: http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
  1279.      *  For 4.0, 4.1, 5.0 seem to be the same
  1280.      *
  1281.      * @param string $name database name to check
  1282.      * @return true in name is correct and PEAR error on failure
  1283.      */
  1284.     function validateDatabaseName($name)
  1285.     {
  1286.         return $this->_validateEntityName($name'Database');
  1287.     }
  1288.  
  1289.     /**
  1290.      * New OPENX method to check entity name according to specifications:
  1291.      *  Mysql specification: http://dev.mysql.com/doc/refman/4.1/en/identifiers.html
  1292.      *  Mysql specification: http://dev.mysql.com/doc/refman/5.0/en/identifiers.html
  1293.      *  For 4.0, 4.1, 5.0 seem to be the same
  1294.      *
  1295.      *  There are some restrictions on the characters that may appear in identifiers:
  1296.      *  - No identifier can contain ASCII 0 (0x00) or a byte with a value of 255.
  1297.      *  - Before MySQL 4.1, identifier quote characters should not be used in identifiers.
  1298.      *  - Database, table, and column names should not end with space characters.
  1299.      *  - Database and table names cannot contain "/", "\", ".", or characters that are not allowed in filenames.
  1300.      *
  1301.      *  Table/Database name maximum length:
  1302.      *  - 64
  1303.      *
  1304.      * @param string $name table name to check
  1305.      * @param string $entityType 
  1306.      *
  1307.      * @return true if name is correct and PEAR error on failure
  1308.      */
  1309.     function _validateEntityName($name$entityType)
  1310.     {
  1311.         // Table name maximum length is 64
  1312.         if (strlen($name> 64{
  1313.             return PEAR::raiseError(
  1314.                $entityType.' names are limited to 64 characters in length');
  1315.         }
  1316.  
  1317.         // Database, table, and column names should not end with space characters.
  1318.         // Extended for leading and ending spaces
  1319.         if ($name != trim($name)) {
  1320.             return PEAR::raiseError(
  1321.                 $entityType.' names should not start or end with space characters');
  1322.         }
  1323.  
  1324.         // No identifier can contain ASCII 0 (0x00) or a byte with a value of 255.
  1325.         if (preg_match'/([\x00\xff])/'$name)) {
  1326.             return PEAR::raiseError(
  1327.                $entityType.' names cannot contain ASCII 0 (0x00) or a byte with a value of 255');
  1328.         }
  1329.  
  1330.         //Before MySQL 4.1, identifier quote characters should not be used in identifiers.
  1331.         //we actually extend that and disallow quoting at all
  1332.         if (preg_match'/(\\\\|\/|\.|\"|\\\'| |\\(|\\)|\\:|\\;)/'$name)) {
  1333.             return PEAR::raiseError(
  1334.                 $entityType.' names cannot contain "/", "\\", ".", or characters that are not allowed in filenames');
  1335.         }
  1336.  
  1337.         return true;
  1338.     }
  1339.  
  1340.     // {{{ createConstraint()
  1341.  
  1342.     /**
  1343.      * create a constraint on a table
  1344.      *
  1345.      * @param string    $table         name of the table on which the constraint is to be created
  1346.      * @param string    $name         name of the constraint to be created
  1347.      * @param array     $definition        associative array that defines properties of the constraint to be created.
  1348.      *                                  Currently, only one property named FIELDS is supported. This property
  1349.      *                                  is also an associative with the names of the constraint fields as array
  1350.      *                                  constraints. Each entry of this array is set to another type of associative
  1351.      *                                  array that specifies properties of the constraint that are specific to
  1352.      *                                  each field.
  1353.      *
  1354.      *                                  Example
  1355.      *                                     array(
  1356.      *                                         'fields' => array(
  1357.      *                                             'user_name' => array(),
  1358.      *                                             'last_login' => array()
  1359.      *                                         )
  1360.      *                                     )
  1361.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  1362.      * @access public
  1363.      */
  1364.     function createConstraint($table$name$definition)
  1365.     {
  1366.         $db $this->getDBInstance();
  1367.         if (MDB2::isError($db)) {
  1368.             return $db;
  1369.         }
  1370.         $table $db->quoteIdentifier($tabletrue);
  1371.         $name $db->quoteIdentifier($db->getIndexName($name)true);
  1372.         if (!empty($definition['primary']&& empty($definition['unique'])) {
  1373.             $query = "ALTER TABLE $table ADD CONSTRAINT $name";
  1374.             if (!empty($definition['primary'])) {
  1375.                 $query.= ' PRIMARY KEY';
  1376.             elseif (!empty($definition['unique'])) {
  1377.                 $query.= ' UNIQUE';
  1378.             }
  1379.         elseif (!empty($definition['unique'])) {
  1380.             $query = "CREATE UNIQUE NONCLUSTERED INDEX $name ON $table";
  1381.         elseif (!empty($definition['foreign'])) {
  1382.             $query = "ALTER TABLE $table ADD CONSTRAINT $name FOREIGN KEY";
  1383.         }
  1384.         $fields = array();
  1385.         foreach (array_keys($definition['fields']as $field{
  1386.             $fields[$db->quoteIdentifier($fieldtrue);
  1387.         }
  1388.         $query .= ' ('implode(', '$fields')';
  1389.         //deals with NULL values and UNIQUE indexes, this solution is only available in SQL Server 2008
  1390.         //https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=299229
  1391.         if (!empty($definition['unique']&& empty($definition['primary'])) {
  1392.             for($i=0;$i<count($fields);$i++$fields[$i.= ' is NOT NULL';
  1393.             $query .= ' WHERE 'implode(' AND '$fields);
  1394.         }
  1395.         if (!empty($definition['foreign'])) {
  1396.             $query.= ' REFERENCES ' $db->quoteIdentifier($definition['references']['table']true);
  1397.             $referenced_fields = array();
  1398.             foreach (array_keys($definition['references']['fields']as $field{
  1399.                 $referenced_fields[$db->quoteIdentifier($fieldtrue);
  1400.             }
  1401.             $query .= ' ('implode(', '$referenced_fields')';
  1402.             $query .= $this->_getAdvancedFKOptions($definition);
  1403.         }
  1404.         $result $db->exec($query);
  1405.         if (MDB2::isError($result)) {
  1406.             return $result;
  1407.         }
  1408.         return MDB2_OK;
  1409.     }
  1410.  
  1411.     // }}}
  1412.  
  1413. }
  1414.  
  1415. // }}}
  1416. ?>

Documentation generated on Mon, 11 Mar 2019 15:51:29 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.