Source for file pdo.php

Documentation is available at pdo.php

  1. <?php
  2. /**
  3.  * @package     Joomla.Platform
  4.  * @subpackage  Database
  5.  *
  6.  * @copyright   Copyright (C) 2005 - 2013 Open Source Matters, Inc. All rights reserved.
  7.  * @license     GNU General Public License version 2 or later; see LICENSE
  8.  */
  9.  
  10. defined('JPATH_PLATFORM'or die;
  11.  
  12. /**
  13.  * Joomla Platform PDO Database Driver Class
  14.  *
  15.  * @package     Joomla.Platform
  16.  * @subpackage  Database
  17.  * @see         http://php.net/pdo
  18.  * @since       12.1
  19.  */
  20. abstract class JDatabaseDriverPdo extends JDatabaseDriver
  21. {
  22.     /**
  23.      * The name of the database driver.
  24.      *
  25.      * @var    string 
  26.      * @since  12.1
  27.      */
  28.     public $name = 'pdo';
  29.  
  30.     /**
  31.      * The character(s) used to quote SQL statement names such as table names or field names,
  32.      * etc.  The child classes should define this as necessary.  If a single character string the
  33.      * same character is used for both sides of the quoted name, else the first character will be
  34.      * used for the opening quote and the second for the closing quote.
  35.      *
  36.      * @var    string 
  37.      * @since  12.1
  38.      */
  39.     protected $nameQuote = "'";
  40.  
  41.     /**
  42.      * The null or zero representation of a timestamp for the database driver.  This should be
  43.      * defined in child classes to hold the appropriate value for the engine.
  44.      *
  45.      * @var    string 
  46.      * @since  12.1
  47.      */
  48.     protected $nullDate = '0000-00-00 00:00:00';
  49.  
  50.     /**
  51.      * @var    resource  The prepared statement.
  52.      * @since  12.1
  53.      */
  54.     protected $prepared;
  55.  
  56.     /**
  57.      * Contains the current query execution status
  58.      *
  59.      * @var array 
  60.      * @since 12.1
  61.      */
  62.     protected $executed = false;
  63.  
  64.     /**
  65.      * Constructor.
  66.      *
  67.      * @param   array  $options  List of options used to configure the connection
  68.      *
  69.      * @since   12.1
  70.      */
  71.     public function __construct($options)
  72.     {
  73.         // Get some basic values from the options.
  74.         $options['driver'(isset($options['driver'])) $options['driver''odbc';
  75.         $options['dsn'(isset($options['dsn'])) $options['dsn''';
  76.         $options['host'(isset($options['host'])) $options['host''localhost';
  77.         $options['database'(isset($options['database'])) $options['database''';
  78.         $options['user'(isset($options['user'])) $options['user''';
  79.         $options['password'(isset($options['password'])) $options['password''';
  80.         $options['driverOptions'(isset($options['driverOptions'])) $options['driverOptions'array();
  81.  
  82.         // Finalize initialisation
  83.         parent::__construct($options);
  84.     }
  85.  
  86.     /**
  87.      * Destructor.
  88.      *
  89.      * @since   12.1
  90.      */
  91.     public function __destruct()
  92.     {
  93.         $this->disconnect();
  94.     }
  95.  
  96.     /**
  97.      * Connects to the database if needed.
  98.      *
  99.      * @return  void  Returns void if the database connected successfully.
  100.      *
  101.      * @since   12.1
  102.      * @throws  RuntimeException
  103.      */
  104.     public function connect()
  105.     {
  106.         if ($this->connection)
  107.         {
  108.             return;
  109.         }
  110.  
  111.         // Make sure the PDO extension for PHP is installed and enabled.
  112.         if (!self::isSupported())
  113.         {
  114.             throw new RuntimeException('PDO Extension is not available.'1);
  115.         }
  116.  
  117.         $replace array();
  118.         $with array();
  119.  
  120.         // Find the correct PDO DSN Format to use:
  121.         switch ($this->options['driver'])
  122.         {
  123.             case 'cubrid':
  124.                 $this->options['port'(isset($this->options['port'])) $this->options['port'33000;
  125.  
  126.                 $format 'cubrid:host=#HOST#;port=#PORT#;dbname=#DBNAME#';
  127.  
  128.                 $replace array('#HOST#''#PORT#''#DBNAME#');
  129.                 $with array($this->options['host']$this->options['port']$this->options['database']);
  130.  
  131.                 break;
  132.  
  133.             case 'dblib':
  134.                 $this->options['port'(isset($this->options['port'])) $this->options['port'1433;
  135.  
  136.                 $format 'dblib:host=#HOST#;port=#PORT#;dbname=#DBNAME#';
  137.  
  138.                 $replace array('#HOST#''#PORT#''#DBNAME#');
  139.                 $with array($this->options['host']$this->options['port']$this->options['database']);
  140.  
  141.                 break;
  142.  
  143.             case 'firebird':
  144.                 $this->options['port'(isset($this->options['port'])) $this->options['port'3050;
  145.  
  146.                 $format 'firebird:dbname=#DBNAME#';
  147.  
  148.                 $replace array('#DBNAME#');
  149.                 $with array($this->options['database']);
  150.  
  151.                 break;
  152.  
  153.             case 'ibm':
  154.                 $this->options['port'(isset($this->options['port'])) $this->options['port'56789;
  155.  
  156.                 if (!empty($this->options['dsn']))
  157.                 {
  158.                     $format 'ibm:DSN=#DSN#';
  159.  
  160.                     $replace array('#DSN#');
  161.                     $with array($this->options['dsn']);
  162.                 }
  163.                 else
  164.                 {
  165.                     $format 'ibm:hostname=#HOST#;port=#PORT#;database=#DBNAME#';
  166.  
  167.                     $replace array('#HOST#''#PORT#''#DBNAME#');
  168.                     $with array($this->options['host']$this->options['port']$this->options['database']);
  169.                 }
  170.  
  171.                 break;
  172.  
  173.             case 'informix':
  174.                 $this->options['port'(isset($this->options['port'])) $this->options['port'1526;
  175.                 $this->options['protocol'(isset($this->options['protocol'])) $this->options['protocol''onsoctcp';
  176.  
  177.                 if (!empty($this->options['dsn']))
  178.                 {
  179.                     $format 'informix:DSN=#DSN#';
  180.  
  181.                     $replace array('#DSN#');
  182.                     $with array($this->options['dsn']);
  183.                 }
  184.                 else
  185.                 {
  186.                     $format 'informix:host=#HOST#;service=#PORT#;database=#DBNAME#;server=#SERVER#;protocol=#PROTOCOL#';
  187.  
  188.                     $replace array('#HOST#''#PORT#''#DBNAME#''#SERVER#''#PROTOCOL#');
  189.                     $with array($this->options['host']$this->options['port']$this->options['database']$this->options['server']$this->options['protocol']);
  190.                 }
  191.  
  192.                 break;
  193.  
  194.             case 'mssql':
  195.                 $this->options['port'(isset($this->options['port'])) $this->options['port'1433;
  196.  
  197.                 $format 'mssql:host=#HOST#;port=#PORT#;dbname=#DBNAME#';
  198.  
  199.                 $replace array('#HOST#''#PORT#''#DBNAME#');
  200.                 $with array($this->options['host']$this->options['port']$this->options['database']);
  201.  
  202.                 break;
  203.  
  204.             case 'mysql':
  205.                 $this->options['port'(isset($this->options['port'])) $this->options['port'3306;
  206.  
  207.                 $format 'mysql:host=#HOST#;port=#PORT#;dbname=#DBNAME#';
  208.  
  209.                 $replace array('#HOST#''#PORT#''#DBNAME#');
  210.                 $with array($this->options['host']$this->options['port']$this->options['database']);
  211.  
  212.                 break;
  213.  
  214.             case 'oci':
  215.                 $this->options['port'(isset($this->options['port'])) $this->options['port'1521;
  216.                 $this->options['charset'(isset($this->options['charset'])) $this->options['charset''AL32UTF8';
  217.  
  218.                 if (!empty($this->options['dsn']))
  219.                 {
  220.                     $format 'oci:dbname=#DSN#';
  221.  
  222.                     $replace array('#DSN#');
  223.                     $with array($this->options['dsn']);
  224.                 }
  225.                 else
  226.                 {
  227.                     $format 'oci:dbname=//#HOST#:#PORT#/#DBNAME#';
  228.  
  229.                     $replace array('#HOST#''#PORT#''#DBNAME#');
  230.                     $with array($this->options['host']$this->options['port']$this->options['database']);
  231.                 }
  232.  
  233.                 $format .= ';charset=' $this->options['charset'];
  234.  
  235.                 break;
  236.  
  237.             case 'odbc':
  238.                 $format 'odbc:DSN=#DSN#;UID:#USER#;PWD=#PASSWORD#';
  239.  
  240.                 $replace array('#DSN#''#USER#''#PASSWORD#');
  241.                 $with array($this->options['dsn']$this->options['user']$this->options['password']);
  242.  
  243.                 break;
  244.  
  245.             case 'pgsql':
  246.                 $this->options['port'(isset($this->options['port'])) $this->options['port'5432;
  247.  
  248.                 $format 'pgsql:host=#HOST#;port=#PORT#;dbname=#DBNAME#';
  249.  
  250.                 $replace array('#HOST#''#PORT#''#DBNAME#');
  251.                 $with array($this->options['host']$this->options['port']$this->options['database']);
  252.  
  253.                 break;
  254.  
  255.             case 'sqlite':
  256.  
  257.                 if (isset($this->options['version']&& $this->options['version'== 2)
  258.                 {
  259.                     $format 'sqlite2:#DBNAME#';
  260.                 }
  261.                 else
  262.                 {
  263.                     $format 'sqlite:#DBNAME#';
  264.                 }
  265.  
  266.                 $replace array('#DBNAME#');
  267.                 $with array($this->options['database']);
  268.  
  269.                 break;
  270.  
  271.             case 'sybase':
  272.                 $this->options['port'(isset($this->options['port'])) $this->options['port'1433;
  273.  
  274.                 $format 'mssql:host=#HOST#;port=#PORT#;dbname=#DBNAME#';
  275.  
  276.                 $replace array('#HOST#''#PORT#''#DBNAME#');
  277.                 $with array($this->options['host']$this->options['port']$this->options['database']);
  278.  
  279.                 break;
  280.         }
  281.  
  282.         // Create the connection string:
  283.         $connectionString str_replace($replace$with$format);
  284.  
  285.         try
  286.         {
  287.             $this->connection = new PDO(
  288.                 $connectionString,
  289.                 $this->options['user'],
  290.                 $this->options['password'],
  291.                 $this->options['driverOptions']
  292.             );
  293.         }
  294.         catch (PDOException $e)
  295.         {
  296.             throw new RuntimeException('Could not connect to PDO: ' $e->getMessage()2$e);
  297.         }
  298.     }
  299.  
  300.     /**
  301.      * Disconnects the database.
  302.      *
  303.      * @return  void 
  304.      *
  305.      * @since   12.1
  306.      */
  307.     public function disconnect()
  308.     {
  309.         foreach ($this->disconnectHandlers as $h)
  310.         {
  311.             call_user_func_array($harray&$this));
  312.         }
  313.  
  314.         $this->freeResult();
  315.         unset($this->connection);
  316.     }
  317.  
  318.     /**
  319.      * Method to escape a string for usage in an SQL statement.
  320.      *
  321.      * Oracle escaping reference:
  322.      * http://www.orafaq.com/wiki/SQL_FAQ#How_does_one_escape_special_characters_when_writing_SQL_queries.3F
  323.      *
  324.      * SQLite escaping notes:
  325.      * http://www.sqlite.org/faq.html#q14
  326.      *
  327.      * Method body is as implemented by the Zend Framework
  328.      *
  329.      * Note: Using query objects with bound variables is
  330.      * preferable to the below.
  331.      *
  332.      * @param   string   $text   The string to be escaped.
  333.      * @param   boolean  $extra  Unused optional parameter to provide extra escaping.
  334.      *
  335.      * @return  string  The escaped string.
  336.      *
  337.      * @since   12.1
  338.      */
  339.     public function escape($text$extra false)
  340.     {
  341.         if (is_int($text|| is_float($text))
  342.         {
  343.             return $text;
  344.         }
  345.  
  346.         $text str_replace("'""''"$text);
  347.  
  348.         return addcslashes($text"\000\n\r\\\032");
  349.     }
  350.  
  351.     /**
  352.      * Execute the SQL statement.
  353.      *
  354.      * @return  mixed  A database cursor resource on success, boolean false on failure.
  355.      *
  356.      * @since   12.1
  357.      * @throws  RuntimeException
  358.      * @throws  Exception
  359.      */
  360.     public function execute()
  361.     {
  362.         $this->connect();
  363.  
  364.         if (!is_object($this->connection))
  365.         {
  366.             JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED'$this->errorNum$this->errorMsg)JLog::ERROR'database');
  367.             throw new RuntimeException($this->errorMsg$this->errorNum);
  368.         }
  369.  
  370.         // Take a local copy so that we don't modify the original query and cause issues later
  371.         $query $this->replacePrefix((string) $this->sql);
  372.  
  373.         if (!($this->sql instanceof JDatabaseQuery&& ($this->limit > || $this->offset > 0))
  374.         {
  375.             // @TODO
  376.             $query .= ' LIMIT ' $this->offset . ', ' $this->limit;
  377.         }
  378.  
  379.         // Increment the query counter.
  380.         $this->count++;
  381.  
  382.         // Reset the error values.
  383.         $this->errorNum = 0;
  384.         $this->errorMsg = '';
  385.  
  386.         // If debugging is enabled then let's log the query.
  387.         if ($this->debug)
  388.         {
  389.             // Add the query to the object queue.
  390.             $this->log[$query;
  391.  
  392.             JLog::add($queryJLog::DEBUG'databasequery');
  393.  
  394.             $this->timings[microtime(true);
  395.         }
  396.  
  397.         // Execute the query.
  398.         $this->executed = false;
  399.         if ($this->prepared instanceof PDOStatement)
  400.         {
  401.             // Bind the variables:
  402.             if ($this->sql instanceof JDatabaseQueryPreparable)
  403.             {
  404.                 $bounded =$this->sql->getBounded();
  405.                 foreach ($bounded as $key => $obj)
  406.                 {
  407.                     $this->prepared->bindParam($key$obj->value$obj->dataType$obj->length$obj->driverOptions);
  408.                 }
  409.             }
  410.  
  411.             $this->executed = $this->prepared->execute();
  412.         }
  413.  
  414.         if ($this->debug)
  415.         {
  416.             $this->timings[microtime(true);
  417.             if (defined('DEBUG_BACKTRACE_IGNORE_ARGS'))
  418.             {
  419.                 $this->callStacks[debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
  420.             }
  421.             else
  422.             {
  423.                 $this->callStacks[debug_backtrace();
  424.             }
  425.         }
  426.  
  427.         // If an error occurred handle it.
  428.         if (!$this->executed)
  429.         {
  430.             // Get the error number and message before we execute any more queries.
  431.             $errorNum = (int) $this->connection->errorCode();
  432.             $errorMsg = (string) 'SQL: ' implode(", "$this->connection->errorInfo());
  433.  
  434.             // Check if the server was disconnected.
  435.             if (!$this->connected())
  436.             {
  437.                 try
  438.                 {
  439.                     // Attempt to reconnect.
  440.                     $this->connection = null;
  441.                     $this->connect();
  442.                 }
  443.                 // If connect fails, ignore that exception and throw the normal exception.
  444.                 catch (RuntimeException $e)
  445.                 {
  446.                     // Get the error number and message.
  447.                     $this->errorNum = (int) $this->connection->errorCode();
  448.                     $this->errorMsg = (string) 'SQL: ' implode(", "$this->connection->errorInfo());
  449.  
  450.                     // Throw the normal query exception.
  451.                     JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED'$this->errorNum$this->errorMsg)JLog::ERROR'databasequery');
  452.                     throw new RuntimeException($this->errorMsg$this->errorNum);
  453.                 }
  454.  
  455.                 // Since we were able to reconnect, run the query again.
  456.                 return $this->execute();
  457.             }
  458.             // The server was not disconnected.
  459.             else
  460.             {
  461.                 // Get the error number and message from before we tried to reconnect.
  462.                 $this->errorNum = $errorNum;
  463.                 $this->errorMsg = $errorMsg;
  464.  
  465.                 // Throw the normal query exception.
  466.                 JLog::add(JText::sprintf('JLIB_DATABASE_QUERY_FAILED'$this->errorNum$this->errorMsg)JLog::ERROR'databasequery');
  467.                 throw new RuntimeException($this->errorMsg$this->errorNum);
  468.             }
  469.         }
  470.  
  471.         return $this->prepared;
  472.     }
  473.  
  474.     /**
  475.      * Retrieve a PDO database connection attribute
  476.      * http://www.php.net/manual/en/pdo.getattribute.php
  477.      *
  478.      * Usage: $db->getOption(PDO::ATTR_CASE);
  479.      *
  480.      * @param   mixed  $key  One of the PDO::ATTR_* Constants
  481.      *
  482.      * @return mixed 
  483.      *
  484.      * @since  12.1
  485.      */
  486.     public function getOption($key)
  487.     {
  488.         $this->connect();
  489.  
  490.         return $this->connection->getAttribute($key);
  491.     }
  492.  
  493.     /**
  494.      * Get a query to run and verify the database is operational.
  495.      *
  496.      * @return  string  The query to check the health of the DB.
  497.      *
  498.      * @since   12.2
  499.      */
  500.     public function getConnectedQuery()
  501.     {
  502.         return 'SELECT 1';
  503.     }
  504.  
  505.     /**
  506.      * Sets an attribute on the PDO database handle.
  507.      * http://www.php.net/manual/en/pdo.setattribute.php
  508.      *
  509.      * Usage: $db->setOption(PDO::ATTR_CASE, PDO::CASE_UPPER);
  510.      *
  511.      * @param   integer  $key    One of the PDO::ATTR_* Constants
  512.      * @param   mixed    $value  One of the associated PDO Constants
  513.      *                            related to the particular attribute
  514.      *                            key.
  515.      *
  516.      * @return boolean 
  517.      *
  518.      * @since  12.1
  519.      */
  520.     public function setOption($key$value)
  521.     {
  522.         $this->connect();
  523.  
  524.         return $this->connection->setAttribute($key$value);
  525.     }
  526.  
  527.     /**
  528.      * Test to see if the PDO extension is available.
  529.      * Override as needed to check for specific PDO Drivers.
  530.      *
  531.      * @return  boolean  True on success, false otherwise.
  532.      *
  533.      * @since   12.1
  534.      */
  535.     public static function isSupported()
  536.     {
  537.         return defined('PDO::ATTR_DRIVER_NAME');
  538.     }
  539.  
  540.     /**
  541.      * Determines if the connection to the server is active.
  542.      *
  543.      * @return  boolean  True if connected to the database engine.
  544.      *
  545.      * @since   12.1
  546.      */
  547.     public function connected()
  548.     {
  549.         // Flag to prevent recursion into this function.
  550.         static $checkingConnected false;
  551.  
  552.         if ($checkingConnected)
  553.         {
  554.             // Reset this flag and throw an exception.
  555.             $checkingConnected true;
  556.             die('Recursion trying to check if connected.');
  557.         }
  558.  
  559.         // Backup the query state.
  560.         $query $this->sql;
  561.         $limit $this->limit;
  562.         $offset $this->offset;
  563.         $prepared $this->prepared;
  564.  
  565.         try
  566.         {
  567.             // Set the checking connection flag.
  568.             $checkingConnected true;
  569.  
  570.             // Run a simple query to check the connection.
  571.             $this->setQuery($this->getConnectedQuery());
  572.             $status = (bool) $this->loadResult();
  573.         }
  574.         // If we catch an exception here, we must not be connected.
  575.         catch (Exception $e)
  576.         {
  577.             $status false;
  578.         }
  579.  
  580.         // Restore the query state.
  581.         $this->sql $query;
  582.         $this->limit $limit;
  583.         $this->offset $offset;
  584.         $this->prepared $prepared;
  585.         $checkingConnected false;
  586.  
  587.         return $status;
  588.     }
  589.  
  590.     /**
  591.      * Get the number of affected rows for the previous executed SQL statement.
  592.      * Only applicable for DELETE, INSERT, or UPDATE statements.
  593.      *
  594.      * @return  integer  The number of affected rows.
  595.      *
  596.      * @since   12.1
  597.      */
  598.     public function getAffectedRows()
  599.     {
  600.         $this->connect();
  601.  
  602.         if ($this->prepared instanceof PDOStatement)
  603.         {
  604.             return $this->prepared->rowCount();
  605.         }
  606.         else
  607.         {
  608.             return 0;
  609.         }
  610.     }
  611.  
  612.     /**
  613.      * Get the number of returned rows for the previous executed SQL statement.
  614.      *
  615.      * @param   resource  $cursor  An optional database cursor resource to extract the row count from.
  616.      *
  617.      * @return  integer   The number of returned rows.
  618.      *
  619.      * @since   12.1
  620.      */
  621.     public function getNumRows($cursor null)
  622.     {
  623.         $this->connect();
  624.  
  625.         if ($cursor instanceof PDOStatement)
  626.         {
  627.             return $cursor->rowCount();
  628.         }
  629.         elseif ($this->prepared instanceof PDOStatement)
  630.         {
  631.             return $this->prepared->rowCount();
  632.         }
  633.         else
  634.         {
  635.             return 0;
  636.         }
  637.     }
  638.  
  639.     /**
  640.      * Method to get the auto-incremented value from the last INSERT statement.
  641.      *
  642.      * @return  string  The value of the auto-increment field from the last inserted row.
  643.      *
  644.      * @since   12.1
  645.      */
  646.     public function insertid()
  647.     {
  648.         $this->connect();
  649.  
  650.         // Error suppress this to prevent PDO warning us that the driver doesn't support this operation.
  651.         return @$this->connection->lastInsertId();
  652.     }
  653.  
  654.     /**
  655.      * Select a database for use.
  656.      *
  657.      * @param   string  $database  The name of the database to select for use.
  658.      *
  659.      * @return  boolean  True if the database was successfully selected.
  660.      *
  661.      * @since   12.1
  662.      * @throws  RuntimeException
  663.      */
  664.     public function select($database)
  665.     {
  666.         $this->connect();
  667.  
  668.         return true;
  669.     }
  670.  
  671.     /**
  672.      * Sets the SQL statement string for later execution.
  673.      *
  674.      * @param   mixed    $query          The SQL statement to set either as a JDatabaseQuery object or a string.
  675.      * @param   integer  $offset         The affected row offset to set.
  676.      * @param   integer  $limit          The maximum affected rows to set.
  677.      * @param   array    $driverOptions  The optional PDO driver options
  678.      *
  679.      * @return  JDatabaseDriver  This object to support method chaining.
  680.      *
  681.      * @since   12.1
  682.      */
  683.     public function setQuery($query$offset null$limit null$driverOptions array())
  684.     {
  685.         $this->connect();
  686.  
  687.         $this->freeResult();
  688.  
  689.         if (is_string($query))
  690.         {
  691.             // Allows taking advantage of bound variables in a direct query:
  692.             $query $this->getQuery(true)->setQuery($query);
  693.         }
  694.  
  695.         if ($query instanceof JDatabaseQueryLimitable && !is_null($offset&& !is_null($limit))
  696.         {
  697.             $query->setLimit($limit$offset);
  698.         }
  699.  
  700.         $query $this->replacePrefix((string) $query);
  701.  
  702.         $this->prepared $this->connection->prepare($query$driverOptions);
  703.  
  704.         // Store reference to the JDatabaseQuery instance:
  705.         parent::setQuery($query$offset$limit);
  706.  
  707.         return $this;
  708.     }
  709.  
  710.     /**
  711.      * Set the connection to use UTF-8 character encoding.
  712.      *
  713.      * @return  boolean  True on success.
  714.      *
  715.      * @since   12.1
  716.      */
  717.     public function setUTF()
  718.     {
  719.         return false;
  720.     }
  721.  
  722.     /**
  723.      * Method to commit a transaction.
  724.      *
  725.      * @param   boolean  $toSavepoint  If true, commit to the last savepoint.
  726.      *
  727.      * @return  void 
  728.      *
  729.      * @since   12.1
  730.      * @throws  RuntimeException
  731.      */
  732.     public function transactionCommit($toSavepoint false)
  733.     {
  734.         $this->connect();
  735.  
  736.         if (!$toSavepoint || $this->transactionDepth == 1)
  737.         {
  738.             $this->connection->commit();
  739.         }
  740.  
  741.         $this->transactionDepth--;
  742.     }
  743.  
  744.     /**
  745.      * Method to roll back a transaction.
  746.      *
  747.      * @param   boolean  $toSavepoint  If true, rollback to the last savepoint.
  748.      *
  749.      * @return  void 
  750.      *
  751.      * @since   12.1
  752.      * @throws  RuntimeException
  753.      */
  754.     public function transactionRollback($toSavepoint false)
  755.     {
  756.         $this->connect();
  757.  
  758.         if (!$toSavepoint || $this->transactionDepth == 1)
  759.         {
  760.             $this->connection->rollBack();
  761.         }
  762.  
  763.         $this->transactionDepth--;
  764.     }
  765.  
  766.     /**
  767.      * Method to initialize a transaction.
  768.      *
  769.      * @param   boolean  $asSavepoint  If true and a transaction is already active, a savepoint will be created.
  770.      *
  771.      * @return  void 
  772.      *
  773.      * @since   12.1
  774.      * @throws  RuntimeException
  775.      */
  776.     public function transactionStart($asSavepoint false)
  777.     {
  778.         $this->connect();
  779.  
  780.         if (!$asSavepoint || !$this->transactionDepth)
  781.         {
  782.             $this->connection->beginTransaction();
  783.         }
  784.  
  785.         $this->transactionDepth++;
  786.     }
  787.  
  788.     /**
  789.      * Method to fetch a row from the result set cursor as an array.
  790.      *
  791.      * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
  792.      *
  793.      * @return  mixed  Either the next row from the result set or false if there are no more rows.
  794.      *
  795.      * @since   12.1
  796.      */
  797.     protected function fetchArray($cursor null)
  798.     {
  799.         if (!empty($cursor&& $cursor instanceof PDOStatement)
  800.         {
  801.             return $cursor->fetch(PDO::FETCH_NUM);
  802.         }
  803.         if ($this->prepared instanceof PDOStatement)
  804.         {
  805.             return $this->prepared->fetch(PDO::FETCH_NUM);
  806.         }
  807.     }
  808.  
  809.     /**
  810.      * Method to fetch a row from the result set cursor as an associative array.
  811.      *
  812.      * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
  813.      *
  814.      * @return  mixed  Either the next row from the result set or false if there are no more rows.
  815.      *
  816.      * @since   12.1
  817.      */
  818.     protected function fetchAssoc($cursor null)
  819.     {
  820.         if (!empty($cursor&& $cursor instanceof PDOStatement)
  821.         {
  822.             return $cursor->fetch(PDO::FETCH_ASSOC);
  823.         }
  824.         if ($this->prepared instanceof PDOStatement)
  825.         {
  826.             return $this->prepared->fetch(PDO::FETCH_ASSOC);
  827.         }
  828.     }
  829.  
  830.     /**
  831.      * Method to fetch a row from the result set cursor as an object.
  832.      *
  833.      * @param   mixed   $cursor  The optional result set cursor from which to fetch the row.
  834.      * @param   string  $class   Unused, only necessary so method signature will be the same as parent.
  835.      *
  836.      * @return  mixed   Either the next row from the result set or false if there are no more rows.
  837.      *
  838.      * @since   12.1
  839.      */
  840.     protected function fetchObject($cursor null$class 'stdClass')
  841.     {
  842.         if (!empty($cursor&& $cursor instanceof PDOStatement)
  843.         {
  844.             return $cursor->fetchObject($class);
  845.         }
  846.         if ($this->prepared instanceof PDOStatement)
  847.         {
  848.             return $this->prepared->fetchObject($class);
  849.         }
  850.     }
  851.  
  852.     /**
  853.      * Method to free up the memory used for the result set.
  854.      *
  855.      * @param   mixed  $cursor  The optional result set cursor from which to fetch the row.
  856.      *
  857.      * @return  void 
  858.      *
  859.      * @since   12.1
  860.      */
  861.     protected function freeResult($cursor null)
  862.     {
  863.         $this->executed false;
  864.  
  865.         if ($cursor instanceof PDOStatement)
  866.         {
  867.             $cursor->closeCursor();
  868.             $cursor null;
  869.         }
  870.         if ($this->prepared instanceof PDOStatement)
  871.         {
  872.             $this->prepared->closeCursor();
  873.             $this->prepared null;
  874.         }
  875.     }
  876.  
  877.     /**
  878.      * Method to get the next row in the result set from the database query as an object.
  879.      *
  880.      * @param   string  $class  The class name to use for the returned row object.
  881.      *
  882.      * @return  mixed   The result of the query as an array, false if there are no more rows.
  883.      *
  884.      * @since   12.1
  885.      * @throws  RuntimeException
  886.      */
  887.     public function loadNextObject($class 'stdClass')
  888.     {
  889.         $this->connect();
  890.  
  891.         // Execute the query and get the result set cursor.
  892.         if (!$this->executed)
  893.         {
  894.             if (!($this->execute()))
  895.             {
  896.                 return $this->errorNum null false;
  897.             }
  898.         }
  899.  
  900.         // Get the next row from the result set as an object of type $class.
  901.         if ($row $this->fetchObject(null$class))
  902.         {
  903.             return $row;
  904.         }
  905.  
  906.         // Free up system resources and return.
  907.         $this->freeResult();
  908.  
  909.         return false;
  910.     }
  911.  
  912.     /**
  913.      * Method to get the next row in the result set from the database query as an array.
  914.      *
  915.      * @return  mixed  The result of the query as an array, false if there are no more rows.
  916.      *
  917.      * @since   12.1
  918.      * @throws  RuntimeException
  919.      */
  920.     public function loadNextAssoc()
  921.     {
  922.         $this->connect();
  923.  
  924.         // Execute the query and get the result set cursor.
  925.         if (!$this->executed)
  926.         {
  927.             if (!($this->execute()))
  928.             {
  929.                 return $this->errorNum null false;
  930.             }
  931.         }
  932.  
  933.         // Get the next row from the result set as an object of type $class.
  934.         if ($row $this->fetchAssoc())
  935.         {
  936.             return $row;
  937.         }
  938.  
  939.         // Free up system resources and return.
  940.         $this->freeResult();
  941.  
  942.         return false;
  943.     }
  944.  
  945.     /**
  946.      * Method to get the next row in the result set from the database query as an array.
  947.      *
  948.      * @return  mixed  The result of the query as an array, false if there are no more rows.
  949.      *
  950.      * @since   12.1
  951.      * @throws  RuntimeException
  952.      */
  953.     public function loadNextRow()
  954.     {
  955.         $this->connect();
  956.  
  957.         // Execute the query and get the result set cursor.
  958.         if (!$this->executed)
  959.         {
  960.             if (!($this->execute()))
  961.             {
  962.                 return $this->errorNum null false;
  963.             }
  964.         }
  965.  
  966.         // Get the next row from the result set as an object of type $class.
  967.         if ($row $this->fetchArray())
  968.         {
  969.             return $row;
  970.         }
  971.  
  972.         // Free up system resources and return.
  973.         $this->freeResult();
  974.  
  975.         return false;
  976.     }
  977.  
  978.     /**
  979.      * PDO does not support serialize
  980.      *
  981.      * @return  array 
  982.      *
  983.      * @since   12.3
  984.      */
  985.     public function __sleep()
  986.     {
  987.         $serializedProperties array();
  988.  
  989.         $reflect new ReflectionClass($this);
  990.  
  991.         // Get properties of the current class
  992.         $properties $reflect->getProperties();
  993.  
  994.         foreach ($properties as $property)
  995.         {
  996.             // Do not serialize properties that are PDO
  997.             if ($property->isStatic(== false && !($this->{$property->nameinstanceof PDO))
  998.             {
  999.                 array_push($serializedProperties$property->name);
  1000.             }
  1001.         }
  1002.  
  1003.         return $serializedProperties;
  1004.     }
  1005.  
  1006.     /**
  1007.      * Wake up after serialization
  1008.      *
  1009.      * @return  array 
  1010.      *
  1011.      * @since   12.3
  1012.      */
  1013.     public function __wakeup()
  1014.     {
  1015.         // Get connection back
  1016.         $this->__construct($this->options);
  1017.     }
  1018. }

Documentation generated on Tue, 19 Nov 2013 15:10:26 +0100 by phpDocumentor 1.4.3