Raised DBAL version from 1.0.1 to 1.0.2
authorOliver Hader <oliver.hader@typo3.org>
Sun, 29 Nov 2009 18:09:30 +0000 (18:09 +0000)
committerOliver Hader <oliver.hader@typo3.org>
Sun, 29 Nov 2009 18:09:30 +0000 (18:09 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@6591 709f56b5-9817-0410-a4d7-c38de5d9e867

ChangeLog
typo3/sysext/dbal/ChangeLog
typo3/sysext/dbal/class.ux_t3lib_db.php
typo3/sysext/dbal/class.ux_t3lib_sqlparser.php
typo3/sysext/dbal/ext_emconf.php
typo3/sysext/dbal/last_synched_target
typo3/sysext/dbal/tests/db_oracle_testcase.php
typo3/sysext/dbal/tests/fixtures/oci8.config.php
typo3/sysext/dbal/tests/sqlparser_general_testcase.php

index 649bd86..9581124 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -28,6 +28,7 @@
        * Fixed bug #11395: TCAdefaults in Page TSConfig without effect on creating new element after existing one (thanks to Tolleiv Nietsch)
        * Fixed bug #12800: Add functionality to work with caching framework and DBAL (thanks to Xavier Perseguers)
        * Fixed bug #12781: The type in t3lib_TCEforms does not work if the type field shall be excluded when translating (thanks to Fabrizio Branca)
+       * Raised DBAL version from 1.0.1 to 1.0.2 
 
 2009-11-26  Francois Suter  <francois@typo3.org>
 
index 894d749..80f4846 100644 (file)
@@ -1,3 +1,13 @@
+2009-11-29  Xavier Perseguers  <typo3@perseguers.ch>
+
+       * Set version to 1.0.2 [TYPO3 4.3.0]
+       * Fixed bug #12800: Add functionality to work with caching framework (support for "IN (subquery)" in where clause)
+       * Follow-up of changeset 26118: parts of initial patch for RFC 12231 had actually not been integrated
+
+2009-11-27  Xavier Perseguers  <typo3@perseguers.ch>
+
+       * Cleanup: Reorganized unit-tests
+
 2009-11-25  Xavier Perseguers  <typo3@perseguers.ch>
 
        * Set version to 1.0.1
index 9f2a36f..766f66d 100644 (file)
@@ -4,6 +4,7 @@
 *
 *  (c) 2004-2009 Kasper Skaarhoj (kasperYYYY@typo3.com)
 *  (c) 2004-2009 Karsten Dambekalns <karsten@typo3.org>
+*  (c) 2009 Xavier Perseguers <typo3@perseguers.ch>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -939,6 +940,19 @@ class ux_t3lib_DB extends t3lib_DB {
        **************************************/
 
        /**
+        * Quotes components of a SELECT subquery.
+        * 
+        * @param array $components     Array of SQL query components
+        * @return array
+        */
+       protected function quoteSELECTsubquery(array $components) {
+               $components['SELECT'] = $this->_quoteFieldNames($components['SELECT']);
+               $components['FROM'] = $this->_quoteFromTables($components['FROM']);
+               $components['WHERE'] = $this->_quoteWhereClause($components['WHERE']);
+               return $components;
+       }
+
+       /**
         * Quotes field (and table) names with the quote character suitable for the DB being used
         * Use quoteFieldNames instead!
         *
@@ -961,6 +975,19 @@ class ux_t3lib_DB extends t3lib_DB {
                if ($this->runningNative()) return $select_fields;
 
                $select_fields = $this->SQLparser->parseFieldList($select_fields);
+               $select_fields = $this->_quoteFieldNames($select_fields);
+
+               return $this->SQLparser->compileFieldList($select_fields);
+       }
+
+       /**
+        * Quotes field (and table) names in a SQL SELECT clause acccording to DB rules
+        *
+        * @param array $select_fields The parsed fields to quote
+        * @return array
+        * @see quoteFieldNames()
+        */
+       protected function _quoteFieldNames(array $select_fields) {
                foreach ($select_fields as $k => $v) {
                        if ($select_fields[$k]['field'] != '' && $select_fields[$k]['field'] != '*') {
                                $select_fields[$k]['field'] = $this->quoteName($select_fields[$k]['field']);
@@ -977,7 +1004,7 @@ class ux_t3lib_DB extends t3lib_DB {
                        }
                }
 
-               return $this->SQLparser->compileFieldList($select_fields);
+               return $select_fields;
        }
 
        /**
@@ -991,6 +1018,18 @@ class ux_t3lib_DB extends t3lib_DB {
                if ($this->runningNative()) return $from_table;
 
                $from_table = $this->SQLparser->parseFromTables($from_table);
+               $from_table = $this->_quoteFromTables($from_table);
+               return $this->SQLparser->compileFromTables($from_table);
+       }
+
+       /**
+        * Quotes table names in a SQL FROM clause acccording to DB rules
+        *
+        * @param array $from_table The parsed FROM clause to quote
+        * @return array
+        * @see quoteFromTables()
+        */
+       protected function _quoteFromTables(array $from_table) {
                foreach ($from_table as $k => $v) {
                        $from_table[$k]['table'] = $this->quoteName($from_table[$k]['table']);
                        if ($from_table[$k]['as'] != '') {
@@ -1007,7 +1046,8 @@ class ux_t3lib_DB extends t3lib_DB {
                                }
                        }
                }
-               return $this->SQLparser->compileFromTables($from_table);
+
+               return $from_table;
        }
 
        /**
@@ -1037,7 +1077,7 @@ class ux_t3lib_DB extends t3lib_DB {
         * @return      array
         * @see quoteWhereClause()
         */
-       protected function _quoteWhereClause($where_clause) {
+       protected function _quoteWhereClause(array $where_clause) {
                foreach ($where_clause as $k => $v) {
                                // Look for sublevel:
                        if (is_array($where_clause[$k]['sub'])) {
@@ -1066,8 +1106,14 @@ class ux_t3lib_DB extends t3lib_DB {
                                        }
                                } else {
                                                // Detecting value type; list or plain:
-                                       if ((!isset($where_clause[$k]['value'][1]) || $where_clause[$k]['value'][1] == '') && is_string($where_clause[$k]['value'][0]) && strstr($where_clause[$k]['value'][0], '.') && !t3lib_div::inList('NOTIN,IN',strtoupper(str_replace(array(" ","\n","\r","\t"),'',$where_clause[$k]['comparator'])))) {
-                                               $where_clause[$k]['value'][0] = $this->quoteFieldNames($where_clause[$k]['value'][0]);
+                                       if (t3lib_div::inList('NOTIN,IN', strtoupper(str_replace(array(' ',"\n", "\r", "\t"), '', $where_clause[$k]['comparator'])))) {
+                                               if (isset($v['subquery'])) {
+                                                       $where_clause[$k]['subquery'] = $this->quoteSELECTsubquery($v['subquery']);
+                                               }
+                                       } else {
+                                               if ((!isset($where_clause[$k]['value'][1]) || $where_clause[$k]['value'][1] == '') && is_string($where_clause[$k]['value'][0]) && strstr($where_clause[$k]['value'][0], '.')) {
+                                                       $where_clause[$k]['value'][0] = $this->quoteFieldNames($where_clause[$k]['value'][0]);
+                                               }
                                        }
                                }
                        }
@@ -2524,6 +2570,14 @@ class ux_t3lib_DB extends t3lib_DB {
                                                }
                                        }
 
+                                               // Do we have a subquery (WHERE parts only)?
+                                       if (isset($sqlPartArray[$k]['subquery'])) {
+                                               $subqueryDefaultTable = $sqlPartArray[$k]['subquery']['FROM'][0]['table'];
+                                               $this->map_sqlParts($sqlPartArray[$k]['subquery']['SELECT'], $subqueryDefaultTable);
+                                               $this->map_sqlParts($sqlPartArray[$k]['subquery']['FROM'], $subqueryDefaultTable);
+                                               $this->map_sqlParts($sqlPartArray[$k]['subquery']['WHERE'], $subqueryDefaultTable);
+                                       }
+
                                                // do we have a field name in the value?
                                                // this is a very simplistic check, beware
                                        if (!is_numeric($sqlPartArray[$k]['value'][0]) && !isset($sqlPartArray[$k]['value'][1])) {
index 5898b9d..62e7c53 100644 (file)
@@ -4,6 +4,7 @@
 *
 *  (c) 2004-2009 Kasper Skaarhoj (kasperYYYY@typo3.com)
 *  (c) 2004-2009 Karsten Dambekalns <karsten@typo3.org>
+*  (c) 2009 Xavier Perseguers <typo3@perseguers.ch>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -32,6 +33,7 @@
  *
  * @author     Kasper Skaarhoj <kasperYYYY@typo3.com>
  * @author     Karsten Dambekalns <k.dambekalns@fishfarm.de>
+ * @author     Xavier Perseguers <typo3@perseguers.ch>
  */
 
 
@@ -210,7 +212,19 @@ class ux_t3lib_sqlparser extends t3lib_sqlparser {
                                $stack[$level][$pnt[$level]]['calc'] = $this->nextPart($parseString, '^(' . $calcOperators . ')');
                                if (strlen($stack[$level][$pnt[$level]]['calc'])) {
                                                // Finding value for calculation:
-                                       $stack[$level][$pnt[$level]]['calc_value'] = $this->getValue($parseString);
+                                       $calc_value = $this->getValue($parseString);
+                                       $stack[$level][$pnt[$level]]['calc_value'] = $calc_value;
+                                       if (count($calc_value) == 1 && is_string($calc_value[0])) {
+                                                       // Value is a field, store it to allow DBAL to post-process it (quoting, remapping)
+                                               $tableField = explode('.', $calc_value[0], 2);
+                                               if (count($tableField) == 2) {
+                                                       $stack[$level][$pnt[$level]]['calc_table'] = $tableField[0];
+                                                       $stack[$level][$pnt[$level]]['calc_field'] = $tableField[1];
+                                               } else {
+                                                       $stack[$level][$pnt[$level]]['calc_table'] = '';
+                                                       $stack[$level][$pnt[$level]]['calc_field'] = $tableField[0];
+                                               }
+                                       }
                                }
 
                                        // Find "comparator":
@@ -240,6 +254,15 @@ class ux_t3lib_sqlparser extends t3lib_sqlparser {
                                                        // Look for ending parenthese:
                                                $this->nextPart($parseString, '([)])');
                                                $stack[$level][$pnt[$level]]['value'] = $values;
+                                       } else if (t3lib_div::inList('IN,NOT IN', $stack[$level][$pnt[$level]]['comparator']) && preg_match('/^[(][[:space:]]*SELECT[[:space:]]+/', $parseString)) {
+                                               $this->nextPart($parseString, '^([(])');
+                                               $stack[$level][$pnt[$level]]['subquery'] = $this->parseSELECT($parseString);
+                                                       // Seek to new position in parseString after parsing of the subquery
+                                               $parseString = $stack[$level][$pnt[$level]]['subquery']['parseString'];
+                                               unset($stack[$level][$pnt[$level]]['subquery']['parseString']);
+                                               if (!$this->nextPart($parseString, '^([)])')) {
+                                                       return 'No ) parenthesis at end of subquery';
+                                               }
                                        } else {
                                                        // Finding value for comparator:
                                                $stack[$level][$pnt[$level]]['value'] = $this->getValue($parseString, $stack[$level][$pnt[$level]]['comparator']);
@@ -252,6 +275,13 @@ class ux_t3lib_sqlparser extends t3lib_sqlparser {
                                        // Finished, increase pointer:
                                $pnt[$level]++;
 
+                                       // Checking if we are back to level 0 and we should still decrease level,
+                                       // meaning we were probably parsing as subquery and should return here:
+                               if ($level === 0 && preg_match('/^[)]/', $parseString)) {
+                                               // Return the stacks lowest level:
+                                       return $stack[0];
+                               }
+
                                        // Checking if the current level is ended, in that case do stack management:
                                while ($this->nextPart($parseString,'^([)])')) {
                                        $level--;               // Decrease level:
@@ -378,11 +408,15 @@ class ux_t3lib_sqlparser extends t3lib_sqlparser {
 
                                                        // Detecting value type; list or plain:
                                                if (t3lib_div::inList('NOTIN,IN', strtoupper(str_replace(array(' ', "\t", "\r", "\n"), '', $v['comparator'])))) {
-                                                       $valueBuffer = array();
-                                                       foreach ($v['value'] as $realValue) {
-                                                               $valueBuffer[] = $realValue[1] . $this->compileAddslashes($realValue[0]) . $realValue[1];
+                                                       if (isset($v['subquery'])) {
+                                                               $output .= ' (' . $this->compileSELECT($v['subquery']) . ')';   
+                                                       } else {
+                                                               $valueBuffer = array();
+                                                               foreach ($v['value'] as $realValue) {
+                                                                       $valueBuffer[] = $realValue[1] . $this->compileAddslashes($realValue[0]) . $realValue[1];
+                                                               }
+                                                               $output .= ' (' . trim(implode(',', $valueBuffer)) . ')';
                                                        }
-                                                       $output .= ' (' . trim(implode(',', $valueBuffer)) . ')';
                                                } else if (isset($v['value']['operator'])) {
                                                        $values = array();
                                                        foreach ($v['value']['args'] as $fieldDef) {
@@ -770,11 +804,15 @@ class ux_t3lib_sqlparser extends t3lib_sqlparser {
 
                                                                                        // Detecting value type; list or plain:
                                                                                if (t3lib_div::inList('NOTIN,IN', strtoupper(str_replace(array(' ', "\t", "\r", "\n"), '', $v['comparator'])))) {
-                                                                                       $valueBuffer = array();
-                                                                                       foreach ($v['value'] as $realValue) {
-                                                                                               $valueBuffer[] = $realValue[1] . $this->compileAddslashes($realValue[0]) . $realValue[1];
+                                                                                       if (isset($v['subquery'])) {
+                                                                                               $output .= ' (' . $this->compileSELECT($v['subquery']) . ')';   
+                                                                                       } else {
+                                                                                               $valueBuffer = array();
+                                                                                               foreach ($v['value'] as $realValue) {
+                                                                                                       $valueBuffer[] = $realValue[1] . $this->compileAddslashes($realValue[0]) . $realValue[1];
+                                                                                               }
+                                                                                               $output .= ' (' . trim(implode(',', $valueBuffer)) . ')';
                                                                                        }
-                                                                                       $output .= ' (' . trim(implode(',', $valueBuffer)) . ')';
                                                                                } else if (isset($v['value']['operator'])) {
                                                                                        $values = array();
                                                                                        foreach ($v['value']['args'] as $fieldDef) {
index 37e24c0..a4b5f47 100644 (file)
@@ -3,7 +3,7 @@
 ########################################################################
 # Extension Manager/Repository config file for ext "dbal".
 #
-# Auto generated 25-11-2009 22:58
+# Auto generated 29-11-2009 18:40
 #
 # Manual updates:
 # Only the data in the array - everything else is removed by next
@@ -32,8 +32,8 @@ $EM_CONF[$_EXTKEY] = array(
        'author_company' => '',
        'CGLcompliance' => '',
        'CGLcompliance_note' => '',
-       'version' => '1.0.1',
-       '_md5_values_when_last_written' => 'a:31:{s:9:"ChangeLog";s:4:"9325";s:26:"class.ux_db_list_extra.php";s:4:"7b9e";s:21:"class.ux_t3lib_db.php";s:4:"9317";s:28:"class.ux_t3lib_sqlparser.php";s:4:"e0b8";s:16:"ext_autoload.php";s:4:"821a";s:21:"ext_conf_template.txt";s:4:"f5cf";s:12:"ext_icon.gif";s:4:"c9ba";s:17:"ext_localconf.php";s:4:"5280";s:14:"ext_tables.php";s:4:"8414";s:14:"ext_tables.sql";s:4:"1f95";s:27:"doc/class.tslib_fe.php.diff";s:4:"0083";s:14:"doc/manual.sxw";s:4:"3d96";s:45:"handlers/class.tx_dbal_handler_openoffice.php";s:4:"d6c1";s:43:"handlers/class.tx_dbal_handler_rawmysql.php";s:4:"2f1b";s:40:"handlers/class.tx_dbal_handler_xmldb.php";s:4:"e363";s:31:"lib/class.tx_dbal_sqlengine.php";s:4:"66a9";s:33:"lib/class.tx_dbal_tsparserext.php";s:4:"ce12";s:14:"mod1/clear.gif";s:4:"cc11";s:13:"mod1/conf.php";s:4:"6e63";s:14:"mod1/index.php";s:4:"6944";s:18:"mod1/locallang.xml";s:4:"0b57";s:22:"mod1/locallang_mod.xml";s:4:"86ef";s:19:"mod1/moduleicon.gif";s:4:"2b8f";s:10:"res/README";s:4:"be19";s:43:"res/postgresql/postgresql-compatibility.sql";s:4:"5299";s:22:"tests/BaseTestCase.php";s:4:"8a4a";s:26:"tests/FakeDbConnection.php";s:4:"ed15";s:29:"tests/db_general_testcase.php";s:4:"aa70";s:28:"tests/db_oracle_testcase.php";s:4:"0b65";s:36:"tests/sqlparser_general_testcase.php";s:4:"7344";s:30:"tests/fixtures/oci8.config.php";s:4:"b932";}',
+       'version' => '1.0.2',
+       '_md5_values_when_last_written' => 'a:31:{s:9:"ChangeLog";s:4:"590a";s:26:"class.ux_db_list_extra.php";s:4:"7b9e";s:21:"class.ux_t3lib_db.php";s:4:"5057";s:28:"class.ux_t3lib_sqlparser.php";s:4:"d2cb";s:16:"ext_autoload.php";s:4:"821a";s:21:"ext_conf_template.txt";s:4:"f5cf";s:12:"ext_icon.gif";s:4:"c9ba";s:17:"ext_localconf.php";s:4:"5280";s:14:"ext_tables.php";s:4:"8414";s:14:"ext_tables.sql";s:4:"1f95";s:27:"doc/class.tslib_fe.php.diff";s:4:"0083";s:14:"doc/manual.sxw";s:4:"3d96";s:45:"handlers/class.tx_dbal_handler_openoffice.php";s:4:"d6c1";s:43:"handlers/class.tx_dbal_handler_rawmysql.php";s:4:"2f1b";s:40:"handlers/class.tx_dbal_handler_xmldb.php";s:4:"e363";s:31:"lib/class.tx_dbal_sqlengine.php";s:4:"66a9";s:33:"lib/class.tx_dbal_tsparserext.php";s:4:"ce12";s:14:"mod1/clear.gif";s:4:"cc11";s:13:"mod1/conf.php";s:4:"6e63";s:14:"mod1/index.php";s:4:"6944";s:18:"mod1/locallang.xml";s:4:"0b57";s:22:"mod1/locallang_mod.xml";s:4:"86ef";s:19:"mod1/moduleicon.gif";s:4:"2b8f";s:10:"res/README";s:4:"be19";s:43:"res/postgresql/postgresql-compatibility.sql";s:4:"5299";s:22:"tests/BaseTestCase.php";s:4:"8a4a";s:26:"tests/FakeDbConnection.php";s:4:"ed15";s:29:"tests/db_general_testcase.php";s:4:"aa70";s:28:"tests/db_oracle_testcase.php";s:4:"917f";s:36:"tests/sqlparser_general_testcase.php";s:4:"8e36";s:30:"tests/fixtures/oci8.config.php";s:4:"9ab9";}',
        'constraints' => array(
                'depends' => array(
                        'adodb' => '5.10.0-',
index 8411f3d..9190bb5 100644 (file)
@@ -1 +1 @@
-https://svn.typo3.org/TYPO3v4/Extensions/dbal/tags/1.0.1/
+https://svn.typo3.org/TYPO3v4/Extensions/dbal/tags/1.0.2/
index f10ae2b..b6e36d6 100644 (file)
@@ -125,6 +125,10 @@ class db_oracle_testcase extends BaseTestCase {
                }
        }
 
+       ///////////////////////////////////////
+       // Tests concerning quoting
+       ///////////////////////////////////////
+
        /**
         * @test
         */
@@ -172,6 +176,73 @@ class db_oracle_testcase extends BaseTestCase {
                $this->assertEquals($expected, $query);
        }
 
+       /** 
+        * @test
+        * @see http://bugs.typo3.org/view.php?id=6198
+        */
+       public function stringsWithinInClauseAreProperlyQuoted() {
+               $query = $this->cleanSql($GLOBALS['TYPO3_DB']->SELECTquery(
+                       'COUNT(DISTINCT tx_dam.uid) AS count',
+                       'tx_dam',
+                       'tx_dam.pid IN (1) AND tx_dam.file_type IN (\'gif\',\'png\',\'jpg\',\'jpeg\') AND tx_dam.deleted = 0'
+               ));
+               $expected = 'SELECT COUNT(DISTINCT "tx_dam"."uid") AS "count" FROM "tx_dam"';
+               $expected .= ' WHERE "tx_dam"."pid" IN (1) AND "tx_dam"."file_type" IN (\'gif\',\'png\',\'jpg\',\'jpeg\') AND "tx_dam"."deleted" = 0';
+               $this->assertEquals($expected, $query);
+       }
+
+       /**
+        * @test
+        * @see http://bugs.typo3.org/view.php?id=12515
+        * @remark Remapping is not expected here
+        */
+       public function concatAfterLikeOperatorIsProperlyQuoted() {
+               $query = $this->cleanSql($GLOBALS['TYPO3_DB']->SELECTquery(
+                       '*',
+                       'sys_refindex, tx_dam_file_tracking',
+                       'sys_refindex.tablename = \'tx_dam_file_tracking\''
+                       . ' AND sys_refindex.ref_string LIKE CONCAT(tx_dam_file_tracking.file_path, tx_dam_file_tracking.file_name)'
+               ));
+               $expected = 'SELECT * FROM "sys_refindex", "tx_dam_file_tracking" WHERE "sys_refindex"."tablename" = \'tx_dam_file_tracking\'';
+               $expected .= ' AND (dbms_lob.instr("sys_refindex"."ref_string", CONCAT("tx_dam_file_tracking"."file_path","tx_dam_file_tracking"."file_name"),1,1) > 0)';
+               $this->assertEquals($expected, $query);
+       }
+
+       /**
+        * @test
+        * @see http://bugs.typo3.org/view.php?id=12231
+        */
+       public function cachingFrameworkQueryIsProperlyQuoted() {
+               $currentTime = time();
+               $query = $this->cleanSql($GLOBALS['TYPO3_DB']->SELECTquery(
+                       'content',
+                       'cache_hash',
+                       'identifier = ' . $GLOBALS['TYPO3_DB']->fullQuoteStr('abbbabaf2d4b3f9a63e8dde781f1c106', 'cache_hash') .
+                               ' AND (crdate + lifetime >= ' . $currentTime . ' OR lifetime = 0)'
+               ));
+               $expected = 'SELECT "content" FROM "cache_hash" WHERE "identifier" = \'abbbabaf2d4b3f9a63e8dde781f1c106\' AND ("crdate"+"lifetime" >= ' . $currentTime . ' OR "lifetime" = 0)';
+               $this->assertEquals($expected, $query);
+       }
+
+       /**
+        * @test
+        * @see http://bugs.typo3.org/view.php?id=12231
+        */
+       public function calculatedFieldsAreProperlyQuoted() {
+               $currentTime = time();
+               $query = $this->cleanSql($GLOBALS['TYPO3_DB']->SELECTquery(
+                       'identifier',
+                       'cachingframework_cache_pages',
+                       'crdate + lifetime < ' . $currentTime . ' AND lifetime > 0'
+               ));
+               $expected = 'SELECT "identifier" FROM "cachingframework_cache_pages" WHERE "crdate"+"lifetime" < ' . $currentTime . ' AND "lifetime" > 0';
+               $this->assertEquals($expected, $query);
+       }
+
+       ///////////////////////////////////////
+       // Tests concerning remapping
+       ///////////////////////////////////////
+
        /**
         * @test
         * @see http://bugs.typo3.org/view.php?id=10411
@@ -194,21 +265,6 @@ class db_oracle_testcase extends BaseTestCase {
                $this->assertEquals($expected, $query);
        }
 
-       /** 
-        * @test
-        * @see http://bugs.typo3.org/view.php?id=6198
-        */
-       public function stringsWithinInClauseAreProperlyQuoted() {
-               $query = $this->cleanSql($GLOBALS['TYPO3_DB']->SELECTquery(
-                       'COUNT(DISTINCT tx_dam.uid) AS count',
-                       'tx_dam',
-                       'tx_dam.pid IN (1) AND tx_dam.file_type IN (\'gif\',\'png\',\'jpg\',\'jpeg\') AND tx_dam.deleted = 0'
-               ));
-               $expected = 'SELECT COUNT(DISTINCT "tx_dam"."uid") AS "count" FROM "tx_dam"';
-               $expected .= ' WHERE "tx_dam"."pid" IN (1) AND "tx_dam"."file_type" IN (\'gif\',\'png\',\'jpg\',\'jpeg\') AND "tx_dam"."deleted" = 0';
-               $this->assertEquals($expected, $query);
-       }
-
        /**
         * @test
         * @see http://bugs.typo3.org/view.php?id=6953
@@ -250,23 +306,6 @@ class db_oracle_testcase extends BaseTestCase {
        /**
         * @test
         * @see http://bugs.typo3.org/view.php?id=12515
-        * @remark Remapping is not expected here
-        */
-       public function concatAfterLikeOperatorIsProperlyQuoted() {
-               $query = $this->cleanSql($GLOBALS['TYPO3_DB']->SELECTquery(
-                       '*',
-                       'sys_refindex, tx_dam_file_tracking',
-                       'sys_refindex.tablename = \'tx_dam_file_tracking\''
-                       . ' AND sys_refindex.ref_string LIKE CONCAT(tx_dam_file_tracking.file_path, tx_dam_file_tracking.file_name)'
-               ));
-               $expected = 'SELECT * FROM "sys_refindex", "tx_dam_file_tracking" WHERE "sys_refindex"."tablename" = \'tx_dam_file_tracking\'';
-               $expected .= ' AND (dbms_lob.instr("sys_refindex"."ref_string", CONCAT("tx_dam_file_tracking"."file_path","tx_dam_file_tracking"."file_name"),1,1) > 0)';
-               $this->assertEquals($expected, $query);
-       }
-
-       /**
-        * @test
-        * @see http://bugs.typo3.org/view.php?id=12515
         * @remark Remapping is expected here
         */
        public function concatAfterLikeOperatorIsRemapped() {
@@ -287,6 +326,29 @@ class db_oracle_testcase extends BaseTestCase {
 
        /**
         * @test
+        * @see http://bugs.typo3.org/view.php?id=5708
+        */
+       public function fieldIsMappedOnRightSideOfAJoinCondition() {
+               $selectFields = 'cpg_categories.uid, cpg_categories.name';
+               $fromTables   = 'cpg_categories, pages';
+               $whereClause  = 'pages.uid = cpg_categories.pid AND pages.deleted = 0 AND 1 = 1';
+               $groupBy      = '';
+               $orderBy      = 'cpg_categories.pos';
+
+               $GLOBALS['TYPO3_DB']->_callRef('map_remapSELECTQueryParts', $selectFields, $fromTables, $whereClause, $groupBy, $orderBy);
+               $query = $this->cleanSql($GLOBALS['TYPO3_DB']->SELECTquery($selectFields, $fromTables, $whereClause, $groupBy, $orderBy));
+
+               $expected = 'SELECT "cpg_categories"."uid", "cpg_categories"."name" FROM "cpg_categories", "pages" WHERE "pages"."uid" = "cpg_categories"."page_id"';
+               $expected .= ' AND "pages"."deleted" = 0 AND 1 = 1 ORDER BY "cpg_categories"."pos"';
+               $this->assertEquals($expected, $query);
+       }
+
+       ///////////////////////////////////////
+       // Tests concerning DB management
+       ///////////////////////////////////////
+
+       /**
+        * @test
         * @see http://bugs.typo3.org/view.php?id=12670
         */
        public function notNullableColumnsWithDefaultEmptyStringAreCreatedAsNullable() {
@@ -372,22 +434,96 @@ class db_oracle_testcase extends BaseTestCase {
                $this->assertEquals($expected, $this->cleanSql($sqlCommands[0]));
        }
 
+       ///////////////////////////////////////
+       // Tests concerning subqueries
+       ///////////////////////////////////////
+
+       /**
+        * @test
+        * @see http://bugs.typo3.org/view.php?id=12758
+        */
+       public function inWhereClauseWithSubqueryIsProperlyQuoted() {
+               $query = $this->cleanSql($GLOBALS['TYPO3_DB']->SELECTquery(
+                       '*',
+                       'tx_crawler_queue',
+                       'process_id IN (SELECT process_id FROM tx_crawler_process WHERE active=0 AND deleted=0)'
+               ));
+               $expected = 'SELECT * FROM "tx_crawler_queue" WHERE "process_id" IN (SELECT "process_id" FROM "tx_crawler_process" WHERE "active" = 0 AND "deleted" = 0)';
+               $this->assertEquals($expected, $query);
+       }
+
        /**
         * @test
-        * @see http://bugs.typo3.org/view.php?id=5708
+        * @see http://bugs.typo3.org/view.php?id=12758
         */
-       public function fieldIsMappedOnRightSideOfAJoinCondition() {
-               $selectFields = 'cpg_categories.uid, cpg_categories.name';
-               $fromTables   = 'cpg_categories, pages';
-               $whereClause  = 'pages.uid = cpg_categories.pid AND pages.deleted = 0 AND 1 = 1';
+       public function subqueryIsRemappedForInWhereClause() {
+               $selectFields = '*';
+               $fromTables   = 'tx_crawler_queue';
+               $whereClause  = 'process_id IN (SELECT process_id FROM tx_crawler_process WHERE active=0 AND deleted=0)';
                $groupBy      = '';
-               $orderBy      = 'cpg_categories.pos';
+               $orderBy      = '';
 
                $GLOBALS['TYPO3_DB']->_callRef('map_remapSELECTQueryParts', $selectFields, $fromTables, $whereClause, $groupBy, $orderBy);
                $query = $this->cleanSql($GLOBALS['TYPO3_DB']->SELECTquery($selectFields, $fromTables, $whereClause, $groupBy, $orderBy));
 
-               $expected = 'SELECT "cpg_categories"."uid", "cpg_categories"."name" FROM "cpg_categories", "pages" WHERE "pages"."uid" = "cpg_categories"."page_id"';
-               $expected .= ' AND "pages"."deleted" = 0 AND 1 = 1 ORDER BY "cpg_categories"."pos"';
+               $expected = 'SELECT * FROM "tx_crawler_queue" WHERE "process_id" IN (SELECT "ps_id" FROM "tx_crawler_ps" WHERE "is_active" = 0 AND "deleted" = 0)';
+               $this->assertEquals($expected, $query);
+       }
+
+       /**
+        * @test
+        * @see http://bugs.typo3.org/view.php?id=12800
+        */
+       public function cachingFrameworkQueryIsSupported() {
+               $currentTime = time();
+               $query = $this->cleanSql($GLOBALS['TYPO3_DB']->DELETEquery(
+                       'cachingframework_cache_hash_tags',
+                       'identifier IN (' .
+                               $GLOBALS['TYPO3_DB']->SELECTsubquery(
+                                       'identifier',
+                                       'cachingframework_cache_pages',
+                                       'crdate + lifetime < ' . $currentTime . ' AND lifetime > 0'
+                               ) .
+                       ')'
+               ));
+               $expected = 'DELETE FROM "cachingframework_cache_hash_tags" WHERE "identifier" IN (';
+               $expected .= 'SELECT "identifier" FROM "cachingframework_cache_pages" WHERE "crdate"+"lifetime" < ' . $currentTime . ' AND "lifetime" > 0';
+               $expected .= ')';
+               $this->assertEquals($expected, $query);
+       }
+
+       /**
+        * @test
+        * @see http://bugs.typo3.org/view.php?id=12800
+        */
+       public function cachingFrameworkQueryIsRemapped() {
+               $currentTime = time();
+               $table = 'cachingframework_cache_hash_tags';
+               $where = 'identifier IN (' .
+                               $GLOBALS['TYPO3_DB']->SELECTsubquery(
+                                       'identifier',
+                                       'cachingframework_cache_pages',
+                                       'crdate + lifetime < ' . $currentTime . ' AND lifetime > 0'
+                               ) .
+                       ')';
+
+                       // Perform remapping (as in method exec_DELETEquery)
+               if ($tableArray = $GLOBALS['TYPO3_DB']->_call('map_needMapping', $table)) {
+                               // Where clause:
+                       $whereParts = $GLOBALS['TYPO3_DB']->SQLparser->parseWhereClause($where);
+                       $GLOBALS['TYPO3_DB']->_callRef('map_sqlParts', $whereParts, $tableArray[0]['table']);
+                       $where = $GLOBALS['TYPO3_DB']->SQLparser->compileWhereClause($whereParts, FALSE);
+
+                               // Table name:
+                       if ($GLOBALS['TYPO3_DB']->mapping[$table]['mapTableName']) {
+                               $table = $GLOBALS['TYPO3_DB']->mapping[$table]['mapTableName'];
+                       }
+               }
+               
+               $query = $this->cleanSql($GLOBALS['TYPO3_DB']->DELETEquery($table, $where));
+               $expected = 'DELETE FROM "cf_cache_hash_tags" WHERE "identifier" IN (';
+               $expected .= 'SELECT "identifier" FROM "cf_cache_pages" WHERE "crdate"+"lifetime" < ' . $currentTime . ' AND "lifetime" > 0';
+               $expected .= ')';
                $this->assertEquals($expected, $query);
        }
 }
index c9ece77..94e9f93 100644 (file)
@@ -24,6 +24,12 @@ $TYPO3_CONF_VARS['EXTCONF']['dbal']['mapping'] = array(
        'cachingframework_cache_hash' => array(
                'mapTableName' => 'cf_cache_hash',
        ),
+       'cachingframework_cache_hash_tags' => array(
+               'mapTableName' => 'cf_cache_hash_tags',
+       ),
+       'cachingframework_cache_pages' => array(
+               'mapTableName' => 'cf_cache_pages',
+       ),
        'cpg_categories' => array(
                'mapFieldNames' => array(
                        'pid' => 'page_id',
@@ -47,6 +53,13 @@ $TYPO3_CONF_VARS['EXTCONF']['dbal']['mapping'] = array(
                        'uid_local' => 'local_uid',
                ),
        ),
+       'tx_crawler_process' => array(
+               'mapTableName' => 'tx_crawler_ps',
+               'mapFieldNames' => array(
+                       'process_id' => 'ps_id',
+                       'active' => 'is_active',
+               ),
+       ),
        'tx_dam_file_tracking' => array(
                'mapFieldNames' => array(
                        'file_name' => 'filename',
index 48f9230..8c81455 100644 (file)
@@ -146,6 +146,32 @@ class sqlparser_general_testcase extends BaseTestCase {
        /**
         * @test
         */
+       public function parseWhereClauseReturnsArray() {
+               $parseString = 'uid IN (1,2) AND (starttime < ' . time() . ' OR cruser_id + 10 < 20)';
+               $where = $this->fixture->parseWhereClause($parseString);
+
+               $this->assertTrue(is_array($where), $where);
+               $this->assertTrue(empty($parseString), 'parseString is not empty');
+       }
+
+       /**
+        * @test
+        */
+       public function canSelectAllFieldsFromPages() {
+               $sql = 'SELECT * FROM pages';
+               $expected = $sql;
+               $actual = $this->cleanSql($this->fixture->debug_testSQL($sql)); 
+
+               $this->assertEquals($expected, $actual);
+       }
+
+       ///////////////////////////////////////
+       // Tests concerning JOINs
+       ///////////////////////////////////////
+
+       /**
+        * @test
+        */
        public function parseFromTablesWithInnerJoinReturnsArray() {
                $parseString = 'be_users INNER JOIN pages ON pages.cruser_id = be_users.uid';
                $tables = $this->fixture->parseFromTables($parseString);
@@ -203,28 +229,6 @@ class sqlparser_general_testcase extends BaseTestCase {
        /**
         * @test
         */
-       public function parseWhereClauseReturnsArray() {
-               $parseString = 'uid IN (1,2) AND (starttime < ' . time() . ' OR cruser_id + 10 < 20)';
-               $where = $this->fixture->parseWhereClause($parseString);
-
-               $this->assertTrue(is_array($where), $where);
-               $this->assertTrue(empty($parseString), 'parseString is not empty');
-       }
-
-       /**
-        * @test
-        */
-       public function canSelectAllFieldsFromPages() {
-               $sql = 'SELECT * FROM pages';
-               $expected = $sql;
-               $actual = $this->cleanSql($this->fixture->debug_testSQL($sql)); 
-
-               $this->assertEquals($expected, $actual);
-       }
-
-       /**
-        * @test
-        */
        public function canUseInnerJoinInSelect() {
                $sql = 'SELECT pages.uid, be_users.username FROM be_users INNER JOIN pages ON pages.cruser_id = be_users.uid';
                $expected = 'SELECT pages.uid, be_users.username FROM be_users INNER JOIN pages ON pages.cruser_id=be_users.uid';
@@ -244,6 +248,10 @@ class sqlparser_general_testcase extends BaseTestCase {
                $this->assertEquals($expected, $actual);
        }
 
+       ///////////////////////////////////////
+       // Tests concerning DB management
+       ///////////////////////////////////////
+
        /** 
         * @test
         * @see http://bugs.typo3.org/view.php?id=4466
@@ -271,5 +279,33 @@ class sqlparser_general_testcase extends BaseTestCase {
                $createTables = $this->fixture->_callRef('parseCREATETABLE', $parseString);
                $this->assertTrue(is_array($createTables), $createTables);
        }
+
+       ///////////////////////////////////////
+       // Tests concerning subqueries
+       ///////////////////////////////////////
+
+       /**
+        * @test
+        * @see http://bugs.typo3.org/view.php?id=12758
+        */
+       public function inWhereClauseSupportsSubquery() {
+               $parseString = 'process_id IN (SELECT process_id FROM tx_crawler_process WHERE active=0 AND deleted=0)';
+               $whereParts = $this->fixture->parseWhereClause($parseString);
+
+               $this->assertTrue(is_array($whereParts), $whereParts);
+               $this->assertTrue(empty($parseString), 'parseString is not empty');
+       }
+
+       /**
+        * @test
+        * @see http://bugs.typo3.org/view.php?id=12758
+        */
+       public function inWhereClauseWithSubqueryIsProperlyCompiled() {
+               $sql = 'SELECT * FROM tx_crawler_queue WHERE process_id IN (SELECT process_id FROM tx_crawler_process WHERE active=0 AND deleted=0)';
+               $expected = 'SELECT * FROM tx_crawler_queue WHERE process_id IN (SELECT process_id FROM tx_crawler_process WHERE active = 0 AND deleted = 0)';
+               $actual = $this->cleanSql($this->fixture->debug_testSQL($sql));
+
+               $this->assertEquals($expected, $actual);
+       }
 }
 ?>
\ No newline at end of file