File indexing completed on 2025-01-19 05:21:02

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Db
0017  * @subpackage Adapter
0018  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id$
0021  */
0022 
0023 
0024 /**
0025  * @see Zend_Db
0026  */
0027 // require_once 'Zend/Db.php';
0028 
0029 /**
0030  * @see Zend_Db_Select
0031  */
0032 // require_once 'Zend/Db/Select.php';
0033 
0034 /**
0035  * Class for connecting to SQL databases and performing common operations.
0036  *
0037  * @category   Zend
0038  * @package    Zend_Db
0039  * @subpackage Adapter
0040  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0041  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0042  */
0043 abstract class Zend_Db_Adapter_Abstract
0044 {
0045 
0046     /**
0047      * User-provided configuration
0048      *
0049      * @var array
0050      */
0051     protected $_config = array();
0052 
0053     /**
0054      * Fetch mode
0055      *
0056      * @var integer
0057      */
0058     protected $_fetchMode = Zend_Db::FETCH_ASSOC;
0059 
0060     /**
0061      * Query profiler object, of type Zend_Db_Profiler
0062      * or a subclass of that.
0063      *
0064      * @var Zend_Db_Profiler
0065      */
0066     protected $_profiler;
0067 
0068     /**
0069      * Default class name for a DB statement.
0070      *
0071      * @var string
0072      */
0073     protected $_defaultStmtClass = 'Zend_Db_Statement';
0074 
0075     /**
0076      * Default class name for the profiler object.
0077      *
0078      * @var string
0079      */
0080     protected $_defaultProfilerClass = 'Zend_Db_Profiler';
0081 
0082     /**
0083      * Database connection
0084      *
0085      * @var object|resource|null
0086      */
0087     protected $_connection = null;
0088 
0089     /**
0090      * Specifies the case of column names retrieved in queries
0091      * Options
0092      * Zend_Db::CASE_NATURAL (default)
0093      * Zend_Db::CASE_LOWER
0094      * Zend_Db::CASE_UPPER
0095      *
0096      * @var integer
0097      */
0098     protected $_caseFolding = Zend_Db::CASE_NATURAL;
0099 
0100     /**
0101      * Specifies whether the adapter automatically quotes identifiers.
0102      * If true, most SQL generated by Zend_Db classes applies
0103      * identifier quoting automatically.
0104      * If false, developer must quote identifiers themselves
0105      * by calling quoteIdentifier().
0106      *
0107      * @var bool
0108      */
0109     protected $_autoQuoteIdentifiers = true;
0110 
0111     /**
0112      * Keys are UPPERCASE SQL datatypes or the constants
0113      * Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE.
0114      *
0115      * Values are:
0116      * 0 = 32-bit integer
0117      * 1 = 64-bit integer
0118      * 2 = float or decimal
0119      *
0120      * @var array Associative array of datatypes to values 0, 1, or 2.
0121      */
0122     protected $_numericDataTypes = array(
0123         Zend_Db::INT_TYPE    => Zend_Db::INT_TYPE,
0124         Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE,
0125         Zend_Db::FLOAT_TYPE  => Zend_Db::FLOAT_TYPE
0126     );
0127 
0128     /** Weither or not that object can get serialized
0129      *
0130      * @var bool
0131      */
0132     protected $_allowSerialization = true;
0133 
0134     /**
0135      * Weither or not the database should be reconnected
0136      * to that adapter when waking up
0137      *
0138      * @var bool
0139      */
0140     protected $_autoReconnectOnUnserialize = false;
0141 
0142     /**
0143      * Constructor.
0144      *
0145      * $config is an array of key/value pairs or an instance of Zend_Config
0146      * containing configuration options.  These options are common to most adapters:
0147      *
0148      * dbname         => (string) The name of the database to user
0149      * username       => (string) Connect to the database as this username.
0150      * password       => (string) Password associated with the username.
0151      * host           => (string) What host to connect to, defaults to localhost
0152      *
0153      * Some options are used on a case-by-case basis by adapters:
0154      *
0155      * port           => (string) The port of the database
0156      * persistent     => (boolean) Whether to use a persistent connection or not, defaults to false
0157      * protocol       => (string) The network protocol, defaults to TCPIP
0158      * caseFolding    => (int) style of case-alteration used for identifiers
0159      * socket         => (string) The socket or named pipe that should be used
0160      *
0161      * @param  array|Zend_Config $config An array or instance of Zend_Config having configuration data
0162      * @throws Zend_Db_Adapter_Exception
0163      */
0164     public function __construct($config)
0165     {
0166         /*
0167          * Verify that adapter parameters are in an array.
0168          */
0169         if (!is_array($config)) {
0170             /*
0171              * Convert Zend_Config argument to a plain array.
0172              */
0173             if ($config instanceof Zend_Config) {
0174                 $config = $config->toArray();
0175             } else {
0176                 /**
0177                  * @see Zend_Db_Adapter_Exception
0178                  */
0179                 // require_once 'Zend/Db/Adapter/Exception.php';
0180                 throw new Zend_Db_Adapter_Exception('Adapter parameters must be in an array or a Zend_Config object');
0181             }
0182         }
0183 
0184         $this->_checkRequiredOptions($config);
0185 
0186         $options = array(
0187             Zend_Db::CASE_FOLDING           => $this->_caseFolding,
0188             Zend_Db::AUTO_QUOTE_IDENTIFIERS => $this->_autoQuoteIdentifiers,
0189             Zend_Db::FETCH_MODE             => $this->_fetchMode,
0190         );
0191         $driverOptions = array();
0192 
0193         /*
0194          * normalize the config and merge it with the defaults
0195          */
0196         if (array_key_exists('options', $config)) {
0197             // can't use array_merge() because keys might be integers
0198             foreach ((array) $config['options'] as $key => $value) {
0199                 $options[$key] = $value;
0200             }
0201         }
0202         if (array_key_exists('driver_options', $config)) {
0203             if (!empty($config['driver_options'])) {
0204                 // can't use array_merge() because keys might be integers
0205                 foreach ((array) $config['driver_options'] as $key => $value) {
0206                     $driverOptions[$key] = $value;
0207                 }
0208             }
0209         }
0210 
0211         if (!isset($config['charset'])) {
0212             $config['charset'] = null;
0213         }
0214 
0215         if (!isset($config['persistent'])) {
0216             $config['persistent'] = false;
0217         }
0218 
0219         $this->_config = array_merge($this->_config, $config);
0220         $this->_config['options'] = $options;
0221         $this->_config['driver_options'] = $driverOptions;
0222 
0223 
0224         // obtain the case setting, if there is one
0225         if (array_key_exists(Zend_Db::CASE_FOLDING, $options)) {
0226             $case = (int) $options[Zend_Db::CASE_FOLDING];
0227             switch ($case) {
0228                 case Zend_Db::CASE_LOWER:
0229                 case Zend_Db::CASE_UPPER:
0230                 case Zend_Db::CASE_NATURAL:
0231                     $this->_caseFolding = $case;
0232                     break;
0233                 default:
0234                     /** @see Zend_Db_Adapter_Exception */
0235                     // require_once 'Zend/Db/Adapter/Exception.php';
0236                     throw new Zend_Db_Adapter_Exception('Case must be one of the following constants: '
0237                         . 'Zend_Db::CASE_NATURAL, Zend_Db::CASE_LOWER, Zend_Db::CASE_UPPER');
0238             }
0239         }
0240 
0241         if (array_key_exists(Zend_Db::FETCH_MODE, $options)) {
0242             if (is_string($options[Zend_Db::FETCH_MODE])) {
0243                 $constant = 'Zend_Db::FETCH_' . strtoupper($options[Zend_Db::FETCH_MODE]);
0244                 if(defined($constant)) {
0245                     $options[Zend_Db::FETCH_MODE] = constant($constant);
0246                 }
0247             }
0248             $this->setFetchMode((int) $options[Zend_Db::FETCH_MODE]);
0249         }
0250 
0251         // obtain quoting property if there is one
0252         if (array_key_exists(Zend_Db::AUTO_QUOTE_IDENTIFIERS, $options)) {
0253             $this->_autoQuoteIdentifiers = (bool) $options[Zend_Db::AUTO_QUOTE_IDENTIFIERS];
0254         }
0255 
0256         // obtain allow serialization property if there is one
0257         if (array_key_exists(Zend_Db::ALLOW_SERIALIZATION, $options)) {
0258             $this->_allowSerialization = (bool) $options[Zend_Db::ALLOW_SERIALIZATION];
0259         }
0260 
0261         // obtain auto reconnect on unserialize property if there is one
0262         if (array_key_exists(Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE, $options)) {
0263             $this->_autoReconnectOnUnserialize = (bool) $options[Zend_Db::AUTO_RECONNECT_ON_UNSERIALIZE];
0264         }
0265 
0266         // create a profiler object
0267         $profiler = false;
0268         if (array_key_exists(Zend_Db::PROFILER, $this->_config)) {
0269             $profiler = $this->_config[Zend_Db::PROFILER];
0270             unset($this->_config[Zend_Db::PROFILER]);
0271         }
0272         $this->setProfiler($profiler);
0273     }
0274 
0275     /**
0276      * Check for config options that are mandatory.
0277      * Throw exceptions if any are missing.
0278      *
0279      * @param array $config
0280      * @throws Zend_Db_Adapter_Exception
0281      */
0282     protected function _checkRequiredOptions(array $config)
0283     {
0284         // we need at least a dbname
0285         if (! array_key_exists('dbname', $config)) {
0286             /** @see Zend_Db_Adapter_Exception */
0287             // require_once 'Zend/Db/Adapter/Exception.php';
0288             throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'dbname' that names the database instance");
0289         }
0290 
0291         if (! array_key_exists('password', $config)) {
0292             /**
0293              * @see Zend_Db_Adapter_Exception
0294              */
0295             // require_once 'Zend/Db/Adapter/Exception.php';
0296             throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'password' for login credentials");
0297         }
0298 
0299         if (! array_key_exists('username', $config)) {
0300             /**
0301              * @see Zend_Db_Adapter_Exception
0302              */
0303             // require_once 'Zend/Db/Adapter/Exception.php';
0304             throw new Zend_Db_Adapter_Exception("Configuration array must have a key for 'username' for login credentials");
0305         }
0306     }
0307 
0308     /**
0309      * Returns the underlying database connection object or resource.
0310      * If not presently connected, this initiates the connection.
0311      *
0312      * @return object|resource|null
0313      */
0314     public function getConnection()
0315     {
0316         $this->_connect();
0317         return $this->_connection;
0318     }
0319 
0320     /**
0321      * Returns the configuration variables in this adapter.
0322      *
0323      * @return array
0324      */
0325     public function getConfig()
0326     {
0327         return $this->_config;
0328     }
0329 
0330     /**
0331      * Set the adapter's profiler object.
0332      *
0333      * The argument may be a boolean, an associative array, an instance of
0334      * Zend_Db_Profiler, or an instance of Zend_Config.
0335      *
0336      * A boolean argument sets the profiler to enabled if true, or disabled if
0337      * false.  The profiler class is the adapter's default profiler class,
0338      * Zend_Db_Profiler.
0339      *
0340      * An instance of Zend_Db_Profiler sets the adapter's instance to that
0341      * object.  The profiler is enabled and disabled separately.
0342      *
0343      * An associative array argument may contain any of the keys 'enabled',
0344      * 'class', and 'instance'. The 'enabled' and 'instance' keys correspond to the
0345      * boolean and object types documented above. The 'class' key is used to name a
0346      * class to use for a custom profiler. The class must be Zend_Db_Profiler or a
0347      * subclass. The class is instantiated with no constructor arguments. The 'class'
0348      * option is ignored when the 'instance' option is supplied.
0349      *
0350      * An object of type Zend_Config may contain the properties 'enabled', 'class', and
0351      * 'instance', just as if an associative array had been passed instead.
0352      *
0353      * @param  Zend_Db_Profiler|Zend_Config|array|boolean $profiler
0354      * @return Zend_Db_Adapter_Abstract Provides a fluent interface
0355      * @throws Zend_Db_Profiler_Exception if the object instance or class specified
0356      *         is not Zend_Db_Profiler or an extension of that class.
0357      */
0358     public function setProfiler($profiler)
0359     {
0360         $enabled          = null;
0361         $profilerClass    = $this->_defaultProfilerClass;
0362         $profilerInstance = null;
0363 
0364         if ($profilerIsObject = is_object($profiler)) {
0365             if ($profiler instanceof Zend_Db_Profiler) {
0366                 $profilerInstance = $profiler;
0367             } else if ($profiler instanceof Zend_Config) {
0368                 $profiler = $profiler->toArray();
0369             } else {
0370                 /**
0371                  * @see Zend_Db_Profiler_Exception
0372                  */
0373                 // require_once 'Zend/Db/Profiler/Exception.php';
0374                 throw new Zend_Db_Profiler_Exception('Profiler argument must be an instance of either Zend_Db_Profiler'
0375                     . ' or Zend_Config when provided as an object');
0376             }
0377         }
0378 
0379         if (is_array($profiler)) {
0380             if (isset($profiler['enabled'])) {
0381                 $enabled = (bool) $profiler['enabled'];
0382             }
0383             if (isset($profiler['class'])) {
0384                 $profilerClass = $profiler['class'];
0385             }
0386             if (isset($profiler['instance'])) {
0387                 $profilerInstance = $profiler['instance'];
0388             }
0389         } else if (!$profilerIsObject) {
0390             $enabled = (bool) $profiler;
0391         }
0392 
0393         if ($profilerInstance === null) {
0394             if (!class_exists($profilerClass)) {
0395                 // require_once 'Zend/Loader.php';
0396                 Zend_Loader::loadClass($profilerClass);
0397             }
0398             $profilerInstance = new $profilerClass();
0399         }
0400 
0401         if (!$profilerInstance instanceof Zend_Db_Profiler) {
0402             /** @see Zend_Db_Profiler_Exception */
0403             // require_once 'Zend/Db/Profiler/Exception.php';
0404             throw new Zend_Db_Profiler_Exception('Class ' . get_class($profilerInstance) . ' does not extend '
0405                 . 'Zend_Db_Profiler');
0406         }
0407 
0408         if (null !== $enabled) {
0409             $profilerInstance->setEnabled($enabled);
0410         }
0411 
0412         $this->_profiler = $profilerInstance;
0413 
0414         return $this;
0415     }
0416 
0417 
0418     /**
0419      * Returns the profiler for this adapter.
0420      *
0421      * @return Zend_Db_Profiler
0422      */
0423     public function getProfiler()
0424     {
0425         return $this->_profiler;
0426     }
0427 
0428     /**
0429      * Get the default statement class.
0430      *
0431      * @return string
0432      */
0433     public function getStatementClass()
0434     {
0435         return $this->_defaultStmtClass;
0436     }
0437 
0438     /**
0439      * Set the default statement class.
0440      *
0441      * @return Zend_Db_Adapter_Abstract Fluent interface
0442      */
0443     public function setStatementClass($class)
0444     {
0445         $this->_defaultStmtClass = $class;
0446         return $this;
0447     }
0448 
0449     /**
0450      * Prepares and executes an SQL statement with bound data.
0451      *
0452      * @param  mixed  $sql  The SQL statement with placeholders.
0453      *                      May be a string or Zend_Db_Select.
0454      * @param  mixed  $bind An array of data to bind to the placeholders.
0455      * @return Zend_Db_Statement_Interface
0456      */
0457     public function query($sql, $bind = array())
0458     {
0459         // connect to the database if needed
0460         $this->_connect();
0461 
0462         // is the $sql a Zend_Db_Select object?
0463         if ($sql instanceof Zend_Db_Select) {
0464             if (empty($bind)) {
0465                 $bind = $sql->getBind();
0466             }
0467 
0468             $sql = $sql->assemble();
0469         }
0470 
0471         // make sure $bind to an array;
0472         // don't use (array) typecasting because
0473         // because $bind may be a Zend_Db_Expr object
0474         if (!is_array($bind)) {
0475             $bind = array($bind);
0476         }
0477 
0478         // prepare and execute the statement with profiling
0479         $stmt = $this->prepare($sql);
0480         $stmt->execute($bind);
0481 
0482         // return the results embedded in the prepared statement object
0483         $stmt->setFetchMode($this->_fetchMode);
0484         return $stmt;
0485     }
0486 
0487     /**
0488      * Leave autocommit mode and begin a transaction.
0489      *
0490      * @return Zend_Db_Adapter_Abstract
0491      */
0492     public function beginTransaction()
0493     {
0494         $this->_connect();
0495         $q = $this->_profiler->queryStart('begin', Zend_Db_Profiler::TRANSACTION);
0496         $this->_beginTransaction();
0497         $this->_profiler->queryEnd($q);
0498         return $this;
0499     }
0500 
0501     /**
0502      * Commit a transaction and return to autocommit mode.
0503      *
0504      * @return Zend_Db_Adapter_Abstract
0505      */
0506     public function commit()
0507     {
0508         $this->_connect();
0509         $q = $this->_profiler->queryStart('commit', Zend_Db_Profiler::TRANSACTION);
0510         $this->_commit();
0511         $this->_profiler->queryEnd($q);
0512         return $this;
0513     }
0514 
0515     /**
0516      * Roll back a transaction and return to autocommit mode.
0517      *
0518      * @return Zend_Db_Adapter_Abstract
0519      */
0520     public function rollBack()
0521     {
0522         $this->_connect();
0523         $q = $this->_profiler->queryStart('rollback', Zend_Db_Profiler::TRANSACTION);
0524         $this->_rollBack();
0525         $this->_profiler->queryEnd($q);
0526         return $this;
0527     }
0528 
0529     /**
0530      * Inserts a table row with specified data.
0531      *
0532      * @param mixed $table The table to insert data into.
0533      * @param array $bind Column-value pairs.
0534      * @return int The number of affected rows.
0535      * @throws Zend_Db_Adapter_Exception
0536      */
0537     public function insert($table, array $bind)
0538     {
0539         // extract and quote col names from the array keys
0540         $cols = array();
0541         $vals = array();
0542         $i = 0;
0543         foreach ($bind as $col => $val) {
0544             $cols[] = $this->quoteIdentifier($col, true);
0545             if ($val instanceof Zend_Db_Expr) {
0546                 $vals[] = $val->__toString();
0547                 unset($bind[$col]);
0548             } else {
0549                 if ($this->supportsParameters('positional')) {
0550                     $vals[] = '?';
0551                 } else {
0552                     if ($this->supportsParameters('named')) {
0553                         unset($bind[$col]);
0554                         $bind[':col'.$i] = $val;
0555                         $vals[] = ':col'.$i;
0556                         $i++;
0557                     } else {
0558                         /** @see Zend_Db_Adapter_Exception */
0559                         // require_once 'Zend/Db/Adapter/Exception.php';
0560                         throw new Zend_Db_Adapter_Exception(get_class($this) ." doesn't support positional or named binding");
0561                     }
0562                 }
0563             }
0564         }
0565 
0566         // build the statement
0567         $sql = "INSERT INTO "
0568              . $this->quoteIdentifier($table, true)
0569              . ' (' . implode(', ', $cols) . ') '
0570              . 'VALUES (' . implode(', ', $vals) . ')';
0571 
0572         // execute the statement and return the number of affected rows
0573         if ($this->supportsParameters('positional')) {
0574             $bind = array_values($bind);
0575         }
0576         $stmt = $this->query($sql, $bind);
0577         $result = $stmt->rowCount();
0578         return $result;
0579     }
0580 
0581     /**
0582      * Updates table rows with specified data based on a WHERE clause.
0583      *
0584      * @param  mixed        $table The table to update.
0585      * @param  array        $bind  Column-value pairs.
0586      * @param  mixed        $where UPDATE WHERE clause(s).
0587      * @return int          The number of affected rows.
0588      * @throws Zend_Db_Adapter_Exception
0589      */
0590     public function update($table, array $bind, $where = '')
0591     {
0592         /**
0593          * Build "col = ?" pairs for the statement,
0594          * except for Zend_Db_Expr which is treated literally.
0595          */
0596         $set = array();
0597         $i = 0;
0598         foreach ($bind as $col => $val) {
0599             if ($val instanceof Zend_Db_Expr) {
0600                 $val = $val->__toString();
0601                 unset($bind[$col]);
0602             } else {
0603                 if ($this->supportsParameters('positional')) {
0604                     $val = '?';
0605                 } else {
0606                     if ($this->supportsParameters('named')) {
0607                         unset($bind[$col]);
0608                         $bind[':col'.$i] = $val;
0609                         $val = ':col'.$i;
0610                         $i++;
0611                     } else {
0612                         /** @see Zend_Db_Adapter_Exception */
0613                         // require_once 'Zend/Db/Adapter/Exception.php';
0614                         throw new Zend_Db_Adapter_Exception(get_class($this) ." doesn't support positional or named binding");
0615                     }
0616                 }
0617             }
0618             $set[] = $this->quoteIdentifier($col, true) . ' = ' . $val;
0619         }
0620 
0621         $where = $this->_whereExpr($where);
0622 
0623         /**
0624          * Build the UPDATE statement
0625          */
0626         $sql = "UPDATE "
0627              . $this->quoteIdentifier($table, true)
0628              . ' SET ' . implode(', ', $set)
0629              . (($where) ? " WHERE $where" : '');
0630 
0631         /**
0632          * Execute the statement and return the number of affected rows
0633          */
0634         if ($this->supportsParameters('positional')) {
0635             $stmt = $this->query($sql, array_values($bind));
0636         } else {
0637             $stmt = $this->query($sql, $bind);
0638         }
0639         $result = $stmt->rowCount();
0640         return $result;
0641     }
0642 
0643     /**
0644      * Deletes table rows based on a WHERE clause.
0645      *
0646      * @param  mixed        $table The table to update.
0647      * @param  mixed        $where DELETE WHERE clause(s).
0648      * @return int          The number of affected rows.
0649      */
0650     public function delete($table, $where = '')
0651     {
0652         $where = $this->_whereExpr($where);
0653 
0654         /**
0655          * Build the DELETE statement
0656          */
0657         $sql = "DELETE FROM "
0658              . $this->quoteIdentifier($table, true)
0659              . (($where) ? " WHERE $where" : '');
0660 
0661         /**
0662          * Execute the statement and return the number of affected rows
0663          */
0664         $stmt = $this->query($sql);
0665         $result = $stmt->rowCount();
0666         return $result;
0667     }
0668 
0669     /**
0670      * Convert an array, string, or Zend_Db_Expr object
0671      * into a string to put in a WHERE clause.
0672      *
0673      * @param mixed $where
0674      * @return string
0675      */
0676     protected function _whereExpr($where)
0677     {
0678         if (empty($where)) {
0679             return $where;
0680         }
0681         if (!is_array($where)) {
0682             $where = array($where);
0683         }
0684         foreach ($where as $cond => &$term) {
0685             // is $cond an int? (i.e. Not a condition)
0686             if (is_int($cond)) {
0687                 // $term is the full condition
0688                 if ($term instanceof Zend_Db_Expr) {
0689                     $term = $term->__toString();
0690                 }
0691             } else {
0692                 // $cond is the condition with placeholder,
0693                 // and $term is quoted into the condition
0694                 $term = $this->quoteInto($cond, $term);
0695             }
0696             $term = '(' . $term . ')';
0697         }
0698 
0699         $where = implode(' AND ', $where);
0700         return $where;
0701     }
0702 
0703     /**
0704      * Creates and returns a new Zend_Db_Select object for this adapter.
0705      *
0706      * @return Zend_Db_Select
0707      */
0708     public function select()
0709     {
0710         return new Zend_Db_Select($this);
0711     }
0712 
0713     /**
0714      * Get the fetch mode.
0715      *
0716      * @return int
0717      */
0718     public function getFetchMode()
0719     {
0720         return $this->_fetchMode;
0721     }
0722 
0723     /**
0724      * Fetches all SQL result rows as a sequential array.
0725      * Uses the current fetchMode for the adapter.
0726      *
0727      * @param string|Zend_Db_Select $sql  An SQL SELECT statement.
0728      * @param mixed                 $bind Data to bind into SELECT placeholders.
0729      * @param mixed                 $fetchMode Override current fetch mode.
0730      * @return array
0731      */
0732     public function fetchAll($sql, $bind = array(), $fetchMode = null)
0733     {
0734         if ($fetchMode === null) {
0735             $fetchMode = $this->_fetchMode;
0736         }
0737         $stmt = $this->query($sql, $bind);
0738         $result = $stmt->fetchAll($fetchMode);
0739         return $result;
0740     }
0741 
0742     /**
0743      * Fetches the first row of the SQL result.
0744      * Uses the current fetchMode for the adapter.
0745      *
0746      * @param string|Zend_Db_Select $sql An SQL SELECT statement.
0747      * @param mixed $bind Data to bind into SELECT placeholders.
0748      * @param mixed                 $fetchMode Override current fetch mode.
0749      * @return mixed Array, object, or scalar depending on fetch mode.
0750      */
0751     public function fetchRow($sql, $bind = array(), $fetchMode = null)
0752     {
0753         if ($fetchMode === null) {
0754             $fetchMode = $this->_fetchMode;
0755         }
0756         $stmt = $this->query($sql, $bind);
0757         $result = $stmt->fetch($fetchMode);
0758         return $result;
0759     }
0760 
0761     /**
0762      * Fetches all SQL result rows as an associative array.
0763      *
0764      * The first column is the key, the entire row array is the
0765      * value.  You should construct the query to be sure that
0766      * the first column contains unique values, or else
0767      * rows with duplicate values in the first column will
0768      * overwrite previous data.
0769      *
0770      * @param string|Zend_Db_Select $sql An SQL SELECT statement.
0771      * @param mixed $bind Data to bind into SELECT placeholders.
0772      * @return array
0773      */
0774     public function fetchAssoc($sql, $bind = array())
0775     {
0776         $stmt = $this->query($sql, $bind);
0777         $data = array();
0778         while ($row = $stmt->fetch(Zend_Db::FETCH_ASSOC)) {
0779             $tmp = array_values(array_slice($row, 0, 1));
0780             $data[$tmp[0]] = $row;
0781         }
0782         return $data;
0783     }
0784 
0785     /**
0786      * Fetches the first column of all SQL result rows as an array.
0787      *
0788      * @param string|Zend_Db_Select $sql An SQL SELECT statement.
0789      * @param mixed $bind Data to bind into SELECT placeholders.
0790      * @return array
0791      */
0792     public function fetchCol($sql, $bind = array())
0793     {
0794         $stmt = $this->query($sql, $bind);
0795         $result = $stmt->fetchAll(Zend_Db::FETCH_COLUMN, 0);
0796         return $result;
0797     }
0798 
0799     /**
0800      * Fetches all SQL result rows as an array of key-value pairs.
0801      *
0802      * The first column is the key, the second column is the
0803      * value.
0804      *
0805      * @param string|Zend_Db_Select $sql An SQL SELECT statement.
0806      * @param mixed $bind Data to bind into SELECT placeholders.
0807      * @return array
0808      */
0809     public function fetchPairs($sql, $bind = array())
0810     {
0811         $stmt = $this->query($sql, $bind);
0812         $data = array();
0813         while ($row = $stmt->fetch(Zend_Db::FETCH_NUM)) {
0814             $data[$row[0]] = $row[1];
0815         }
0816         return $data;
0817     }
0818 
0819     /**
0820      * Fetches the first column of the first row of the SQL result.
0821      *
0822      * @param string|Zend_Db_Select $sql An SQL SELECT statement.
0823      * @param mixed $bind Data to bind into SELECT placeholders.
0824      * @return string
0825      */
0826     public function fetchOne($sql, $bind = array())
0827     {
0828         $stmt = $this->query($sql, $bind);
0829         $result = $stmt->fetchColumn(0);
0830         return $result;
0831     }
0832 
0833     /**
0834      * Quote a raw string.
0835      *
0836      * @param string $value     Raw string
0837      * @return string           Quoted string
0838      */
0839     protected function _quote($value)
0840     {
0841         if (is_int($value)) {
0842             return $value;
0843         } elseif (is_float($value)) {
0844             return sprintf('%F', $value);
0845         }
0846         return "'" . addcslashes($value, "\000\n\r\\'\"\032") . "'";
0847     }
0848 
0849     /**
0850      * Safely quotes a value for an SQL statement.
0851      *
0852      * If an array is passed as the value, the array values are quoted
0853      * and then returned as a comma-separated string.
0854      *
0855      * @param mixed $value The value to quote.
0856      * @param mixed $type  OPTIONAL the SQL datatype name, or constant, or null.
0857      * @return mixed An SQL-safe quoted value (or string of separated values).
0858      */
0859     public function quote($value, $type = null)
0860     {
0861         $this->_connect();
0862 
0863         if ($value instanceof Zend_Db_Select) {
0864             return '(' . $value->assemble() . ')';
0865         }
0866 
0867         if ($value instanceof Zend_Db_Expr) {
0868             return $value->__toString();
0869         }
0870 
0871         if (is_array($value)) {
0872             foreach ($value as &$val) {
0873                 $val = $this->quote($val, $type);
0874             }
0875             return implode(', ', $value);
0876         }
0877 
0878         if ($type !== null && array_key_exists($type = strtoupper($type), $this->_numericDataTypes)) {
0879             $quotedValue = '0';
0880             switch ($this->_numericDataTypes[$type]) {
0881                 case Zend_Db::INT_TYPE: // 32-bit integer
0882                     $quotedValue = (string) intval($value);
0883                     break;
0884                 case Zend_Db::BIGINT_TYPE: // 64-bit integer
0885                     // ANSI SQL-style hex literals (e.g. x'[\dA-F]+')
0886                     // are not supported here, because these are string
0887                     // literals, not numeric literals.
0888                     if (preg_match('/^(
0889                           [+-]?                  # optional sign
0890                           (?:
0891                             0[Xx][\da-fA-F]+     # ODBC-style hexadecimal
0892                             |\d+                 # decimal or octal, or MySQL ZEROFILL decimal
0893                             (?:[eE][+-]?\d+)?    # optional exponent on decimals or octals
0894                           )
0895                         )/x',
0896                         (string) $value, $matches)) {
0897                         $quotedValue = $matches[1];
0898                     }
0899                     break;
0900                 case Zend_Db::FLOAT_TYPE: // float or decimal
0901                     $quotedValue = sprintf('%F', $value);
0902             }
0903             return $quotedValue;
0904         }
0905 
0906         return $this->_quote($value);
0907     }
0908 
0909     /**
0910      * Quotes a value and places into a piece of text at a placeholder.
0911      *
0912      * The placeholder is a question-mark; all placeholders will be replaced
0913      * with the quoted value.   For example:
0914      *
0915      * <code>
0916      * $text = "WHERE date < ?";
0917      * $date = "2005-01-02";
0918      * $safe = $sql->quoteInto($text, $date);
0919      * // $safe = "WHERE date < '2005-01-02'"
0920      * </code>
0921      *
0922      * @param string  $text  The text with a placeholder.
0923      * @param mixed   $value The value to quote.
0924      * @param string  $type  OPTIONAL SQL datatype
0925      * @param integer $count OPTIONAL count of placeholders to replace
0926      * @return string An SQL-safe quoted value placed into the original text.
0927      */
0928     public function quoteInto($text, $value, $type = null, $count = null)
0929     {
0930         if ($count === null) {
0931             return str_replace('?', $this->quote($value, $type), $text);
0932         } else {
0933             return implode($this->quote($value, $type), explode('?', $text, $count + 1));
0934         }
0935     }
0936 
0937     /**
0938      * Quotes an identifier.
0939      *
0940      * Accepts a string representing a qualified indentifier. For Example:
0941      * <code>
0942      * $adapter->quoteIdentifier('myschema.mytable')
0943      * </code>
0944      * Returns: "myschema"."mytable"
0945      *
0946      * Or, an array of one or more identifiers that may form a qualified identifier:
0947      * <code>
0948      * $adapter->quoteIdentifier(array('myschema','my.table'))
0949      * </code>
0950      * Returns: "myschema"."my.table"
0951      *
0952      * The actual quote character surrounding the identifiers may vary depending on
0953      * the adapter.
0954      *
0955      * @param string|array|Zend_Db_Expr $ident The identifier.
0956      * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option.
0957      * @return string The quoted identifier.
0958      */
0959     public function quoteIdentifier($ident, $auto=false)
0960     {
0961         return $this->_quoteIdentifierAs($ident, null, $auto);
0962     }
0963 
0964     /**
0965      * Quote a column identifier and alias.
0966      *
0967      * @param string|array|Zend_Db_Expr $ident The identifier or expression.
0968      * @param string $alias An alias for the column.
0969      * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option.
0970      * @return string The quoted identifier and alias.
0971      */
0972     public function quoteColumnAs($ident, $alias, $auto=false)
0973     {
0974         return $this->_quoteIdentifierAs($ident, $alias, $auto);
0975     }
0976 
0977     /**
0978      * Quote a table identifier and alias.
0979      *
0980      * @param string|array|Zend_Db_Expr $ident The identifier or expression.
0981      * @param string $alias An alias for the table.
0982      * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option.
0983      * @return string The quoted identifier and alias.
0984      */
0985     public function quoteTableAs($ident, $alias = null, $auto = false)
0986     {
0987         return $this->_quoteIdentifierAs($ident, $alias, $auto);
0988     }
0989 
0990     /**
0991      * Quote an identifier and an optional alias.
0992      *
0993      * @param string|array|Zend_Db_Expr $ident The identifier or expression.
0994      * @param string $alias An optional alias.
0995      * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option.
0996      * @param string $as The string to add between the identifier/expression and the alias.
0997      * @return string The quoted identifier and alias.
0998      */
0999     protected function _quoteIdentifierAs($ident, $alias = null, $auto = false, $as = ' AS ')
1000     {
1001         if ($ident instanceof Zend_Db_Expr) {
1002             $quoted = $ident->__toString();
1003         } elseif ($ident instanceof Zend_Db_Select) {
1004             $quoted = '(' . $ident->assemble() . ')';
1005         } else {
1006             if (is_string($ident)) {
1007                 $ident = explode('.', $ident);
1008             }
1009             if (is_array($ident)) {
1010                 $segments = array();
1011                 foreach ($ident as $segment) {
1012                     if ($segment instanceof Zend_Db_Expr) {
1013                         $segments[] = $segment->__toString();
1014                     } else {
1015                         $segments[] = $this->_quoteIdentifier($segment, $auto);
1016                     }
1017                 }
1018                 if ($alias !== null && end($ident) == $alias) {
1019                     $alias = null;
1020                 }
1021                 $quoted = implode('.', $segments);
1022             } else {
1023                 $quoted = $this->_quoteIdentifier($ident, $auto);
1024             }
1025         }
1026         if ($alias !== null) {
1027             $quoted .= $as . $this->_quoteIdentifier($alias, $auto);
1028         }
1029         return $quoted;
1030     }
1031 
1032     /**
1033      * Quote an identifier.
1034      *
1035      * @param  string $value The identifier or expression.
1036      * @param boolean $auto If true, heed the AUTO_QUOTE_IDENTIFIERS config option.
1037      * @return string        The quoted identifier and alias.
1038      */
1039     protected function _quoteIdentifier($value, $auto=false)
1040     {
1041         if ($auto === false || $this->_autoQuoteIdentifiers === true) {
1042             $q = $this->getQuoteIdentifierSymbol();
1043             return ($q . str_replace("$q", "$q$q", $value) . $q);
1044         }
1045         return $value;
1046     }
1047 
1048     /**
1049      * Returns the symbol the adapter uses for delimited identifiers.
1050      *
1051      * @return string
1052      */
1053     public function getQuoteIdentifierSymbol()
1054     {
1055         return '"';
1056     }
1057 
1058     /**
1059      * Return the most recent value from the specified sequence in the database.
1060      * This is supported only on RDBMS brands that support sequences
1061      * (e.g. Oracle, PostgreSQL, DB2).  Other RDBMS brands return null.
1062      *
1063      * @param string $sequenceName
1064      * @return string
1065      */
1066     public function lastSequenceId($sequenceName)
1067     {
1068         return null;
1069     }
1070 
1071     /**
1072      * Generate a new value from the specified sequence in the database, and return it.
1073      * This is supported only on RDBMS brands that support sequences
1074      * (e.g. Oracle, PostgreSQL, DB2).  Other RDBMS brands return null.
1075      *
1076      * @param string $sequenceName
1077      * @return string
1078      */
1079     public function nextSequenceId($sequenceName)
1080     {
1081         return null;
1082     }
1083 
1084     /**
1085      * Helper method to change the case of the strings used
1086      * when returning result sets in FETCH_ASSOC and FETCH_BOTH
1087      * modes.
1088      *
1089      * This is not intended to be used by application code,
1090      * but the method must be public so the Statement class
1091      * can invoke it.
1092      *
1093      * @param string $key
1094      * @return string
1095      */
1096     public function foldCase($key)
1097     {
1098         switch ($this->_caseFolding) {
1099             case Zend_Db::CASE_LOWER:
1100                 $value = strtolower((string) $key);
1101                 break;
1102             case Zend_Db::CASE_UPPER:
1103                 $value = strtoupper((string) $key);
1104                 break;
1105             case Zend_Db::CASE_NATURAL:
1106             default:
1107                 $value = (string) $key;
1108         }
1109         return $value;
1110     }
1111 
1112     /**
1113      * called when object is getting serialized
1114      * This disconnects the DB object that cant be serialized
1115      *
1116      * @throws Zend_Db_Adapter_Exception
1117      * @return array
1118      */
1119     public function __sleep()
1120     {
1121         if ($this->_allowSerialization == false) {
1122             /** @see Zend_Db_Adapter_Exception */
1123             // require_once 'Zend/Db/Adapter/Exception.php';
1124             throw new Zend_Db_Adapter_Exception(
1125                 get_class($this) . ' is not allowed to be serialized'
1126             );
1127         }
1128         $this->_connection = null;
1129 
1130         return array_keys(
1131             array_diff_key(get_object_vars($this), array('_connection' => null))
1132         );
1133     }
1134 
1135     /**
1136      * called when object is getting unserialized
1137      *
1138      * @return void
1139      */
1140     public function __wakeup()
1141     {
1142         if ($this->_autoReconnectOnUnserialize == true) {
1143             $this->getConnection();
1144         }
1145     }
1146 
1147     /**
1148      * Abstract Methods
1149      */
1150 
1151     /**
1152      * Returns a list of the tables in the database.
1153      *
1154      * @return array
1155      */
1156     abstract public function listTables();
1157 
1158     /**
1159      * Returns the column descriptions for a table.
1160      *
1161      * The return value is an associative array keyed by the column name,
1162      * as returned by the RDBMS.
1163      *
1164      * The value of each array element is an associative array
1165      * with the following keys:
1166      *
1167      * SCHEMA_NAME => string; name of database or schema
1168      * TABLE_NAME  => string;
1169      * COLUMN_NAME => string; column name
1170      * COLUMN_POSITION => number; ordinal position of column in table
1171      * DATA_TYPE   => string; SQL datatype name of column
1172      * DEFAULT     => string; default expression of column, null if none
1173      * NULLABLE    => boolean; true if column can have nulls
1174      * LENGTH      => number; length of CHAR/VARCHAR
1175      * SCALE       => number; scale of NUMERIC/DECIMAL
1176      * PRECISION   => number; precision of NUMERIC/DECIMAL
1177      * UNSIGNED    => boolean; unsigned property of an integer type
1178      * PRIMARY     => boolean; true if column is part of the primary key
1179      * PRIMARY_POSITION => integer; position of column in primary key
1180      *
1181      * @param string $tableName
1182      * @param string $schemaName OPTIONAL
1183      * @return array
1184      */
1185     abstract public function describeTable($tableName, $schemaName = null);
1186 
1187     /**
1188      * Creates a connection to the database.
1189      *
1190      * @return void
1191      */
1192     abstract protected function _connect();
1193 
1194     /**
1195      * Test if a connection is active
1196      *
1197      * @return boolean
1198      */
1199     abstract public function isConnected();
1200 
1201     /**
1202      * Force the connection to close.
1203      *
1204      * @return void
1205      */
1206     abstract public function closeConnection();
1207 
1208     /**
1209      * Prepare a statement and return a PDOStatement-like object.
1210      *
1211      * @param string|Zend_Db_Select $sql SQL query
1212      * @return Zend_Db_Statement|PDOStatement
1213      */
1214     abstract public function prepare($sql);
1215 
1216     /**
1217      * Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column.
1218      *
1219      * As a convention, on RDBMS brands that support sequences
1220      * (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence
1221      * from the arguments and returns the last id generated by that sequence.
1222      * On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method
1223      * returns the last value generated for such a column, and the table name
1224      * argument is disregarded.
1225      *
1226      * @param string $tableName   OPTIONAL Name of table.
1227      * @param string $primaryKey  OPTIONAL Name of primary key column.
1228      * @return string
1229      */
1230     abstract public function lastInsertId($tableName = null, $primaryKey = null);
1231 
1232     /**
1233      * Begin a transaction.
1234      */
1235     abstract protected function _beginTransaction();
1236 
1237     /**
1238      * Commit a transaction.
1239      */
1240     abstract protected function _commit();
1241 
1242     /**
1243      * Roll-back a transaction.
1244      */
1245     abstract protected function _rollBack();
1246 
1247     /**
1248      * Set the fetch mode.
1249      *
1250      * @param integer $mode
1251      * @return void
1252      * @throws Zend_Db_Adapter_Exception
1253      */
1254     abstract public function setFetchMode($mode);
1255 
1256     /**
1257      * Adds an adapter-specific LIMIT clause to the SELECT statement.
1258      *
1259      * @param mixed $sql
1260      * @param integer $count
1261      * @param integer $offset
1262      * @return string
1263      */
1264     abstract public function limit($sql, $count, $offset = 0);
1265 
1266     /**
1267      * Check if the adapter supports real SQL parameters.
1268      *
1269      * @param string $type 'positional' or 'named'
1270      * @return bool
1271      */
1272     abstract public function supportsParameters($type);
1273 
1274     /**
1275      * Retrieve server version in PHP style
1276      *
1277      * @return string
1278      */
1279     abstract public function getServerVersion();
1280 }