Version 1
[yaffs-website] / vendor / gabordemooij / redbean / RedBeanPHP / Driver / RPDO.php
diff --git a/vendor/gabordemooij/redbean/RedBeanPHP/Driver/RPDO.php b/vendor/gabordemooij/redbean/RedBeanPHP/Driver/RPDO.php
new file mode 100755 (executable)
index 0000000..1033986
--- /dev/null
@@ -0,0 +1,621 @@
+<?php
+
+namespace RedBeanPHP\Driver;
+
+use RedBeanPHP\Driver as Driver;
+use RedBeanPHP\Logger as Logger;
+use RedBeanPHP\QueryWriter\AQueryWriter as AQueryWriter;
+use RedBeanPHP\RedException as RedException;
+use RedBeanPHP\RedException\SQL as SQL;
+use RedBeanPHP\Logger\RDefault as RDefault;
+use RedBeanPHP\PDOCompatible as PDOCompatible;
+use RedBeanPHP\Cursor\PDOCursor as PDOCursor;
+
+/**
+ * PDO Driver
+ * This Driver implements the RedBean Driver API.
+ * for RedBeanPHP. This is the standard / default database driver
+ * for RedBeanPHP.
+ *
+ * @file    RedBeanPHP/PDO.php
+ * @author  Gabor de Mooij and the RedBeanPHP Community, Desfrenes
+ * @license BSD/GPLv2
+ *
+ * @copyright
+ * copyright (c) Desfrenes & Gabor de Mooij and the RedBeanPHP community
+ * This source file is subject to the BSD/GPLv2 License that is bundled
+ * with this source code in the file license.txt.
+ */
+class RPDO implements Driver
+{
+       /**
+        * @var integer
+        */
+       protected $max;
+
+       /**
+        * @var string
+        */
+       protected $dsn;
+
+       /**
+        * @var boolean
+        */
+       protected $loggingEnabled = FALSE;
+
+       /**
+        * @var Logger
+        */
+       protected $logger = NULL;
+
+       /**
+        * @var PDO
+        */
+       protected $pdo;
+
+       /**
+        * @var integer
+        */
+       protected $affectedRows;
+
+       /**
+        * @var integer
+        */
+       protected $resultArray;
+
+       /**
+        * @var array
+        */
+       protected $connectInfo = array();
+
+       /**
+        * @var boolean
+        */
+       protected $isConnected = FALSE;
+
+       /**
+        * @var bool
+        */
+       protected $flagUseStringOnlyBinding = FALSE;
+
+       /**
+        * @var integer
+        */
+       protected $queryCounter = 0;
+
+       /**
+        * @var string
+        */
+       protected $mysqlEncoding = '';
+
+       /**
+        * Binds parameters. This method binds parameters to a PDOStatement for
+        * Query Execution. This method binds parameters as NULL, INTEGER or STRING
+        * and supports both named keys and question mark keys.
+        *
+        * @param PDOStatement $statement PDO Statement instance
+        * @param array        $bindings  values that need to get bound to the statement
+        *
+        * @return void
+        */
+       protected function bindParams( $statement, $bindings )
+       {
+               foreach ( $bindings as $key => &$value ) {
+                       if ( is_integer( $key ) ) {
+                               if ( is_null( $value ) ) {
+                                       $statement->bindValue( $key + 1, NULL, \PDO::PARAM_NULL );
+                               } elseif ( !$this->flagUseStringOnlyBinding && AQueryWriter::canBeTreatedAsInt( $value ) && abs( $value ) <= $this->max ) {
+                                       $statement->bindParam( $key + 1, $value, \PDO::PARAM_INT );
+                               } else {
+                                       $statement->bindParam( $key + 1, $value, \PDO::PARAM_STR );
+                               }
+                       } else {
+                               if ( is_null( $value ) ) {
+                                       $statement->bindValue( $key, NULL, \PDO::PARAM_NULL );
+                               } elseif ( !$this->flagUseStringOnlyBinding && AQueryWriter::canBeTreatedAsInt( $value ) && abs( $value ) <= $this->max ) {
+                                       $statement->bindParam( $key, $value, \PDO::PARAM_INT );
+                               } else {
+                                       $statement->bindParam( $key, $value, \PDO::PARAM_STR );
+                               }
+                       }
+               }
+       }
+
+       /**
+        * This method runs the actual SQL query and binds a list of parameters to the query.
+        * slots. The result of the query will be stored in the protected property
+        * $rs (always array). The number of rows affected (result of rowcount, if supported by database)
+        * is stored in protected property $affectedRows. If the debug flag is set
+        * this function will send debugging output to screen buffer.
+        *
+        * @param string $sql      the SQL string to be send to database server
+        * @param array  $bindings the values that need to get bound to the query slots
+        * @param array  $options
+        *
+        * @return mixed
+        * @throws SQL
+        */
+       protected function runQuery( $sql, $bindings, $options = array() )
+       {
+               $this->connect();
+               if ( $this->loggingEnabled && $this->logger ) {
+                       $this->logger->log( $sql, $bindings );
+               }
+               try {
+                       if ( strpos( 'pgsql', $this->dsn ) === 0 ) {
+                               if ( defined( '\PDO::PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT' ) ) {
+                                       $statement = $this->pdo->prepare( $sql, array( \PDO::PGSQL_ATTR_DISABLE_NATIVE_PREPARED_STATEMENT => TRUE ) );
+                               } else {
+                                       $statement = $this->pdo->prepare( $sql );
+                               }
+                       } else {
+                               $statement = $this->pdo->prepare( $sql );
+                       }
+                       $this->bindParams( $statement, $bindings );
+                       $statement->execute();
+                       $this->queryCounter ++;
+                       $this->affectedRows = $statement->rowCount();
+                       if ( $statement->columnCount() ) {
+                               $fetchStyle = ( isset( $options['fetchStyle'] ) ) ? $options['fetchStyle'] : NULL;
+                               if ( isset( $options['noFetch'] ) && $options['noFetch'] ) {
+                                       $this->resultArray = array();
+                                       return $statement;
+                               }
+                               $this->resultArray = $statement->fetchAll( $fetchStyle );
+                               if ( $this->loggingEnabled && $this->logger ) {
+                                       $this->logger->log( 'resultset: ' . count( $this->resultArray ) . ' rows' );
+                               }
+                       } else {
+                               $this->resultArray = array();
+                       }
+               } catch ( \PDOException $e ) {
+                       //Unfortunately the code field is supposed to be int by default (php)
+                       //So we need a property to convey the SQL State code.
+                       $err = $e->getMessage();
+                       if ( $this->loggingEnabled && $this->logger ) $this->logger->log( 'An error occurred: ' . $err );
+                       $exception = new SQL( $err, 0 );
+                       $exception->setSQLState( $e->getCode() );
+                       throw $exception;
+               }
+       }
+
+       /**
+        * Try to fix MySQL character encoding problems.
+        * MySQL < 5.5 does not support proper 4 byte unicode but they
+        * seem to have added it with version 5.5 under a different label: utf8mb4.
+        * We try to select the best possible charset based on your version data.
+        *
+        * @return void
+        */
+       protected function setEncoding()
+       {
+               $driver = $this->pdo->getAttribute( \PDO::ATTR_DRIVER_NAME );
+               $version = floatval( $this->pdo->getAttribute( \PDO::ATTR_SERVER_VERSION ) );
+               if ($driver === 'mysql') {
+                       $encoding = ($version >= 5.5) ? 'utf8mb4' : 'utf8';
+                       $this->pdo->setAttribute(\PDO::MYSQL_ATTR_INIT_COMMAND, 'SET NAMES '.$encoding ); //on every re-connect
+                       $this->pdo->exec(' SET NAMES '. $encoding); //also for current connection
+                       $this->mysqlEncoding = $encoding;
+               }
+       }
+
+       /**
+        * Constructor. You may either specify dsn, user and password or
+        * just give an existing PDO connection.
+        *
+        * Examples:
+        *    $driver = new RPDO($dsn, $user, $password);
+        *    $driver = new RPDO($existingConnection);
+        *
+        * @param string|object $dsn  database connection string
+        * @param string        $user optional, usename to sign in
+        * @param string        $pass optional, password for connection login
+        *
+        * @return void
+        */
+       public function __construct( $dsn, $user = NULL, $pass = NULL )
+       {
+               if ( is_object( $dsn ) ) {
+                       $this->pdo = $dsn;
+                       $this->isConnected = TRUE;
+                       $this->setEncoding();
+                       $this->pdo->setAttribute( \PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION );
+                       $this->pdo->setAttribute( \PDO::ATTR_DEFAULT_FETCH_MODE,\PDO::FETCH_ASSOC );
+                       // make sure that the dsn at least contains the type
+                       $this->dsn = $this->getDatabaseType();
+               } else {
+                       $this->dsn = $dsn;
+                       $this->connectInfo = array( 'pass' => $pass, 'user' => $user );
+               }
+
+               //PHP 5.3 PDO SQLite has a bug with large numbers:
+               if ( ( strpos( $this->dsn, 'sqlite' ) === 0 && PHP_MAJOR_VERSION === 5 && PHP_MINOR_VERSION === 3 ) ||  defined('HHVM_VERSION') || $this->dsn === 'test-sqlite-53' ) {
+                       $this->max = 2147483647; //otherwise you get -2147483648 ?! demonstrated in build #603 on Travis.
+               } elseif ( strpos( $this->dsn, 'cubrid' ) === 0 ) {
+                       $this->max = 2147483647; //bindParam in pdo_cubrid also fails...
+               } else {
+                       $this->max = PHP_INT_MAX; //the normal value of course (makes it possible to use large numbers in LIMIT clause)
+               }
+       }
+
+       /**
+        * Returns the best possible encoding for MySQL based on version data.
+        *
+        * @return string
+        */
+       public function getMysqlEncoding()
+       {
+               return $this->mysqlEncoding;
+       }
+
+       /**
+        * Whether to bind all parameters as strings.
+        * If set to TRUE this will cause all integers to be bound as STRINGS.
+        * This will NOT affect NULL values.
+        *
+        * @param boolean $yesNo pass TRUE to bind all parameters as strings.
+        *
+        * @return void
+        */
+       public function setUseStringOnlyBinding( $yesNo )
+       {
+               $this->flagUseStringOnlyBinding = (boolean) $yesNo;
+       }
+
+       /**
+        * Sets the maximum value to be bound as integer, normally
+        * this value equals PHP's MAX INT constant, however sometimes
+        * PDO driver bindings cannot bind large integers as integers.
+        * This method allows you to manually set the max integer binding
+        * value to manage portability/compatibility issues among different
+        * PHP builds. This method will return the old value.
+        *
+        * @param integer $max maximum value for integer bindings
+        *
+        * @return integer
+        */
+       public function setMaxIntBind( $max )
+       {
+               if ( !is_integer( $max ) ) throw new RedException( 'Parameter has to be integer.' );
+               $oldMax = $this->max;
+               $this->max = $max;
+               return $oldMax;
+       }
+
+       /**
+        * Establishes a connection to the database using PHP\PDO
+        * functionality. If a connection has already been established this
+        * method will simply return directly. This method also turns on
+        * UTF8 for the database and PDO-ERRMODE-EXCEPTION as well as
+        * PDO-FETCH-ASSOC.
+        *
+        * @return void
+        */
+       public function connect()
+       {
+               if ( $this->isConnected ) return;
+               try {
+                       $user = $this->connectInfo['user'];
+                       $pass = $this->connectInfo['pass'];
+                       $this->pdo = new \PDO(
+                               $this->dsn,
+                               $user,
+                               $pass
+                       );
+                       $this->setEncoding();
+                       $this->pdo->setAttribute( \PDO::ATTR_STRINGIFY_FETCHES, TRUE );
+                       //cant pass these as argument to constructor, CUBRID driver does not understand...
+                       $this->pdo->setAttribute( \PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION );
+                       $this->pdo->setAttribute( \PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC );
+                       $this->isConnected = TRUE;
+               } catch ( \PDOException $exception ) {
+                       $matches = array();
+                       $dbname  = ( preg_match( '/dbname=(\w+)/', $this->dsn, $matches ) ) ? $matches[1] : '?';
+                       throw new \PDOException( 'Could not connect to database (' . $dbname . ').', $exception->getCode() );
+               }
+       }
+
+       /**
+        * Directly sets PDO instance into driver.
+        * This method might improve performance, however since the driver does
+        * not configure this instance terrible things may happen... only use
+        * this method if you are an expert on RedBeanPHP, PDO and UTF8 connections and
+        * you know your database server VERY WELL.
+        *
+        * @param PDO $pdo PDO instance
+        *
+        * @return void
+        */
+       public function setPDO( \PDO $pdo ) {
+               $this->pdo = $pdo;
+       }
+
+       /**
+        * @see Driver::GetAll
+        */
+       public function GetAll( $sql, $bindings = array() )
+       {
+               $this->runQuery( $sql, $bindings );
+               return $this->resultArray;
+       }
+
+       /**
+        * @see Driver::GetAssocRow
+        */
+       public function GetAssocRow( $sql, $bindings = array() )
+       {
+               $this->runQuery( $sql, $bindings, array(
+                               'fetchStyle' => \PDO::FETCH_ASSOC
+                       )
+               );
+               return $this->resultArray;
+       }
+
+       /**
+        * @see Driver::GetCol
+        */
+       public function GetCol( $sql, $bindings = array() )
+       {
+               $rows = $this->GetAll( $sql, $bindings );
+               $cols = array();
+               if ( $rows && is_array( $rows ) && count( $rows ) > 0 ) {
+                       foreach ( $rows as $row ) {
+                               $cols[] = array_shift( $row );
+                       }
+               }
+
+               return $cols;
+       }
+
+       /**
+        * @see Driver::GetOne
+        */
+       public function GetOne( $sql, $bindings = array() )
+       {
+               $arr = $this->GetAll( $sql, $bindings );
+               $res = NULL;
+               if ( !is_array( $arr ) ) return NULL;
+               if ( count( $arr ) === 0 ) return NULL;
+               $row1 = array_shift( $arr );
+               if ( !is_array( $row1 ) ) return NULL;
+               if ( count( $row1 ) === 0 ) return NULL;
+               $col1 = array_shift( $row1 );
+               return $col1;
+       }
+
+       /**
+        * Alias for getOne().
+        * Backward compatibility.
+        *
+        * @param string $sql      SQL
+        * @param array  $bindings bindings
+        *
+        * @return mixed
+        */
+       public function GetCell( $sql, $bindings = array() )
+       {
+               return $this->GetOne( $sql, $bindings );
+       }
+
+       /**
+        * @see Driver::GetRow
+        */
+       public function GetRow( $sql, $bindings = array() )
+       {
+               $arr = $this->GetAll( $sql, $bindings );
+               return array_shift( $arr );
+       }
+
+       /**
+        * @see Driver::Excecute
+        */
+       public function Execute( $sql, $bindings = array() )
+       {
+               $this->runQuery( $sql, $bindings );
+               return $this->affectedRows;
+       }
+
+       /**
+        * @see Driver::GetInsertID
+        */
+       public function GetInsertID()
+       {
+               $this->connect();
+
+               return (int) $this->pdo->lastInsertId();
+       }
+
+       /**
+        * @see Driver::GetCursor
+        */
+       public function GetCursor( $sql, $bindings = array() )
+       {
+               $statement = $this->runQuery( $sql, $bindings, array( 'noFetch' => TRUE ) );
+               $cursor = new PDOCursor( $statement, \PDO::FETCH_ASSOC );
+               return $cursor;
+       }
+
+       /**
+        * @see Driver::Affected_Rows
+        */
+       public function Affected_Rows()
+       {
+               $this->connect();
+               return (int) $this->affectedRows;
+       }
+
+       /**
+        * Toggles debug mode. In debug mode the driver will print all
+        * SQL to the screen together with some information about the
+        * results.
+        *
+        * @param boolean $trueFalse turn on/off
+        * @param Logger  $logger    logger instance
+        *
+        * @return void
+        */
+       public function setDebugMode( $tf, $logger = NULL )
+       {
+               $this->connect();
+               $this->loggingEnabled = (bool) $tf;
+               if ( $this->loggingEnabled and !$logger ) {
+                       $logger = new RDefault();
+               }
+               $this->setLogger( $logger );
+       }
+
+       /**
+        * Injects Logger object.
+        * Sets the logger instance you wish to use.
+        *
+        * @param Logger $logger the logger instance to be used for logging
+        *
+        * @return void
+        */
+       public function setLogger( Logger $logger )
+       {
+               $this->logger = $logger;
+       }
+
+       /**
+        * Gets Logger object.
+        * Returns the currently active Logger instance.
+        *
+        * @return Logger
+        */
+       public function getLogger()
+       {
+               return $this->logger;
+       }
+
+       /**
+        * @see Driver::StartTrans
+        */
+       public function StartTrans()
+       {
+               $this->connect();
+               $this->pdo->beginTransaction();
+       }
+
+       /**
+        * @see Driver::CommitTrans
+        */
+       public function CommitTrans()
+       {
+               $this->connect();
+               $this->pdo->commit();
+       }
+
+       /**
+        * @see Driver::FailTrans
+        */
+       public function FailTrans()
+       {
+               $this->connect();
+               $this->pdo->rollback();
+       }
+
+       /**
+        * Returns the name of database driver for PDO.
+        * Uses the PDO attribute DRIVER NAME to obtain the name of the
+        * PDO driver.
+        *
+        * @return string
+        */
+       public function getDatabaseType()
+       {
+               $this->connect();
+
+               return $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME );
+       }
+
+       /**
+        * Returns the version number of the database.
+        *
+        * @return mixed
+        */
+       public function getDatabaseVersion()
+       {
+               $this->connect();
+               return $this->pdo->getAttribute(\PDO::ATTR_CLIENT_VERSION );
+       }
+
+       /**
+        * Returns the underlying PHP PDO instance.
+        *
+        * @return PDO
+        */
+       public function getPDO()
+       {
+               $this->connect();
+               return $this->pdo;
+       }
+
+       /**
+        * Closes database connection by destructing PDO.
+        *
+        * @return void
+        */
+       public function close()
+       {
+               $this->pdo         = NULL;
+               $this->isConnected = FALSE;
+       }
+
+       /**
+        * Returns TRUE if the current PDO instance is connected.
+        *
+        * @return boolean
+        */
+       public function isConnected()
+       {
+               return $this->isConnected && $this->pdo;
+       }
+
+       /**
+        * Toggles logging, enables or disables logging.
+        *
+        * @param boolean $enable TRUE to enable logging
+        *
+        * @return self
+        */
+       public function setEnableLogging( $enable )
+       {
+               $this->loggingEnabled = (boolean) $enable;
+       }
+
+       /**
+        * Resets the internal Query Counter.
+        *
+        * @return self
+        */
+       public function resetCounter()
+       {
+               $this->queryCounter = 0;
+               return $this;
+       }
+
+       /**
+        * Returns the number of SQL queries processed.
+        *
+        * @return integer
+        */
+       public function getQueryCount()
+       {
+               return $this->queryCounter;
+       }
+
+       /**
+        * Returns the maximum value treated as integer parameter
+        * binding.
+        *
+        * This method is mainly for testing purposes but it can help
+        * you solve some issues relating to integer bindings.
+        *
+        * @return integer
+        */
+       public function getIntegerBindingMax()
+       {
+               return $this->max;
+       }
+}