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

Source for file Common.php

Documentation is available at Common.php

  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PHP versions 4 and 5                                                 |
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1998-2007 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. // | Author: Lukas Smith <smith@pooteeweet.org>                           |
  43. // +----------------------------------------------------------------------+
  44. //
  45. // $Id: Common.php,v 1.137 2008/02/17 18:53:40 afz Exp $
  46.  
  47. require_once 'MDB2/LOB.php';
  48.  
  49. /**
  50.  * @package  MDB2
  51.  * @category Database
  52.  * @author   Lukas Smith <smith@pooteeweet.org>
  53.  */
  54.  
  55. /**
  56.  * MDB2_Driver_Common: Base class that is extended by each MDB2 driver
  57.  *
  58.  * To load this module in the MDB2 object:
  59.  * $mdb->loadModule('Datatype');
  60.  *
  61.  * @package MDB2
  62.  * @category Database
  63.  * @author Lukas Smith <smith@pooteeweet.org>
  64.  */
  65. {
  66.     var $valid_default_values = array(
  67.         'text'      => '',
  68.         'boolean'   => true,
  69.         'integer'   => 0,
  70.         'decimal'   => 0.0,
  71.         'float'     => 0.0,
  72.         'timestamp' => '1970-01-01 00:00:00',
  73.         'time'      => '00:00:00',
  74.         'date'      => '1970-01-01',
  75.         'clob'      => '',
  76.         'blob'      => '',
  77.     );
  78.  
  79.     /**
  80.      * contains all LOB objects created with this MDB2 instance
  81.      * @var array 
  82.      * @access protected
  83.      */
  84.     var $lobs = array();
  85.  
  86.     // }}}
  87.     // {{{ getValidTypes()
  88.  
  89.     /**
  90.      * Get the list of valid types
  91.      *
  92.      * This function returns an array of valid types as keys with the values
  93.      * being possible default values for all native datatypes and mapped types
  94.      * for custom datatypes.
  95.      *
  96.      * @return mixed array on success, a MDB2 error on failure
  97.      * @access public
  98.      */
  99.     function getValidTypes()
  100.     {
  101.         $types $this->valid_default_values;
  102.         $db =$this->getDBInstance();
  103.         if (PEAR::isError($db)) {
  104.             return $db;
  105.         }
  106.         if (!empty($db->options['datatype_map'])) {
  107.             foreach ($db->options['datatype_map'as $type => $mapped_type{
  108.                 if (array_key_exists($mapped_type$types)) {
  109.                     $types[$type$types[$mapped_type];
  110.                 elseif (!empty($db->options['datatype_map_callback'][$type])) {
  111.                     $parameter = array('type' => $type'mapped_type' => $mapped_type);
  112.                     $default =  call_user_func_array($db->options['datatype_map_callback'][$type]array(&$db__FUNCTION__$parameter));
  113.                     $types[$type$default;
  114.                 }
  115.             }
  116.         }
  117.         return $types;
  118.     }
  119.  
  120.     // }}}
  121.     // {{{ checkResultTypes()
  122.  
  123.     /**
  124.      * Define the list of types to be associated with the columns of a given
  125.      * result set.
  126.      *
  127.      * This function may be called before invoking fetchRow(), fetchOne()
  128.      * fetchCole() and fetchAll() so that the necessary data type
  129.      * conversions are performed on the data to be retrieved by them. If this
  130.      * function is not called, the type of all result set columns is assumed
  131.      * to be text, thus leading to not perform any conversions.
  132.      *
  133.      * @param array $types array variable that lists the
  134.      *        data types to be expected in the result set columns. If this array
  135.      *        contains less types than the number of columns that are returned
  136.      *        in the result set, the remaining columns are assumed to be of the
  137.      *        type text. Currently, the types clob and blob are not fully
  138.      *        supported.
  139.      * @return mixed MDB2_OK on success, a MDB2 error on failure
  140.      * @access public
  141.      */
  142.     function checkResultTypes($types)
  143.     {
  144.         $types is_array($types$types : array($types);
  145.         foreach ($types as $key => $type{
  146.             if (!isset($this->valid_default_values[$type])) {
  147.                 $db =$this->getDBInstance();
  148.                 if (PEAR::isError($db)) {
  149.                     return $db;
  150.                 }
  151.                 if (empty($db->options['datatype_map'][$type])) {
  152.                     return $db->raiseError(MDB2_ERROR_UNSUPPORTEDnullnull,
  153.                         $type.' for '.$key.' is not a supported column type'__FUNCTION__);
  154.                 }
  155.             }
  156.         }
  157.         return $types;
  158.     }
  159.  
  160.     // }}}
  161.     // {{{ _baseConvertResult()
  162.  
  163.     /**
  164.      * General type conversion method
  165.      *
  166.      * @param mixed   $value reference to a value to be converted
  167.      * @param string  $type  specifies which type to convert to
  168.      * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text
  169.      * @return object an MDB2 error on failure
  170.      * @access protected
  171.      */
  172.     function _baseConvertResult($value$type$rtrim = true)
  173.     {
  174.         switch ($type{
  175.         case 'text':
  176.             if ($rtrim{
  177.                 $value rtrim($value);
  178.             }
  179.             return $value;
  180.         case 'integer':
  181.             return intval($value);
  182.         case 'boolean':
  183.             return !empty($value);
  184.         case 'decimal':
  185.             return $value;
  186.         case 'float':
  187.             return doubleval($value);
  188.         case 'date':
  189.             return $value;
  190.         case 'time':
  191.             return $value;
  192.         case 'timestamp':
  193.             return $value;
  194.         case 'clob':
  195.         case 'blob':
  196.             $this->lobs[= array(
  197.                 'buffer' => null,
  198.                 'position' => 0,
  199.                 'lob_index' => null,
  200.                 'endOfLOB' => false,
  201.                 'resource' => $value,
  202.                 'value' => null,
  203.                 'loaded' => false,
  204.             );
  205.             end($this->lobs);
  206.             $lob_index key($this->lobs);
  207.             $this->lobs[$lob_index]['lob_index'$lob_index;
  208.             return fopen('MDB2LOB://'.$lob_index.'@'.$this->db_index'r+');
  209.         }
  210.  
  211.         $db =$this->getDBInstance();
  212.         if (PEAR::isError($db)) {
  213.             return $db;
  214.         }
  215.  
  216.         return $db->raiseError(MDB2_ERROR_INVALIDnullnull,
  217.             'attempt to convert result value to an unknown type :' $type__FUNCTION__);
  218.     }
  219.  
  220.     // }}}
  221.     // {{{ convertResult()
  222.  
  223.     /**
  224.      * Convert a value to a RDBMS indipendent MDB2 type
  225.      *
  226.      * @param mixed   $value value to be converted
  227.      * @param string  $type  specifies which type to convert to
  228.      * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text
  229.      * @return mixed converted value
  230.      * @access public
  231.      */
  232.     function convertResult($value$type$rtrim = true)
  233.     {
  234.         if (is_null($value)) {
  235.             return null;
  236.         }
  237.         $db =$this->getDBInstance();
  238.         if (PEAR::isError($db)) {
  239.             return $db;
  240.         }
  241.         if (!empty($db->options['datatype_map'][$type])) {
  242.             $type $db->options['datatype_map'][$type];
  243.             if (!empty($db->options['datatype_map_callback'][$type])) {
  244.                 $parameter = array('type' => $type'value' => $value'rtrim' => $rtrim);
  245.                 return call_user_func_array($db->options['datatype_map_callback'][$type]array(&$db__FUNCTION__$parameter));
  246.             }
  247.         }
  248.         return $this->_baseConvertResult($value$type$rtrim);
  249.     }
  250.  
  251.     // }}}
  252.     // {{{ convertResultRow()
  253.  
  254.     /**
  255.      * Convert a result row
  256.      *
  257.      * @param array   $types 
  258.      * @param array   $row   specifies the types to convert to
  259.      * @param boolean $rtrim [optional] when TRUE [default], apply rtrim() to text
  260.      * @return mixed MDB2_OK on success, an MDB2 error on failure
  261.      * @access public
  262.      */
  263.     function convertResultRow($types$row$rtrim = true)
  264.     {
  265.         $types $this->_sortResultFieldTypes(array_keys($row)$types);
  266.         foreach ($row as $key => $value{
  267.             if (empty($types[$key])) {
  268.                 continue;
  269.             }
  270.             $value $this->convertResult($row[$key]$types[$key]$rtrim);
  271.             if (PEAR::isError($value)) {
  272.                 return $value;
  273.             }
  274.             $row[$key$value;
  275.         }
  276.         return $row;
  277.     }
  278.  
  279.     // }}}
  280.     // {{{ _sortResultFieldTypes()
  281.  
  282.     /**
  283.      * convert a result row
  284.      *
  285.      * @param array $types 
  286.      * @param array $row specifies the types to convert to
  287.      * @param bool   $rtrim   if to rtrim text values or not
  288.      * @return mixed MDB2_OK on success,  a MDB2 error on failure
  289.      * @access public
  290.      */
  291.     function _sortResultFieldTypes($columns$types)
  292.     {
  293.         $n_cols count($columns);
  294.         $n_types count($types);
  295.         if ($n_cols $n_types{
  296.             for ($i$n_cols $n_types$i >= 0; $i--{
  297.                 $types[= null;
  298.             }
  299.         }
  300.         $sorted_types = array();
  301.         foreach ($columns as $col{
  302.             $sorted_types[$col= null;
  303.         }
  304.         foreach ($types as $name => $type{
  305.             if (array_key_exists($name$sorted_types)) {
  306.                 $sorted_types[$name$type;
  307.                 unset($types[$name]);
  308.             }
  309.         }
  310.         // if there are left types in the array, fill the null values of the
  311.         // sorted array with them, in order.
  312.         if (count($types)) {
  313.             reset($types);
  314.             foreach (array_keys($sorted_typesas $k{
  315.                 if (is_null($sorted_types[$k])) {
  316.                     $sorted_types[$kcurrent($types);
  317.                     next($types);
  318.                 }
  319.             }
  320.         }
  321.         return $sorted_types;
  322.     }
  323.  
  324.     // }}}
  325.     // {{{ getDeclaration()
  326.  
  327.     /**
  328.      * Obtain DBMS specific SQL code portion needed to declare
  329.      * of the given type
  330.      *
  331.      * @param string $type type to which the value should be converted to
  332.      * @param string  $name   name the field to be declared.
  333.      * @param string  $field  definition of the field
  334.      * @return string  DBMS specific SQL code portion that should be used to
  335.      *                  declare the specified field.
  336.      * @access public
  337.      */
  338.     function getDeclaration($type$name$field)
  339.     {
  340.         $db =$this->getDBInstance();
  341.         if (PEAR::isError($db)) {
  342.             return $db;
  343.         }
  344.  
  345.         if (!empty($db->options['datatype_map'][$type])) {
  346.             $type $db->options['datatype_map'][$type];
  347.             if (!empty($db->options['datatype_map_callback'][$type])) {
  348.                 $parameter = array('type' => $type'name' => $name'field' => $field);
  349.                 return call_user_func_array($db->options['datatype_map_callback'][$type]array(&$db__FUNCTION__$parameter));
  350.             }
  351.             $field['type'$type;
  352.         }
  353.  
  354.         if (!method_exists($this"_get{$type}Declaration")) {
  355.             return $db->raiseError(MDB2_ERROR_NOT_FOUNDnullnull,
  356.                 'type not defined: '.$type__FUNCTION__);
  357.         }
  358.         return $this->{"_get{$type}Declaration"}($name$field);
  359.     }
  360.  
  361.     // }}}
  362.     // {{{ getTypeDeclaration()
  363.  
  364.     /**
  365.      * Obtain DBMS specific SQL code portion needed to declare an text type
  366.      * field to be used in statements like CREATE TABLE.
  367.      *
  368.      * @param array $field  associative array with the name of the properties
  369.      *       of the field being declared as array indexes. Currently, the types
  370.      *       of supported field properties are as follows:
  371.      *
  372.      *       length
  373.      *           Integer value that determines the maximum length of the text
  374.      *           field. If this argument is missing the field should be
  375.      *           declared to have the longest length allowed by the DBMS.
  376.      *
  377.      *       default
  378.      *           Text value to be used as default for this field.
  379.      *
  380.      *       notnull
  381.      *           Boolean flag that indicates whether this field is constrained
  382.      *           to not be set to null.
  383.      * @return string  DBMS specific SQL code portion that should be used to
  384.      *       declare the specified field.
  385.      * @access public
  386.      */
  387.     function getTypeDeclaration($field)
  388.     {
  389.         $db =$this->getDBInstance();
  390.         if (PEAR::isError($db)) {
  391.             return $db;
  392.         }
  393.  
  394.         switch ($field['type']{
  395.         case 'text':
  396.             $length !empty($field['length']$field['length'$db->options['default_text_field_length'];
  397.             $fixed !empty($field['fixed']$field['fixed': false;
  398.             return $fixed ($length 'CHAR('.$length.')' 'CHAR('.$db->options['default_text_field_length'].')')
  399.                 : ($length 'VARCHAR('.$length.')' 'TEXT');
  400.         case 'clob':
  401.             return 'TEXT';
  402.         case 'blob':
  403.             return 'TEXT';
  404.         case 'integer':
  405.             return 'INT';
  406.         case 'boolean':
  407.             return 'INT';
  408.         case 'date':
  409.             return 'CHAR ('.strlen('YYYY-MM-DD').')';
  410.         case 'time':
  411.             return 'CHAR ('.strlen('HH:MM:SS').')';
  412.         case 'timestamp':
  413.             return 'CHAR ('.strlen('YYYY-MM-DD HH:MM:SS').')';
  414.         case 'float':
  415.             return 'TEXT';
  416.         case 'decimal':
  417.             return 'TEXT';
  418.         }
  419.         return '';
  420.     }
  421.  
  422.     // }}}
  423.     // {{{ _getDeclaration()
  424.  
  425.     /**
  426.      * Obtain DBMS specific SQL code portion needed to declare a generic type
  427.      * field to be used in statements like CREATE TABLE.
  428.      *
  429.      * @param string $name   name the field to be declared.
  430.      * @param array  $field  associative array with the name of the properties
  431.      *       of the field being declared as array indexes. Currently, the types
  432.      *       of supported field properties are as follows:
  433.      *
  434.      *       length
  435.      *           Integer value that determines the maximum length of the text
  436.      *           field. If this argument is missing the field should be
  437.      *           declared to have the longest length allowed by the DBMS.
  438.      *
  439.      *       default
  440.      *           Text value to be used as default for this field.
  441.      *
  442.      *       notnull
  443.      *           Boolean flag that indicates whether this field is constrained
  444.      *           to not be set to null.
  445.      *       charset
  446.      *           Text value with the default CHARACTER SET for this field.
  447.      *       collation
  448.      *           Text value with the default COLLATION for this field.
  449.      * @return string  DBMS specific SQL code portion that should be used to
  450.      *       declare the specified field, or a MDB2_Error on failure
  451.      * @access protected
  452.      */
  453.     function _getDeclaration($name$field)
  454.     {
  455.         $db =$this->getDBInstance();
  456.         if (PEAR::isError($db)) {
  457.             return $db;
  458.         }
  459.  
  460.         $name $db->quoteIdentifier($nametrue);
  461.         $declaration_options $db->datatype->_getDeclarationOptions($field);
  462.         if (PEAR::isError($declaration_options)) {
  463.             return $declaration_options;
  464.         }
  465.         return $name.' '.$this->getTypeDeclaration($field).$declaration_options;
  466.     }
  467.  
  468.     // }}}
  469.     // {{{ _getDeclarationOptions()
  470.  
  471.     /**
  472.      * Obtain DBMS specific SQL code portion needed to declare a generic type
  473.      * field to be used in statement like CREATE TABLE, without the field name
  474.      * and type values (ie. just the character set, default value, if the
  475.      * field is permitted to be NULL or not, and the collation options).
  476.      *
  477.      * @param array  $field  associative array with the name of the properties
  478.      *       of the field being declared as array indexes. Currently, the types
  479.      *       of supported field properties are as follows:
  480.      *
  481.      *       default
  482.      *           Text value to be used as default for this field.
  483.      *       notnull
  484.      *           Boolean flag that indicates whether this field is constrained
  485.      *           to not be set to null.
  486.      *       charset
  487.      *           Text value with the default CHARACTER SET for this field.
  488.      *       collation
  489.      *           Text value with the default COLLATION for this field.
  490.      * @return string  DBMS specific SQL code portion that should be used to
  491.      *       declare the specified field's options.
  492.      * @access protected
  493.      */
  494.     function _getDeclarationOptions($field)
  495.     {
  496.         $charset = empty($field['charset']'' :
  497.             ' '.$this->_getCharsetFieldDeclaration($field['charset']);
  498.  
  499.         $notnull = empty($field['notnull']'' ' NOT NULL';
  500.         $default '';
  501.         if (array_key_exists('default'$field)) {
  502.             if ($field['default'=== ''{
  503.                 $db =$this->getDBInstance();
  504.                 if (PEAR::isError($db)) {
  505.                     return $db;
  506.                 }
  507.                 $valid_default_values $this->getValidTypes();
  508.                 $field['default'$valid_default_values[$field['type']];
  509.                 if ($field['default'=== ''&& ($db->options['portability'MDB2_PORTABILITY_EMPTY_TO_NULL)) {
  510.                     $field['default'' ';
  511.                 }
  512.             }
  513.             if (!is_null($field['default'])) {
  514.                 $default ' DEFAULT ' $this->quote($field['default']$field['type']);
  515.             }
  516.         }
  517.  
  518.         $collation = empty($field['collation']'' :
  519.             ' '.$this->_getCollationFieldDeclaration($field['collation']);
  520.  
  521.         return $charset.$default.$notnull.$collation;
  522.     }
  523.  
  524.     // }}}
  525.     // {{{ _getCharsetFieldDeclaration()
  526.     
  527.     /**
  528.      * Obtain DBMS specific SQL code portion needed to set the CHARACTER SET
  529.      * of a field declaration to be used in statements like CREATE TABLE.
  530.      *
  531.      * @param string $charset   name of the charset
  532.      * @return string  DBMS specific SQL code portion needed to set the CHARACTER SET
  533.      *                  of a field declaration.
  534.      */
  535.     function _getCharsetFieldDeclaration($charset)
  536.     {
  537.         return '';
  538.     }
  539.  
  540.     // }}}
  541.     // {{{ _getCollationFieldDeclaration()
  542.  
  543.     /**
  544.      * Obtain DBMS specific SQL code portion needed to set the COLLATION
  545.      * of a field declaration to be used in statements like CREATE TABLE.
  546.      *
  547.      * @param string $collation   name of the collation
  548.      * @return string  DBMS specific SQL code portion needed to set the COLLATION
  549.      *                  of a field declaration.
  550.      */
  551.     function _getCollationFieldDeclaration($collation)
  552.     {
  553.         return '';
  554.     }
  555.  
  556.     // }}}
  557.     // {{{ _getIntegerDeclaration()
  558.  
  559.     /**
  560.      * Obtain DBMS specific SQL code portion needed to declare an integer type
  561.      * field to be used in statements like CREATE TABLE.
  562.      *
  563.      * @param string $name name the field to be declared.
  564.      * @param array $field associative array with the name of the properties
  565.      *        of the field being declared as array indexes. Currently, the types
  566.      *        of supported field properties are as follows:
  567.      *
  568.      *        unsigned
  569.      *            Boolean flag that indicates whether the field should be
  570.      *            declared as unsigned integer if possible.
  571.      *
  572.      *        default
  573.      *            Integer value to be used as default for this field.
  574.      *
  575.      *        notnull