* 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>
+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
*
* (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
*
**************************************/
+ /**
+ * 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!
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']);
}
}
- return $this->SQLparser->compileFieldList($select_fields);
+ return $select_fields;
}
/**
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'] != '') {
}
}
}
- return $this->SQLparser->compileFromTables($from_table);
+
+ return $from_table;
}
/**
* @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'])) {
}
} 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]);
+ }
}
}
}
}
}
+ // 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])) {
*
* (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
*
* @author Kasper Skaarhoj <kasperYYYY@typo3.com>
* @author Karsten Dambekalns <k.dambekalns@fishfarm.de>
+ * @author Xavier Perseguers <typo3@perseguers.ch>
*/
$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":
// 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']);
// 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:
// 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) {
// 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) {
########################################################################
# 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
'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-',
-https://svn.typo3.org/TYPO3v4/Extensions/dbal/tags/1.0.1/
+https://svn.typo3.org/TYPO3v4/Extensions/dbal/tags/1.0.2/
}
}
+ ///////////////////////////////////////
+ // Tests concerning quoting
+ ///////////////////////////////////////
+
/**
* @test
*/
$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
$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
$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=12515
$this->assertEquals($expected, $query);
}
+ /**
+ * @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
$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);
}
}
'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',
'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',
$this->assertEquals($expected, $values);
}
+ /**
+ * @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
*/
$this->assertTrue(empty($parseString), 'parseString is not empty');
}
- /**
- * @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
*/
$this->assertEquals($expected, $actual);
}
+ ///////////////////////////////////////
+ // Tests concerning DB management
+ ///////////////////////////////////////
+
/**
* @test
* @see http://bugs.typo3.org/view.php?id=4466
$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