Author: Sergey Alexeev
Date: 2007-05-03 21:19:57 +0200 (Thu, 03 May 2007)
New Revision: 5028

Log:
- Added feature #7772: SQL Server implementation for the Database package. 
                       Based on contributions by Friedel Hill.


Added:
   trunk/Database/src/handlers/mssql.php
   trunk/Database/src/sqlabstraction/implementations/expression_mssql.php
   trunk/Database/src/sqlabstraction/implementations/query_select_mssql.php
Modified:
   trunk/Database/ChangeLog
   trunk/Database/src/db_autoload.php
   trunk/Database/src/factory.php
   trunk/Database/src/query_autoload.php
   trunk/Database/tests/factory_test.php
   trunk/Database/tests/handler_test.php
   trunk/Database/tests/pdo_test.php
   trunk/Database/tests/sqlabstraction/expression_test.php
   trunk/Database/tests/sqlabstraction/query_insert_test.php
   trunk/Database/tests/sqlabstraction/query_select_test_impl.php
   trunk/Database/tests/sqlabstraction/query_subselect_test.php
   trunk/Database/tests/sqlabstraction/query_subselect_test_impl.php
   trunk/Database/tests/suite.php

Modified: trunk/Database/ChangeLog
===================================================================
--- trunk/Database/ChangeLog    2007-05-03 16:43:33 UTC (rev 5027)
+++ trunk/Database/ChangeLog    2007-05-03 19:19:57 UTC (rev 5028)
@@ -10,6 +10,8 @@
 - Fixed issue #9526: Implemented expression now() for each database handler.
 - Fixed issue #10529: Tests for quoting of strings in query expressions.
 - Added feature #8448: Select Distinct not supported
+- Added feature #7772: SQL Server implementation for the Database package. 
+                       Based on contributions by Friedel Hill.
 
 1.2 - Monday 18 December 2006
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Modified: trunk/Database/src/db_autoload.php
===================================================================
--- trunk/Database/src/db_autoload.php  2007-05-03 16:43:33 UTC (rev 5027)
+++ trunk/Database/src/db_autoload.php  2007-05-03 19:19:57 UTC (rev 5028)
@@ -17,6 +17,7 @@
     'ezcDbHandler'                   => 'Database/handler.php',
     'ezcDbUtilities'                 => 
'Database/sqlabstraction/utilities.php',
     'ezcDbFactory'                   => 'Database/factory.php',
+    'ezcDbHandlerMssql'              => 'Database/handlers/mssql.php',
     'ezcDbHandlerMysql'              => 'Database/handlers/mysql.php',
     'ezcDbHandlerOracle'             => 'Database/handlers/oracle.php',
     'ezcDbHandlerPgsql'              => 'Database/handlers/pgsql.php',

Modified: trunk/Database/src/factory.php
===================================================================
--- trunk/Database/src/factory.php      2007-05-03 16:43:33 UTC (rev 5027)
+++ trunk/Database/src/factory.php      2007-05-03 19:19:57 UTC (rev 5028)
@@ -53,7 +53,8 @@
     static private $implementations = array( 'mysql'  => 'ezcDbHandlerMysql',
                                              'pgsql'  => 'ezcDbHandlerPgsql',
                                              'oracle' => 'ezcDbHandlerOracle',
-                                             'sqlite' => 'ezcDbHandlerSqlite' 
);
+                                             'sqlite' => 'ezcDbHandlerSqlite',
+                                             'mssql' => 'ezcDbHandlerMssql', );
 
     /**
      * Adds a database implementation to the list of known implementations.
@@ -340,7 +341,6 @@
                 }
             }
         }
-
         return $parsed;
     }
 }

Added: trunk/Database/src/handlers/mssql.php
===================================================================
--- trunk/Database/src/handlers/mssql.php       2007-05-03 16:43:33 UTC (rev 
5027)
+++ trunk/Database/src/handlers/mssql.php       2007-05-03 19:19:57 UTC (rev 
5028)
@@ -0,0 +1,217 @@
+<?php
+/**
+ * File containing the ezcDbHandlerMssql class.
+ *
+ * @package Database
+ * @version //autogentag//
+ * @copyright Copyright (C) 2005-2007 eZ systems as. All rights reserved.
+ * @license http://ez.no/licenses/new_bsd New BSD License
+ */
+
+/**
+ * MS SQL Server driver implementation
+ *
+ * @see ezcDbHandler
+ * @package Database
+ */
+
+class ezcDbHandlerMssql extends ezcDbHandler
+{
+    /**
+     * Constructs a handler object from the parameters $dbParams.
+     *
+     * Supported database parameters are:
+     * - dbname|database: Database name
+     * - host|hostspec:   Name of the host database is running on
+     * - port:            TCP port
+     * - user|username:   Database user name
+     * - pass|password:   Database user password
+     *
+     * @param array $dbparams Database connection parameters (key=>value 
pairs).
+     * @throws ezcDbMissingParameterException if the database name was not 
specified.
+     */
+    public function __construct( $dbParams )
+    {
+        $database = null;
+        $host     = null;
+        $port     = null;
+
+        foreach ( $dbParams as $key => $val )
+        {
+            switch ( $key )
+            {
+                case 'database':
+                case 'dbname':
+                    $database = $val;
+                    break;
+
+                case 'host':
+                case 'hostspec':
+                    $host = $val;
+                    break;
+
+                case 'port':
+                    $port = $val;
+                    break;
+            }
+        }
+
+        if ( !isset( $database ) )
+        {
+            throw new ezcDbMissingParameterException( 'database', 'dbParams' );
+        }
+
+        $dsn = "dblib:dbname=$database";
+
+        if ( isset( $host ) && $host )
+        {
+            $dsn .= ";host=$host";
+                        if ( isset( $port ) && $port )
+                       {
+                               $dsn .= ":$port";
+                       }
+       
+       }
+
+        parent::__construct( $dbParams, $dsn );
+    }
+
+
+    /**
+     * Returns a new ezcQueryExpression derived object with SQL Server 
implementation specifics.
+     *
+     * @return ezcQueryExpressionMssql
+     */
+    public function createExpression()
+    {
+        return new ezcQueryExpressionMssql( $this );
+    }
+
+    /**
+     * Returns 'mssql'.
+     *
+     * @return string
+     */
+    static public function getName()
+    {
+        return 'mssql';
+    }
+
+    /**
+     * Returns a new ezcQuerySelectMssql derived object with SQL Server 
implementation specifics.
+     *
+     * @return ezcQuerySelectMssql
+     */
+    public function createSelectQuery()
+    {
+        return new ezcQuerySelectMssql( $this );
+    }
+
+    /**
+     * Begins a transaction.
+     *
+     * This method executes a begin transaction query unless a
+     * transaction has already been started (transaction nesting level > 0 )
+     *
+     * Each call to begin() must have a corresponding commit() or rollback() 
call.
+     *
+     * @see commit()
+     * @see rollback()
+     * @return bool
+     */
+    public function beginTransaction()
+    {
+        $retval = true;
+        if ( $this->transactionNestingLevel == 0 )
+        {
+            $retval = $this->exec("BEGIN TRANSACTION");
+        }
+        // else NOP
+
+        $this->transactionNestingLevel++;
+        return $retval;
+    }
+
+    /**
+     * Commits a transaction.
+     *
+     * If this this call to commit corresponds to the outermost call to
+     * begin() and all queries within this transaction were successful,
+     * a commit query is executed. If one of the queries
+     * returned with an error, a rollback query is executed instead.
+     *
+     * This method returns true if the transaction was successful. If the
+     * transaction failed and rollback was called, false is returned.
+     *
+     * @see begin()
+     * @see rollback()
+     * @return bool
+     */
+    public function commit()
+    {
+        if ( $this->transactionNestingLevel <= 0 )
+        {
+            $this->transactionNestingLevel = 0;
+
+            throw new ezcDbTransactionException( "commit() called before 
beginTransaction()." );
+        }
+
+        $retval = true;
+        if ( $this->transactionNestingLevel == 1 )
+        {
+            if ( $this->transactionErrorFlag )
+            {
+                $this->exec("ROLLBACK TRANSACTION");
+                $this->transactionErrorFlag = false; // reset error flag
+                $retval = false;
+            }
+            else
+            {
+                $this->exec("COMMIT TRANSACTION");
+            }
+        }
+        // else NOP
+
+        $this->transactionNestingLevel--;
+        return $retval;
+    }
+
+    /**
+     * Rollback a transaction.
+     *
+     * If this this call to rollback corresponds to the outermost call to
+     * begin(), a rollback query is executed. If this is an inner transaction
+     * (nesting level > 1) the error flag is set, leaving the rollback to the
+     * outermost transaction.
+     *
+     * This method always returns true.
+     *
+     * @see begin()
+     * @see commit()
+     * @return bool
+     */
+    public function rollback()
+    {
+        if ( $this->transactionNestingLevel <= 0 )
+        {
+            $this->transactionNestingLevel = 0;
+            throw new ezcDbTransactionException( "rollback() called without 
previous beginTransaction()." );
+        }
+
+        if ( $this->transactionNestingLevel == 1 )
+        {
+            $this->exec("ROLLBACK TRANSACTION");
+            $this->transactionErrorFlag = false; // reset error flag
+        }
+        else
+        {
+            // set the error flag, so that if there is outermost commit
+            // then ROLLBACK will be done instead of COMMIT
+            $this->transactionErrorFlag = true;
+        }
+
+        $this->transactionNestingLevel--;
+        return true;
+    }
+}
+?>


Property changes on: trunk/Database/src/handlers/mssql.php
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/Database/src/query_autoload.php
===================================================================
--- trunk/Database/src/query_autoload.php       2007-05-03 16:43:33 UTC (rev 
5027)
+++ trunk/Database/src/query_autoload.php       2007-05-03 19:19:57 UTC (rev 
5028)
@@ -17,10 +17,12 @@
     'ezcQueryExpression'             => 
'Database/sqlabstraction/expression.php',
     'ezcQuerySelect'                 => 
'Database/sqlabstraction/query_select.php',
     'ezcQueryDelete'                 => 
'Database/sqlabstraction/query_delete.php',
+    'ezcQueryExpressionMssql'        => 
'Database/sqlabstraction/implementations/expression_mssql.php',
     'ezcQueryExpressionOracle'       => 
'Database/sqlabstraction/implementations/expression_oracle.php',
     'ezcQueryExpressionPgsql'        => 
'Database/sqlabstraction/implementations/expression_pgsql.php',
     'ezcQueryExpressionSqlite'       => 
'Database/sqlabstraction/implementations/expression_sqlite.php',
     'ezcQueryInsert'                 => 
'Database/sqlabstraction/query_insert.php',
+    'ezcQuerySelectMssql'            => 
'Database/sqlabstraction/implementations/query_select_mssql.php',
     'ezcQuerySelectOracle'           => 
'Database/sqlabstraction/implementations/query_select_oracle.php',
     'ezcQuerySelectSqlite'           => 
'Database/sqlabstraction/implementations/query_select_sqlite.php',
     'ezcQuerySqliteFunctions'        => 
'Database/sqlabstraction/implementations/query_sqlite_function_implementations.php',

Added: trunk/Database/src/sqlabstraction/implementations/expression_mssql.php
===================================================================
--- trunk/Database/src/sqlabstraction/implementations/expression_mssql.php      
2007-05-03 16:43:33 UTC (rev 5027)
+++ trunk/Database/src/sqlabstraction/implementations/expression_mssql.php      
2007-05-03 19:19:57 UTC (rev 5028)
@@ -0,0 +1,128 @@
+<?php
+/**
+ * File containing the ezcQueryExpressionMssql class.
+ *
+ * @package Database
+ * @version 1.0
+ * @copyright Copyright (C) 2005, 2006 eZ systems as. All rights reserved.
+ * @license http://ez.no/licenses/new_bsd New BSD License
+ */
+
+/**
+ * The ezcQueryExpressionMssql class is used to create SQL expression for SQL 
Server.
+ *
+ * This class reimplements the methods that have a different syntax in SQL 
Server.
+ *
+ * @package Database
+ */
+class ezcQueryExpressionMssql extends ezcQueryExpression
+{
+
+    /**
+     * Returns the remainder of the division operation
+     * $expression1 / $expression2.
+     *
+     * @param string $expression1
+     * @param string $expression2
+     * @return string
+     */
+    public function mod( $expression1, $expression2 )
+    {
+        $expression1 = $this->getIdentifier( $expression1 );
+        $expression2 = $this->getIdentifier( $expression2 );
+        return "{$expression1} % {$expression2}";
+    }
+
+    /**
+     * Returns the md5 sum of a field. 
+     * There is two variants of implementation for this feature.
+     * Both not ideal though.
+     * First don't require additional setup of MS SQL Server
+     * and uses undocumented function master.dbo.fn_varbintohexstr()
+     * to convert result of Transact-SQL HashBytes() function to string.
+     *
+     * Second one requires the stored procedure
+     * from http://www.thecodeproject.com/database/xp_md5.asp to 
+     * be installed and wrapped by the user defined function fn_md5
+     *
+     * @return string
+     */
+    public function md5( $column )
+    {
+        $column = $this->getIdentifier( $column );
+        return "SUBSTRING( master.dbo.fn_varbintohexstr( HashBytes( 'MD5', 
{$column} ) ), 3, 32)";
+        // alternative
+        // return "dbo.fn_md5( {$column} )";
+    }
+    
+    /**
+     * Returns the length of a text field.
+     *
+     * @param string $column
+     * @return string
+     */
+    public function length( $column )
+    {
+        $column = $this->getIdentifier( $column );
+        return "LEN( {$column} )";
+    }
+
+    /**
+     * Returns the current system date.
+     *
+     * @return string
+     */
+    public function now()
+    {
+        return "GETDATE()";
+    }
+
+    /**
+     * Returns part of a string.
+     *
+     * Note: Not SQL92, but common functionality.
+     *
+     * @param string $value the target $value the string or the string column.
+     * @param int $from extract from this characeter.
+     * @param int $len extract this amount of characters. If $len is not 
+     *            provided it's assumed to be the number of characters 
+     *            to get the whole remainder of the string.
+     * @return string sql that extracts part of a string.
+     */
+    public function subString( $value, $from, $len = null )
+    {
+        $value = $this->getIdentifier( $value );
+        if ( $len === null )
+        {
+            return "SUBSTRING( {$value}, {$from}, LEN({$value})-({$from}-1) )";
+        }
+        else
+        {
+            $len = $this->getIdentifier( $len );
+            return "SUBSTRING( {$value}, {$from}, {$len} )";
+        }
+    }
+    
+    /**
+     * Returns a series of strings concatinated
+     *
+     * concat() accepts an arbitrary number of parameters. Each parameter
+     * must contain an expression or an array with expressions.
+     *
+     * @param string|array(string) strings that will be concatinated.
+     */
+    public function concat()
+    {
+        $args = func_get_args();
+        $cols = ezcQuerySelect::arrayFlatten( $args );
+
+        if ( count( $cols ) < 1 )
+        {
+            throw new ezcQueryVariableParameterException( 'concat', count( 
$args ), 1 );
+        }
+
+        $cols = $this->getIdentifiers( $cols );
+        return join( ' + ', $cols );
+    }
+}
+?>


Property changes on: 
trunk/Database/src/sqlabstraction/implementations/expression_mssql.php
___________________________________________________________________
Name: svn:eol-style
   + native

Added: trunk/Database/src/sqlabstraction/implementations/query_select_mssql.php
===================================================================
--- trunk/Database/src/sqlabstraction/implementations/query_select_mssql.php    
2007-05-03 16:43:33 UTC (rev 5027)
+++ trunk/Database/src/sqlabstraction/implementations/query_select_mssql.php    
2007-05-03 19:19:57 UTC (rev 5028)
@@ -0,0 +1,127 @@
+<?php
+/**
+ * File containing the ezcQuerySelectMssql class.
+ *
+ * @package Database
+ * @version 1.0
+ * @copyright Copyright (C) 2005, 2006 eZ systems as. All rights reserved.
+ * @license http://ez.no/licenses/new_bsd New BSD License
+ */
+
+/**
+ * SQL Server specific implementation of ezcQuery.
+ *
+ * This class reimplements the LIMIT method in which the
+ * SQL Server differs from the standard implementation in ezcQuery. 
+ *
+ * @see ezcQuery
+ * @package Database
+ */
+class ezcQuerySelectMssql extends ezcQuerySelect
+{
+    /**
+     * If a limit and/or offset has been set for this query.
+     */
+    private $hasLimit = false;
+    private $limit = 0;
+    private $offset = 0;
+    
+    /**
+     * Same as ezcQuerySelect::$orderString but inverted
+     * for use in the LIMIT functionality.
+     *
+     * @var string
+     */
+    private $invertedOrderString = null;
+
+    /**
+     * Resets the query object for reuse.
+     *
+     * @return void
+     */
+    public function reset()
+    {
+        $this->hasLimit = false;
+        $this->limit = 0;
+        $this->offset = 0;
+        $this->orderColumns = array();
+        parent::reset();
+    }
+
+    /**
+     * Returns SQL that limits the result set.
+     *
+     * $limit controls the maximum number of rows that will be returned.
+     * $offset controls which row that will be the first in the result
+     * set from the total amount of matching rows.
+     *
+     * @param $limit integer expression
+     * @param $offset integer expression
+     * @return void
+     */
+    public function limit( $limit, $offset = 0 )
+    {
+        $this->hasLimit = true;
+        $this->limit = $limit;
+        $this->offset = $offset;
+        return $this;
+    }
+
+    /**
+     * Saves the ordered columns in an internal array so we can invert that 
order
+     * if we need to in the limit() workaround
+     */
+    public function orderBy( $column, $type = self::ASC )
+    {
+        if($this->invertedOrderString) {
+            $this->invertedOrderString .= ', ';
+        }
+        else
+        {
+            $this->invertedOrderString = 'ORDER BY ';
+        }
+        $this->invertedOrderString .= $column . ' ' . ( $type == self::ASC ? 
self::DESC : self::ASC );
+        return parent::orderBy($column, $type);
+    }
+    
+    /**
+     * Transforms the $query to make it only select the $rowCount first rows
+     *
+     * @param int $rowCount number of rows to return
+     * @param string $query SQL select query
+     * @return string
+     */
+    static private function top($rowCount, $query) {
+        return 'SELECT TOP ' . $rowCount . substr( $query, strlen( 'SELECT' ) 
);
+    }
+
+    /**
+     * Transforms the query from the parent to provide LIMIT functionality.
+     *
+     * Note: doesn't work exactly like the MySQL equivalent; it will always 
return 
+     * $limit rows even if $offset + $limit exceeds the total number of rows. 
+     *
+     * @throws ezcQueryInvalidException if offset is used and orderBy is not.
+     * @return string
+     */
+    public function getQuery()
+    {
+        $query = parent::getQuery();
+        if ( $this->hasLimit )
+        {
+            if( $this->offset) 
+            {
+                if(!$this->orderString) 
+                {
+                    //Uh ow. We need some columns to sort in the oposite order 
to make this work
+                    throw new ezcQueryInvalidException( "LIMIT workaround for 
MS SQL", "orderBy() was not called before getQuery()." );
+                }
+                return 'SELECT * FROM ( SELECT TOP ' . $this->limit . ' * FROM 
( ' . self::top( $this->offset + $this->limit, $query ) . ' ) AS ezcDummyTable1 
' . $this->invertedOrderString . ' ) AS ezcDummyTable2 ' . $this->orderString;
+            }
+            return self::top( $this->limit, $query );
+        }
+        return $query;
+    }
+}
+
+?>


Property changes on: 
trunk/Database/src/sqlabstraction/implementations/query_select_mssql.php
___________________________________________________________________
Name: svn:eol-style
   + native

Modified: trunk/Database/tests/factory_test.php
===================================================================
--- trunk/Database/tests/factory_test.php       2007-05-03 16:43:33 UTC (rev 
5027)
+++ trunk/Database/tests/factory_test.php       2007-05-03 19:19:57 UTC (rev 
5028)
@@ -45,14 +45,14 @@
     public function testGetImplementations()
     {
         $array = ezcDbFactory::getImplementations();
-        $this->assertEquals( array( 'mysql', 'pgsql', 'oracle', 'sqlite' ), 
$array );
+        $this->assertEquals( array( 'mysql', 'pgsql', 'oracle', 'sqlite', 
'mssql' ), $array );
     }
 
     public function testGetImplementationsAfterAddingOne()
     {
         ezcDbFactory::addImplementation( 'test', 'ezcDbHandlerTest' );
         $array = ezcDbFactory::getImplementations();
-        $this->assertEquals( array( 'mysql', 'pgsql', 'oracle', 'sqlite', 
'test' ), $array );
+        $this->assertEquals( array( 'mysql', 'pgsql', 'oracle', 'sqlite', 
'mssql', 'test' ), $array );
     }
 
     public function testSqliteDSN1()

Modified: trunk/Database/tests/handler_test.php
===================================================================
--- trunk/Database/tests/handler_test.php       2007-05-03 16:43:33 UTC (rev 
5027)
+++ trunk/Database/tests/handler_test.php       2007-05-03 19:19:57 UTC (rev 
5028)
@@ -52,6 +52,7 @@
             case "ezcDbHandlerOracle":
             case "ezcDbHandlerPgsql":
             case "ezcDbHandlerSqlite":
+            case "ezcDbHandlerMssql":
                 $quoteChars = array( '"', '"' );
                 break;
                 
@@ -76,6 +77,7 @@
             case "ezcDbHandlerOracle":
             case "ezcDbHandlerPgsql":
             case "ezcDbHandlerSqlite":
+            case "ezcDbHandlerMssql":
                 $quoteChars = array( '"', '"' );
                 break;
                 

Modified: trunk/Database/tests/pdo_test.php
===================================================================
--- trunk/Database/tests/pdo_test.php   2007-05-03 16:43:33 UTC (rev 5027)
+++ trunk/Database/tests/pdo_test.php   2007-05-03 19:19:57 UTC (rev 5028)
@@ -14,7 +14,7 @@
  * @package Database
  * @subpackage Tests
  */
-class PDOTest extends ezcTestCase
+class ezcPdoTest extends ezcTestCase
 {
     protected function setUp()
     {
@@ -52,6 +52,11 @@
     public function testIdNotFound()
     {
         $db = ezcDbInstance::get();
+        if ( $db->getName() != 'mysql' )
+        {
+            return;  // no need to test it in RDBMS other than MySQL
+        }
+        
         $q = $db->prepare("INSERT INTO query_test VALUES( 1, 'name', 
'section', 22)" );
         $q->execute();
 
@@ -68,6 +73,7 @@
 
 
     // Works in PHP 5.2.1RC2, segfaults in PHP 5.1.4
+/*
     public function testSegfaultWrongFunctionCall()
     {
         $db = ezcDbInstance::get();
@@ -77,12 +83,15 @@
 
         $q->oasdfa(); // Wrong method call.
     }
-
-
+*/
     // Works in PHP 5.1.4, Fails (hangs) in PHP 5.2.1RC2-dev.
     public function testInsertWithWrongColon()
     {
         $db = ezcDbInstance::get();
+        if ( $db->getName() != 'mysql' )
+        {
+            return;  // no need to test it in RDBMS other than MySQL.
+        }
 
         $q = $db->prepare("INSERT INTO query_test VALUES( ':id', 'name', 
'section', 22)" ); // <-- ':id' should be :id (or a string without ":")
         $q->execute();
@@ -90,7 +99,7 @@
 
     public static function suite()
     {
-         return new PHPUnit_Framework_TestSuite( "PDOTest" );
+         return new PHPUnit_Framework_TestSuite( "ezcPdoTest" );
     }
 }
 

Modified: trunk/Database/tests/sqlabstraction/expression_test.php
===================================================================
--- trunk/Database/tests/sqlabstraction/expression_test.php     2007-05-03 
16:43:33 UTC (rev 5027)
+++ trunk/Database/tests/sqlabstraction/expression_test.php     2007-05-03 
19:19:57 UTC (rev 5028)
@@ -45,7 +45,7 @@
         catch ( Exception $e ) {} // eat
 
         // insert some data
-        $this->db->exec( 'CREATE TABLE query_test ( id int, company 
VARCHAR(255), section VARCHAR(255), employees int )' );
+        $this->db->exec( 'CREATE TABLE query_test ( id int, company 
VARCHAR(255), section VARCHAR(255), employees int NULL)' );
         $this->db->exec( "INSERT INTO query_test VALUES ( 1, 'eZ systems', 
'Norway', 20 )" );
         $this->db->exec( "INSERT INTO query_test VALUES ( 2, 'IBM', 'Norway', 
500 )" );
         $this->db->exec( "INSERT INTO query_test VALUES ( 3, 'eZ systems', 
'Ukraine', 10 )" );
@@ -360,6 +360,10 @@
                 $reference = " encode( digest( name, 'md5' ), 'hex' ) ";
             }
         }
+        else if ( $this->db->getName() == 'mssql' )
+        {
+            $reference = "SUBSTRING( master.dbo.fn_varbintohexstr( HashBytes( 
'MD5', name ) ), 3, 32)";
+        }
         else
         {
             $reference = 'MD5( name )';
@@ -370,6 +374,10 @@
     public function testLength()
     {
         $reference = 'LENGTH( name )';
+        if ( $this->db->getName() == 'mssql' )
+        {
+            $reference = 'LEN( name )';
+        }
         $this->assertEquals( $reference, $this->e->length( 'name' ) );
     }
 
@@ -382,6 +390,10 @@
     public function testMod()
     {
         $reference = 'MOD( 10, 3 )';
+        if ( $this->db->getName() == 'mssql' )
+        {
+            $reference = '10 % 3';
+        }
         $this->assertEquals( $reference, $this->e->mod( 10, 3 ) );
     }
 
@@ -404,9 +416,11 @@
             case 'ezcDbHandlerOracle':
                 $reference = "LOCALTIMESTAMP";
                 break;
+                
+            case 'ezcDbHandlerMssql':
 
             default:
-                $reference = 'NOW()';
+                $reference = 'GETDATE()';
                 break;
         }
 
@@ -779,14 +793,32 @@
     public function testMd5Impl()
     {
         $company = 'eZ systems';
-        $this->q->select( 'company',
-                          $this->e->md5( $this->e->round( $this->e->avg( 
'employees' ), 0 ) ) )
-            ->from( 'query_test' )
-            ->where( $this->e->eq( 'company', $this->q->bindParam( $company ) 
) )
-            ->groupBy( 'company' );
-        $stmt = $this->q->prepare();
-        $stmt->execute();
-
+        if ( $this->db->getName() == 'mssql' ) // use a bit different test for 
MSSQL as it's MD5() implementation
+                                               // requires text parameter but 
result of round() has type int.
+        {
+            $this->q->select( 'company', $this->e->round( $this->e->avg( 
'employees' ), 0 ) )
+                ->from( 'query_test' )
+                ->where( $this->e->eq( 'company', $this->q->bindParam( 
$company ) ) )
+                ->groupBy( 'company' );
+            $stmt = $this->q->prepare();
+            $stmt->execute();
+            
+            $tmpValue = $stmt->fetchColumn( 1 );
+            $this->q->reset();
+            $this->q->select( 0, $this->q->expr->md5( "'$tmpValue'" ) )  ;
+            $stmt = $this->q->prepare();
+            $stmt->execute();
+        }
+        else
+        {
+            $this->q->select( 'company',
+                              $this->e->md5( $this->e->round( $this->e->avg( 
'employees' ), 0 ) ) )
+                ->from( 'query_test' )
+                ->where( $this->e->eq( 'company', $this->q->bindParam( 
$company ) ) )
+                ->groupBy( 'company' );
+            $stmt = $this->q->prepare();
+            $stmt->execute();
+        }
         $this->assertEquals( '9bf31c7ff062936a96d3c8bd1f8f2ff3',
                              $stmt->fetchColumn( 1 ) );
     }
@@ -1134,14 +1166,33 @@
     {
         $this->q->setAliases( array( 'text' => 'company', 'empl' => 
'employees' ) );
         $company = 'eZ systems';
-        $this->q->select( 'text',
-                          $this->q->expr->md5( $this->q->expr->round( 
$this->q->expr->avg( 'empl' ), 0 ) ) )
-            ->from( 'query_test' )
-            ->where( $this->q->expr->eq( 'text', $this->q->bindParam( $company 
) ) )
-            ->groupBy( 'text' );
-        $stmt = $this->q->prepare();
-        $stmt->execute();
-
+        
+        if ( $this->db->getName() == 'mssql' ) // use a bit different test for 
MSSQL as it's MD5() implementation
+                                               // requires text parameter but 
result of round() has type int.
+        {
+            $this->q->select( 'text', $this->q->expr->round( 
$this->q->expr->avg( 'empl' ), 0 ) )
+                ->from( 'query_test' )
+                ->where( $this->q->expr->eq( 'text', $this->q->bindParam( 
$company ) ) )
+                ->groupBy( 'text' );
+            $stmt = $this->q->prepare();
+            $stmt->execute();
+            
+            $this->q->reset();
+            $tmpValue = $stmt->fetchColumn( 1 );
+            $this->q->select( 0, $this->q->expr->md5( "'$tmpValue'" ) )  ;
+            $stmt = $this->q->prepare();
+            $stmt->execute();
+        }
+        else
+        {
+            $this->q->select( 'text',
+                              $this->q->expr->md5( $this->q->expr->round( 
$this->q->expr->avg( 'empl' ), 0 ) ) )
+                ->from( 'query_test' )
+                ->where( $this->q->expr->eq( 'text', $this->q->bindParam( 
$company ) ) )
+                ->groupBy( 'text' );
+            $stmt = $this->q->prepare();
+            $stmt->execute();
+        }
         $this->assertEquals( '9bf31c7ff062936a96d3c8bd1f8f2ff3',
                              $stmt->fetchColumn( 1 ) );
     }

Modified: trunk/Database/tests/sqlabstraction/query_insert_test.php
===================================================================
--- trunk/Database/tests/sqlabstraction/query_insert_test.php   2007-05-03 
16:43:33 UTC (rev 5027)
+++ trunk/Database/tests/sqlabstraction/query_insert_test.php   2007-05-03 
19:19:57 UTC (rev 5028)
@@ -214,9 +214,9 @@
         $section1 = "Norway";
         $section2 = "Ukraine";
 
-        if ( $db->getName() == 'mysql' || $db->getName() == 'sqlite' )
+        if ( $db->getName() == 'mysql' || $db->getName() == 'sqlite' || 
$db->getName() == 'mssql')
         {
-            return;  // no need to test it in MySQL and SQLite as they have 
autoincrement
+            return;  // no need to test it in MySQL, SQLite and MSSQL as they 
have autoincrement
         }
 
         if ( $db->getName() == 'oracle' )

Modified: trunk/Database/tests/sqlabstraction/query_select_test_impl.php
===================================================================
--- trunk/Database/tests/sqlabstraction/query_select_test_impl.php      
2007-05-03 16:43:33 UTC (rev 5027)
+++ trunk/Database/tests/sqlabstraction/query_select_test_impl.php      
2007-05-03 19:19:57 UTC (rev 5028)
@@ -46,14 +46,14 @@
         catch ( Exception $e ) {} // eat
 
         // insert some data
-        $this->db->exec( 'CREATE TABLE query_test ( id int, company 
VARCHAR(255), section VARCHAR(255), employees int )' );
+        $this->db->exec( 'CREATE TABLE query_test ( id int, company 
VARCHAR(255), section VARCHAR(255), employees int NULL )' );
         $this->db->exec( "INSERT INTO query_test VALUES ( 1, 'eZ systems', 
'Norway', 20 )" );
         $this->db->exec( "INSERT INTO query_test VALUES ( 2, 'IBM', 'Norway', 
500 )" );
         $this->db->exec( "INSERT INTO query_test VALUES ( 3, 'eZ systems', 
'Ukraine', 10 )" );
         $this->db->exec( "INSERT INTO query_test VALUES ( 4, 'IBM', 'Germany', 
null )" );
         
         // insert some data
-        $this->db->exec( 'CREATE TABLE query_test2 ( id int, company 
VARCHAR(255), section VARCHAR(255), employees int )' );
+        $this->db->exec( 'CREATE TABLE query_test2 ( id int, company 
VARCHAR(255), section VARCHAR(255), employees int NULL )' );
         $this->db->exec( "INSERT INTO query_test2 VALUES ( 1, 'eZ systems', 
'Norway', 20 )" );
         $this->db->exec( "INSERT INTO query_test2 VALUES ( 2, 'IBM', 'Norway', 
500 )" );
         $this->db->exec( "INSERT INTO query_test2 VALUES ( 3, 'eZ systems', 
'Ukraine', 10 )" );

Modified: trunk/Database/tests/sqlabstraction/query_subselect_test.php
===================================================================
--- trunk/Database/tests/sqlabstraction/query_subselect_test.php        
2007-05-03 16:43:33 UTC (rev 5027)
+++ trunk/Database/tests/sqlabstraction/query_subselect_test.php        
2007-05-03 19:19:57 UTC (rev 5028)
@@ -104,7 +104,7 @@
             ->selectDistinct( '*' )
             ->from( 'table' )
             ->where( 
-                $this->q->expr->eq( 'id', $q2 )
+                $this->q->expr->eq( 'id', $q2->getQuery() )
             );
 
         $this->assertEquals( $reference, $this->q->getQuery() );

Modified: trunk/Database/tests/sqlabstraction/query_subselect_test_impl.php
===================================================================
--- trunk/Database/tests/sqlabstraction/query_subselect_test_impl.php   
2007-05-03 16:43:33 UTC (rev 5027)
+++ trunk/Database/tests/sqlabstraction/query_subselect_test_impl.php   
2007-05-03 19:19:57 UTC (rev 5028)
@@ -46,14 +46,14 @@
         catch ( Exception $e ) {} // eat
 
         // insert some data
-        $this->db->exec( 'CREATE TABLE query_test ( id int, company 
VARCHAR(255), section VARCHAR(255), employees int )' );
+        $this->db->exec( 'CREATE TABLE query_test ( id int, company 
VARCHAR(255), section VARCHAR(255), employees int NULL )' );
         $this->db->exec( "INSERT INTO query_test VALUES ( 1, 'eZ systems', 
'Norway', 20 )" );
         $this->db->exec( "INSERT INTO query_test VALUES ( 2, 'IBM', 'Norway', 
500 )" );
         $this->db->exec( "INSERT INTO query_test VALUES ( 3, 'eZ systems', 
'Ukraine', 10 )" );
         $this->db->exec( "INSERT INTO query_test VALUES ( 4, 'IBM', 'Germany', 
null )" );
         
         // insert some data
-        $this->db->exec( 'CREATE TABLE query_test2 ( id int, company 
VARCHAR(255), section VARCHAR(255), employees int )' );
+        $this->db->exec( 'CREATE TABLE query_test2 ( id int, company 
VARCHAR(255), section VARCHAR(255), employees int NULL )' );
         $this->db->exec( "INSERT INTO query_test2 VALUES ( 1, 'eZ systems', 
'Norway', 20 )" );
         $this->db->exec( "INSERT INTO query_test2 VALUES ( 2, 'IBM', 'Norway', 
500 )" );
         $this->db->exec( "INSERT INTO query_test2 VALUES ( 3, 'eZ systems', 
'Ukraine', 10 )" );
@@ -108,12 +108,12 @@
 
         // bind values
         $q2->selectDistinct( 'section' )
-                ->from( 'query_test' );
+                ->from( 'query_test' )
+                ->where( ' id = 1 OR id = 2 ');
 
         $q->selectDistinct( 'company' )
             ->from( 'query_test2' )
-            ->where( $q->expr->in( 'section', $q2 ) );
-
+            ->where( $q->expr->in( 'section', $q2->getQuery() ) );
         $stmt = $q->prepare();
         $stmt->execute();
 

Modified: trunk/Database/tests/suite.php
===================================================================
--- trunk/Database/tests/suite.php      2007-05-03 16:43:33 UTC (rev 5027)
+++ trunk/Database/tests/suite.php      2007-05-03 19:19:57 UTC (rev 5028)
@@ -14,6 +14,7 @@
 require_once 'factory_test.php';
 require_once 'transactions_test.php';
 require_once 'instance_test.php';
+require_once 'pdo_test.php';
 require_once 'instance_delayed_init_test.php';
 require_once 'handler_test.php';
 require_once 'sqlabstraction/expression_test.php';
@@ -52,6 +53,7 @@
         $this->addTest( ezcQueryInsertTest::suite() );
         $this->addTest( ezcQueryUpdateTest::suite() );
         $this->addTest( ezcQueryDeleteTest::suite() );
+        $this->addTest( ezcPdoTest::suite() );
        }
 
     public static function suite()

-- 
svn-components mailing list
[email protected]
http://lists.ez.no/mailman/listinfo/svn-components

Reply via email to