diff options
| author | xue <> | 2006-11-24 04:21:06 +0000 | 
|---|---|---|
| committer | xue <> | 2006-11-24 04:21:06 +0000 | 
| commit | 9478fba18018c1f072f5f6dd4335c5828f23bc80 (patch) | |
| tree | f3718d9fd6af53c8aebc591b047a1b257804fa17 | |
| parent | 750f6c453bb21d6cef0eed50ed742fe7048709d2 (diff) | |
Added DB layer.
| -rw-r--r-- | .gitattributes | 8 | ||||
| -rw-r--r-- | framework/Data/TDbCommand.php | 262 | ||||
| -rw-r--r-- | framework/Data/TDbConnection.php | 512 | ||||
| -rw-r--r-- | framework/Data/TDbDataReader.php | 208 | ||||
| -rw-r--r-- | framework/Data/TDbTransaction.php | 113 | ||||
| -rw-r--r-- | tests/unit/Data/TDbCommandTest.php | 131 | ||||
| -rw-r--r-- | tests/unit/Data/TDbConnectionTest.php | 114 | ||||
| -rw-r--r-- | tests/unit/Data/TDbDataReaderTest.php | 114 | ||||
| -rw-r--r-- | tests/unit/Data/TDbTransactionTest.php | 73 | 
9 files changed, 1535 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes index 29c0c88d..5faafb57 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1398,6 +1398,10 @@ framework/Collections/TStack.php -text  framework/Configuration/Provider/TProviderBase.php -text  framework/Configuration/Provider/TProviderException.php -text  framework/Configuration/TProtectedConfiguration.php -text +framework/Data/TDbCommand.php -text +framework/Data/TDbConnection.php -text +framework/Data/TDbDataReader.php -text +framework/Data/TDbTransaction.php -text  framework/DataAccess/SQLMap/Configuration/TConfigDeserialize.php -text  framework/DataAccess/SQLMap/Configuration/TDiscriminator.php -text  framework/DataAccess/SQLMap/Configuration/TDomSqlMapBuilder.php -text @@ -2309,6 +2313,10 @@ tests/test_tools/simpletest/simpletest.php -text  tests/test_tools/simpletest/test_case.php -text  tests/unit/Collections/TListTest.php -text  tests/unit/Collections/TMapTest.php -text +tests/unit/Data/TDbCommandTest.php -text +tests/unit/Data/TDbConnectionTest.php -text +tests/unit/Data/TDbDataReaderTest.php -text +tests/unit/Data/TDbTransactionTest.php -text  tests/unit/I18N/core/CultureInfoTest.php -text  tests/unit/I18N/core/DateFormatTest.php -text  tests/unit/I18N/core/DateTimeFormatInfoTest.php -text diff --git a/framework/Data/TDbCommand.php b/framework/Data/TDbCommand.php new file mode 100644 index 00000000..3d0e367a --- /dev/null +++ b/framework/Data/TDbCommand.php @@ -0,0 +1,262 @@ +<?php
 +/**
 + * TDbCommand class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Id $
 + * @package System.Data
 + */
 +
 +/**
 + * TDbCommand class.
 + *
 + * TDbCommand represents an SQL statement to execute against a database.
 + * It is usually created by calling {@link TDbConnection::createCommand}.
 + * The SQL statement to be executed may be set via {@link setText Text}.
 + *
 + * To execute a non-query SQL (such as insert, delete, update), call
 + * {@link execute}. To execute an SQL statement that returns result data set
 + * (such as select), use {@link query} or its convenient versions {@link queryRow}
 + * and {@link queryScalar}.
 + *
 + * TDbCommand supports SQL statment preparation and parameter binding.
 + * Call {@link bindParameter} to bind a PHP variable to a parameter in SQL.
 + * Call {@link bindValue} to bind a value to an SQL parameter.
 + * When binding a parameter, the SQL statement is automatically prepared.
 + * You may also call {@link prepare} to explicitly prepare an SQL statement.
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @version $Id $
 + * @package System.Data
 + * @since 3.0
 + */
 +class TDbCommand extends TComponent
 +{
 +	private $_connection;
 +	private $_text='';
 +	private $_statement=null;
 +
 +	/**
 +	 * Constructor.
 +	 * @param TDbConnection the database connection
 +	 * @param string the SQL statement to be executed
 +	 */
 +	public function __construct(TDbConnection $connection,$text)
 +	{
 +		$this->_connection=$connection;
 +		$this->setText($text);
 +	}
 +
 +	/**
 +	 * @return string the SQL statement to be executed
 +	 */
 +	public function getText()
 +	{
 +		return $this->_text;
 +	}
 +
 +	/**
 +	 * Specifies the SQL statement to be executed.
 +	 * Any previous execution will be terminated or cancel.
 +	 * @param string the SQL statement to be executed
 +	 */
 +	public function setText($value)
 +	{
 +		$this->_text=$value;
 +		$this->cancel();
 +	}
 +
 +	/**
 +	 * @return TDbConnection the connection associated with this command
 +	 */
 +	public function getConnection()
 +	{
 +		return $this->_connection;
 +	}
 +
 +	/**
 +	 * @return PDOStatement the underlying PDOStatement for this command
 +	 * It could be null if the statement is not created yet.
 +	 */
 +	public function getPdoStatement()
 +	{
 +		return $this->_statement;
 +	}
 +
 +	/**
 +	 * Prepares the SQL statement to be executed.
 +	 * For complex SQL statement that is to be executed multiple times,
 +	 * this may improve performance.
 +	 * For SQL statement with binding parameters, this method is invoked
 +	 * automatically.
 +	 */
 +	public function prepare()
 +	{
 +		if($this->_statement==null)
 +		{
 +			try
 +			{
 +				$this->_statement=$this->getConnection()->getPdoInstance()->prepare($sql);
 +			}
 +			catch(Exception $e)
 +			{
 +				throw new TDbException('dbcommand_prepare_failed',$e->getMessage());
 +			}
 +		}
 +	}
 +
 +	/**
 +	 * Cancels the execution of the SQL statement.
 +	 */
 +	public function cancel()
 +	{
 +		$this->_statement=null;
 +	}
 +
 +	/**
 +	 * Binds a parameter to the SQL statement to be executed.
 +	 * @param mixed Parameter identifier. For a prepared statement
 +	 * using named placeholders, this will be a parameter name of
 +	 * the form :name. For a prepared statement using question mark
 +	 * placeholders, this will be the 1-indexed position of the parameter.
 +	 * @param mixed Name of the PHP variable to bind to the SQL statement parameter
 +	 * @param int SQL data type of the parameter
 +	 * @param int length of the data type
 +	 * @see http://www.php.net/manual/en/function.pdostatement-bindparam.php
 +	 */
 +	public function bindParameter($name, &$value, $dataType=null, $length=null)
 +	{
 +		$this->prepare();
 +		if($dataType===null)
 +			$this->_statement->bindParam($name,$value);
 +		else if($length===null)
 +			$this->_statement->bindParam($name,$value,$dataType);
 +		else
 +			$this->_statement->bindParam($name,$value,$dataType,$length);
 +	}
 +
 +	/**
 +	 * Binds a value to a parameter.
 +	 * @param mixed Parameter identifier. For a prepared statement
 +	 * using named placeholders, this will be a parameter name of
 +	 * the form :name. For a prepared statement using question mark
 +	 * placeholders, this will be the 1-indexed position of the parameter.
 +	 * @param mixed The value to bind to the parameter
 +	 * @param int SQL data type of the parameter
 +	 * @see http://www.php.net/manual/en/function.pdostatement-bindvalue.php
 +	 */
 +	public function bindValue($name, $value, $dataType=null)
 +	{
 +		$this->prepare();
 +		if($dataType===null)
 +			$this->_statement->bindParam($name,$value);
 +		else
 +			$this->_statement->bindParam($name,$value,$dataType);
 +	}
 +
 +	/**
 +	 * Executes the SQL statement.
 +	 * This method is meant only for executing non-query SQL statement.
 +	 * No result set will be returned.
 +	 * @return integer number of rows affected by the execution.
 +	 * @throws TDbException execution failed
 +	 */
 +	public function execute()
 +	{
 +		try
 +		{
 +			if($this->_statement instanceof PDOStatement)
 +			{
 +				$this->_statement->execute();
 +				return $this->_statement->rowCount();
 +			}
 +			else
 +				return $this->getConnection()->getPdoInstance()->exec($this->getText());
 +		}
 +		catch(Exception $e)
 +		{
 +			throw new TDbException('dbcommand_execute_failed',$e->getMessage());
 +		}
 +	}
 +
 +	/**
 +	 * Executes the SQL statement and returns query result.
 +	 * This method is for executing an SQL query that returns result set.
 +	 * @return TDbDataReader the reader object for fetching the query result
 +	 * @throws TDbException execution failed
 +	 */
 +	public function query()
 +	{
 +		try
 +		{
 +			if($this->_statement instanceof PDOStatement)
 +				$this->_statement->execute();
 +			else
 +				$this->_statement=$this->getConnection()->getPdoInstance()->query($this->getText());
 +			return new TDbDataReader($this);
 +		}
 +		catch(Exception $e)
 +		{
 +			throw new TDbException('dbcommand_query_failed',$e->getMessage());
 +		}
 +	}
 +
 +	/**
 +	 * Executes the SQL statement and returns the first row of the result.
 +	 * This is a convenient method of {@link query} when only the first row of data is needed.
 +	 * @param boolean whether the row should be returned as an associated array with
 +	 * column names as the keys or the array keys are column indexes (0-based).
 +	 * @return array the first row of the query result, false if not result.
 +	 * @throws TDbException execution failed
 +	 */
 +	public function queryRow($fetchAssociative=true)
 +	{
 +		try
 +		{
 +			if($this->_statement instanceof PDOStatement)
 +				$this->_statement->execute();
 +			else
 +				$this->_statement=$this->getConnection()->getPdoInstance()->query($sql);
 +			$result=$this->_statement->fetch($fetchAssociative ? PDO::FETCH_ASSOC : PDO::FETCH_NUM);
 +			$this->_statement->closeCursor();
 +			return $result;
 +		}
 +		catch(Exception $e)
 +		{
 +			throw new TDbException('dbcommand_query_failed',$e->getMessage());
 +		}
 +	}
 +
 +	/**
 +	 * Executes the SQL statement and returns the value of the first column in the first row of data.
 +	 * This is a convenient method of {@link query} when only a single scalar
 +	 * value is needed (e.g. obtaining the count of the records).
 +	 * @return mixed the value of the first column in the first row of the query result.
 +	 * @throws TDbException execution failed or there is no data
 +	 */
 +	public function queryScalar()
 +	{
 +		try
 +		{
 +			if($this->_statement instanceof PDOStatement)
 +				$this->_statement->execute();
 +			else
 +				$this->_statement=$this->getConnection()->getPdoInstance()->query($sql);
 +			$result=$this->_statement->fetchColumn();
 +			$this->_statement->closeCursor();
 +			if($result!==false)
 +				return $result;
 +			else
 +				throw new TDbException('dbcommand_column_empty');
 +		}
 +		catch(Exception $e)
 +		{
 +			throw new TDbException('dbcommand_queryscalar_failed',$e->getMessage());
 +		}
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/framework/Data/TDbConnection.php b/framework/Data/TDbConnection.php new file mode 100644 index 00000000..cfb4fd72 --- /dev/null +++ b/framework/Data/TDbConnection.php @@ -0,0 +1,512 @@ +<?php
 +/**
 + * TDbConnection class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Id $
 + * @package System.Data
 + */
 +
 +Prado::using('System.Data.TDbTransaction');
 +Prado::using('System.Data.TDbCommand');
 +
 +/**
 + * TDbConnection class
 + *
 + * TDbConnection represents a connection to a database.
 + *
 + * TDbConnection works together with {@link TDbCommand}, {@link TDbDataReader}
 + * and {@link TDbTransaction} to provide data access to various DBMS
 + * in a common set of APIs, thanks to the {@link http://www.php.net/manual/en/ref.pdo.php PDO}
 + * PHP extension.
 + *
 + * To establish a connection, set {@link setActive Active} to true after
 + * specifying {@link setConnectionString ConnectionString}, {@link setUsername Username}
 + * and {@link setPassword Password}.
 + *
 + * The following example shows how to create a TDbConnection instance and establish
 + * the actual connection:
 + * <code>
 + * $connection=new TDbConnection($dsn,$username,$password);
 + * $connection->Active=true;
 + * </code>
 + *
 + * After the DB connection is established, one can execute an SQL statement like the following:
 + * <code>
 + * $command=$connection->createCommand($sqlStatement);
 + * $command->execute();   // a non-query SQL statement execution
 + * // or execute an SQL query and fetch the result set
 + * $reader=$command->query();
 + * foreach($reader as $row) ...  // each $row is an array representing a row of data
 + * </code>
 + *
 + * One can do prepared SQL execution and bind parameters to the prepared SQL:
 + * <code>
 + * $command=$connection->createCommand($sqlStatement);
 + * $command->bindParameter($name1,$value1);
 + * $command->bindParameter($name2,$value2);
 + * $command->execute();
 + * </code>
 + *
 + * To use transaction, do like the following:
 + * <code>
 + * try
 + * {
 + *    $transaction=$connection->beginTransaction();
 + *    $connection->createCommand($sql1)->execute();
 + *    $connection->createCommand($sql2)->execute();
 + *    //.... other SQL executions
 + *    $transaction->commit();
 + * }
 + * catch(Exception $e)
 + * {
 + *    $transaction->rollBack();
 + * }
 + * </code>
 + *
 + * TDbConnection provides a set of methods to support setting and querying
 + * of certain DBMS attributes, such as {@link getNullConversion NullConversion}.
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @version $Id $
 + * @package System.Data
 + * @since 3.0
 + */
 +class TDbConnection extends TComponent
 +{
 +	private $_dsn;
 +	private $_username;
 +	private $_password;
 +	private $_attributes=array();
 +	private $_active=false;
 +	private $_pdo=null;
 +
 +	/**
 +	 * Constructor.
 +	 * Note, the DB connection is not established when this connection
 +	 * instance is created. Set {@link setActive Active} property to true
 +	 * to establish the connection.
 +	 * @param string The Data Source Name, or DSN, contains the information required to connect to the database.
 +	 * @param string The user name for the DSN string.
 +	 * @param string The password for the DSN string.
 +	 * @see http://www.php.net/manual/en/function.pdo-construct.php
 +	 */
 +	public function __construct($dsn='',$username='',$password='')
 +	{
 +		$this->_dsn=$dsn;
 +		$this->_username=$username;
 +		$this->_password=$password;
 +	}
 +
 +	/**
 +	 * @return boolean whether the DB connection is established
 +	 */
 +	public function getActive()
 +	{
 +		return $this->_active;
 +	}
 +
 +	/**
 +	 * Open or close the DB connection.
 +	 * @param boolean whether to open or close DB connection
 +	 * @throws TDbException if connection fails
 +	 */
 +	public function setActive($value)
 +	{
 +		$value=TPropertyValue::ensureBoolean($value);
 +		if($value!==$this->_active)
 +		{
 +			if($value)
 +				$this->open();
 +			else
 +				$this->close();
 +		}
 +	}
 +
 +	/**
 +	 * Opens DB connection if it is currently not
 +	 * @throws TDbException if connection fails
 +	 */
 +	protected function open()
 +	{
 +		if($this->_pdo===null)
 +		{
 +			try
 +			{
 +				$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
 +				$this->_pdo=new PDO($this->getConnectionString(),$this->getUsername(),$this->getPassword(),$this->_attributes);
 +				$this->_active=true;
 +			}
 +			catch(PDOException $e)
 +			{
 +				throw new TDbException('dbconnection_open_failed',$e->getMessage());
 +			}
 +		}
 +	}
 +
 +	/**
 +	 * Closes the currently active DB connection.
 +	 * It does nothing if the connection is already closed.
 +	 */
 +	protected function close()
 +	{
 +		$this->_pdo=null;
 +		$this->_active=false;
 +	}
 +
 +	/**
 +	 * @return string The Data Source Name, or DSN, contains the information required to connect to the database.
 +	 */
 +	public function getConnectionString()
 +	{
 +		return $this->_dsn;
 +	}
 +
 +	/**
 +	 * @param string The Data Source Name, or DSN, contains the information required to connect to the database.
 +	 * @see http://www.php.net/manual/en/function.pdo-construct.php
 +	 */
 +	public function setConnectionString($value)
 +	{
 +		$this->_dsn=$value;
 +	}
 +
 +	/**
 +	 * @return string the username for establishing DB connection. Defaults to empty string.
 +	 */
 +	public function getUsername()
 +	{
 +		return $this->_username;
 +	}
 +
 +	/**
 +	 * @param string the username for establishing DB connection
 +	 */
 +	public function setUsername($value)
 +	{
 +		$this->_username=$value;
 +	}
 +
 +	/**
 +	 * @return string the password for establishing DB connection. Defaults to empty string.
 +	 */
 +	public function getPassword()
 +	{
 +		return $this->_password;
 +	}
 +
 +	/**
 +	 * @param string the password for establishing DB connection
 +	 */
 +	public function setPassword($value)
 +	{
 +		$this->_password=$value;
 +	}
 +
 +	/**
 +	 * @return PDO the PDO instance, null if the connection is not established yet
 +	 */
 +	public function getPdoInstance()
 +	{
 +		return $this->_pdo;
 +	}
 +
 +	/**
 +	 * Creates a command for execution.
 +	 * @param string SQL statement associated with the new command.
 +	 * @return TDbCommand the DB command
 +	 * @throws TDbException if the connection is not active
 +	 */
 +	public function createCommand($sql)
 +	{
 +		if($this->getActive())
 +			return new TDbCommand($this,$sql);
 +		else
 +			throw new TDbException('dbconnection_connection_inactive');
 +	}
 +
 +	/**
 +	 * Starts a transaction.
 +	 * @return TDbTransaction the transaction initiated
 +	 * @throws TDbException if the connection is not active
 +	 */
 +	public function beginTransaction()
 +	{
 +		if($this->getActive())
 +		{
 +			$this->_pdo->beginTransaction();
 +			return new TDbTransaction($this);
 +		}
 +		else
 +			throw new TDbException('dbconnection_connection_inactive');
 +	}
 +
 +	/**
 +	 * Returns the ID of the last inserted row or sequence value.
 +	 * @param string name of the sequence object (required by some DBMS)
 +	 * @return string the row ID of the last row inserted, or the last value retrieved from the sequence object
 +	 * @see http://www.php.net/manual/en/function.pdo-lastinsertid.php
 +	 */
 +	public function getLastInsertID($sequenceName='')
 +	{
 +		if($this->getActive())
 +			return $this->_pdo->lastInsertId($sequenceName);
 +		else
 +			throw new TDbException('dbconnection_connection_inactive');
 +	}
 +
 +	/**
 +	 * Quotes a string for use in a query.
 +	 * @param string string to be quoted
 +	 * @return string the properly quoted string
 +	 * @see http://www.php.net/manual/en/function.pdo-quote.php
 +	 */
 +	public function quoteString($str)
 +	{
 +		if($this->getActive())
 +			return $this->_pdo->quote($str);
 +		else
 +			throw new TDbException('dbconnection_connection_inactive');
 +	}
 +
 +	/**
 +	 * @return TDbColumnCaseMode the case of the column names
 +	 */
 +	public function getColumnCase()
 +	{
 +		switch($this->getAttribute(PDO::ATTR_CASE))
 +		{
 +			case PDO::CASE_NATURAL:
 +				return TDbColumnCaseMode::Preserved;
 +			case PDO::CASE_LOWER:
 +				return TDbColumnCaseMode::LowerCase;
 +			case PDO::CASE_UPPER:
 +				return TDbColumnCaseMode::UpperCase;
 +			default:
 +				throw new TDbException('dbconnection_columncase_unknown');
 +		}
 +	}
 +
 +	/**
 +	 * @param TDbColumnCaseMode the case of the column names
 +	 */
 +	public function setColumnCase($value)
 +	{
 +		switch(TPropertyValue::ensureEnum($value,'TDbColumnCaseMode'))
 +		{
 +			case TDbColumnCaseMode::Preserved:
 +				$value=PDO::CASE_NATURAL;
 +				break;
 +			case TDbColumnCaseMode::LowerCase:
 +				$value=PDO::CASE_LOWER;
 +				break;
 +			case TDbColumnCaseMode::UpperCase:
 +				$value=PDO::CASE_UPPER;
 +				break;
 +		}
 +		$this->setAttribute(PDO::ATTR_CASE,$value);
 +	}
 +
 +	/**
 +	 * @return TDbNullConversionMode how the null and empty strings are converted
 +	 */
 +	public function getNullConversion()
 +	{
 +		switch($this->getAttribute(PDO::ATTR_ORACLE_NULLS))
 +		{
 +			case PDO::NULL_NATURAL:
 +				return TDbNullConversionMode::Preserved;
 +			case PDO::NULL_EMPTY_STRING:
 +				return TDbNullConversionMode::EmptyStringToNull;
 +			case PDO::NULL_TO_STRING:
 +				return TDbNullConversionMode::NullToEmptyString;
 +			default:
 +				throw new TDbException('dbconnection_nullconversion_unknown');
 +		}
 +	}
 +
 +	/**
 +	 * @param TDbNullConversionMode how the null and empty strings are converted
 +	 */
 +	public function setNullConversion($value)
 +	{
 +		switch(TPropertyValue::ensureEnum($value,'TDbNullConversionMode'))
 +		{
 +			case TDbNullConversionMode::Preserved:
 +				$value=PDO::NULL_NATURAL;
 +				break;
 +			case TDbNullConversionMode::EmptyStringToNull:
 +				$value=PDO::NULL_EMPTY_STRING;
 +				break;
 +			case TDbNullConversionMode::NullToEmptyString:
 +				$value=PDO::NULL_TO_STRING;
 +				break;
 +		}
 +		$this->setAttribute(PDO::ATTR_ORACLE_NULLS,$value);
 +	}
 +
 +	/**
 +	 * @return boolean whether creating or updating a DB record will be automatically committed.
 +	 * Some DBMS (such as sqlite) may not support this feature.
 +	 */
 +	public function getAutoCommit()
 +	{
 +		return $this->getAttribute(PDO::ATTR_AUTOCOMMIT);
 +	}
 +
 +	/**
 +	 * @param boolean whether creating or updating a DB record will be automatically committed.
 +	 * Some DBMS (such as sqlite) may not support this feature.
 +	 */
 +	public function setAutoCommit($value)
 +	{
 +		$this->setAttribute(PDO::ATTR_AUTOCOMMIT,TPropertyValue::ensureBoolean($value));
 +	}
 +
 +	/**
 +	 * @return string name of the DB driver
 +	 */
 +	public function getDriverName()
 +	{
 +		return $this->getAttribute(PDO::ATTR_DRIVER_NAME);
 +	}
 +
 +	/**
 +	 * @return string the version information of the DB driver
 +	 */
 +	public function getClientVersion()
 +	{
 +		return $this->getAttribute(PDO::ATTR_CLIENT_VERSION);
 +	}
 +
 +	/**
 +	 * @return string the status of the connection
 +	 * Some DBMS (such as sqlite) may not support this feature.
 +	 */
 +	public function getConnectionStatus()
 +	{
 +		return $this->getAttribute(PDO::ATTR_CONNECTION_STATUS);
 +	}
 +
 +	/**
 +	 * @return boolean whether the connection is persistent or not
 +	 * Some DBMS (such as sqlite) may not support this feature.
 +	 */
 +	public function getPersistent()
 +	{
 +		return $this->getAttribute(PDO::ATTR_PERSISTENT);
 +	}
 +
 +	/**
 +	 * @return boolean whether the connection performs data prefetching
 +	 */
 +	public function getPrefetch()
 +	{
 +		return $this->getAttribute(PDO::ATTR_PREFETCH);
 +	}
 +
 +	/**
 +	 * @return string the information of DBMS server
 +	 */
 +	public function getServerInfo()
 +	{
 +		return $this->getAttribute(PDO::ATTR_SERVER_INFO);
 +	}
 +
 +	/**
 +	 * @return string the version information of DBMS server
 +	 */
 +	public function getServerVersion()
 +	{
 +		return $this->getAttribute(PDO::ATTR_SERVER_VERSION);
 +	}
 +
 +	/**
 +	 * @return int timeout settings for the connection
 +	 */
 +	public function getTimeout()
 +	{
 +		return $this->getAttribute(PDO::ATTR_TIMEOUT);
 +	}
 +
 +	/**
 +	 * Obtains a specific DB connection attribute information.
 +	 * @param int the attribute to be queried
 +	 * @return mixed the corresponding attribute information
 +	 * @see http://www.php.net/manual/en/function.pdo-getattribute.php
 +	 */
 +	public function getAttribute($name)
 +	{
 +		if($this->getActive())
 +			return $this->_pdo->getAttribute($name);
 +		else
 +			throw new TDbException('dbconnection_connection_inactive');
 +	}
 +
 +	/**
 +	 * Sets an attribute on the database connection.
 +	 * @param int the attribute to be set
 +	 * @param mixed the attribute value
 +	 * @see http://www.php.net/manual/en/function.pdo-setattribute.php
 +	 */
 +	public function setAttribute($name,$value)
 +	{
 +		if($this->getActive())
 +			$this->_pdo->setAttribute($name,$value);
 +		else
 +			$this->_attributes[$name]=$value;
 +	}
 +}
 +
 +/**
 + * TDbColumnCaseMode
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @version $Id $
 + * @package System.Data
 + * @since 3.0
 + */
 +class TDbColumnCaseMode extends TEnumerable
 +{
 +	/**
 +	 * Column name cases are kept as is from the database
 +	 */
 +	const Preserved='Preserved';
 +	/**
 +	 * Column names are converted to lower case
 +	 */
 +	const LowerCase='LowerCase';
 +	/**
 +	 * Column names are converted to upper case
 +	 */
 +	const UpperCase='UpperCase';
 +}
 +
 +/**
 + * TDbNullConversionMode
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @version $Id $
 + * @package System.Data
 + * @since 3.0
 + */
 +class TDbNullConversionMode extends TEnumerable
 +{
 +	/**
 +	 * No conversion is performed for null and empty values.
 +	 */
 +	const Preserved='Preserved';
 +	/**
 +	 * NULL is converted to empty string
 +	 */
 +	const NullToEmptyString='NullToEmptyString';
 +	/**
 +	 * Empty string is converted to NULL
 +	 */
 +	const EmptyStringToNull='EmptyStringToNull';
 +}
 +
 +?>
\ No newline at end of file diff --git a/framework/Data/TDbDataReader.php b/framework/Data/TDbDataReader.php new file mode 100644 index 00000000..32b86c1d --- /dev/null +++ b/framework/Data/TDbDataReader.php @@ -0,0 +1,208 @@ +<?php
 +/**
 + * TDbDataReader class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Id $
 + * @package System.Data
 + */
 +
 +/**
 + * TDbDataReader class.
 + *
 + * TDbDataReader represents a forward-only stream of rows from a query result set.
 + *
 + * To read the current row of data, call {@link read}. The method {@link readAll}
 + * returns all the rows in a single array.
 + *
 + * TDbDataReader implements Iterator interface and thus can be used in foreach like the following:
 + * <code>
 + * foreach($reader as $row)
 + *     // $row represents a row of data
 + * </code>
 + *
 + * It is possible to use a specific mode of data fetching by setting
 + * {@link setFetchMode FetchMode}. See {@link
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @version $Id $
 + * @package System.Data
 + * @since 3.0
 + */
 +class TDbDataReader extends TComponent implements Iterator
 +{
 +	private $_statement;
 +	private $_closed=false;
 +	private $_row;
 +	private $_index=-1;
 +
 +	/**
 +	 * Constructor.
 +	 * @param TDbCommand the command generating the query result
 +	 */
 +	public function __construct(TDbCommand $command)
 +	{
 +		$this->_statement=$command->getPdoStatement();
 +		$this->_statement->setFetchMode(PDO::FETCH_ASSOC);
 +	}
 +
 +	/**
 +	 * Binds a column to a PHP variable.
 +	 * When rows of data are being fetched, the corresponding column value
 +	 * will be set in the variable. Note, the fetch mode must include PDO::FETCH_BOUND.
 +	 * @param mixed Number of the column (1-indexed) or name of the column
 +	 * in the result set. If using the column name, be aware that the name
 +	 * should match the case of the column, as returned by the driver.
 +	 * @param mixed Name of the PHP variable to which the column will be bound.
 +	 * @param int Data type of the parameter
 +	 * @see http://www.php.net/manual/en/function.pdostatement-bindcolumn.php
 +	 */
 +	public function bindColumn($column, &$value, $dataType=null)
 +	{
 +		if($dataType===null)
 +			$this->_statement->bindColumn($column,$value);
 +		else
 +			$this->_statement->bindColumn($column,$value,$dataType);
 +	}
 +
 +	/**
 +	 * @see http://www.php.net/manual/en/function.pdostatement-setfetchmode.php
 +	 */
 +	public function setFetchMode($mode)
 +	{
 +		$params=func_get_args();
 +		call_user_func_array(array($this->_statement,'setFetchMode'),$params);
 +	}
 +
 +	/**
 +	 * Advances the reader to the next record in a result set.
 +	 * @return array|false the current record, false if no more row available
 +	 */
 +	public function read()
 +	{
 +		return $this->_statement->fetch();
 +	}
 +
 +	/**
 +	 * Reads the whole result set into an array.
 +	 * @return array|false the result set (each array element represents a row of data), false if no data is available.
 +	 */
 +	public function readAll()
 +	{
 +		return $this->_statement->fetchAll();
 +	}
 +
 +	/**
 +	 * Advances the reader to the next result when reading the results of a batch of statements.
 +	 * This method is only useful when there are multiple result sets
 +	 * returned by the query. Not all DBMS support this feature.
 +	 */
 +	public function nextResult()
 +	{
 +		return $this->_statement->nextRowset();
 +	}
 +
 +	/**
 +	 * Closes the reader.
 +	 * Any further data reading will result in an exception.
 +	 */
 +	public function close()
 +	{
 +		$this->_statement->closeCursor();
 +		$this->_closed=true;
 +	}
 +
 +	/**
 +	 * @return boolean whether the reader is closed or not.
 +	 */
 +	public function getIsClosed()
 +	{
 +		return $this->_closed;
 +	}
 +
 +	/**
 +	 * @return boolean whether the result contains any row of data
 +	 */
 +	public function getHasRows()
 +	{
 +		return $this->getRowCount()>0;
 +	}
 +
 +	/**
 +	 * @return int number of rows contained in the result.
 +	 * Note, some DBMS may not give a meaningful count.
 +	 */
 +	public function getRowCount()
 +	{
 +		return $this->_statement->rowCount();
 +	}
 +
 +	/**
 +	 * @return int the number of columns in the result set, 0 if the result is empty
 +	 */
 +	public function getColumnCount()
 +	{
 +		return $this->_statement->columnCount();
 +	}
 +
 +	/**
 +	 * Resets the iterator to the initial state.
 +	 * This method is required by the interface Iterator.
 +	 * @throws TDbException if this method is invoked twice
 +	 */
 +	public function rewind()
 +	{
 +		if($this->_index<0)
 +		{
 +			$this->_row=$this->_statement->fetch();
 +			$this->_index=0;
 +		}
 +		else
 +			throw new TDbException('dbdatareader_rewind_invalid');
 +	}
 +
 +	/**
 +	 * Returns the index of the current row.
 +	 * This method is required by the interface Iterator.
 +	 * @return integer the index of the current row.
 +	 */
 +	public function key()
 +	{
 +		return $this->_index;
 +	}
 +
 +	/**
 +	 * Returns the current row.
 +	 * This method is required by the interface Iterator.
 +	 * @return mixed the current row.
 +	 */
 +	public function current()
 +	{
 +		return $this->_row;
 +	}
 +
 +	/**
 +	 * Moves the internal pointer to the next row.
 +	 * This method is required by the interface Iterator.
 +	 */
 +	public function next()
 +	{
 +		$this->_row=$this->_statement->fetch();
 +		$this->_index++;
 +	}
 +
 +	/**
 +	 * Returns whether there is a row of data at current position.
 +	 * This method is required by the interface Iterator.
 +	 * @return boolean whether there is a row of data at current position.
 +	 */
 +	public function valid()
 +	{
 +		return $this->_row!==false;
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/framework/Data/TDbTransaction.php b/framework/Data/TDbTransaction.php new file mode 100644 index 00000000..c3f68c97 --- /dev/null +++ b/framework/Data/TDbTransaction.php @@ -0,0 +1,113 @@ +<?php
 +/**
 + * TDbTransaction class file
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @link http://www.pradosoft.com/
 + * @copyright Copyright © 2006 PradoSoft
 + * @license http://www.pradosoft.com/license/
 + * @version $Id $
 + * @package System.Data
 + */
 +
 +Prado::using('System.Data.TDbDataReader');
 +
 +/**
 + * TDbTransaction class.
 + *
 + * TDbTransaction represents a DB transaction.
 + * It is usually created by calling {@link TDbConnection::beginTransaction}.
 + *
 + * The following code is a common scenario of using transactions:
 + * <code>
 + * try
 + * {
 + *    $transaction=$connection->beginTransaction();
 + *    $connection->createCommand($sql1)->execute();
 + *    $connection->createCommand($sql2)->execute();
 + *    //.... other SQL executions
 + *    $transaction->commit();
 + * }
 + * catch(Exception $e)
 + * {
 + *    $transaction->rollBack();
 + * }
 + * </code>
 + *
 + * @author Qiang Xue <qiang.xue@gmail.com>
 + * @version $Id $
 + * @package System.Data
 + * @since 3.0
 + */
 +class TDbTransaction extends TComponent
 +{
 +	private $_connection=null;
 +	private $_active;
 +
 +	/**
 +	 * Constructor.
 +	 * @param TDbConnection the connection associated with this transaction
 +	 * @see TDbConnection::beginTransaction
 +	 */
 +	public function __construct(TDbConnection $connection)
 +	{
 +		$this->_connection=$connection;
 +		$this->setActive(true);
 +	}
 +
 +	/**
 +	 * Commits a transaction.
 +	 * @throws TDbException if the transaction or the DB connection is not active.
 +	 */
 +	public function commit()
 +	{
 +		if($this->_active && $this->_connection->getActive())
 +		{
 +			$this->_connection->getPdoInstance()->commit();
 +			$this->_active=false;
 +		}
 +		else
 +			throw new TDbException('dbtransaction_transaction_inactive');
 +	}
 +
 +	/**
 +	 * Rolls back a transaction.
 +	 * @throws TDbException if the transaction or the DB connection is not active.
 +	 */
 +	public function rollback()
 +	{
 +		if($this->_active && $this->_connection->getActive())
 +		{
 +			$this->_connection->getPdoInstance()->rollBack();
 +			$this->_active=false;
 +		}
 +		else
 +			throw new TDbException('dbtransaction_transaction_inactive');
 +	}
 +
 +	/**
 +	 * @return TDbConnection the DB connection for this transaction
 +	 */
 +	public function getConnection()
 +	{
 +		return $this->_connection;
 +	}
 +
 +	/**
 +	 * @return boolean whether this transaction is active
 +	 */
 +	public function getActive()
 +	{
 +		return $this->_active;
 +	}
 +
 +	/**
 +	 * @param boolean whether this transaction is active
 +	 */
 +	protected function setActive($value)
 +	{
 +		$this->_active=TPropertyValue::ensureBoolean($value);
 +	}
 +}
 +
 +?>
\ No newline at end of file diff --git a/tests/unit/Data/TDbCommandTest.php b/tests/unit/Data/TDbCommandTest.php new file mode 100644 index 00000000..f0c02f75 --- /dev/null +++ b/tests/unit/Data/TDbCommandTest.php @@ -0,0 +1,131 @@ +<?php + +require_once(dirname(__FILE__).'/../phpunit2.php'); + +Prado::using('System.Data.*'); + +define('TEST_DB_FILE',dirname(__FILE__).'/db/test.db'); + +/** + * @package System.Data.PDO + */ +class TDbCommandTest extends PHPUnit2_Framework_TestCase +{ +	private $_connection; + +	public function setUp() +	{ +		@unlink(TEST_DB_FILE); +		$this->_connection=new TDbConnection('sqlite:'.TEST_DB_FILE); +		$this->_connection->Active=true; +		$this->_connection->createCommand('CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(8))')->execute(); +		$this->_connection->createCommand('INSERT TABLE foo (name) VALUES (\'my name\')')->execute; +	} + +	public function tearDown() +	{ +		$this->_connection=null; +	} + +	public function testGetText() +	{ +		$sql='SELECT * FROM foo'; +		$command=$this->_connection->createCommand($sql); +		$this->assertEquals($command->Text,$sql); +	} + +	public function testSetText() +	{ +		$sql='SELECT * FROM foo'; +		$newSql='SELECT id FROM foo'; +		$command=$this->_connection->createCommand($sql); +		$command->query()->read(); +		$command->Text=$newSql; +		$this->assertEquals($command->Text,$newSql); +		$row=$command->query()->read(); +		$this->assertEquals($row['id'],1); +	} + +/* +	public function testActive() +	{ +	    $this->assertFalse($this->_connection2->Active); + +	    $this->_connection2->Active=true; +	    $this->assertTrue($this->_connection2->Active); +	    $pdo=$this->_connection2->PdoInstance; +	    // test setting Active repeatedly doesn't re-connect DB +	    $this->_connection2->Active=true; +	    $this->assertTrue($pdo===$this->_connection2->PdoInstance); + +		$this->_connection2->Active=false; +	    $this->assertFalse($this->_connection2->Active); +	} + +	public function testCreateCommand() +	{ +		$sql='CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(8))'; +		try +		{ +			$this->_connection2->createCommand($sql); +			$this->fail('Expected exception is not raised'); +		} +		catch(TDbException $e) +		{ +		} + +		$command=$this->_connection->createCommand($sql); +		$this->assertTrue($command instanceof TDbCommand); +	} + +	public function testBeginTransaction() +	{ +		$sql='INSERT INTO foo(id,name) VALUES (1,\'my name\')'; +		$transaction=$this->_connection->beginTransaction(); +		try +		{ +			$this->_connection->createCommand($sql)->execute(); +			$this->_connection->createCommand($sql)->execute(); +			$this->fail('Expected exception not raised'); +			$transaction->commit(); +		} +		catch(Exception $e) +		{ +			$transaction->rollBack(); +			$reader=$this->_connection->createCommand('SELECT * FROM foo')->query(); +			$this->assertFalse($reader->read()); +		} +	} + +	public function testLastInsertID() +	{ +		$sql='INSERT INTO foo(name) VALUES (\'my name\')'; +		$this->_connection->createCommand($sql)->execute(); +		$value=$this->_connection->LastInsertID; +		$this->assertEquals($this->_connection->LastInsertID,'1'); +	} + +	public function testQuoteString() +	{ +		$str="this is 'my' name"; +		$expectedStr="'this is ''my'' name'"; +		$this->assertEquals($expectedStr,$this->_connection->quoteString($str)); +	} + +	public function testColumnNameCase() +	{ +		$this->assertEquals(TDbColumnCaseMode::Preserved,$this->_connection->ColumnCase); +		$this->_connection->ColumnCase=TDbColumnCaseMode::LowerCase; +		$this->assertEquals(TDbColumnCaseMode::LowerCase,$this->_connection->ColumnCase); +	} + +	public function testNullConversion() +	{ +		$this->assertEquals(TDbNullConversionMode::Preserved,$this->_connection->NullConversion); +		$this->_connection->NullConversion=TDbNullConversionMode::NullToEmptyString; +		$this->assertEquals(TDbNullConversionMode::NullToEmptyString,$this->_connection->NullConversion); +	} +	*/ +} + +?>
\ No newline at end of file diff --git a/tests/unit/Data/TDbConnectionTest.php b/tests/unit/Data/TDbConnectionTest.php new file mode 100644 index 00000000..21d6730b --- /dev/null +++ b/tests/unit/Data/TDbConnectionTest.php @@ -0,0 +1,114 @@ +<?php + +require_once(dirname(__FILE__).'/../phpunit2.php'); + +Prado::using('System.Data.*'); + +define('TEST_DB_FILE',dirname(__FILE__).'/db/test.db'); +define('TEST_DB_FILE2',dirname(__FILE__).'/db/test2.db'); + +/** + * @package System.Data.PDO + */ +class TDbConnectionTest extends PHPUnit2_Framework_TestCase +{ +	private $_connection1; +	private $_connection2; + +	public function setUp() +	{ +		@unlink(TEST_DB_FILE); +		@unlink(TEST_DB_FILE2); +		$this->_connection1=new TDbConnection('sqlite:'.TEST_DB_FILE); +		$this->_connection1->Active=true; +		$this->_connection1->createCommand('CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(8))')->execute(); +		$this->_connection2=new TDbConnection('sqlite:'.TEST_DB_FILE2); +	} + +	public function tearDown() +	{ +		$this->_connection1=null; +		$this->_connection2=null; +	} + +	public function testActive() +	{ +	    $this->assertFalse($this->_connection2->Active); + +	    $this->_connection2->Active=true; +	    $this->assertTrue($this->_connection2->Active); +	    $pdo=$this->_connection2->PdoInstance; +	    // test setting Active repeatedly doesn't re-connect DB +	    $this->_connection2->Active=true; +	    $this->assertTrue($pdo===$this->_connection2->PdoInstance); + +		$this->_connection2->Active=false; +	    $this->assertFalse($this->_connection2->Active); +	} + +	public function testCreateCommand() +	{ +		$sql='CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(8))'; +		try +		{ +			$this->_connection2->createCommand($sql); +			$this->fail('Expected exception is not raised'); +		} +		catch(TDbException $e) +		{ +		} + +		$command=$this->_connection1->createCommand($sql); +		$this->assertTrue($command instanceof TDbCommand); +	} + +	public function testBeginTransaction() +	{ +		$sql='INSERT INTO foo(id,name) VALUES (1,\'my name\')'; +		$transaction=$this->_connection1->beginTransaction(); +		try +		{ +			$this->_connection1->createCommand($sql)->execute(); +			$this->_connection1->createCommand($sql)->execute(); +			$this->fail('Expected exception not raised'); +			$transaction->commit(); +		} +		catch(Exception $e) +		{ +			$transaction->rollBack(); +			$reader=$this->_connection1->createCommand('SELECT * FROM foo')->query(); +			$this->assertFalse($reader->read()); +		} +	} + +	public function testLastInsertID() +	{ +		$sql='INSERT INTO foo(name) VALUES (\'my name\')'; +		$this->_connection1->createCommand($sql)->execute(); +		$value=$this->_connection1->LastInsertID; +		$this->assertEquals($this->_connection1->LastInsertID,'1'); +	} + +	public function testQuoteString() +	{ +		$str="this is 'my' name"; +		$expectedStr="'this is ''my'' name'"; +		$this->assertEquals($expectedStr,$this->_connection1->quoteString($str)); +	} + +	public function testColumnNameCase() +	{ +		$this->assertEquals(TDbColumnCaseMode::Preserved,$this->_connection1->ColumnCase); +		$this->_connection1->ColumnCase=TDbColumnCaseMode::LowerCase; +		$this->assertEquals(TDbColumnCaseMode::LowerCase,$this->_connection1->ColumnCase); +	} + +	public function testNullConversion() +	{ +		$this->assertEquals(TDbNullConversionMode::Preserved,$this->_connection1->NullConversion); +		$this->_connection1->NullConversion=TDbNullConversionMode::NullToEmptyString; +		$this->assertEquals(TDbNullConversionMode::NullToEmptyString,$this->_connection1->NullConversion); +	} +} + +?>
\ No newline at end of file diff --git a/tests/unit/Data/TDbDataReaderTest.php b/tests/unit/Data/TDbDataReaderTest.php new file mode 100644 index 00000000..21d6730b --- /dev/null +++ b/tests/unit/Data/TDbDataReaderTest.php @@ -0,0 +1,114 @@ +<?php + +require_once(dirname(__FILE__).'/../phpunit2.php'); + +Prado::using('System.Data.*'); + +define('TEST_DB_FILE',dirname(__FILE__).'/db/test.db'); +define('TEST_DB_FILE2',dirname(__FILE__).'/db/test2.db'); + +/** + * @package System.Data.PDO + */ +class TDbConnectionTest extends PHPUnit2_Framework_TestCase +{ +	private $_connection1; +	private $_connection2; + +	public function setUp() +	{ +		@unlink(TEST_DB_FILE); +		@unlink(TEST_DB_FILE2); +		$this->_connection1=new TDbConnection('sqlite:'.TEST_DB_FILE); +		$this->_connection1->Active=true; +		$this->_connection1->createCommand('CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(8))')->execute(); +		$this->_connection2=new TDbConnection('sqlite:'.TEST_DB_FILE2); +	} + +	public function tearDown() +	{ +		$this->_connection1=null; +		$this->_connection2=null; +	} + +	public function testActive() +	{ +	    $this->assertFalse($this->_connection2->Active); + +	    $this->_connection2->Active=true; +	    $this->assertTrue($this->_connection2->Active); +	    $pdo=$this->_connection2->PdoInstance; +	    // test setting Active repeatedly doesn't re-connect DB +	    $this->_connection2->Active=true; +	    $this->assertTrue($pdo===$this->_connection2->PdoInstance); + +		$this->_connection2->Active=false; +	    $this->assertFalse($this->_connection2->Active); +	} + +	public function testCreateCommand() +	{ +		$sql='CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(8))'; +		try +		{ +			$this->_connection2->createCommand($sql); +			$this->fail('Expected exception is not raised'); +		} +		catch(TDbException $e) +		{ +		} + +		$command=$this->_connection1->createCommand($sql); +		$this->assertTrue($command instanceof TDbCommand); +	} + +	public function testBeginTransaction() +	{ +		$sql='INSERT INTO foo(id,name) VALUES (1,\'my name\')'; +		$transaction=$this->_connection1->beginTransaction(); +		try +		{ +			$this->_connection1->createCommand($sql)->execute(); +			$this->_connection1->createCommand($sql)->execute(); +			$this->fail('Expected exception not raised'); +			$transaction->commit(); +		} +		catch(Exception $e) +		{ +			$transaction->rollBack(); +			$reader=$this->_connection1->createCommand('SELECT * FROM foo')->query(); +			$this->assertFalse($reader->read()); +		} +	} + +	public function testLastInsertID() +	{ +		$sql='INSERT INTO foo(name) VALUES (\'my name\')'; +		$this->_connection1->createCommand($sql)->execute(); +		$value=$this->_connection1->LastInsertID; +		$this->assertEquals($this->_connection1->LastInsertID,'1'); +	} + +	public function testQuoteString() +	{ +		$str="this is 'my' name"; +		$expectedStr="'this is ''my'' name'"; +		$this->assertEquals($expectedStr,$this->_connection1->quoteString($str)); +	} + +	public function testColumnNameCase() +	{ +		$this->assertEquals(TDbColumnCaseMode::Preserved,$this->_connection1->ColumnCase); +		$this->_connection1->ColumnCase=TDbColumnCaseMode::LowerCase; +		$this->assertEquals(TDbColumnCaseMode::LowerCase,$this->_connection1->ColumnCase); +	} + +	public function testNullConversion() +	{ +		$this->assertEquals(TDbNullConversionMode::Preserved,$this->_connection1->NullConversion); +		$this->_connection1->NullConversion=TDbNullConversionMode::NullToEmptyString; +		$this->assertEquals(TDbNullConversionMode::NullToEmptyString,$this->_connection1->NullConversion); +	} +} + +?>
\ No newline at end of file diff --git a/tests/unit/Data/TDbTransactionTest.php b/tests/unit/Data/TDbTransactionTest.php new file mode 100644 index 00000000..9d34857d --- /dev/null +++ b/tests/unit/Data/TDbTransactionTest.php @@ -0,0 +1,73 @@ +<?php + +require_once(dirname(__FILE__).'/../phpunit2.php'); + +Prado::using('System.Data.*'); + +define('TEST_DB_FILE',dirname(__FILE__).'/db/test.db'); + +/** + * @package System.Data.PDO + */ +class TDbTransactionTest extends PHPUnit2_Framework_TestCase +{ +	private $_connection; + +	public function setUp() +	{ +		@unlink(TEST_DB_FILE); +		$this->_connection=new TDbConnection('sqlite:'.TEST_DB_FILE); +		$this->_connection->Active=true; +		$this->_connection->createCommand('CREATE TABLE foo (id INTEGER NOT NULL PRIMARY KEY, name VARCHAR(8))')->execute(); +	} + +	public function tearDown() +	{ +		$this->_connection=null; +	} + +	public function testRollBack() +	{ +		$sql='INSERT INTO foo(id,name) VALUES (1,\'my name\')'; +		$transaction=$this->_connection->beginTransaction(); +		try +		{ +			$this->_connection->createCommand($sql)->execute(); +			$this->_connection->createCommand($sql)->execute(); +			$this->fail('Expected exception not raised'); +			$transaction->commit(); +		} +		catch(Exception $e) +		{ +			$this->assertTrue($transaction->Active); +			$transaction->rollBack(); +			$this->assertFalse($transaction->Active); +			$reader=$this->_connection->createCommand('SELECT * FROM foo')->query(); +			$this->assertFalse($reader->read()); +		} +	} + +	public function testCommit() +	{ +		$sql1='INSERT INTO foo(id,name) VALUES (1,\'my name\')'; +		$sql2='INSERT INTO foo(id,name) VALUES (2,\'my name\')'; +		$transaction=$this->_connection->beginTransaction(); +		try +		{ +			$this->_connection->createCommand($sql1)->execute(); +			$this->_connection->createCommand($sql2)->execute(); +			$this->assertTrue($transaction->Active); +			$transaction->commit(); +			$this->assertFalse($transaction->Active); +		} +		catch(Exception $e) +		{ +			$transaction->rollBack(); +			$this->fail('Unexpected exception'); +		} +		$result=$this->_connection->createCommand('SELECT * FROM foo')->query()->readAll(); +		$this->assertEquals(count($result),2); +	} +} + +?>
\ No newline at end of file  | 
