Fixed bug #6196: IFNULL operator cannot be parsed
[Packages/TYPO3.CMS.git] / typo3 / sysext / dbal / class.ux_t3lib_db.php
index 7888984..2b112c6 100644 (file)
@@ -4,6 +4,7 @@
 *
 *  (c) 2004-2009 Kasper Skaarhoj (kasperYYYY@typo3.com)
 *  (c) 2004-2009 Karsten Dambekalns <karsten@typo3.org>
+*  (c) 2009-2010 Xavier Perseguers <typo3@perseguers.ch>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -220,7 +221,7 @@ class ux_t3lib_DB extends t3lib_DB {
         * 
         * @return void
         */
-       protected function cacheFieldInfo() {
+       public function cacheFieldInfo() {
                $extSQL = '';
                $parsedExtSQL = array();
 
@@ -489,6 +490,32 @@ class ux_t3lib_DB extends t3lib_DB {
        }
 
        /**
+        * Creates and executes an INSERT SQL-statement for $table with multiple rows.
+        * This method uses exec_INSERTquery() and is just a syntax wrapper to it.
+        *
+        * @param       string          Table name
+        * @param       array           Field names
+        * @param       array           Table rows. Each row should be an array with field values mapping to $fields
+        * @param       string/array            See fullQuoteArray()
+        * @return      mixed           Result from last handler, usually TRUE when success and FALSE on failure
+        */
+       public function exec_INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE) {
+               if ((string)$this->handlerCfg[$this->lastHandlerKey]['type'] === 'native') {
+                       return parent::exec_INSERTmultipleRows($table, $fields, $rows, $no_quote_fields);
+               }
+
+               foreach ($rows as $row) {
+                       $fields_values = array();
+                       foreach ($fields as $key => $value) {
+                               $fields_values[$value] = $row[$key];
+                       }
+                       $res = $this->exec_INSERTquery($table, $fields_values, $no_quote_fields);
+               }
+
+               return $res;
+       }
+
+       /**
         * Updates a record from $table
         *
         * @param       string          Database tablename
@@ -726,6 +753,117 @@ class ux_t3lib_DB extends t3lib_DB {
                return $sqlResult;
        }
 
+       /**
+        * Truncates a table.
+        * 
+        * @param       string          Database tablename
+        * @return      mixed           Result from handler
+        */
+       public function exec_TRUNCATEquery($table) {
+               if ($this->debug) {
+                       $pt = t3lib_div::milliseconds();
+               }
+
+                       // Do table/field mapping:
+               $ORIG_tableName = $table;
+               if ($tableArray = $this->map_needMapping($table)) {
+                               // Table name:
+                       if ($this->mapping[$table]['mapTableName']) {
+                               $table = $this->mapping[$table]['mapTableName'];
+                       }
+               }
+
+                       // Select API
+               $this->lastHandlerKey = $this->handler_getFromTableList($ORIG_tableName);
+               switch ((string)$this->handlerCfg[$this->lastHandlerKey]['type']) {
+                       case 'native':
+                               $this->lastQuery = $this->TRUNCATEquery($table);
+                               $sqlResult = mysql_query($this->lastQuery, $this->handlerInstance[$this->lastHandlerKey]['link']);
+                               break;
+                       case 'adodb':
+                               $this->lastQuery = $this->TRUNCATEquery($table);
+                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->_query($this->lastQuery, FALSE);
+                               break;
+                       case 'userdefined':
+                               $sqlResult = $this->handlerInstance[$this->lastHandlerKey]->exec_TRUNCATEquery($table,$where);
+                               break;
+               }
+
+               if ($this->printErrors && $this->sql_error()) {
+                       debug(array($this->lastQuery, $this->sql_error()));
+               }
+
+               if ($this->debug) {
+                       $this->debugHandler(
+                               'exec_TRUNCATEquery',
+                               t3lib_div::milliseconds() - $pt,
+                               array(
+                                       'handlerType' => $hType,
+                                       'args' => array($table),
+                                       'ORIG_from_table' => $ORIG_tableName
+                               )
+                       );
+               }
+
+                       // Return result:
+               return $sqlResult;
+       }
+
+       /**
+        * Executes a query.
+        * EXPERIMENTAL since TYPO3 4.4.
+        * 
+        * @param array $queryParts SQL parsed by method parseSQL() of t3lib_sqlparser
+        * @return pointer Result pointer / DBAL object
+        * @see ux_t3lib_db::sql_query()
+        */
+       protected function exec_query(array $queryParts) {
+               switch ($queryParts['type']) {
+                       case 'SELECT':
+                               $selectFields = $this->SQLparser->compileFieldList($queryParts['SELECT']);
+                               $fromTables = $this->SQLparser->compileFromTables($queryParts['FROM']);
+                               $whereClause = isset($queryParts['WHERE']) ? $this->SQLparser->compileWhereClause($queryParts['WHERE']) : '1=1';
+                               $groupBy = isset($queryParts['GROUPBY']) ? $this->SQLparser->compileWhereClause($queryParts['GROUPBY']) : '';
+                               $orderBy = isset($queryParts['GROUPBY']) ? $this->SQLparser->compileWhereClause($queryParts['ORDERBY']) : '';
+                               $limit = isset($queryParts['LIMIT']) ? $this->SQLparser->compileWhereClause($queryParts['LIMIT']) : '';
+                               return $this->exec_SELECTquery($selectFields, $fromTables, $whereClause, $groupBy, $orderBy, $limit);
+
+                       case 'UPDATE':
+                               $table = $queryParts['TABLE'];
+                               $fields = array();
+                               foreach ($components['FIELDS'] as $fN => $fV) {
+                                       $fields[$fN] = $fV[0];
+                               }
+                               $whereClause = isset($queryParts['WHERE']) ? $this->SQLparser->compileWhereClause($queryParts['WHERE']) : '1=1';
+                               return $this->exec_UPDATEquery($table, $whereClause, $fields);
+
+                       case 'INSERT':
+                               $table = $queryParts['TABLE'];
+                               $values = array();
+                               if (isset($queryParts['VALUES_ONLY']) && is_array($queryParts['VALUES_ONLY'])) {
+                                       $fields = $GLOBALS['TYPO3_DB']->cache_fieldType[$table];
+                                       $fc = 0;
+                                       foreach ($fields as $fn => $fd) {
+                                               $values[$fn] = $queryParts['VALUES_ONLY'][$fc++][0];
+                                       }
+                               } else {
+                                       foreach ($queryParts['FIELDS'] as $fN => $fV) {
+                                               $values[$fN] = $fV[0];
+                                       }
+                               }
+                               return $this->exec_INSERTquery($table, $values);
+                               
+                       case 'DELETE':
+                               $table = $queryParts['TABLE'];
+                               $whereClause = isset($queryParts['WHERE']) ? $this->SQLparser->compileWhereClause($queryParts['WHERE']) : '1=1';
+                               return $this->exec_DELETEquery($table, $whereClause);
+
+                       case 'TRUNCATETABLE':
+                               $table = $queryParts['TABLE'];
+                               return $this->exec_TRUNCATEquery($table);
+               }
+       }
+
 
 
        /**************************************
@@ -766,7 +904,11 @@ class ux_t3lib_DB extends t3lib_DB {
                                                // Add slashes old-school:
                                                // cast numerical values
                                        $mt = $this->sql_field_metatype($table, $k);
-                                       $v = (($mt{0} == 'I') || ($mt{0} == 'F')) ? (int)$v : $v;
+                                       if ($mt{0} == 'I') {
+                                               $v = (int)$v;
+                                       } else if ($mt{0} == 'F') {
+                                               $v = (double)$v;
+                                       }
 
                                        $nArr[$this->quoteFieldNames($k)] = (!in_array($k,$no_quote_fields)) ? $this->fullQuoteStr($v, $table) : $v;
                                }
@@ -804,6 +946,39 @@ class ux_t3lib_DB extends t3lib_DB {
        }
 
        /**
+        * Creates an INSERT SQL-statement for $table with multiple rows.
+        * This method will create multiple INSERT queries concatenated with ';'
+        *
+        * @param       string          Table name
+        * @param       array           Field names
+        * @param       array           Table rows. Each row should be an array with field values mapping to $fields
+        * @param       string/array            See fullQuoteArray()
+        * @return      array           Full SQL query for INSERT as array of strings (unless $fields_values does not contain any elements in which case it will be FALSE). If BLOB fields will be affected and one is not running the native type, an array will be returned for each row, where 0 => plain SQL, 1 => fieldname/value pairs of BLOB fields.
+        */
+       public function INSERTmultipleRows($table, array $fields, array $rows, $no_quote_fields = FALSE) {
+               if ((string)$this->handlerCfg[$this->lastHandlerKey]['type'] === 'native') {
+                       return parent::INSERTmultipleRows($table, $fields, $rows, $no_quote_fields);
+               }
+
+               $result = array();
+
+               foreach ($rows as $row) {
+                       $fields_values = array();
+                       foreach ($fields as $key => $value) {
+                               $fields_values[$value] = $row[$key];
+                       }
+                       $rowQuery = $this->INSERTquery($table, $fields_values, $no_quote_fields);
+                       if (is_array($rowQuery)) {
+                               $result[] = $rowQuery;
+                       } else {
+                               $result[][0] = $rowQuery;
+                       }
+               }
+
+               return $result;
+       }
+
+       /**
         * Creates an UPDATE SQL-statement for $table where $where-clause (typ. 'uid=...') from the array with field/value pairs $fields_values.
         * Usage count/core: 6
         *
@@ -837,7 +1012,11 @@ class ux_t3lib_DB extends t3lib_DB {
                                                        // Add slashes old-school:
                                                        // cast numeric values
                                                $mt = $this->sql_field_metatype($table, $k);
-                                               $v = (($mt{0} == 'I') || ($mt{0} == 'F')) ? (int)$v : $v;
+                                               if ($mt{0} == 'I') {
+                                                       $v = (int)$v;
+                                               } else if ($mt{0} == 'F') {
+                                                       $v = (double)$v;
+                                               }
                                                $nArr[] = $this->quoteFieldNames($k) . '=' . ((!in_array($k, $no_quote_fields)) ? $this->fullQuoteStr($v, $table) : $v);
                                        }
                                }
@@ -923,6 +1102,25 @@ class ux_t3lib_DB extends t3lib_DB {
                return $query;
        }
 
+       /**
+        * Creates a TRUNCATE TABLE SQL-statement
+        * 
+        * @param       string          See exec_TRUNCATEquery()
+        * @return      string          Full SQL query for TRUNCATE TABLE
+        */
+       public function TRUNCATEquery($table) {
+               $table = $this->quoteFromTables($table);
+
+                       // Call parent method to build actual query
+               $query = parent::TRUNCATEquery($table);
+
+               if ($this->debugOutput || $this->store_lastBuiltQuery) {
+                       $this->debug_lastBuiltQuery = $query;
+               }
+
+               return $query;
+       }
+
 
        /**************************************
        *
@@ -931,6 +1129,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!
         *
@@ -953,11 +1164,27 @@ class ux_t3lib_DB extends t3lib_DB {
                if ($this->runningNative()) return $select_fields;
 
                $select_fields = $this->SQLparser->parseFieldList($select_fields);
+               if ($this->SQLparser->parse_error) {
+                       die($this->SQLparser->parse_error . ' in ' . __FILE__ . ' : ' . __LINE__);
+               }
+               $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'] != '*') {
+                       if ($select_fields[$k]['field'] != '' && $select_fields[$k]['field'] != '*' && !is_numeric($select_fields[$k]['field'])) {
                                $select_fields[$k]['field'] = $this->quoteName($select_fields[$k]['field']);
                        }
-                       if ($select_fields[$k]['table'] != '') {
+                       if ($select_fields[$k]['table'] != '' && !is_numeric($select_fields[$k]['table'])) {
                                $select_fields[$k]['table'] = $this->quoteName($select_fields[$k]['table']);
                        }
                        if ($select_fields[$k]['as'] != '') {
@@ -967,9 +1194,20 @@ class ux_t3lib_DB extends t3lib_DB {
                                $select_fields[$k]['func_content.'][0]['func_content'] = $this->quoteFieldNames($select_fields[$k]['func_content.'][0]['func_content']);
                                $select_fields[$k]['func_content'] = $this->quoteFieldNames($select_fields[$k]['func_content']);
                        }
+                       if (isset($select_fields[$k]['flow-control'])) {
+                                       // Quoting flow-control statements
+                               if ($select_fields[$k]['flow-control']['type'] === 'CASE') {
+                                       if (isset($select_fields[$k]['flow-control']['case_field'])) {
+                                               $select_fields[$k]['flow-control']['case_field'] = $this->quoteFieldNames($select_fields[$k]['flow-control']['case_field']);
+                                       }
+                                       foreach ($select_fields[$k]['flow-control']['when'] as $key => $when) {
+                                               $select_fields[$k]['flow-control']['when'][$key]['when_value'] = $this->_quoteWhereClause($when['when_value']);
+                                       } 
+                               }
+                       }
                }
 
-               return $this->SQLparser->compileFieldList($select_fields);
+               return $select_fields;
        }
 
        /**
@@ -983,6 +1221,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'] != '') {
@@ -999,7 +1249,8 @@ class ux_t3lib_DB extends t3lib_DB {
                                }
                        }
                }
-               return $this->SQLparser->compileFromTables($from_table);
+
+               return $from_table;
        }
 
        /**
@@ -1029,11 +1280,26 @@ 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'])) {
                                $where_clause[$k]['sub'] = $this->_quoteWhereClause($where_clause[$k]['sub']);
+                       } elseif (isset($v['func'])) {
+                               switch ($where_clause[$k]['func']['type']) {
+                                       case 'EXISTS':
+                                               $where_clause[$k]['func']['subquery'] = $this->quoteSELECTsubquery($v['func']['subquery']);
+                                               break;
+                                       case 'IFNULL':
+                                       case 'LOCATE':
+                                               if ($where_clause[$k]['func']['table'] != '') {
+                                                       $where_clause[$k]['func']['table'] = $this->quoteName($v['func']['table']);
+                                               }
+                                               if ($where_clause[$k]['func']['field'] != '') {
+                                                       $where_clause[$k]['func']['field'] = $this->quoteName($v['func']['field']);
+                                               }
+                                       break;
+                               }
                        } else {
                                if ($where_clause[$k]['table'] != '') {
                                        $where_clause[$k]['table'] = $this->quoteName($where_clause[$k]['table']);
@@ -1058,8 +1324,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]);
+                                               }
                                        }
                                }
                        }
@@ -1625,7 +1897,7 @@ class ux_t3lib_DB extends t3lib_DB {
        /**********
        *
        * Legacy functions, bound to _DEFAULT handler. (Overriding parent methods)
-       * Deprecated.
+       * Deprecated or still experimental.
        *
        **********/
 
@@ -1643,16 +1915,26 @@ class ux_t3lib_DB extends t3lib_DB {
        }
 
        /**
-        * Executes query (on DEFAULT handler!)
-        * DEPRECATED - use exec_* functions from this class instead!
+        * Executes a query
+        * EXPERIMENTAL - This method will make its best to handle the query correctly
+        * but if it cannot, it will simply pass the query to DEFAULT handler.
         *
-        * If you don't, anything that uses not the _DEFAULT handler will break!
+        * You should use exec_* function from this class instead!
+        * If you don't, anything that does not use the _DEFAULT handler will probably break!
+        * 
+        * This method was deprecated in TYPO3 4.1 but is considered experimental since TYPO3 4.4
+        * as it tries to handle the query correctly anyway.
         *
         * @param       string          Query to execute
         * @return      pointer         Result pointer / DBAL object
-        * @deprecated since TYPO3 4.1
         */
        public function sql_query($query) {
+                       // This method is heavily used by Extbase, try to handle it with DBAL-native methods
+               $queryParts = $this->SQLparser->parseSQL($query);
+               if (is_array($queryParts) && t3lib_div::inList('SELECT,UPDATE,INSERT,DELETE', $queryParts['type'])) {
+                       return $this->exec_query($queryParts);
+               }
+
                switch ($this->handlerCfg['_DEFAULT']['type']) {
                        case 'native':
                                $sqlResult = mysql_query($query, $this->handlerInstance['_DEFAULT']['link']);
@@ -2039,6 +2321,7 @@ class ux_t3lib_DB extends t3lib_DB {
                                        $this->map_genericQueryParsed($parsedQuery);
                                        break;
                                case 'INSERT':
+                               case 'TRUNCATETABLE':
                                        $this->map_genericQueryParsed($parsedQuery);
                                        break;
                                case 'CREATEDATABASE':
@@ -2067,8 +2350,11 @@ class ux_t3lib_DB extends t3lib_DB {
                                case 'adodb':
                                                // Compiling query:
                                        $compiledQuery =  $this->SQLparser->compileSQL($this->lastParsedAndMappedQueryArray);
-                                       if ($this->lastParsedAndMappedQueryArray['type']=='INSERT') {
-                                               return $this->exec_INSERTquery($this->lastParsedAndMappedQueryArray['TABLE'],$compiledQuery);
+                                       switch ($this->lastParsedAndMappedQueryArray['type']) {
+                                               case 'INSERT':
+                                                       return $this->exec_INSERTquery($this->lastParsedAndMappedQueryArray['TABLE'], $compiledQuery);
+                                               case 'TRUNCATETABLE':
+                                                       return $this->exec_TRUNCATEquery($this->lastParsedAndMappedQueryArray['TABLE']);
                                        }
                                        return $this->handlerInstance[$this->lastHandlerKey]->DataDictionary->ExecuteSQLArray($compiledQuery);
                                        break;
@@ -2442,7 +2728,7 @@ class ux_t3lib_DB extends t3lib_DB {
                        // Select fields:
                $expFields = $this->SQLparser->parseFieldList($select_fields);
                $this->map_sqlParts($expFields,$defaultTable);
-               $select_fields = $this->SQLparser->compileFieldList($expFields);
+               $select_fields = $this->SQLparser->compileFieldList($expFields, FALSE, FALSE);
 
                        // Group By fields
                $expFields = $this->SQLparser->parseFieldList($groupBy);
@@ -2469,15 +2755,69 @@ class ux_t3lib_DB extends t3lib_DB {
                if (is_array($sqlPartArray)) {
                        foreach ($sqlPartArray as $k => $v) {
 
+                               if (isset($sqlPartArray[$k]['type'])) {
+                                       switch ($sqlPartArray[$k]['type']) {
+                                               case 'flow-control':
+                                                       $temp = array($sqlPartArray[$k]['flow-control']);
+                                                       $this->map_sqlParts($temp, $defaultTable);      // Call recursively!
+                                                       $sqlPartArray[$k]['flow-control'] = $temp[0];
+                                                       break;
+                                               case 'CASE':
+                                                       if (isset($sqlPartArray[$k]['case_field'])) {
+                                                               $fieldArray = explode('.', $sqlPartArray[$k]['case_field']);
+                                                               if (count($fieldArray) == 1 && is_array($this->mapping[$defaultTable]['mapFieldNames']) && isset($this->mapping[$defaultTable]['mapFieldNames'][$fieldArray[0]])) {
+                                                                       $sqlPartArray[$k]['case_field'] = $this->mapping[$defaultTable]['mapFieldNames'][$fieldArray[0]];
+                                                               }
+                                                               elseif (count($fieldArray) == 2) {
+                                                                               // Map the external table
+                                                                       $table = $fieldArray[0];
+                                                                       if (isset($this->mapping[$fieldArray[0]]['mapTableName'])) {
+                                                                               $table = $this->mapping[$fieldArray[0]]['mapTableName'];
+                                                                       }
+                                                                               // Map the field itself
+                                                                       $field = $fieldArray[1];
+                                                                       if (is_array($this->mapping[$fieldArray[0]]['mapFieldNames']) && isset($this->mapping[$fieldArray[0]]['mapFieldNames'][$fieldArray[1]])) {
+                                                                               $field = $this->mapping[$fieldArray[0]]['mapFieldNames'][$fieldArray[1]];
+                                                                       }
+                                                                       $sqlPartArray[$k]['case_field'] = $table . '.' . $field;
+                                                               }
+                                                       }
+                                                       foreach ($sqlPartArray[$k]['when'] as $key => $when) {
+                                                               $this->map_sqlParts($sqlPartArray[$k]['when'][$key]['when_value'], $defaultTable);
+                                                       }
+                                                       break;
+                                       }
+                               }
+
                                        // Look for sublevel (WHERE parts only)
                                if (is_array($sqlPartArray[$k]['sub'])) {
                                        $this->map_sqlParts($sqlPartArray[$k]['sub'], $defaultTable);   // Call recursively!
+                               } elseif (isset($sqlPartArray[$k]['func'])) {
+                                       switch ($sqlPartArray[$k]['func']['type']) {
+                                               case 'EXISTS':
+                                                       $subqueryDefaultTable = $sqlPartArray[$k]['func']['subquery']['FROM'][0]['table'];
+                                                       $this->map_sqlParts($sqlPartArray[$k]['func']['subquery']['SELECT'], $subqueryDefaultTable);
+                                                       $this->map_sqlParts($sqlPartArray[$k]['func']['subquery']['FROM'], $subqueryDefaultTable);
+                                                       $this->map_sqlParts($sqlPartArray[$k]['func']['subquery']['WHERE'], $subqueryDefaultTable);
+                                                       break;
+                                               case 'IFNULL':
+                                               case 'LOCATE':
+                                                               // For the field, look for table mapping (generic):
+                                                       $t = $sqlPartArray[$k]['func']['table'] ? $sqlPartArray[$k]['func']['table'] : $defaultTable;
+                                                       if (is_array($this->mapping[$t]['mapFieldNames']) && $this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['func']['field']]) {
+                                                               $sqlPartArray[$k]['func']['field'] = $this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['func']['field']];
+                                                       }
+                                                       if ($this->mapping[$t]['mapTableName']) {
+                                                               $sqlPartArray[$k]['func']['table'] = $this->mapping[$t]['mapTableName'];
+                                                       }
+                                                       break;
+                                       }
                                } else {
                                                // For the field, look for table mapping (generic):
                                        $t = $sqlPartArray[$k]['table'] ? $sqlPartArray[$k]['table'] : $defaultTable;
 
                                                // Mapping field name, if set:
-                                       if (is_array($this->mapping[$t]['mapFieldNames']) && $this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['field']]) {
+                                       if (is_array($this->mapping[$t]['mapFieldNames']) && isset($this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['field']])) {
                                                $sqlPartArray[$k]['field'] = $this->mapping[$t]['mapFieldNames'][$sqlPartArray[$k]['field']];
                                        }
 
@@ -2502,6 +2842,15 @@ class ux_t3lib_DB extends t3lib_DB {
                                                        $sqlPartArray[$k]['func_content.'][0]['func_content'] = $table . '.' . $field;
                                                        $sqlPartArray[$k]['func_content'] = $table . '.' . $field;
                                                }
+
+                                                       // Mapping flow-control statements
+                                               if (isset($sqlPartArray[$k]['flow-control'])) {                                                 
+                                                       if (isset($sqlPartArray[$k]['flow-control']['type'])) {
+                                                               $temp = array($sqlPartArray[$k]['flow-control']);
+                                                               $this->map_sqlParts($temp, $t); // Call recursively!
+                                                               $sqlPartArray[$k]['flow-control'] = $temp[0];
+                                                       }
+                                               }
                                        }
 
                                                // Do we have a function (e.g., CONCAT)
@@ -2516,6 +2865,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])) {